From 276680dc4d4acba5e5c3849b8caef3dd59fa1bd0 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Tue, 12 Sep 2023 15:13:22 -0500 Subject: [PATCH 01/34] bump version --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0131227..ed60b71b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) ## Establish project -project(anari VERSION 0.7.2 LANGUAGES C CXX) +project(anari VERSION 0.7.3 LANGUAGES C CXX) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) From cf04b36f46ad6a5b3651a3dddfd691b7bce1c615 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Tue, 12 Sep 2023 15:13:05 -0500 Subject: [PATCH 02/34] don't invoke library creation function when there's an error on load --- libs/anari/API.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/anari/API.cpp b/libs/anari/API.cpp index 5326edef..80ab549a 100644 --- a/libs/anari/API.cpp +++ b/libs/anari/API.cpp @@ -129,6 +129,7 @@ extern "C" ANARILibrary anariLoadLibrary(const char *libraryName, ANARI_LIBRARY, ANARI_SEVERITY_ERROR, ANARI_STATUS_INVALID_OPERATION); + return nullptr; } return newLibraryFcn(lib, statusCB, statusCBUserPtr); From 04a2cb7ead089368563819f008232e0d93706f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20G=C3=BCnther?= Date: Wed, 13 Sep 2023 19:40:46 +0200 Subject: [PATCH 03/34] Fix extension query in CTS --- cts/src/anariWrapper.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cts/src/anariWrapper.cpp b/cts/src/anariWrapper.cpp index a0175348..3572020f 100644 --- a/cts/src/anariWrapper.cpp +++ b/cts/src/anariWrapper.cpp @@ -72,15 +72,12 @@ std::vector> queryExtensions( deviceName = *devices; } - anari::Device d = anariNewDevice(lib, deviceName.c_str()); - // query extension std::vector> result; ANARIExtensions extension; - if (anariGetObjectExtensionStruct( - &extension, d, ANARI_DEVICE, deviceName.c_str())) { - printf("WARNING: library didn't return feature list\n"); + if (anariGetDeviceExtensionStruct(&extension, lib, deviceName.c_str())) { + printf("WARNING: library didn't return extension list for device\n"); return result; } @@ -98,7 +95,6 @@ std::vector> queryExtensions( result.push_back({featureNames[i], test.vec[i]}); } - anari::release(d, d); anari::unloadLibrary(lib); return result; From 9b142e78d24c1ca2af317cd2dbac5bbf01dc8aef Mon Sep 17 00:00:00 2001 From: Stefan Zellmann Date: Sun, 17 Sep 2023 23:28:00 +0200 Subject: [PATCH 04/34] Add a light editor widget for HDRI lights --- libs/anari_viewer/CMakeLists.txt | 1 + libs/anari_viewer/HDRImage.cpp | 63 + libs/anari_viewer/HDRImage.h | 20 + libs/anari_viewer/external/tinyexr/tinyexr.h | 14977 +++++++++++++++++ libs/anari_viewer/windows/LightsEditor.cpp | 95 +- libs/anari_viewer/windows/LightsEditor.h | 6 +- 6 files changed, 15158 insertions(+), 4 deletions(-) create mode 100644 libs/anari_viewer/HDRImage.cpp create mode 100644 libs/anari_viewer/HDRImage.h create mode 100644 libs/anari_viewer/external/tinyexr/tinyexr.h diff --git a/libs/anari_viewer/CMakeLists.txt b/libs/anari_viewer/CMakeLists.txt index e2e7e75e..6329b6f9 100644 --- a/libs/anari_viewer/CMakeLists.txt +++ b/libs/anari_viewer/CMakeLists.txt @@ -18,6 +18,7 @@ INTERFACE ${CMAKE_CURRENT_LIST_DIR}/windows/Viewport.cpp ${CMAKE_CURRENT_LIST_DIR}/windows/Window.cpp ${CMAKE_CURRENT_LIST_DIR}/Application.cpp + ${CMAKE_CURRENT_LIST_DIR}/HDRImage.cpp ${CMAKE_CURRENT_LIST_DIR}/Orbit.cpp ${CMAKE_CURRENT_LIST_DIR}/ui_anari.cpp ) diff --git a/libs/anari_viewer/HDRImage.cpp b/libs/anari_viewer/HDRImage.cpp new file mode 100644 index 00000000..cbf04ce6 --- /dev/null +++ b/libs/anari_viewer/HDRImage.cpp @@ -0,0 +1,63 @@ +#include +#include + +#define STB_IMAGE_IMPLEMENTATION 1 +#define TINYEXR_IMPLEMENTATION 1 +#include "external/stb_image/stb_image.h" +#include "external/stb_image/stb_image_write.h" +#include "external/tinyexr/tinyexr.h" + +#include "HDRImage.h" + +namespace importers { + +bool HDRImage::load(std::string fileName) +{ + if (fileName.size() < 4) + return false; + + // check the extension + std::string extension = std::string(strrchr(fileName.c_str(), '.')); + std::transform(extension.data(), + extension.data() + extension.size(), + std::addressof(extension[0]), + [](unsigned char c) { return std::tolower(c); }); + + if (extension.compare(".hdr") != 0 && extension.compare(".exr") != 0) + return false; + + if (extension.compare(".hdr") == 0) { + int w, h, n; + float *imgData = stbi_loadf(fileName.c_str(), &w, &h, &n, STBI_rgb); + width = w; + height = h; + numComponents = n; + pixel.resize(w * h * n); + memcpy(pixel.data(), imgData, w * h * n * sizeof(float)); + stbi_image_free(imgData); + return width > 0 && height > 0 + && (numComponents == 3 || numComponents == 4); + } else { + int w, h, n; + float *imgData; + const char *err; + int ret = LoadEXR(&imgData, &w, &h, fileName.c_str(), &err); + if (ret != 0) { + printf("Error loading EXR: %s\n", err); + return false; + } + n = 4; + + width = w; + height = h; + numComponents = n; + pixel.resize(w * h * n); + memcpy(pixel.data(), imgData, w * h * n * sizeof(float)); + return width > 0 && height > 0 + && (numComponents == 3 || numComponents == 4); + } + + return false; +} + +} // namespace importers diff --git a/libs/anari_viewer/HDRImage.h b/libs/anari_viewer/HDRImage.h new file mode 100644 index 00000000..a7708f85 --- /dev/null +++ b/libs/anari_viewer/HDRImage.h @@ -0,0 +1,20 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +namespace importers { + +struct HDRImage +{ + bool load(std::string fileName); + + unsigned width; + unsigned height; + unsigned numComponents; + std::vector pixel; +}; + +} // namespace importers diff --git a/libs/anari_viewer/external/tinyexr/tinyexr.h b/libs/anari_viewer/external/tinyexr/tinyexr.h new file mode 100644 index 00000000..d5ec5394 --- /dev/null +++ b/libs/anari_viewer/external/tinyexr/tinyexr.h @@ -0,0 +1,14977 @@ +#ifndef TINYEXR_H_ +#define TINYEXR_H_ +/* +Copyright (c) 2014 - 2020, Syoyo Fujita and many contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Syoyo Fujita nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// TinyEXR contains some OpenEXR code, which is licensed under ------------ + +/////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2002, Industrial Light & Magic, a division of Lucas +// Digital Ltd. LLC +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Industrial Light & Magic nor the names of +// its contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////// + +// End of OpenEXR license ------------------------------------------------- + + +// +// +// Do this: +// #define TINYEXR_IMPLEMENTATION +// before you include this file in *one* C or C++ file to create the +// implementation. +// +// // i.e. it should look like this: +// #include ... +// #include ... +// #include ... +// #define TINYEXR_IMPLEMENTATION +// #include "tinyexr.h" +// +// + +#include // for size_t +#include // guess stdint.h is available(C99) + +#ifdef __cplusplus +extern "C" { +#endif + +// Use embedded miniz or not to decode ZIP format pixel. Linking with zlib +// required if this flas is 0. +#ifndef TINYEXR_USE_MINIZ +#define TINYEXR_USE_MINIZ (1) +#endif + +// Disable PIZ comporession when applying cpplint. +#ifndef TINYEXR_USE_PIZ +#define TINYEXR_USE_PIZ (1) +#endif + +#ifndef TINYEXR_USE_ZFP +#define TINYEXR_USE_ZFP (0) // TinyEXR extension. +// http://computation.llnl.gov/projects/floating-point-compression +#endif + +#ifndef TINYEXR_USE_THREAD +#define TINYEXR_USE_THREAD (0) // No threaded loading. +// http://computation.llnl.gov/projects/floating-point-compression +#endif + +#ifndef TINYEXR_USE_OPENMP +#ifdef _OPENMP +#define TINYEXR_USE_OPENMP (1) +#else +#define TINYEXR_USE_OPENMP (0) +#endif +#endif + +#define TINYEXR_SUCCESS (0) +#define TINYEXR_ERROR_INVALID_MAGIC_NUMBER (-1) +#define TINYEXR_ERROR_INVALID_EXR_VERSION (-2) +#define TINYEXR_ERROR_INVALID_ARGUMENT (-3) +#define TINYEXR_ERROR_INVALID_DATA (-4) +#define TINYEXR_ERROR_INVALID_FILE (-5) +#define TINYEXR_ERROR_INVALID_PARAMETER (-6) +#define TINYEXR_ERROR_CANT_OPEN_FILE (-7) +#define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-8) +#define TINYEXR_ERROR_INVALID_HEADER (-9) +#define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-10) +#define TINYEXR_ERROR_CANT_WRITE_FILE (-11) +#define TINYEXR_ERROR_SERIALZATION_FAILED (-12) +#define TINYEXR_ERROR_LAYER_NOT_FOUND (-13) + +// @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf } + +// pixel type: possible values are: UINT = 0 HALF = 1 FLOAT = 2 +#define TINYEXR_PIXELTYPE_UINT (0) +#define TINYEXR_PIXELTYPE_HALF (1) +#define TINYEXR_PIXELTYPE_FLOAT (2) + +#define TINYEXR_MAX_HEADER_ATTRIBUTES (1024) +#define TINYEXR_MAX_CUSTOM_ATTRIBUTES (128) + +#define TINYEXR_COMPRESSIONTYPE_NONE (0) +#define TINYEXR_COMPRESSIONTYPE_RLE (1) +#define TINYEXR_COMPRESSIONTYPE_ZIPS (2) +#define TINYEXR_COMPRESSIONTYPE_ZIP (3) +#define TINYEXR_COMPRESSIONTYPE_PIZ (4) +#define TINYEXR_COMPRESSIONTYPE_ZFP (128) // TinyEXR extension + +#define TINYEXR_ZFP_COMPRESSIONTYPE_RATE (0) +#define TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION (1) +#define TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY (2) + +#define TINYEXR_TILE_ONE_LEVEL (0) +#define TINYEXR_TILE_MIPMAP_LEVELS (1) +#define TINYEXR_TILE_RIPMAP_LEVELS (2) + +#define TINYEXR_TILE_ROUND_DOWN (0) +#define TINYEXR_TILE_ROUND_UP (1) + +typedef struct _EXRVersion { + int version; // this must be 2 + // tile format image; + // not zero for only a single-part "normal" tiled file (according to spec.) + int tiled; + int long_name; // long name attribute + // deep image(EXR 2.0); + // for a multi-part file, indicates that at least one part is of type deep* (according to spec.) + int non_image; + int multipart; // multi-part(EXR 2.0) +} EXRVersion; + +typedef struct _EXRAttribute { + char name[256]; // name and type are up to 255 chars long. + char type[256]; + unsigned char *value; // uint8_t* + int size; + int pad0; +} EXRAttribute; + +typedef struct _EXRChannelInfo { + char name[256]; // less than 255 bytes long + int pixel_type; + int x_sampling; + int y_sampling; + unsigned char p_linear; + unsigned char pad[3]; +} EXRChannelInfo; + +typedef struct _EXRTile { + int offset_x; + int offset_y; + int level_x; + int level_y; + + int width; // actual width in a tile. + int height; // actual height int a tile. + + unsigned char **images; // image[channels][pixels] +} EXRTile; + +typedef struct _EXRBox2i { + int min_x; + int min_y; + int max_x; + int max_y; +} EXRBox2i; + +typedef struct _EXRHeader { + float pixel_aspect_ratio; + int line_order; + EXRBox2i data_window; + EXRBox2i display_window; + float screen_window_center[2]; + float screen_window_width; + + int chunk_count; + + // Properties for tiled format(`tiledesc`). + int tiled; + int tile_size_x; + int tile_size_y; + int tile_level_mode; + int tile_rounding_mode; + + int long_name; + // for a single-part file, agree with the version field bit 11 + // for a multi-part file, it is consistent with the type of part + int non_image; + int multipart; + unsigned int header_len; + + // Custom attributes(exludes required attributes(e.g. `channels`, + // `compression`, etc) + int num_custom_attributes; + EXRAttribute *custom_attributes; // array of EXRAttribute. size = + // `num_custom_attributes`. + + EXRChannelInfo *channels; // [num_channels] + + int *pixel_types; // Loaded pixel type(TINYEXR_PIXELTYPE_*) of `images` for + // each channel. This is overwritten with `requested_pixel_types` when + // loading. + int num_channels; + + int compression_type; // compression type(TINYEXR_COMPRESSIONTYPE_*) + int *requested_pixel_types; // Filled initially by + // ParseEXRHeaderFrom(Meomory|File), then users + // can edit it(only valid for HALF pixel type + // channel) + // name attribute required for multipart files; + // must be unique and non empty (according to spec.); + // use EXRSetNameAttr for setting value; + // max 255 character allowed - excluding terminating zero + char name[256]; +} EXRHeader; + +typedef struct _EXRMultiPartHeader { + int num_headers; + EXRHeader *headers; + +} EXRMultiPartHeader; + +typedef struct _EXRImage { + EXRTile *tiles; // Tiled pixel data. The application must reconstruct image + // from tiles manually. NULL if scanline format. + struct _EXRImage* next_level; // NULL if scanline format or image is the last level. + int level_x; // x level index + int level_y; // y level index + + unsigned char **images; // image[channels][pixels]. NULL if tiled format. + + int width; + int height; + int num_channels; + + // Properties for tile format. + int num_tiles; + +} EXRImage; + +typedef struct _EXRMultiPartImage { + int num_images; + EXRImage *images; + +} EXRMultiPartImage; + +typedef struct _DeepImage { + const char **channel_names; + float ***image; // image[channels][scanlines][samples] + int **offset_table; // offset_table[scanline][offsets] + int num_channels; + int width; + int height; + int pad0; +} DeepImage; + +// @deprecated { For backward compatibility. Not recommended to use. } +// Loads single-frame OpenEXR image. Assume EXR image contains A(single channel +// alpha) or RGB(A) channels. +// Application must free image data as returned by `out_rgba` +// Result image format is: float x RGBA x width x hight +// Returns negative value and may set error string in `err` when there's an +// error +extern int LoadEXR(float **out_rgba, int *width, int *height, + const char *filename, const char **err); + +// Loads single-frame OpenEXR image by specifying layer name. Assume EXR image +// contains A(single channel alpha) or RGB(A) channels. Application must free +// image data as returned by `out_rgba` Result image format is: float x RGBA x +// width x hight Returns negative value and may set error string in `err` when +// there's an error When the specified layer name is not found in the EXR file, +// the function will return `TINYEXR_ERROR_LAYER_NOT_FOUND`. +extern int LoadEXRWithLayer(float **out_rgba, int *width, int *height, + const char *filename, const char *layer_name, + const char **err); + +// +// Get layer infos from EXR file. +// +// @param[out] layer_names List of layer names. Application must free memory +// after using this. +// @param[out] num_layers The number of layers +// @param[out] err Error string(will be filled when the function returns error +// code). Free it using FreeEXRErrorMessage after using this value. +// +// @return TINYEXR_SUCCEES upon success. +// +extern int EXRLayers(const char *filename, const char **layer_names[], + int *num_layers, const char **err); + +// @deprecated { to be removed. } +// Simple wrapper API for ParseEXRHeaderFromFile. +// checking given file is a EXR file(by just look up header) +// @return TINYEXR_SUCCEES for EXR image, TINYEXR_ERROR_INVALID_HEADER for +// others +extern int IsEXR(const char *filename); + +// @deprecated { to be removed. } +// Saves single-frame OpenEXR image. Assume EXR image contains RGB(A) channels. +// components must be 1(Grayscale), 3(RGB) or 4(RGBA). +// Input image format is: `float x width x height`, or `float x RGB(A) x width x +// hight` +// Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero +// value. +// Save image as fp32(FLOAT) format when `save_as_fp16` is 0. +// Use ZIP compression by default. +// Returns negative value and may set error string in `err` when there's an +// error +extern int SaveEXR(const float *data, const int width, const int height, + const int components, const int save_as_fp16, + const char *filename, const char **err); + +// Returns the number of resolution levels of the image (including the base) +extern int EXRNumLevels(const EXRImage* exr_image); + +// Initialize EXRHeader struct +extern void InitEXRHeader(EXRHeader *exr_header); + +// Set name attribute of EXRHeader struct (it makes a copy) +extern void EXRSetNameAttr(EXRHeader *exr_header, const char* name); + +// Initialize EXRImage struct +extern void InitEXRImage(EXRImage *exr_image); + +// Frees internal data of EXRHeader struct +extern int FreeEXRHeader(EXRHeader *exr_header); + +// Frees internal data of EXRImage struct +extern int FreeEXRImage(EXRImage *exr_image); + +// Frees error message +extern void FreeEXRErrorMessage(const char *msg); + +// Parse EXR version header of a file. +extern int ParseEXRVersionFromFile(EXRVersion *version, const char *filename); + +// Parse EXR version header from memory-mapped EXR data. +extern int ParseEXRVersionFromMemory(EXRVersion *version, + const unsigned char *memory, size_t size); + +// Parse single-part OpenEXR header from a file and initialize `EXRHeader`. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int ParseEXRHeaderFromFile(EXRHeader *header, const EXRVersion *version, + const char *filename, const char **err); + +// Parse single-part OpenEXR header from a memory and initialize `EXRHeader`. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int ParseEXRHeaderFromMemory(EXRHeader *header, + const EXRVersion *version, + const unsigned char *memory, size_t size, + const char **err); + +// Parse multi-part OpenEXR headers from a file and initialize `EXRHeader*` +// array. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers, + int *num_headers, + const EXRVersion *version, + const char *filename, + const char **err); + +// Parse multi-part OpenEXR headers from a memory and initialize `EXRHeader*` +// array +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers, + int *num_headers, + const EXRVersion *version, + const unsigned char *memory, + size_t size, const char **err); + +// Loads single-part OpenEXR image from a file. +// Application must setup `ParseEXRHeaderFromFile` before calling this function. +// Application can free EXRImage using `FreeEXRImage` +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header, + const char *filename, const char **err); + +// Loads single-part OpenEXR image from a memory. +// Application must setup `EXRHeader` with +// `ParseEXRHeaderFromMemory` before calling this function. +// Application can free EXRImage using `FreeEXRImage` +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header, + const unsigned char *memory, + const size_t size, const char **err); + +// Loads multi-part OpenEXR image from a file. +// Application must setup `ParseEXRMultipartHeaderFromFile` before calling this +// function. +// Application can free EXRImage using `FreeEXRImage` +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRMultipartImageFromFile(EXRImage *images, + const EXRHeader **headers, + unsigned int num_parts, + const char *filename, + const char **err); + +// Loads multi-part OpenEXR image from a memory. +// Application must setup `EXRHeader*` array with +// `ParseEXRMultipartHeaderFromMemory` before calling this function. +// Application can free EXRImage using `FreeEXRImage` +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRMultipartImageFromMemory(EXRImage *images, + const EXRHeader **headers, + unsigned int num_parts, + const unsigned char *memory, + const size_t size, const char **err); + +// Saves multi-channel, single-frame OpenEXR image to a file. +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int SaveEXRImageToFile(const EXRImage *image, + const EXRHeader *exr_header, const char *filename, + const char **err); + +// Saves multi-channel, single-frame OpenEXR image to a memory. +// Image is compressed using EXRImage.compression value. +// Return the number of bytes if success. +// Return zero and will set error string in `err` when there's an +// error. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern size_t SaveEXRImageToMemory(const EXRImage *image, + const EXRHeader *exr_header, + unsigned char **memory, const char **err); + +// Saves multi-channel, multi-frame OpenEXR image to a memory. +// Image is compressed using EXRImage.compression value. +// File global attributes (eg. display_window) must be set in the first header. +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int SaveEXRMultipartImageToFile(const EXRImage *images, + const EXRHeader **exr_headers, + unsigned int num_parts, + const char *filename, const char **err); + +// Saves multi-channel, multi-frame OpenEXR image to a memory. +// Image is compressed using EXRImage.compression value. +// File global attributes (eg. display_window) must be set in the first header. +// Return the number of bytes if success. +// Return zero and will set error string in `err` when there's an +// error. +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern size_t SaveEXRMultipartImageToMemory(const EXRImage *images, + const EXRHeader **exr_headers, + unsigned int num_parts, + unsigned char **memory, const char **err); +// Loads single-frame OpenEXR deep image. +// Application must free memory of variables in DeepImage(image, offset_table) +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadDeepEXR(DeepImage *out_image, const char *filename, + const char **err); + +// NOT YET IMPLEMENTED: +// Saves single-frame OpenEXR deep image. +// Returns negative value and may set error string in `err` when there's an +// error +// extern int SaveDeepEXR(const DeepImage *in_image, const char *filename, +// const char **err); + +// NOT YET IMPLEMENTED: +// Loads multi-part OpenEXR deep image. +// Application must free memory of variables in DeepImage(image, offset_table) +// extern int LoadMultiPartDeepEXR(DeepImage **out_image, int num_parts, const +// char *filename, +// const char **err); + +// For emscripten. +// Loads single-frame OpenEXR image from memory. Assume EXR image contains +// RGB(A) channels. +// Returns negative value and may set error string in `err` when there's an +// error +// When there was an error message, Application must free `err` with +// FreeEXRErrorMessage() +extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height, + const unsigned char *memory, size_t size, + const char **err); + +#ifdef __cplusplus +} +#endif + +#endif // TINYEXR_H_ + +#ifdef TINYEXR_IMPLEMENTATION +#ifndef TINYEXR_IMPLEMENTATION_DEFINED +#define TINYEXR_IMPLEMENTATION_DEFINED + +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include // for UTF-8 + +#endif + +#include +#include +#include +#include +#include +#include + +// #include // debug + +#include +#include +#include +#include + +// https://stackoverflow.com/questions/5047971/how-do-i-check-for-c11-support +#if __cplusplus > 199711L || (defined(_MSC_VER) && _MSC_VER >= 1900) +#define TINYEXR_HAS_CXX11 (1) +// C++11 +#include + +#if TINYEXR_USE_THREAD +#include +#include +#endif + +#endif // __cplusplus > 199711L + +#if TINYEXR_USE_OPENMP +#include +#endif + +#if TINYEXR_USE_MINIZ +#else +// Issue #46. Please include your own zlib-compatible API header before +// including `tinyexr.h` +//#include "zlib.h" +#endif + +#if TINYEXR_USE_ZFP + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Weverything" +#endif + +#include "zfp.h" + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +namespace tinyexr { + +#if __cplusplus > 199711L +// C++11 +typedef uint64_t tinyexr_uint64; +typedef int64_t tinyexr_int64; +#else +// Although `long long` is not a standard type pre C++11, assume it is defined +// as a compiler's extension. +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif +typedef unsigned long long tinyexr_uint64; +typedef long long tinyexr_int64; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +#endif + +#if TINYEXR_USE_MINIZ + +namespace miniz { + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wc++11-extensions" +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wunused-function" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#pragma clang diagnostic ignored "-Wundef" + +#if __has_warning("-Wcomma") +#pragma clang diagnostic ignored "-Wcomma" +#endif + +#if __has_warning("-Wmacro-redefined") +#pragma clang diagnostic ignored "-Wmacro-redefined" +#endif + +#if __has_warning("-Wcast-qual") +#pragma clang diagnostic ignored "-Wcast-qual" +#endif + +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#if __has_warning("-Wtautological-constant-compare") +#pragma clang diagnostic ignored "-Wtautological-constant-compare" +#endif + +#if __has_warning("-Wextra-semi-stmt") +#pragma clang diagnostic ignored "-Wextra-semi-stmt" +#endif + +#endif + +/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP + reading/writing/appending, PNG writing + See "unlicense" statement at the end of this file. + Rich Geldreich , last updated Oct. 13, 2013 + Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: + http://www.ietf.org/rfc/rfc1951.txt + + Most API's defined in miniz.c are optional. For example, to disable the + archive related functions just define + MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO + (see the list below for more macros). + + * Change History + 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major + release with Zip64 support (almost there!): + - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug + (thanks kahmyong.moon@hp.com) which could cause locate files to not find + files. This bug + would only have occurred in earlier versions if you explicitly used this + flag, OR if you used mz_zip_extract_archive_file_to_heap() or + mz_zip_add_mem_to_archive_file_in_place() + (which used this flag). If you can't switch to v1.15 but want to fix + this bug, just remove the uses of this flag from both helper funcs (and of + course don't use the flag). + - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when + pUser_read_buf is not NULL and compressed size is > uncompressed size + - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract + compressed data from directory entries, to account for weird zipfiles which + contain zero-size compressed data on dir entries. + Hopefully this fix won't cause any issues on weird zip archives, + because it assumes the low 16-bits of zip external attributes are DOS + attributes (which I believe they always are in practice). + - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the + internal attributes, just the filename and external attributes + - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed + - Added cmake support for Linux builds which builds all the examples, + tested with clang v3.3 and gcc v4.6. + - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti + - Merged MZ_FORCEINLINE fix from hdeanclark + - Fix include before config #ifdef, thanks emil.brink + - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping + (super useful for OpenGL apps), and explicit control over the compression + level (so you can + set it to 1 for real-time compression). + - Merged in some compiler fixes from paulharris's github repro. + - Retested this build under Windows (VS 2010, including static analysis), + tcc 0.9.26, gcc v4.6 and clang v3.3. + - Added example6.c, which dumps an image of the mandelbrot set to a PNG + file. + - Modified example2 to help test the + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more. + - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix + possible src file fclose() leak if alignment bytes+local header file write + faiiled + - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): + Was pushing the wrong central dir header offset, appears harmless in this + release, but it became a problem in the zip64 branch + 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, + #include (thanks fermtect). + 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix + mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. + - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and + re-ran a randomized regression test on ~500k files. + - Eliminated a bunch of warnings when compiling with GCC 32-bit/64. + - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze + (static analysis) option and fixed all warnings (except for the silly + "Use of the comma-operator in a tested expression.." analysis warning, + which I purposely use to work around a MSVC compiler warning). + - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and + tested Linux executables. The codeblocks workspace is compatible with + Linux+Win32/x64. + - Added miniz_tester solution/project, which is a useful little app + derived from LZHAM's tester app that I use as part of the regression test. + - Ran miniz.c and tinfl.c through another series of regression testing on + ~500,000 files and archives. + - Modified example5.c so it purposely disables a bunch of high-level + functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the + MINIZ_NO_STDIO bug report.) + - Fix ftell() usage in examples so they exit with an error on files which + are too large (a limitation of the examples, not miniz itself). + 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple + minor level_and_flags issues in the archive API's. + level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce + Dawson for the feedback/bug report. + 5/28/11 v1.11 - Added statement from unlicense.org + 5/27/11 v1.10 - Substantial compressor optimizations: + - Level 1 is now ~4x faster than before. The L1 compressor's throughput + now varies between 70-110MB/sec. on a + - Core i7 (actual throughput varies depending on the type of data, and x64 + vs. x86). + - Improved baseline L2-L9 compression perf. Also, greatly improved + compression perf. issues on some file types. + - Refactored the compression code for better readability and + maintainability. + - Added level 10 compression level (L10 has slightly better ratio than + level 9, but could have a potentially large + drop in throughput on some files). + 5/15/11 v1.09 - Initial stable release. + + * Low-level Deflate/Inflate implementation notes: + + Compression: Use the "tdefl" API's. The compressor supports raw, static, + and dynamic blocks, lazy or + greedy parsing, match length filtering, RLE-only, and Huffman-only streams. + It performs and compresses + approximately as well as zlib. + + Decompression: Use the "tinfl" API's. The entire decompressor is + implemented as a single function + coroutine: see tinfl_decompress(). It supports decompression into a 32KB + (or larger power of 2) wrapping buffer, or into a memory + block large enough to hold the entire file. + + The low-level tdefl/tinfl API's do not make any use of dynamic memory + allocation. + + * zlib-style API notes: + + miniz.c implements a fairly large subset of zlib. There's enough + functionality present for it to be a drop-in + zlib replacement in many apps: + The z_stream struct, optional memory allocation callbacks + deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound + inflateInit/inflateInit2/inflate/inflateEnd + compress, compress2, compressBound, uncompress + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly + routines. + Supports raw deflate streams or standard zlib streams with adler-32 + checking. + + Limitations: + The callback API's are not implemented yet. No support for gzip headers or + zlib static dictionaries. + I've tried to closely emulate zlib's various flavors of stream flushing + and return status codes, but + there are no guarantees that miniz.c pulls this off perfectly. + + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, + originally written by + Alex Evans. Supports 1-4 bytes/pixel images. + + * ZIP archive API notes: + + The ZIP archive API's where designed with simplicity and efficiency in + mind, with just enough abstraction to + get the job done with minimal fuss. There are simple API's to retrieve file + information, read files from + existing archives, create new archives, append new files to existing + archives, or clone archive data from + one archive to another. It supports archives located in memory or the heap, + on disk (using stdio.h), + or you can specify custom file read/write callbacks. + + - Archive reading: Just call this function to read a single file from a + disk archive: + + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const + char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + + For more complex cases, use the "mz_zip_reader" functions. Upon opening an + archive, the entire central + directory is located and read as-is into memory, and subsequent file access + only occurs when reading individual files. + + - Archives file scanning: The simple way is to use this function to scan a + loaded archive for a specific file: + + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, + const char *pComment, mz_uint flags); + + The locate operation can optionally check file comments too, which (as one + example) can be used to identify + multiple versions of the same file in an archive. This function uses a + simple linear search through the central + directory, so it's not very fast. + + Alternately, you can iterate through all the files in an archive (using + mz_zip_reader_get_num_files()) and + retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer + immediately writes compressed file data + to disk and builds an exact image of the central directory in memory. The + central directory image is written + all at once at the end of the archive file when the archive is finalized. + + The archive writer can optionally align each file's local header and file + data to any power of 2 alignment, + which can be useful when the archive will be read from optical media. Also, + the writer supports placing + arbitrary data blobs at the very beginning of ZIP archives. Archives + written using either feature are still + readable by any ZIP tool. + + - Archive appending: The simple way to add a single file to an archive is + to call this function: + + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, + const char *pArchive_name, + const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 + comment_size, mz_uint level_and_flags); + + The archive will be created if it doesn't already exist, otherwise it'll be + appended to. + Note the appending is done in-place and is not an atomic operation, so if + something goes wrong + during the operation it's possible the archive could be left without a + central directory (although the local + file headers and file data will be fine, so the archive will be + recoverable). + + For more complex archive modification scenarios: + 1. The safest way is to use a mz_zip_reader to read the existing archive, + cloning only those bits you want to + preserve into a new archive using using the + mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and + rename the newly written archive, and + you're done. This is safe but requires a bunch of temporary disk space or + heap memory. + + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using + mz_zip_writer_init_from_reader(), + append new files as needed, then finalize the archive which will write an + updated central directory to the + original archive. (This is basically what + mz_zip_add_mem_to_archive_file_in_place() does.) There's a + possibility that the archive's central directory could be lost with this + method if anything goes wrong, though. + + - ZIP archive support limitations: + No zip64 or spanning support. Extraction functions can only handle + unencrypted, stored or deflated files. + Requires streams capable of seeking. + + * This is a header file library, like stb_image.c. To get only a header file, + either cut and paste the + below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then + include miniz.c from it. + + * Important: For best perf. be sure to customize the below macros for your + target platform: + #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 + #define MINIZ_LITTLE_ENDIAN 1 + #define MINIZ_HAS_64BIT_REGISTERS 1 + + * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before + including miniz.c to ensure miniz + uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be + able to process large files + (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). +*/ + +#ifndef MINIZ_HEADER_INCLUDED +#define MINIZ_HEADER_INCLUDED + +//#include + +// Defines to completely disable specific portions of miniz.c: +// If all macros here are defined the only functionality remaining will be +// CRC-32, adler-32, tinfl, and tdefl. + +// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on +// stdio for file I/O. +//#define MINIZ_NO_STDIO + +// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able +// to get the current time, or +// get/set file times, and the C run-time funcs that get/set times won't be +// called. +// The current downside is the times written to your archives will be from 1979. +#define MINIZ_NO_TIME + +// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. +#define MINIZ_NO_ARCHIVE_APIS + +// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive +// API's. +//#define MINIZ_NO_ARCHIVE_WRITING_APIS + +// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression +// API's. +//#define MINIZ_NO_ZLIB_APIS + +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent +// conflicts against stock zlib. +//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. +// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom +// user alloc/free/realloc +// callbacks to the zlib and archive API's, and a few stand-alone helper API's +// which don't provide custom user +// functions (such as tdefl_compress_mem_to_heap() and +// tinfl_decompress_mem_to_heap()) won't work. +//#define MINIZ_NO_MALLOC + +#if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) +// TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc +// on Linux +#define MINIZ_NO_TIME +#endif + +#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) +//#include +#endif + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \ + defined(__i386) || defined(__i486__) || defined(__i486) || \ + defined(i386) || defined(__ia64__) || defined(__x86_64__) +// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. +#define MINIZ_X86_OR_X64_CPU 1 +#endif + +#if defined(__sparcv9) +// Big endian +#else +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#endif +#endif + +#if MINIZ_X86_OR_X64_CPU +// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient +// integer loads and stores from unaligned addresses. +//#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES \ + 0 // disable to suppress compiler warnings +#endif + +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || \ + defined(_LP64) || defined(__LP64__) || defined(__ia64__) || \ + defined(__x86_64__) +// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are +// reasonably fast (and don't involve compiler generated calls to helper +// functions). +#define MINIZ_HAS_64BIT_REGISTERS 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ------------------- zlib-style API Definitions. + +// For more compatibility with zlib, miniz.c uses unsigned long for some +// parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! +typedef unsigned long mz_ulong; + +// mz_free() internally uses the MZ_FREE() macro (which by default calls free() +// unless you've modified the MZ_MALLOC macro) to release a block allocated from +// the heap. +void mz_free(void *p); + +#define MZ_ADLER32_INIT (1) +// mz_adler32() returns the initial adler-32 value to use when called with +// ptr==NULL. +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); + +#define MZ_CRC32_INIT (0) +// mz_crc32() returns the initial CRC-32 value to use when called with +// ptr==NULL. +mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); + +// Compression strategies. +enum { + MZ_DEFAULT_STRATEGY = 0, + MZ_FILTERED = 1, + MZ_HUFFMAN_ONLY = 2, + MZ_RLE = 3, + MZ_FIXED = 4 +}; + +// Method +#define MZ_DEFLATED 8 + +#ifndef MINIZ_NO_ZLIB_APIS + +// Heap allocation callbacks. +// Note that mz_alloc_func parameter types purpsosely differ from zlib's: +// items/size is size_t, not unsigned long. +typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); +typedef void (*mz_free_func)(void *opaque, void *address); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, + size_t size); + +#define MZ_VERSION "9.1.15" +#define MZ_VERNUM 0x91F0 +#define MZ_VER_MAJOR 9 +#define MZ_VER_MINOR 1 +#define MZ_VER_REVISION 15 +#define MZ_VER_SUBREVISION 0 + +// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The +// other values are for advanced use (refer to the zlib docs). +enum { + MZ_NO_FLUSH = 0, + MZ_PARTIAL_FLUSH = 1, + MZ_SYNC_FLUSH = 2, + MZ_FULL_FLUSH = 3, + MZ_FINISH = 4, + MZ_BLOCK = 5 +}; + +// Return status codes. MZ_PARAM_ERROR is non-standard. +enum { + MZ_OK = 0, + MZ_STREAM_END = 1, + MZ_NEED_DICT = 2, + MZ_ERRNO = -1, + MZ_STREAM_ERROR = -2, + MZ_DATA_ERROR = -3, + MZ_MEM_ERROR = -4, + MZ_BUF_ERROR = -5, + MZ_VERSION_ERROR = -6, + MZ_PARAM_ERROR = -10000 +}; + +// Compression levels: 0-9 are the standard zlib-style levels, 10 is best +// possible compression (not zlib compatible, and may be very slow), +// MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. +enum { + MZ_NO_COMPRESSION = 0, + MZ_BEST_SPEED = 1, + MZ_BEST_COMPRESSION = 9, + MZ_UBER_COMPRESSION = 10, + MZ_DEFAULT_LEVEL = 6, + MZ_DEFAULT_COMPRESSION = -1 +}; + +// Window bits +#define MZ_DEFAULT_WINDOW_BITS 15 + +struct mz_internal_state; + +// Compression/decompression stream struct. +typedef struct mz_stream_s { + const unsigned char *next_in; // pointer to next byte to read + unsigned int avail_in; // number of bytes available at next_in + mz_ulong total_in; // total number of bytes consumed so far + + unsigned char *next_out; // pointer to next byte to write + unsigned int avail_out; // number of bytes that can be written to next_out + mz_ulong total_out; // total number of bytes produced so far + + char *msg; // error msg (unused) + struct mz_internal_state *state; // internal state, allocated by zalloc/zfree + + mz_alloc_func + zalloc; // optional heap allocation function (defaults to malloc) + mz_free_func zfree; // optional heap free function (defaults to free) + void *opaque; // heap alloc function user pointer + + int data_type; // data_type (unused) + mz_ulong adler; // adler32 of the source or uncompressed data + mz_ulong reserved; // not used +} mz_stream; + +typedef mz_stream *mz_streamp; + +// Returns the version string of miniz.c. +const char *mz_version(void); + +// mz_deflateInit() initializes a compressor with default options: +// Parameters: +// pStream must point to an initialized mz_stream struct. +// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. +// level 1 enables a specially optimized compression function that's been +// optimized purely for performance, not ratio. +// (This special func. is currently only enabled when +// MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if the input parameters are bogus. +// MZ_MEM_ERROR on out of memory. +int mz_deflateInit(mz_streamp pStream, int level); + +// mz_deflateInit2() is like mz_deflate(), except with more control: +// Additional parameters: +// method must be MZ_DEFLATED +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with +// zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no +// header or footer) +// mem_level must be between [1, 9] (it's checked but ignored by miniz.c) +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, + int mem_level, int strategy); + +// Quickly resets a compressor without having to reallocate anything. Same as +// calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). +int mz_deflateReset(mz_streamp pStream); + +// mz_deflate() compresses the input to output, consuming as much of the input +// and producing as much output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update +// the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or +// MZ_FINISH. +// Return values: +// MZ_OK on success (when flushing, or if more input is needed but not +// available, and/or there's more output to be written but the output buffer +// is full). +// MZ_STREAM_END if all input has been consumed and all output bytes have been +// written. Don't call mz_deflate() on the stream anymore. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input and/or +// output buffers are empty. (Fill up the input buffer or free up some output +// space and try again.) +int mz_deflate(mz_streamp pStream, int flush); + +// mz_deflateEnd() deinitializes a compressor: +// Return values: +// MZ_OK on success. +// MZ_STREAM_ERROR if the stream is bogus. +int mz_deflateEnd(mz_streamp pStream); + +// mz_deflateBound() returns a (very) conservative upper bound on the amount of +// data that could be generated by deflate(), assuming flush is set to only +// MZ_NO_FLUSH or MZ_FINISH. +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); + +// Single-call compression functions mz_compress() and mz_compress2(): +// Returns MZ_OK on success, or one of the error codes from mz_deflate() on +// failure. +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len); +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len, int level); + +// mz_compressBound() returns a (very) conservative upper bound on the amount of +// data that could be generated by calling mz_compress(). +mz_ulong mz_compressBound(mz_ulong source_len); + +// Initializes a decompressor. +int mz_inflateInit(mz_streamp pStream); + +// mz_inflateInit2() is like mz_inflateInit() with an additional option that +// controls the window size and whether or not the stream has been wrapped with +// a zlib header/footer: +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or +// -MZ_DEFAULT_WINDOW_BITS (raw deflate). +int mz_inflateInit2(mz_streamp pStream, int window_bits); + +// Decompresses the input stream to the output, consuming only as much of the +// input as needed, and writing as much to the output as possible. +// Parameters: +// pStream is the stream to read from and write to. You must initialize/update +// the next_in, avail_in, next_out, and avail_out members. +// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. +// On the first call, if flush is MZ_FINISH it's assumed the input and output +// buffers are both sized large enough to decompress the entire stream in a +// single call (this is slightly faster). +// MZ_FINISH implies that there are no more source bytes available beside +// what's already in the input buffer, and that the output buffer is large +// enough to hold the rest of the decompressed data. +// Return values: +// MZ_OK on success. Either more input is needed but not available, and/or +// there's more output to be written but the output buffer is full. +// MZ_STREAM_END if all needed input has been consumed and all output bytes +// have been written. For zlib streams, the adler-32 of the decompressed data +// has also been verified. +// MZ_STREAM_ERROR if the stream is bogus. +// MZ_DATA_ERROR if the deflate stream is invalid. +// MZ_PARAM_ERROR if one of the parameters is invalid. +// MZ_BUF_ERROR if no forward progress is possible because the input buffer is +// empty but the inflater needs more input to continue, or if the output +// buffer is not large enough. Call mz_inflate() again +// with more input data, or with more room in the output buffer (except when +// using single call decompression, described above). +int mz_inflate(mz_streamp pStream, int flush); + +// Deinitializes a decompressor. +int mz_inflateEnd(mz_streamp pStream); + +// Single-call decompression. +// Returns MZ_OK on success, or one of the error codes from mz_inflate() on +// failure. +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len); + +// Returns a string description of the specified error code, or NULL if the +// error code is invalid. +const char *mz_error(int err); + +// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used +// as a drop-in replacement for the subset of zlib that miniz.c supports. +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you +// use zlib in the same project. +#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES +typedef unsigned char Byte; +typedef unsigned int uInt; +typedef mz_ulong uLong; +typedef Byte Bytef; +typedef uInt uIntf; +typedef char charf; +typedef int intf; +typedef void *voidpf; +typedef uLong uLongf; +typedef void *voidp; +typedef void *const voidpc; +#define Z_NULL 0 +#define Z_NO_FLUSH MZ_NO_FLUSH +#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH +#define Z_SYNC_FLUSH MZ_SYNC_FLUSH +#define Z_FULL_FLUSH MZ_FULL_FLUSH +#define Z_FINISH MZ_FINISH +#define Z_BLOCK MZ_BLOCK +#define Z_OK MZ_OK +#define Z_STREAM_END MZ_STREAM_END +#define Z_NEED_DICT MZ_NEED_DICT +#define Z_ERRNO MZ_ERRNO +#define Z_STREAM_ERROR MZ_STREAM_ERROR +#define Z_DATA_ERROR MZ_DATA_ERROR +#define Z_MEM_ERROR MZ_MEM_ERROR +#define Z_BUF_ERROR MZ_BUF_ERROR +#define Z_VERSION_ERROR MZ_VERSION_ERROR +#define Z_PARAM_ERROR MZ_PARAM_ERROR +#define Z_NO_COMPRESSION MZ_NO_COMPRESSION +#define Z_BEST_SPEED MZ_BEST_SPEED +#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION +#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION +#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY +#define Z_FILTERED MZ_FILTERED +#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY +#define Z_RLE MZ_RLE +#define Z_FIXED MZ_FIXED +#define Z_DEFLATED MZ_DEFLATED +#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS +#define alloc_func mz_alloc_func +#define free_func mz_free_func +#define internal_state mz_internal_state +#define z_stream mz_stream +#define deflateInit mz_deflateInit +#define deflateInit2 mz_deflateInit2 +#define deflateReset mz_deflateReset +#define deflate mz_deflate +#define deflateEnd mz_deflateEnd +#define deflateBound mz_deflateBound +#define compress mz_compress +#define compress2 mz_compress2 +#define compressBound mz_compressBound +#define inflateInit mz_inflateInit +#define inflateInit2 mz_inflateInit2 +#define inflate mz_inflate +#define inflateEnd mz_inflateEnd +#define uncompress mz_uncompress +#define crc32 mz_crc32 +#define adler32 mz_adler32 +#define MAX_WBITS 15 +#define MAX_MEM_LEVEL 9 +#define zError mz_error +#define ZLIB_VERSION MZ_VERSION +#define ZLIB_VERNUM MZ_VERNUM +#define ZLIB_VER_MAJOR MZ_VER_MAJOR +#define ZLIB_VER_MINOR MZ_VER_MINOR +#define ZLIB_VER_REVISION MZ_VER_REVISION +#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +#define zlibVersion mz_version +#define zlib_version mz_version() +#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES + +#endif // MINIZ_NO_ZLIB_APIS + +// ------------------- Types and macros + +typedef unsigned char mz_uint8; +typedef signed short mz_int16; +typedef unsigned short mz_uint16; +typedef unsigned int mz_uint32; +typedef unsigned int mz_uint; +typedef long long mz_int64; +typedef unsigned long long mz_uint64; +typedef int mz_bool; + +#define MZ_FALSE (0) +#define MZ_TRUE (1) + +// An attempt to work around MSVC's spammy "warning C4127: conditional +// expression is constant" message. +#ifdef _MSC_VER +#define MZ_MACRO_END while (0, 0) +#else +#define MZ_MACRO_END while (0) +#endif + +// ------------------- ZIP archive reading/writing + +#ifndef MINIZ_NO_ARCHIVE_APIS + +enum { + MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, + MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, + MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 +}; + +typedef struct { + mz_uint32 m_file_index; + mz_uint32 m_central_dir_ofs; + mz_uint16 m_version_made_by; + mz_uint16 m_version_needed; + mz_uint16 m_bit_flag; + mz_uint16 m_method; +#ifndef MINIZ_NO_TIME + time_t m_time; +#endif + mz_uint32 m_crc32; + mz_uint64 m_comp_size; + mz_uint64 m_uncomp_size; + mz_uint16 m_internal_attr; + mz_uint32 m_external_attr; + mz_uint64 m_local_header_ofs; + mz_uint32 m_comment_size; + char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; + char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; +} mz_zip_archive_file_stat; + +typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, + void *pBuf, size_t n); +typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, + const void *pBuf, size_t n); + +struct mz_zip_internal_state_tag; +typedef struct mz_zip_internal_state_tag mz_zip_internal_state; + +typedef enum { + MZ_ZIP_MODE_INVALID = 0, + MZ_ZIP_MODE_READING = 1, + MZ_ZIP_MODE_WRITING = 2, + MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 +} mz_zip_mode; + +typedef struct mz_zip_archive_tag { + mz_uint64 m_archive_size; + mz_uint64 m_central_directory_file_ofs; + mz_uint m_total_files; + mz_zip_mode m_zip_mode; + + mz_uint m_file_offset_alignment; + + mz_alloc_func m_pAlloc; + mz_free_func m_pFree; + mz_realloc_func m_pRealloc; + void *m_pAlloc_opaque; + + mz_file_read_func m_pRead; + mz_file_write_func m_pWrite; + void *m_pIO_opaque; + + mz_zip_internal_state *m_pState; + +} mz_zip_archive; + +typedef enum { + MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, + MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, + MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 +} mz_zip_flags; + +// ZIP archive reading + +// Inits a ZIP archive reader. +// These functions read and validate the archive's central directory. +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, + mz_uint32 flags); +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, + size_t size, mz_uint32 flags); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint32 flags); +#endif + +// Returns the total number of files in the archive. +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); + +// Returns detailed information about an archive file entry. +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, + mz_zip_archive_file_stat *pStat); + +// Determines if an archive file entry is a directory entry. +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, + mz_uint file_index); +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, + mz_uint file_index); + +// Retrieves the filename of an archive file entry. +// Returns the number of bytes written to pFilename, or if filename_buf_size is +// 0 this function returns the number of bytes needed to fully store the +// filename. +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, + char *pFilename, mz_uint filename_buf_size); + +// Attempts to locates a file in the archive's central directory. +// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH +// Returns -1 if the file cannot be found. +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, + const char *pComment, mz_uint flags); + +// Extracts a archive file to a memory buffer using no memory allocation. +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, + mz_uint file_index, void *pBuf, + size_t buf_size, mz_uint flags, + void *pUser_read_buf, + size_t user_read_buf_size); +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc( + mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, + mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); + +// Extracts a archive file to a memory buffer. +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, + void *pBuf, size_t buf_size, + mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, + const char *pFilename, void *pBuf, + size_t buf_size, mz_uint flags); + +// Extracts a archive file to a dynamically allocated heap buffer. +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, + size_t *pSize, mz_uint flags); +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, + const char *pFilename, size_t *pSize, + mz_uint flags); + +// Extracts a archive file using a callback function to output the file's data. +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, + mz_uint file_index, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, + const char *pFilename, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags); + +#ifndef MINIZ_NO_STDIO +// Extracts a archive file to a disk file and sets its last accessed and +// modified times. +// This function only extracts files, not archive directory records. +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, + const char *pDst_filename, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, + const char *pArchive_filename, + const char *pDst_filename, + mz_uint flags); +#endif + +// Ends archive reading, freeing all allocations, and closing the input archive +// file if mz_zip_reader_init_file() was used. +mz_bool mz_zip_reader_end(mz_zip_archive *pZip); + +// ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +// Inits a ZIP archive writer. +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, + size_t size_to_reserve_at_beginning, + size_t initial_allocation_size); + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint64 size_to_reserve_at_beginning); +#endif + +// Converts a ZIP archive reader object into a writer object, to allow efficient +// in-place file appends to occur on an existing archive. +// For archives opened using mz_zip_reader_init_file, pFilename must be the +// archive's filename so it can be reopened for writing. If the file can't be +// reopened, mz_zip_reader_end() will be called. +// For archives opened using mz_zip_reader_init_mem, the memory block must be +// growable using the realloc callback (which defaults to realloc unless you've +// overridden it). +// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's +// user provided m_pWrite function cannot be NULL. +// Note: In-place archive modification is not recommended unless you know what +// you're doing, because if execution stops or something goes wrong before +// the archive is finalized the file's central directory will be hosed. +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, + const char *pFilename); + +// Adds the contents of a memory buffer to an archive. These functions record +// the current local time into the archive. +// To add a directory entry, call this method with an archive name ending in a +// forwardslash with empty buffer. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or +// just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, + const void *pBuf, size_t buf_size, + mz_uint level_and_flags); +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, + const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, + mz_uint16 comment_size, + mz_uint level_and_flags, mz_uint64 uncomp_size, + mz_uint32 uncomp_crc32); + +#ifndef MINIZ_NO_STDIO +// Adds the contents of a disk file to an archive. This function also records +// the disk file's modified time into the archive. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or +// just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, + const char *pSrc_filename, const void *pComment, + mz_uint16 comment_size, mz_uint level_and_flags); +#endif + +// Adds a file to an archive by fully cloning the data from another archive. +// This function fully clones the source file's compressed data (no +// recompression), along with its full filename, extra data, and comment fields. +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, + mz_zip_archive *pSource_zip, + mz_uint file_index); + +// Finalizes the archive by writing the central directory records followed by +// the end of central directory record. +// After an archive is finalized, the only valid call on the mz_zip_archive +// struct is mz_zip_writer_end(). +// An archive must be manually finalized by calling this function for it to be +// valid. +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, + size_t *pSize); + +// Ends archive writing, freeing all allocations, and closing the output file if +// mz_zip_writer_init_file() was used. +// Note for the archive to be valid, it must have been finalized before ending. +mz_bool mz_zip_writer_end(mz_zip_archive *pZip); + +// Misc. high-level helper functions: + +// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) +// appends a memory blob to a ZIP archive. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or +// just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_add_mem_to_archive_file_in_place( + const char *pZip_filename, const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, mz_uint16 comment_size, + mz_uint level_and_flags); + +// Reads a single file from an archive into a heap block. +// Returns NULL on failure. +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, + const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + +// ------------------- Low-level Decompression API Definitions + +// Decompression flags used by tinfl_decompress(). +// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and +// ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the +// input is a raw deflate stream. +// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available +// beyond the end of the supplied input buffer. If clear, the input buffer +// contains all remaining input. +// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large +// enough to hold the entire decompressed stream. If clear, the output buffer is +// at least the size of the dictionary (typically 32KB). +// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the +// decompressed bytes. +enum { + TINFL_FLAG_PARSE_ZLIB_HEADER = 1, + TINFL_FLAG_HAS_MORE_INPUT = 2, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, + TINFL_FLAG_COMPUTE_ADLER32 = 8 +}; + +// High level decompression functions: +// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block +// allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data +// to decompress. +// On return: +// Function returns a pointer to the decompressed data, or NULL on failure. +// *pOut_len will be set to the decompressed data's size, which could be larger +// than src_buf_len on uncompressible data. +// The caller must call mz_free() on the returned block when it's no longer +// needed. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags); + +// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block +// in memory. +// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes +// written on success. +#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags); + +// tinfl_decompress_mem_to_callback() decompresses a block in memory to an +// internal 32KB buffer, and a user provided callback function will be called to +// flush the buffer. +// Returns 1 on success or 0 on failure. +typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, + tinfl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags); + +struct tinfl_decompressor_tag; +typedef struct tinfl_decompressor_tag tinfl_decompressor; + +// Max size of LZ dictionary. +#define TINFL_LZ_DICT_SIZE 32768 + +// Return status. +typedef enum { + TINFL_STATUS_BAD_PARAM = -3, + TINFL_STATUS_ADLER32_MISMATCH = -2, + TINFL_STATUS_FAILED = -1, + TINFL_STATUS_DONE = 0, + TINFL_STATUS_NEEDS_MORE_INPUT = 1, + TINFL_STATUS_HAS_MORE_OUTPUT = 2 +} tinfl_status; + +// Initializes the decompressor to its initial state. +#define tinfl_init(r) \ + do { \ + (r)->m_state = 0; \ + } \ + MZ_MACRO_END +#define tinfl_get_adler32(r) (r)->m_check_adler32 + +// Main low-level decompressor coroutine function. This is the only function +// actually needed for decompression. All the other functions are just +// high-level helpers for improved usability. +// This is a universal API, i.e. it can be used as a building block to build any +// desired higher level decompression API. In the limit case, it can be called +// once per every byte input or output. +tinfl_status tinfl_decompress(tinfl_decompressor *r, + const mz_uint8 *pIn_buf_next, + size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, + mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, + const mz_uint32 decomp_flags); + +// Internal/private bits follow. +enum { + TINFL_MAX_HUFF_TABLES = 3, + TINFL_MAX_HUFF_SYMBOLS_0 = 288, + TINFL_MAX_HUFF_SYMBOLS_1 = 32, + TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, + TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +}; + +typedef struct { + mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], + m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; +} tinfl_huff_table; + +#if MINIZ_HAS_64BIT_REGISTERS +#define TINFL_USE_64BIT_BITBUF 1 +#endif + +#if TINFL_USE_64BIT_BITBUF +typedef mz_uint64 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (64) +#else +typedef mz_uint32 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (32) +#endif + +struct tinfl_decompressor_tag { + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, + m_check_adler32, m_dist, m_counter, m_num_extra, + m_table_sizes[TINFL_MAX_HUFF_TABLES]; + tinfl_bit_buf_t m_bit_buf; + size_t m_dist_from_out_buf_start; + tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; + mz_uint8 m_raw_header[4], + m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; +}; + +// ------------------- Low-level Compression API Definitions + +// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly +// slower, and raw/dynamic blocks will be output more frequently). +#define TDEFL_LESS_MEMORY 0 + +// tdefl_init() compression flags logically OR'd together (low 12 bits contain +// the max. number of probes per dictionary search): +// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes +// per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap +// compression), 4095=Huffman+LZ (slowest/best compression). +enum { + TDEFL_HUFFMAN_ONLY = 0, + TDEFL_DEFAULT_MAX_PROBES = 128, + TDEFL_MAX_PROBES_MASK = 0xFFF +}; + +// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before +// the deflate data, and the Adler-32 of the source data at the end. Otherwise, +// you'll get raw deflate data. +// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even +// when not writing zlib headers). +// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more +// efficient lazy parsing. +// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's +// initialization time to the minimum, but the output may vary from run to run +// given the same input (depending on the contents of memory). +// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) +// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. +// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. +// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. +// The low 12 bits are reserved to control the max # of hash probes per +// dictionary lookup (see TDEFL_MAX_PROBES_MASK). +enum { + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, + TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 +}; + +// High level compression functions: +// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block +// allocated via malloc(). +// On entry: +// pSrc_buf, src_buf_len: Pointer and size of source block to compress. +// flags: The max match finder probes (default is 128) logically OR'd against +// the above flags. Higher probes are slower but improve compression. +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pOut_len will be set to the compressed data's size, which could be larger +// than src_buf_len on uncompressible data. +// The caller must free() the returned block when it's no longer needed. +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags); + +// tdefl_compress_mem_to_mem() compresses a block in memory to another block in +// memory. +// Returns 0 on failure. +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags); + +// Compresses an image to a compressed PNG file in memory. +// On entry: +// pImage, w, h, and num_chans describe the image to compress. num_chans may be +// 1, 2, 3, or 4. +// The image pitch in bytes per scanline will be w*num_chans. The leftmost +// pixel on the top scanline is stored first in memory. +// level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL +// If flip is true, the image will be flipped on the Y axis (useful for OpenGL +// apps). +// On return: +// Function returns a pointer to the compressed data, or NULL on failure. +// *pLen_out will be set to the size of the PNG image file. +// The caller must mz_free() the returned heap block (which will typically be +// larger than *pLen_out) when it's no longer needed. +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, + int h, int num_chans, + size_t *pLen_out, + mz_uint level, mz_bool flip); +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, + int num_chans, size_t *pLen_out); + +// Output stream interface. The compressor uses this interface to write +// compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, + void *pUser); + +// tdefl_compress_mem_to_output() compresses a block to an output stream. The +// above helpers use this function internally. +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags); + +enum { + TDEFL_MAX_HUFF_TABLES = 3, + TDEFL_MAX_HUFF_SYMBOLS_0 = 288, + TDEFL_MAX_HUFF_SYMBOLS_1 = 32, + TDEFL_MAX_HUFF_SYMBOLS_2 = 19, + TDEFL_LZ_DICT_SIZE = 32768, + TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, + TDEFL_MIN_MATCH_LEN = 3, + TDEFL_MAX_MATCH_LEN = 258 +}; + +// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed +// output block (using static/fixed Huffman codes). +#if TDEFL_LESS_MEMORY +enum { + TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 12, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#else +enum { + TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 15, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; +#endif + +// The low-level tdefl functions below may be used directly if the above helper +// functions aren't flexible enough. The low-level functions don't make any heap +// allocations, unlike the above helper functions. +typedef enum { + TDEFL_STATUS_BAD_PARAM = -2, + TDEFL_STATUS_PUT_BUF_FAILED = -1, + TDEFL_STATUS_OKAY = 0, + TDEFL_STATUS_DONE = 1 +} tdefl_status; + +// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums +typedef enum { + TDEFL_NO_FLUSH = 0, + TDEFL_SYNC_FLUSH = 2, + TDEFL_FULL_FLUSH = 3, + TDEFL_FINISH = 4 +} tdefl_flush; + +// tdefl's compression state structure. +typedef struct { + tdefl_put_buf_func_ptr m_pPut_buf_func; + void *m_pPut_buf_user; + mz_uint m_flags, m_max_probes[2]; + int m_greedy_parsing; + mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; + mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, + m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, + m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, + m_wants_to_finish; + tdefl_status m_prev_return_status; + const void *m_pIn_buf; + void *m_pOut_buf; + size_t *m_pIn_buf_size, *m_pOut_buf_size; + tdefl_flush m_flush; + const mz_uint8 *m_pSrc; + size_t m_src_buf_left, m_out_buf_ofs; + mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; + mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; + mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; + mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; + mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; + mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; +} tdefl_compressor; + +// Initializes the compressor. +// There is no corresponding deinit() function because the tdefl API's do not +// dynamically allocate memory. +// pBut_buf_func: If NULL, output data will be supplied to the specified +// callback. In this case, the user should call the tdefl_compress_buffer() API +// for compression. +// If pBut_buf_func is NULL the user should always call the tdefl_compress() +// API. +// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, +// etc.) +tdefl_status tdefl_init(tdefl_compressor *d, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags); + +// Compresses a block of data, consuming as much of the specified input buffer +// as possible, and writing as much compressed data to the specified output +// buffer as possible. +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, + size_t *pIn_buf_size, void *pOut_buf, + size_t *pOut_buf_size, tdefl_flush flush); + +// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a +// non-NULL tdefl_put_buf_func_ptr. +// tdefl_compress_buffer() always consumes the entire input buffer. +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, + size_t in_buf_size, tdefl_flush flush); + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); +mz_uint32 tdefl_get_adler32(tdefl_compressor *d); + +// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't +// defined, because it uses some of its macros. +#ifndef MINIZ_NO_ZLIB_APIS +// Create tdefl_compress() flags given zlib-style compression parameters. +// level may range from [0,10] (where 10 is absolute max compression, but may be +// much slower on some files) +// window_bits may be -15 (raw deflate) or 15 (zlib) +// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, +// MZ_RLE, or MZ_FIXED +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, + int strategy); +#endif // #ifndef MINIZ_NO_ZLIB_APIS + +#ifdef __cplusplus +} +#endif + +#endif // MINIZ_HEADER_INCLUDED + +// ------------------- End of Header: Implementation follows. (If you only want +// the header, define MINIZ_HEADER_FILE_ONLY.) + +#ifndef MINIZ_HEADER_FILE_ONLY + +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; + +//#include +//#include + +#define MZ_ASSERT(x) assert(x) + +#ifdef MINIZ_NO_MALLOC +#define MZ_MALLOC(x) NULL +#define MZ_FREE(x) (void)x, ((void)0) +#define MZ_REALLOC(p, x) NULL +#else +#define MZ_MALLOC(x) malloc(x) +#define MZ_FREE(x) free(x) +#define MZ_REALLOC(p, x) realloc(p, x) +#endif + +#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) +#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#else +#define MZ_READ_LE16(p) \ + ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) +#define MZ_READ_LE32(p) \ + ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#endif + +#ifdef _MSC_VER +#define MZ_FORCEINLINE __forceinline +#elif defined(__GNUC__) +#define MZ_FORCEINLINE inline __attribute__((__always_inline__)) +#else +#define MZ_FORCEINLINE inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// ------------------- zlib-style API's + +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); + size_t block_len = buf_len % 5552; + if (!ptr) return MZ_ADLER32_INIT; + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + return (s2 << 16) + s1; +} + +// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C +// implementation that balances processor cache usage against speed": +// http://www.geocities.com/malbrain/ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { + static const mz_uint32 s_crc32[16] = { + 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, + 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c}; + mz_uint32 crcu32 = (mz_uint32)crc; + if (!ptr) return MZ_CRC32_INIT; + crcu32 = ~crcu32; + while (buf_len--) { + mz_uint8 b = *ptr++; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; + } + return ~crcu32; +} + +void mz_free(void *p) { MZ_FREE(p); } + +#ifndef MINIZ_NO_ZLIB_APIS + +static void *def_alloc_func(void *opaque, size_t items, size_t size) { + (void)opaque, (void)items, (void)size; + return MZ_MALLOC(items * size); +} +static void def_free_func(void *opaque, void *address) { + (void)opaque, (void)address; + MZ_FREE(address); +} +// static void *def_realloc_func(void *opaque, void *address, size_t items, +// size_t size) { +// (void)opaque, (void)address, (void)items, (void)size; +// return MZ_REALLOC(address, items * size); +//} + +const char *mz_version(void) { return MZ_VERSION; } + +int mz_deflateInit(mz_streamp pStream, int level) { + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, + MZ_DEFAULT_STRATEGY); +} + +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, + int mem_level, int strategy) { + tdefl_compressor *pComp; + mz_uint comp_flags = + TDEFL_COMPUTE_ADLER32 | + tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + + if (!pStream) return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || + ((window_bits != MZ_DEFAULT_WINDOW_BITS) && + (-window_bits != MZ_DEFAULT_WINDOW_BITS))) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = MZ_ADLER32_INIT; + pStream->msg = NULL; + pStream->reserved = 0; + pStream->total_in = 0; + pStream->total_out = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, + sizeof(tdefl_compressor)); + if (!pComp) return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pComp; + + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) { + mz_deflateEnd(pStream); + return MZ_PARAM_ERROR; + } + + return MZ_OK; +} + +int mz_deflateReset(mz_streamp pStream) { + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || + (!pStream->zfree)) + return MZ_STREAM_ERROR; + pStream->total_in = pStream->total_out = 0; + tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, + ((tdefl_compressor *)pStream->state)->m_flags); + return MZ_OK; +} + +int mz_deflate(mz_streamp pStream, int flush) { + size_t in_bytes, out_bytes; + mz_ulong orig_total_in, orig_total_out; + int mz_status = MZ_OK; + + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || + (!pStream->next_out)) + return MZ_STREAM_ERROR; + if (!pStream->avail_out) return MZ_BUF_ERROR; + + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + + if (((tdefl_compressor *)pStream->state)->m_prev_return_status == + TDEFL_STATUS_DONE) + return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; + + orig_total_in = pStream->total_in; + orig_total_out = pStream->total_out; + for (;;) { + tdefl_status defl_status; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + + defl_status = tdefl_compress((tdefl_compressor *)pStream->state, + pStream->next_in, &in_bytes, pStream->next_out, + &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); + + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (defl_status < 0) { + mz_status = MZ_STREAM_ERROR; + break; + } else if (defl_status == TDEFL_STATUS_DONE) { + mz_status = MZ_STREAM_END; + break; + } else if (!pStream->avail_out) + break; + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) { + if ((flush) || (pStream->total_in != orig_total_in) || + (pStream->total_out != orig_total_out)) + break; + return MZ_BUF_ERROR; // Can't make forward progress without some input. + } + } + return mz_status; +} + +int mz_deflateEnd(mz_streamp pStream) { + if (!pStream) return MZ_STREAM_ERROR; + if (pStream->state) { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) { + (void)pStream; + // This is really over conservative. (And lame, but it's actually pretty + // tricky to compute a true upper bound given the way tdefl's blocking works.) + return MZ_MAX(128 + (source_len * 110) / 100, + 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); +} + +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len, int level) { + int status; + mz_stream stream; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_deflateInit(&stream, level); + if (status != MZ_OK) return status; + + status = mz_deflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) { + mz_deflateEnd(&stream); + return (status == MZ_OK) ? MZ_BUF_ERROR : status; + } + + *pDest_len = stream.total_out; + return mz_deflateEnd(&stream); +} + +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len) { + return mz_compress2(pDest, pDest_len, pSource, source_len, + MZ_DEFAULT_COMPRESSION); +} + +mz_ulong mz_compressBound(mz_ulong source_len) { + return mz_deflateBound(NULL, source_len); +} + +typedef struct { + tinfl_decompressor m_decomp; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; + int m_window_bits; + mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; + tinfl_status m_last_status; +} inflate_state; + +int mz_inflateInit2(mz_streamp pStream, int window_bits) { + inflate_state *pDecomp; + if (!pStream) return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && + (-window_bits != MZ_DEFAULT_WINDOW_BITS)) + return MZ_PARAM_ERROR; + + pStream->data_type = 0; + pStream->adler = 0; + pStream->msg = NULL; + pStream->total_in = 0; + pStream->total_out = 0; + pStream->reserved = 0; + if (!pStream->zalloc) pStream->zalloc = def_alloc_func; + if (!pStream->zfree) pStream->zfree = def_free_func; + + pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, + sizeof(inflate_state)); + if (!pDecomp) return MZ_MEM_ERROR; + + pStream->state = (struct mz_internal_state *)pDecomp; + + tinfl_init(&pDecomp->m_decomp); + pDecomp->m_dict_ofs = 0; + pDecomp->m_dict_avail = 0; + pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; + pDecomp->m_first_call = 1; + pDecomp->m_has_flushed = 0; + pDecomp->m_window_bits = window_bits; + + return MZ_OK; +} + +int mz_inflateInit(mz_streamp pStream) { + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +} + +int mz_inflate(mz_streamp pStream, int flush) { + inflate_state *pState; + mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; + size_t in_bytes, out_bytes, orig_avail_in; + tinfl_status status; + + if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; + + pState = (inflate_state *)pStream->state; + if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + orig_avail_in = pStream->avail_in; + + first_call = pState->m_first_call; + pState->m_first_call = 0; + if (pState->m_last_status < 0) return MZ_DATA_ERROR; + + if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + pState->m_has_flushed |= (flush == MZ_FINISH); + + if ((flush == MZ_FINISH) && (first_call)) { + // MZ_FINISH on the first call implies that the input and output buffers are + // large enough to hold the entire compressed/decompressed file. + decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, + pStream->next_out, pStream->next_out, &out_bytes, + decomp_flags); + pState->m_last_status = status; + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; + + if (status < 0) + return MZ_DATA_ERROR; + else if (status != TINFL_STATUS_DONE) { + pState->m_last_status = TINFL_STATUS_FAILED; + return MZ_BUF_ERROR; + } + return MZ_STREAM_END; + } + // flush != MZ_FINISH then we must assume there's more input. + if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + + if (pState->m_dict_avail) { + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && + (!pState->m_dict_avail)) + ? MZ_STREAM_END + : MZ_OK; + } + + for (;;) { + in_bytes = pStream->avail_in; + out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; + + status = tinfl_decompress( + &pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, + pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + pState->m_last_status = status; + + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); + + pState->m_dict_avail = (mz_uint)out_bytes; + + n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); + memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + + if (status < 0) + return MZ_DATA_ERROR; // Stream is corrupted (there could be some + // uncompressed data left in the output dictionary - + // oh well). + else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) + return MZ_BUF_ERROR; // Signal caller that we can't make forward progress + // without supplying more input or by setting flush + // to MZ_FINISH. + else if (flush == MZ_FINISH) { + // The output buffer MUST be large to hold the remaining uncompressed data + // when flush==MZ_FINISH. + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's + // at least 1 more byte on the way. If there's no more room left in the + // output buffer then something is wrong. + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || + (!pStream->avail_out) || (pState->m_dict_avail)) + break; + } + + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) + ? MZ_STREAM_END + : MZ_OK; +} + +int mz_inflateEnd(mz_streamp pStream) { + if (!pStream) return MZ_STREAM_ERROR; + if (pStream->state) { + pStream->zfree(pStream->opaque, pStream->state); + pStream->state = NULL; + } + return MZ_OK; +} + +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len) { + mz_stream stream; + int status; + memset(&stream, 0, sizeof(stream)); + + // In case mz_ulong is 64-bits (argh I hate longs). + if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + + stream.next_in = pSource; + stream.avail_in = (mz_uint32)source_len; + stream.next_out = pDest; + stream.avail_out = (mz_uint32)*pDest_len; + + status = mz_inflateInit(&stream); + if (status != MZ_OK) return status; + + status = mz_inflate(&stream, MZ_FINISH); + if (status != MZ_STREAM_END) { + mz_inflateEnd(&stream); + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR + : status; + } + *pDest_len = stream.total_out; + + return mz_inflateEnd(&stream); +} + +const char *mz_error(int err) { + static struct { + int m_err; + const char *m_pDesc; + } s_error_descs[] = {{MZ_OK, ""}, + {MZ_STREAM_END, "stream end"}, + {MZ_NEED_DICT, "need dictionary"}, + {MZ_ERRNO, "file error"}, + {MZ_STREAM_ERROR, "stream error"}, + {MZ_DATA_ERROR, "data error"}, + {MZ_MEM_ERROR, "out of memory"}, + {MZ_BUF_ERROR, "buf error"}, + {MZ_VERSION_ERROR, "version error"}, + {MZ_PARAM_ERROR, "parameter error"}}; + mz_uint i; + for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) + if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; + return NULL; +} + +#endif // MINIZ_NO_ZLIB_APIS + +// ------------------- Low-level Decompression (completely independent from all +// compression API's) + +#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) +#define TINFL_MEMSET(p, c, l) memset(p, c, l) + +#define TINFL_CR_BEGIN \ + switch (r->m_state) { \ + case 0: +#define TINFL_CR_RETURN(state_index, result) \ + do { \ + status = result; \ + r->m_state = state_index; \ + goto common_exit; \ + case state_index:; \ + } \ + MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) \ + do { \ + for (;;) { \ + TINFL_CR_RETURN(state_index, result); \ + } \ + } \ + MZ_MACRO_END +#define TINFL_CR_FINISH } + +// TODO: If the caller has indicated that there's no more input, and we attempt +// to read beyond the input buf, then something is wrong with the input because +// the inflator never +// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of +// the stream with 0's in this scenario. +#define TINFL_GET_BYTE(state_index, c) \ + do { \ + if (pIn_buf_cur >= pIn_buf_end) { \ + for (;;) { \ + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ + TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ + if (pIn_buf_cur < pIn_buf_end) { \ + c = *pIn_buf_cur++; \ + break; \ + } \ + } else { \ + c = 0; \ + break; \ + } \ + } \ + } else \ + c = *pIn_buf_cur++; \ + } \ + MZ_MACRO_END + +#define TINFL_NEED_BITS(state_index, n) \ + do { \ + mz_uint c; \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) \ + do { \ + if (num_bits < (mz_uint)(n)) { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) \ + do { \ + if (num_bits < (mz_uint)(n)) { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + b = bit_buf & ((1 << (n)) - 1); \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END + +// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes +// remaining in the input buffer falls below 2. +// It reads just enough bytes from the input stream that are needed to decode +// the next Huffman code (and absolutely no more). It works by trying to fully +// decode a +// Huffman code by using whatever bits are currently present in the bit buffer. +// If this fails, it reads another byte, and tries again until it succeeds or +// until the +// bit buffer contains >=15 bits (deflate's max. Huffman code size). +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) break; \ + } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); \ + if (temp >= 0) break; \ + } \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < 15); + +// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex +// than you would initially expect because the zlib API expects the decompressor +// to never read +// beyond the final byte of the deflate stream. (In other words, when this macro +// wants to read another byte from the input, it REALLY needs another byte in +// order to fully +// decode the next Huffman code.) Handling this properly is particularly +// important on raw deflate (non-zlib) streams, which aren't followed by a byte +// aligned adler-32. +// The slow path is only executed at the very end of the input buffer. +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ + do { \ + int temp; \ + mz_uint code_len, c; \ + if (num_bits < 15) { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } else { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | \ + (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ + pIn_buf_cur += 2; \ + num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= \ + 0) \ + code_len = temp >> 9, temp &= 511; \ + else { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while (temp < 0); \ + } \ + sym = temp; \ + bit_buf >>= code_len; \ + num_bits -= code_len; \ + } \ + MZ_MACRO_END + +tinfl_status tinfl_decompress(tinfl_decompressor *r, + const mz_uint8 *pIn_buf_next, + size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, + mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, + const mz_uint32 decomp_flags) { + static const int s_length_base[31] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const int s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, + 4, 4, 5, 5, 5, 5, 0, 0, 0}; + static const int s_dist_base[32] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, + 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, + 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; + static const int s_dist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + static const mz_uint8 s_length_dezigzag[19] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + static const int s_min_table_sizes[3] = {257, 1, 4}; + + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; + tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = + pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = + pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = + (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) + ? (size_t)-1 + : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, + dist_from_out_buf_start; + + // Ensure the output buffer's size is a power of 2, unless the output buffer + // is large enough to hold the entire output file (in which case it doesn't + // matter). + if (((out_buf_size_mask + 1) & out_buf_size_mask) || + (pOut_buf_next < pOut_buf_start)) { + *pIn_buf_size = *pOut_buf_size = 0; + return TINFL_STATUS_BAD_PARAM; + } + + num_bits = r->m_num_bits; + bit_buf = r->m_bit_buf; + dist = r->m_dist; + counter = r->m_counter; + num_extra = r->m_num_extra; + dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; + r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { + TINFL_GET_BYTE(1, r->m_zhdr0); + TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || + (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || + ((out_buf_size_mask + 1) < + (size_t)(1ULL << (8U + (r->m_zhdr0 >> 4))))); + if (counter) { + TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); + } + } + + do { + TINFL_GET_BITS(3, r->m_final, 3); + r->m_type = r->m_final >> 1; + if (r->m_type == 0) { + TINFL_SKIP_BITS(5, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { + if (num_bits) + TINFL_GET_BITS(6, r->m_raw_header[counter], 8); + else + TINFL_GET_BYTE(7, r->m_raw_header[counter]); + } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != + (mz_uint)(0xFFFF ^ + (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { + TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); + } + while ((counter) && (num_bits)) { + TINFL_GET_BITS(51, dist, 8); + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)dist; + counter--; + } + while (counter) { + size_t n; + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); + } + while (pIn_buf_cur >= pIn_buf_end) { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { + TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); + } else { + TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); + } + } + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), + (size_t)(pIn_buf_end - pIn_buf_cur)), + counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); + pIn_buf_cur += n; + pOut_buf_cur += n; + counter -= (mz_uint)n; + } + } else if (r->m_type == 3) { + TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); + } else { + if (r->m_type == 1) { + mz_uint8 *p = r->m_tables[0].m_code_size; + mz_uint i; + r->m_table_sizes[0] = 288; + r->m_table_sizes[1] = 32; + TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for (i = 0; i <= 143; ++i) *p++ = 8; + for (; i <= 255; ++i) *p++ = 9; + for (; i <= 279; ++i) *p++ = 7; + for (; i <= 287; ++i) *p++ = 8; + } else { + for (counter = 0; counter < 3; counter++) { + TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); + r->m_table_sizes[counter] += s_min_table_sizes[counter]; + } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); + for (counter = 0; counter < r->m_table_sizes[2]; counter++) { + mz_uint s; + TINFL_GET_BITS(14, s, 3); + r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; + } + r->m_table_sizes[2] = 19; + } + for (; (int)r->m_type >= 0; r->m_type--) { + int tree_next, tree_cur; + tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], + total_syms[16]; + pTable = &r->m_tables[r->m_type]; + MZ_CLEAR_OBJ(total_syms); + MZ_CLEAR_OBJ(pTable->m_look_up); + MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) + total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; + next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) { + used_syms += total_syms[i]; + next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); + } + if ((65536 != total) && (used_syms > 1)) { + TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); + } + for (tree_next = -1, sym_index = 0; + sym_index < r->m_table_sizes[r->m_type]; ++sym_index) { + mz_uint rev_code = 0, l, cur_code, + code_size = pTable->m_code_size[sym_index]; + if (!code_size) continue; + cur_code = next_code[code_size]++; + for (l = code_size; l > 0; l--, cur_code >>= 1) + rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) { + mz_int16 k = (mz_int16)((code_size << 9) | sym_index); + while (rev_code < TINFL_FAST_LOOKUP_SIZE) { + pTable->m_look_up[rev_code] = k; + rev_code += (1 << code_size); + } + continue; + } + if (0 == + (tree_cur = pTable->m_look_up[rev_code & + (TINFL_FAST_LOOKUP_SIZE - 1)])) { + pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = + (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) { + pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } else + tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); + pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + } + if (r->m_type == 2) { + for (counter = 0; + counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) { + mz_uint s; + TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); + if (dist < 16) { + r->m_len_codes[counter++] = (mz_uint8)dist; + continue; + } + if ((dist == 16) && (!counter)) { + TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); + } + num_extra = "\02\03\07"[dist - 16]; + TINFL_GET_BITS(18, s, num_extra); + s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, + (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); + counter += s; + } + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) { + TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); + } + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, + r->m_table_sizes[0]); + TINFL_MEMCPY(r->m_tables[1].m_code_size, + r->m_len_codes + r->m_table_sizes[0], + r->m_table_sizes[1]); + } + } + for (;;) { + mz_uint8 *pSrc; + for (;;) { + if (((pIn_buf_end - pIn_buf_cur) < 4) || + ((pOut_buf_end - pOut_buf_cur) < 2)) { + TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); + if (counter >= 256) break; + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = (mz_uint8)counter; + } else { + int sym2; + mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) { + bit_buf |= + (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 4; + num_bits += 32; + } +#else + if (num_bits < 15) { + bit_buf |= + (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = + r->m_tables[0] + .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= + 0) + code_len = sym2 >> 9; + else { + code_len = TINFL_FAST_LOOKUP_BITS; + do { + sym2 = r->m_tables[0] + .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + counter = sym2; + bit_buf >>= code_len; + num_bits -= code_len; + if (counter & 256) break; + +#if !TINFL_USE_64BIT_BITBUF + if (num_bits < 15) { + bit_buf |= + (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = + r->m_tables[0] + .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= + 0) + code_len = sym2 >> 9; + else { + code_len = TINFL_FAST_LOOKUP_BITS; + do { + sym2 = r->m_tables[0] + .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + bit_buf >>= code_len; + num_bits -= code_len; + + pOut_buf_cur[0] = (mz_uint8)counter; + if (sym2 & 256) { + pOut_buf_cur++; + counter = sym2; + break; + } + pOut_buf_cur[1] = (mz_uint8)sym2; + pOut_buf_cur += 2; + } + } + if ((counter &= 511) == 256) break; + + num_extra = s_length_extra[counter - 257]; + counter = s_length_base[counter - 257]; + if (num_extra) { + mz_uint extra_bits; + TINFL_GET_BITS(25, extra_bits, num_extra); + counter += extra_bits; + } + + TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); + num_extra = s_dist_extra[dist]; + dist = s_dist_base[dist]; + if (num_extra) { + mz_uint extra_bits; + TINFL_GET_BITS(27, extra_bits, num_extra); + dist += extra_bits; + } + + dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; + if ((dist > dist_from_out_buf_start) && + (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) { + TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); + } + + pSrc = pOut_buf_start + + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) { + while (counter--) { + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = + pOut_buf_start[(dist_from_out_buf_start++ - dist) & + out_buf_size_mask]; + } + continue; + } +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + else if ((counter >= 9) && (counter <= dist)) { + const mz_uint8 *pSrc_end = pSrc + (counter & ~7); + do { + ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; + ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; + pOut_buf_cur += 8; + } while ((pSrc += 8) < pSrc_end); + if ((counter &= 7) < 3) { + if (counter) { + pOut_buf_cur[0] = pSrc[0]; + if (counter > 1) pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + continue; + } + } +#endif + do { + pOut_buf_cur[0] = pSrc[0]; + pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur[2] = pSrc[2]; + pOut_buf_cur += 3; + pSrc += 3; + } while ((int)(counter -= 3) > 2); + if ((int)counter > 0) { + pOut_buf_cur[0] = pSrc[0]; + if ((int)counter > 1) pOut_buf_cur[1] = pSrc[1]; + pOut_buf_cur += counter; + } + } + } + } while (!(r->m_final & 1)); + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { + TINFL_SKIP_BITS(32, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { + mz_uint s; + if (num_bits) + TINFL_GET_BITS(41, s, 8); + else + TINFL_GET_BYTE(42, s); + r->m_z_adler32 = (r->m_z_adler32 << 8) | s; + } + } + TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); + TINFL_CR_FINISH + +common_exit: + r->m_num_bits = num_bits; + r->m_bit_buf = bit_buf; + r->m_dist = dist; + r->m_counter = counter; + r->m_num_extra = num_extra; + r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; + *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & + (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && + (status >= 0)) { + const mz_uint8 *ptr = pOut_buf_next; + size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, + s2 = r->m_check_adler32 >> 16; + size_t block_len = buf_len % 5552; + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; + } + for (; i < block_len; ++i) s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; + } + r->m_check_adler32 = (s2 << 16) + s1; + if ((status == TINFL_STATUS_DONE) && + (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && + (r->m_check_adler32 != r->m_z_adler32)) + status = TINFL_STATUS_ADLER32_MISMATCH; + } + return status; +} + +// Higher level helper functions. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags) { + tinfl_decompressor decomp; + void *pBuf = NULL, *pNew_buf; + size_t src_buf_ofs = 0, out_buf_capacity = 0; + *pOut_len = 0; + tinfl_init(&decomp); + for (;;) { + size_t src_buf_size = src_buf_len - src_buf_ofs, + dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress( + &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, + (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, + &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + src_buf_ofs += src_buf_size; + *pOut_len += dst_buf_size; + if (status == TINFL_STATUS_DONE) break; + new_out_buf_capacity = out_buf_capacity * 2; + if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; + pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); + if (!pNew_buf) { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; + } + pBuf = pNew_buf; + out_buf_capacity = new_out_buf_capacity; + } + return pBuf; +} + +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags) { + tinfl_decompressor decomp; + tinfl_status status; + tinfl_init(&decomp); + status = + tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, + (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED + : out_buf_len; +} + +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, + tinfl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags) { + int result = 0; + tinfl_decompressor decomp; + mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); + size_t in_buf_ofs = 0, dict_ofs = 0; + if (!pDict) return TINFL_STATUS_FAILED; + tinfl_init(&decomp); + for (;;) { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, + dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = + tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, + &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + in_buf_ofs += in_buf_size; + if ((dst_buf_size) && + (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + break; + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) { + result = (status == TINFL_STATUS_DONE); + break; + } + dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); + } + MZ_FREE(pDict); + *pIn_buf_size = in_buf_ofs; + return result; +} + +// ------------------- Low-level Compression (independent from all decompression +// API's) + +// Purposely making these tables static for faster init and thread safety. +static const mz_uint16 s_tdefl_len_sym[256] = { + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, + 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, + 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, + 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, + 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279, + 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 285}; + +static const mz_uint8 s_tdefl_len_extra[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0}; + +static const mz_uint8 s_tdefl_small_dist_sym[512] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17}; + +static const mz_uint8 s_tdefl_small_dist_extra[512] = { + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; + +static const mz_uint8 s_tdefl_large_dist_sym[128] = { + 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, + 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29}; + +static const mz_uint8 s_tdefl_large_dist_extra[128] = { + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; + +// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted +// values. +typedef struct { + mz_uint16 m_key, m_sym_index; +} tdefl_sym_freq; +static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, + tdefl_sym_freq *pSyms0, + tdefl_sym_freq *pSyms1) { + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; + tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; + MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) { + mz_uint freq = pSyms0[i].m_key; + hist[freq & 0xFF]++; + hist[256 + ((freq >> 8) & 0xFF)]++; + } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) + total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) { + const mz_uint32 *pHist = &hist[pass << 8]; + mz_uint offsets[256], cur_ofs = 0; + for (i = 0; i < 256; i++) { + offsets[i] = cur_ofs; + cur_ofs += pHist[i]; + } + for (i = 0; i < num_syms; i++) + pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = + pCur_syms[i]; + { + tdefl_sym_freq *t = pCur_syms; + pCur_syms = pNew_syms; + pNew_syms = t; + } + } + return pCur_syms; +} + +// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, +// alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) { + int root, leaf, next, avbl, used, dpth; + if (n == 0) + return; + else if (n == 1) { + A[0].m_key = 1; + return; + } + A[0].m_key += A[1].m_key; + root = 0; + leaf = 2; + for (next = 1; next < n - 1; next++) { + if (leaf >= n || A[root].m_key < A[leaf].m_key) { + A[next].m_key = A[root].m_key; + A[root++].m_key = (mz_uint16)next; + } else + A[next].m_key = A[leaf++].m_key; + if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) { + A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); + A[root++].m_key = (mz_uint16)next; + } else + A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); + } + A[n - 2].m_key = 0; + for (next = n - 3; next >= 0; next--) + A[next].m_key = A[A[next].m_key].m_key + 1; + avbl = 1; + used = dpth = 0; + root = n - 2; + next = n - 1; + while (avbl > 0) { + while (root >= 0 && (int)A[root].m_key == dpth) { + used++; + root--; + } + while (avbl > used) { + A[next--].m_key = (mz_uint16)(dpth); + avbl--; + } + avbl = 2 * used; + dpth++; + used = 0; + } +} + +// Limits canonical Huffman code table's max code size. +enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, + int code_list_len, + int max_code_size) { + int i; + mz_uint32 total = 0; + if (code_list_len <= 1) return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) + pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) + total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) { + pNum_codes[max_code_size]--; + for (i = max_code_size - 1; i > 0; i--) + if (pNum_codes[i]) { + pNum_codes[i]--; + pNum_codes[i + 1] += 2; + break; + } + total--; + } +} + +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, + int table_len, int code_size_limit, + int static_table) { + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; + mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; + MZ_CLEAR_OBJ(num_codes); + if (static_table) { + for (i = 0; i < table_len; i++) + num_codes[d->m_huff_code_sizes[table_num][i]]++; + } else { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], + *pSyms; + int num_used_syms = 0; + const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; + for (i = 0; i < table_len; i++) + if (pSym_count[i]) { + syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; + syms0[num_used_syms++].m_sym_index = (mz_uint16)i; + } + + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); + tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + + for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; + + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, + code_size_limit); + + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); + MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + for (i = 1, j = num_used_syms; i <= code_size_limit; i++) + for (l = num_codes[i]; l > 0; l--) + d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + } + + next_code[1] = 0; + for (j = 0, i = 2; i <= code_size_limit; i++) + next_code[i] = j = ((j + num_codes[i - 1]) << 1); + + for (i = 0; i < table_len; i++) { + mz_uint rev_code = 0, code, code_size; + if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; + code = next_code[code_size]++; + for (l = code_size; l > 0; l--, code >>= 1) + rev_code = (rev_code << 1) | (code & 1); + d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; + } +} + +#define TDEFL_PUT_BITS(b, l) \ + do { \ + mz_uint bits = b; \ + mz_uint len = l; \ + MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); \ + d->m_bits_in += len; \ + while (d->m_bits_in >= 8) { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ + } \ + MZ_MACRO_END + +#define TDEFL_RLE_PREV_CODE_SIZE() \ + { \ + if (rle_repeat_count) { \ + if (rle_repeat_count < 3) { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)( \ + d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) \ + packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } else { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 16; \ + packed_code_sizes[num_packed_code_sizes++] = \ + (mz_uint8)(rle_repeat_count - 3); \ + } \ + rle_repeat_count = 0; \ + } \ + } + +#define TDEFL_RLE_ZERO_CODE_SIZE() \ + { \ + if (rle_z_count) { \ + if (rle_z_count < 3) { \ + d->m_huff_count[2][0] = \ + (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ + while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ + } else if (rle_z_count <= 10) { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 17; \ + packed_code_sizes[num_packed_code_sizes++] = \ + (mz_uint8)(rle_z_count - 3); \ + } else { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 18; \ + packed_code_sizes[num_packed_code_sizes++] = \ + (mz_uint8)(rle_z_count - 11); \ + } \ + rle_z_count = 0; \ + } \ + } + +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +static void tdefl_start_dynamic_block(tdefl_compressor *d) { + int num_lit_codes, num_dist_codes, num_bit_lengths; + mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, + rle_repeat_count, packed_code_sizes_index; + mz_uint8 + code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], + packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], + prev_code_size = 0xFF; + + d->m_huff_count[0][256] = 1; + + tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); + tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); + + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) + if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) + if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; + + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], + num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; + num_packed_code_sizes = 0; + rle_z_count = 0; + rle_repeat_count = 0; + + memset(&d->m_huff_count[2][0], 0, + sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) { + mz_uint8 code_size = code_sizes_to_pack[i]; + if (!code_size) { + TDEFL_RLE_PREV_CODE_SIZE(); + if (++rle_z_count == 138) { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + } else { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = + (mz_uint16)(d->m_huff_count[2][code_size] + 1); + packed_code_sizes[num_packed_code_sizes++] = code_size; + } else if (++rle_repeat_count == 6) { + TDEFL_RLE_PREV_CODE_SIZE(); + } + } + prev_code_size = code_size; + } + if (rle_repeat_count) { + TDEFL_RLE_PREV_CODE_SIZE(); + } else { + TDEFL_RLE_ZERO_CODE_SIZE(); + } + + tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); + + TDEFL_PUT_BITS(2, 2); + + TDEFL_PUT_BITS(num_lit_codes - 257, 5); + TDEFL_PUT_BITS(num_dist_codes - 1, 5); + + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) + if (d->m_huff_code_sizes + [2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) + break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); + TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) + TDEFL_PUT_BITS( + d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + + for (packed_code_sizes_index = 0; + packed_code_sizes_index < num_packed_code_sizes;) { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; + MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); + if (code >= 16) + TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], + "\02\03\07"[code - 16]); + } +} + +static void tdefl_start_static_block(tdefl_compressor *d) { + mz_uint i; + mz_uint8 *p = &d->m_huff_code_sizes[0][0]; + + for (i = 0; i <= 143; ++i) *p++ = 8; + for (; i <= 255; ++i) *p++ = 9; + for (; i <= 279; ++i) *p++ = 7; + for (; i <= 287; ++i) *p++ = 8; + + memset(d->m_huff_code_sizes[1], 5, 32); + + tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); + tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); + + TDEFL_PUT_BITS(1, 2); +} + +static const mz_uint mz_bitmasks[17] = { + 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, + 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF}; + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \ + MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { + mz_uint flags; + mz_uint8 *pLZ_codes; + mz_uint8 *pOutput_buf = d->m_pOutput_buf; + mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; + mz_uint64 bit_buffer = d->m_bit_buffer; + mz_uint bits_in = d->m_bits_in; + +#define TDEFL_PUT_BITS_FAST(b, l) \ + { \ + bit_buffer |= (((mz_uint64)(b)) << bits_in); \ + bits_in += (l); \ + } + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; + flags >>= 1) { + if (flags == 1) flags = *pLZ_codes++ | 0x100; + + if (flags & 1) { + mz_uint s0, s1, n0, n1, sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], + match_dist = *(const mz_uint16 *)(pLZ_codes + 1); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], + d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], + s_tdefl_len_extra[match_len]); + + // This sequence coaxes MSVC into using cmov's vs. jmp's. + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + n0 = s_tdefl_small_dist_extra[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[match_dist >> 8]; + n1 = s_tdefl_large_dist_extra[match_dist >> 8]; + sym = (match_dist < 512) ? s0 : s1; + num_extra_bits = (match_dist < 512) ? n0 : n1; + + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], + d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], + num_extra_bits); + } else { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], + d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], + d->m_huff_code_sizes[0][lit]); + + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { + flags >>= 1; + lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], + d->m_huff_code_sizes[0][lit]); + } + } + } + + if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE; + + *(mz_uint64 *)pOutput_buf = bit_buffer; + pOutput_buf += (bits_in >> 3); + bit_buffer >>= (bits_in & ~7); + bits_in &= 7; + } + +#undef TDEFL_PUT_BITS_FAST + + d->m_pOutput_buf = pOutput_buf; + d->m_bits_in = 0; + d->m_bit_buffer = 0; + + while (bits_in) { + mz_uint32 n = MZ_MIN(bits_in, 16); + TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); + bit_buffer >>= n; + bits_in -= n; + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#else +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { + mz_uint flags; + mz_uint8 *pLZ_codes; + + flags = 1; + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; + flags >>= 1) { + if (flags == 1) flags = *pLZ_codes++ | 0x100; + if (flags & 1) { + mz_uint sym, num_extra_bits; + mz_uint match_len = pLZ_codes[0], + match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + pLZ_codes += 3; + + MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], + d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], + s_tdefl_len_extra[match_len]); + + if (match_dist < 512) { + sym = s_tdefl_small_dist_sym[match_dist]; + num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } else { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; + num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; + } + MZ_ASSERT(d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); + } else { + mz_uint lit = *pLZ_codes++; + MZ_ASSERT(d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + } + } + + TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); + + return (d->m_pOutput_buf < d->m_pOutput_buf_end); +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && + // MINIZ_HAS_64BIT_REGISTERS + +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) { + if (static_block) + tdefl_start_static_block(d); + else + tdefl_start_dynamic_block(d); + return tdefl_compress_lz_codes(d); +} + +static int tdefl_flush_block(tdefl_compressor *d, int flush) { + mz_uint saved_bit_buf, saved_bits_in; + mz_uint8 *pSaved_output_buf; + mz_bool comp_block_succeeded = MZ_FALSE; + int n, use_raw_block = + ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && + (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = + ((d->m_pPut_buf_func == NULL) && + ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) + ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) + : d->m_output_buf; + + d->m_pOutput_buf = pOutput_buf_start; + d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; + + MZ_ASSERT(!d->m_output_flush_remaining); + d->m_output_flush_ofs = 0; + d->m_output_flush_remaining = 0; + + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); + d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); + + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { + TDEFL_PUT_BITS(0x78, 8); + TDEFL_PUT_BITS(0x01, 8); + } + + TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); + + pSaved_output_buf = d->m_pOutput_buf; + saved_bit_buf = d->m_bit_buffer; + saved_bits_in = d->m_bits_in; + + if (!use_raw_block) + comp_block_succeeded = + tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || + (d->m_total_lz_bytes < 48)); + + // If the block gets expanded, forget the current contents of the output + // buffer and send a raw block instead. + if (((use_raw_block) || + ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= + d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) { + mz_uint i; + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + TDEFL_PUT_BITS(0, 2); + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) { + TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); + } + for (i = 0; i < d->m_total_lz_bytes; ++i) { + TDEFL_PUT_BITS( + d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], + 8); + } + } + // Check for the extremely unlikely (if not impossible) case of the compressed + // block not fitting into the output buffer when using dynamic codes. + else if (!comp_block_succeeded) { + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + tdefl_compress_block(d, MZ_TRUE); + } + + if (flush) { + if (flush == TDEFL_FINISH) { + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { + mz_uint i, a = d->m_adler32; + for (i = 0; i < 4; i++) { + TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); + a <<= 8; + } + } + } else { + mz_uint i, z = 0; + TDEFL_PUT_BITS(0, 3); + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, z ^= 0xFFFF) { + TDEFL_PUT_BITS(z & 0xFFFF, 16); + } + } + } + + MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); + + memset(&d->m_huff_count[0][0], 0, + sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, + sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; + d->m_total_lz_bytes = 0; + d->m_block_index++; + + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) { + if (d->m_pPut_buf_func) { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) + return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); + } else if (pOutput_buf_start == d->m_output_buf) { + int bytes_to_copy = (int)MZ_MIN( + (size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, + bytes_to_copy); + d->m_out_buf_ofs += bytes_to_copy; + if ((n -= bytes_to_copy) != 0) { + d->m_output_flush_ofs = bytes_to_copy; + d->m_output_flush_remaining = n; + } + } else { + d->m_out_buf_ofs += n; + } + } + + return d->m_output_flush_remaining; +} + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES +#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p) +static MZ_FORCEINLINE void tdefl_find_match( + tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, + mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, + match_len = *pMatch_len, probe_pos = pos, next_probe_pos, + probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), + s01 = TDEFL_READ_UNALIGNED_WORD(s); + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) return; + for (;;) { + for (;;) { + if (--num_probes_left == 0) return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || \ + ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) break; + q = (const mz_uint16 *)(d->m_dict + probe_pos); + if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; + p = s; + probe_len = 32; + do { + } while ( + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && + (--probe_len > 0)); + if (!probe_len) { + *pMatch_dist = dist; + *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); + break; + } else if ((probe_len = ((mz_uint)(p - s) * 2) + + (mz_uint)(*(const mz_uint8 *)p == + *(const mz_uint8 *)q)) > match_len) { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == + max_match_len) + break; + c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); + } + } +} +#else +static MZ_FORCEINLINE void tdefl_find_match( + tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, + mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, + match_len = *pMatch_len, probe_pos = pos, next_probe_pos, + probe_len; + mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; + const mz_uint8 *s = d->m_dict + pos, *p, *q; + mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) return; + for (;;) { + for (;;) { + if (--num_probes_left == 0) return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || \ + ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && \ + (d->m_dict[probe_pos + match_len - 1] == c1)) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; + } + if (!dist) break; + p = s; + q = d->m_dict + probe_pos; + for (probe_len = 0; probe_len < max_match_len; probe_len++) + if (*p++ != *q++) break; + if (probe_len > match_len) { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = probe_len) == max_match_len) return; + c0 = d->m_dict[pos + match_len]; + c1 = d->m_dict[pos + match_len - 1]; + } + } +} +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN +static mz_bool tdefl_compress_fast(tdefl_compressor *d) { + // Faster, minimally featured LZRW1-style match+parse loop with better + // register utilization. Intended for applications where raw throughput is + // valued more highly than ratio. + mz_uint lookahead_pos = d->m_lookahead_pos, + lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, + total_lz_bytes = d->m_total_lz_bytes, + num_flags_left = d->m_num_flags_left; + mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; + mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) { + const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; + mz_uint dst_pos = + (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN( + d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + d->m_src_buf_left -= num_bytes_to_process; + lookahead_size += num_bytes_to_process; + + while (num_bytes_to_process) { + mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); + memcpy(d->m_dict + dst_pos, d->m_pSrc, n); + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, + MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + d->m_pSrc += n; + dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; + num_bytes_to_process -= n; + } + + dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) + break; + + while (lookahead_size >= 4) { + mz_uint cur_match_dist, cur_match_len = 1; + mz_uint8 *pCur_dict = d->m_dict + cur_pos; + mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; + mz_uint hash = + (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & + TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint probe_pos = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)lookahead_pos; + + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= + dict_size) && + ((*(const mz_uint32 *)(d->m_dict + + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & + 0xFFFFFF) == first_trigram)) { + const mz_uint16 *p = (const mz_uint16 *)pCur_dict; + const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + mz_uint32 probe_len = 32; + do { + } while ((TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && + (TDEFL_READ_UNALIGNED_WORD(++p) == + TDEFL_READ_UNALIGNED_WORD(++q)) && + (--probe_len > 0)); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + if (!probe_len) + cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; + + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || + ((cur_match_len == TDEFL_MIN_MATCH_LEN) && + (cur_match_dist >= 8U * 1024U))) { + cur_match_len = 1; + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } else { + mz_uint32 s0, s1; + cur_match_len = MZ_MIN(cur_match_len, lookahead_size); + + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && + (cur_match_dist >= 1) && + (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + + cur_match_dist--; + + pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); + *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; + pLZ_code_buf += 3; + *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); + + s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; + s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; + d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; + + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - + TDEFL_MIN_MATCH_LEN]]++; + } + } else { + *pLZ_code_buf++ = (mz_uint8)first_trigram; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + d->m_huff_count[0][(mz_uint8)first_trigram]++; + } + + if (--num_flags_left == 0) { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + total_lz_bytes += cur_match_len; + lookahead_pos += cur_match_len; + dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; + MZ_ASSERT(lookahead_size >= cur_match_len); + lookahead_size -= cur_match_len; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + + while (lookahead_size) { + mz_uint8 lit = d->m_dict[cur_pos]; + + total_lz_bytes++; + *pLZ_code_buf++ = lit; + *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); + if (--num_flags_left == 0) { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } + + d->m_huff_count[0][lit]++; + + lookahead_pos++; + dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); + cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + lookahead_size--; + + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { + int n; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; + } + } + } + + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; + return MZ_TRUE; +} +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, + mz_uint8 lit) { + d->m_total_lz_bytes++; + *d->m_pLZ_code_buf++ = lit; + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); + if (--d->m_num_flags_left == 0) { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + d->m_huff_count[0][lit]++; +} + +static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, + mz_uint match_len, + mz_uint match_dist) { + mz_uint32 s0, s1; + + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && + (match_dist <= TDEFL_LZ_DICT_SIZE)); + + d->m_total_lz_bytes += match_len; + + d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); + + match_dist -= 1; + d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); + d->m_pLZ_code_buf += 3; + + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); + if (--d->m_num_flags_left == 0) { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } + + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; + + if (match_len >= TDEFL_MIN_MATCH_LEN) + d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; +} + +static mz_bool tdefl_compress_normal(tdefl_compressor *d) { + const mz_uint8 *pSrc = d->m_pSrc; + size_t src_buf_left = d->m_src_buf_left; + tdefl_flush flush = d->m_flush; + + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) { + mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; + // Update dictionary and hash chains. Keeps the lookahead size equal to + // TDEFL_MAX_MATCH_LEN. + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & + TDEFL_LZ_DICT_SIZE_MASK, + ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] + << TDEFL_LZ_HASH_SHIFT) ^ + d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN( + src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; + src_buf_left -= num_bytes_to_process; + d->m_lookahead_size += num_bytes_to_process; + while (pSrc != pSrc_end) { + mz_uint8 c = *pSrc++; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + ins_pos++; + } + } else { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & + TDEFL_LZ_DICT_SIZE_MASK; + src_buf_left--; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) { + mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] + << (TDEFL_LZ_HASH_SHIFT * 2)) ^ + (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] + << TDEFL_LZ_HASH_SHIFT) ^ + c) & + (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + } + } + } + d->m_dict_size = + MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break; + + // Simple lazy/greedy parsing state machine. + len_to_move = 1; + cur_match_dist = 0; + cur_match_len = + d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); + cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) { + mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; + cur_match_len = 0; + while (cur_match_len < d->m_lookahead_size) { + if (d->m_dict[cur_pos + cur_match_len] != c) break; + cur_match_len++; + } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) + cur_match_len = 0; + else + cur_match_dist = 1; + } + } else { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, + d->m_lookahead_size, &cur_match_dist, &cur_match_len); + } + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && + (cur_match_dist >= 8U * 1024U)) || + (cur_pos == cur_match_dist) || + ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) { + cur_match_dist = cur_match_len = 0; + } + if (d->m_saved_match_len) { + if (cur_match_len > d->m_saved_match_len) { + tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); + if (cur_match_len >= 128) { + tdefl_record_match(d, cur_match_len, cur_match_dist); + d->m_saved_match_len = 0; + len_to_move = cur_match_len; + } else { + d->m_saved_lit = d->m_dict[cur_pos]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + } else { + tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); + len_to_move = d->m_saved_match_len - 1; + d->m_saved_match_len = 0; + } + } else if (!cur_match_dist) + tdefl_record_literal(d, + d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || + (cur_match_len >= 128)) { + tdefl_record_match(d, cur_match_len, cur_match_dist); + len_to_move = cur_match_len; + } else { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; + } + // Move the lookahead forward by len_to_move bytes. + d->m_lookahead_pos += len_to_move; + MZ_ASSERT(d->m_lookahead_size >= len_to_move); + d->m_lookahead_size -= len_to_move; + d->m_dict_size = + MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE); + // Check if it's time to flush the current LZ codes to the internal output + // buffer. + if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ((d->m_total_lz_bytes > 31 * 1024) && + (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= + d->m_total_lz_bytes) || + (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) { + int n; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + if ((n = tdefl_flush_block(d, 0)) != 0) + return (n < 0) ? MZ_FALSE : MZ_TRUE; + } + } + + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; + return MZ_TRUE; +} + +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) { + if (d->m_pIn_buf_size) { + *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; + } + + if (d->m_pOut_buf_size) { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, + d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, + d->m_output_buf + d->m_output_flush_ofs, n); + d->m_output_flush_ofs += (mz_uint)n; + d->m_output_flush_remaining -= (mz_uint)n; + d->m_out_buf_ofs += n; + + *d->m_pOut_buf_size = d->m_out_buf_ofs; + } + + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE + : TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, + size_t *pIn_buf_size, void *pOut_buf, + size_t *pOut_buf_size, tdefl_flush flush) { + if (!d) { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return TDEFL_STATUS_BAD_PARAM; + } + + d->m_pIn_buf = pIn_buf; + d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; + d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); + d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_out_buf_ofs = 0; + d->m_flush = flush; + + if (((d->m_pPut_buf_func != NULL) == + ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || + (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || + (pIn_buf_size && *pIn_buf_size && !pIn_buf) || + (pOut_buf_size && *pOut_buf_size && !pOut_buf)) { + if (pIn_buf_size) *pIn_buf_size = 0; + if (pOut_buf_size) *pOut_buf_size = 0; + return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); + } + d->m_wants_to_finish |= (flush == TDEFL_FINISH); + + if ((d->m_output_flush_remaining) || (d->m_finished)) + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); + +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && + ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | + TDEFL_RLE_MATCHES)) == 0)) { + if (!tdefl_compress_fast(d)) return d->m_prev_return_status; + } else +#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN + { + if (!tdefl_compress_normal(d)) return d->m_prev_return_status; + } + + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && + (pIn_buf)) + d->m_adler32 = + (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, + d->m_pSrc - (const mz_uint8 *)pIn_buf); + + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && + (!d->m_output_flush_remaining)) { + if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status; + d->m_finished = (flush == TDEFL_FINISH); + if (flush == TDEFL_FULL_FLUSH) { + MZ_CLEAR_OBJ(d->m_hash); + MZ_CLEAR_OBJ(d->m_next); + d->m_dict_size = 0; + } + } + + return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); +} + +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, + size_t in_buf_size, tdefl_flush flush) { + MZ_ASSERT(d->m_pPut_buf_func); + return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +} + +tdefl_status tdefl_init(tdefl_compressor *d, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags) { + d->m_pPut_buf_func = pPut_buf_func; + d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); + d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; + d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; + d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = + d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = + d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; + d->m_pOutput_buf_end = d->m_output_buf; + d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; + d->m_adler32 = 1; + d->m_pIn_buf = NULL; + d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; + d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; + memset(&d->m_huff_count[0][0], 0, + sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, + sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + return TDEFL_STATUS_OKAY; +} + +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) { + return d->m_prev_return_status; +} + +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; } + +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags) { + tdefl_compressor *pComp; + mz_bool succeeded; + if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; + pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + if (!pComp) return MZ_FALSE; + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == + TDEFL_STATUS_OKAY); + succeeded = + succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == + TDEFL_STATUS_DONE); + MZ_FREE(pComp); + return succeeded; +} + +typedef struct { + size_t m_size, m_capacity; + mz_uint8 *m_pBuf; + mz_bool m_expandable; +} tdefl_output_buffer; + +static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, + void *pUser) { + tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; + size_t new_size = p->m_size + len; + if (new_size > p->m_capacity) { + size_t new_capacity = p->m_capacity; + mz_uint8 *pNew_buf; + if (!p->m_expandable) return MZ_FALSE; + do { + new_capacity = MZ_MAX(128U, new_capacity << 1U); + } while (new_size > new_capacity); + pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); + if (!pNew_buf) return MZ_FALSE; + p->m_pBuf = pNew_buf; + p->m_capacity = new_capacity; + } + memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); + p->m_size = new_size; + return MZ_TRUE; +} + +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags) { + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) + return MZ_FALSE; + else + *pOut_len = 0; + out_buf.m_expandable = MZ_TRUE; + if (!tdefl_compress_mem_to_output( + pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return NULL; + *pOut_len = out_buf.m_size; + return out_buf.m_pBuf; +} + +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags) { + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) return 0; + out_buf.m_pBuf = (mz_uint8 *)pOut_buf; + out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output( + pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return 0; + return out_buf.m_size; +} + +#ifndef MINIZ_NO_ZLIB_APIS +static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32, + 128, 256, 512, 768, 1500}; + +// level may actually range from [0,10] (10 is a "hidden" max level, where we +// want a bit more compression and it's fine if throughput to fall off a cliff +// on some files). +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, + int strategy) { + mz_uint comp_flags = + s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | + ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; + + if (!level) + comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) + comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) + comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) + comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) + comp_flags |= TDEFL_RLE_MATCHES; + + return comp_flags; +} +#endif // MINIZ_NO_ZLIB_APIS + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) // nonstandard extension used : non-constant + // aggregate initializer (also supported by GNU + // C and C99, so no big deal) +#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is + // deprecated. Instead, use the ISO C and C++ + // conformant name: _strdup. +#endif + +// Simple PNG writer function by Alex Evans, 2011. Released into the public +// domain: https://gist.github.com/908299, more context at +// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. +// This is actually a modification of Alex's original code so PNG files +// generated by this function pass pngcheck. +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, + int h, int num_chans, + size_t *pLen_out, + mz_uint level, mz_bool flip) { + // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was + // defined. + static const mz_uint s_tdefl_png_num_probes[11] = { + 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; + tdefl_compressor *pComp = + (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + tdefl_output_buffer out_buf; + int i, bpl = w * num_chans, y, z; + mz_uint32 c; + *pLen_out = 0; + if (!pComp) return NULL; + MZ_CLEAR_OBJ(out_buf); + out_buf.m_expandable = MZ_TRUE; + out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); + if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) { + MZ_FREE(pComp); + return NULL; + } + // write dummy header + for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); + // compress image data + tdefl_init( + pComp, tdefl_output_buffer_putter, &out_buf, + s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) { + tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); + tdefl_compress_buffer(pComp, + (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, + bpl, TDEFL_NO_FLUSH); + } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != + TDEFL_STATUS_DONE) { + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + // write real header + *pLen_out = out_buf.m_size - 41; + { + static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; + mz_uint8 pnghdr[41] = {0x89, + 0x50, + 0x4e, + 0x47, + 0x0d, + 0x0a, + 0x1a, + 0x0a, + 0x00, + 0x00, + 0x00, + 0x0d, + 0x49, + 0x48, + 0x44, + 0x52, + 0, + 0, + (mz_uint8)(w >> 8), + (mz_uint8)w, + 0, + 0, + (mz_uint8)(h >> 8), + (mz_uint8)h, + 8, + chans[num_chans], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + (mz_uint8)(*pLen_out >> 24), + (mz_uint8)(*pLen_out >> 16), + (mz_uint8)(*pLen_out >> 8), + (mz_uint8)*pLen_out, + 0x49, + 0x44, + 0x41, + 0x54}; + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); + for (i = 0; i < 4; ++i, c <<= 8) + ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); + memcpy(out_buf.m_pBuf, pnghdr, 41); + } + // write footer (IDAT CRC-32, followed by IEND chunk) + if (!tdefl_output_buffer_putter( + "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { + *pLen_out = 0; + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, + *pLen_out + 4); + for (i = 0; i < 4; ++i, c <<= 8) + (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); + // compute final size of file, grab compressed data buffer and return + *pLen_out += 57; + MZ_FREE(pComp); + return out_buf.m_pBuf; +} +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, + int num_chans, size_t *pLen_out) { + // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we + // can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's + // where #defined out) + return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, + pLen_out, 6, MZ_FALSE); +} + +// ------------------- .ZIP archive reading + +#ifndef MINIZ_NO_ARCHIVE_APIS +#error "No arvhive APIs" + +#ifdef MINIZ_NO_STDIO +#define MZ_FILE void * +#else +#include +#include + +#if defined(_MSC_VER) || defined(__MINGW64__) +static FILE *mz_fopen(const char *pFilename, const char *pMode) { + FILE *pFile = NULL; + fopen_s(&pFile, pFilename, pMode); + return pFile; +} +static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { + FILE *pFile = NULL; + if (freopen_s(&pFile, pPath, pMode, pStream)) return NULL; + return pFile; +} +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN mz_fopen +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 _ftelli64 +#define MZ_FSEEK64 _fseeki64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN mz_freopen +#define MZ_DELETE_FILE remove +#elif defined(__MINGW32__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__TINYC__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__GNUC__) && defined(_LARGEFILE64_SOURCE) && _LARGEFILE64_SOURCE +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen64(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT stat64 +#define MZ_FILE_STAT stat64 +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) +#define MZ_DELETE_FILE remove +#else +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello +#define MZ_FSEEK64 fseeko +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#endif // #ifdef _MSC_VER +#endif // #ifdef MINIZ_NO_STDIO + +#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) + +// Various ZIP archive enums. To completely avoid cross platform compiler +// alignment and platform endian issues, miniz.c doesn't use structs for any of +// this stuff. +enum { + // ZIP archive identifiers and record sizes + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, + MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + // Central directory header record offsets + MZ_ZIP_CDH_SIG_OFS = 0, + MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, + MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, + MZ_ZIP_CDH_BIT_FLAG_OFS = 8, + MZ_ZIP_CDH_METHOD_OFS = 10, + MZ_ZIP_CDH_FILE_TIME_OFS = 12, + MZ_ZIP_CDH_FILE_DATE_OFS = 14, + MZ_ZIP_CDH_CRC32_OFS = 16, + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, + MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, + MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, + MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, + MZ_ZIP_CDH_DISK_START_OFS = 34, + MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, + MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + // Local directory header offsets + MZ_ZIP_LDH_SIG_OFS = 0, + MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, + MZ_ZIP_LDH_BIT_FLAG_OFS = 6, + MZ_ZIP_LDH_METHOD_OFS = 8, + MZ_ZIP_LDH_FILE_TIME_OFS = 10, + MZ_ZIP_LDH_FILE_DATE_OFS = 12, + MZ_ZIP_LDH_CRC32_OFS = 14, + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, + MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, + MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, + // End of central directory offsets + MZ_ZIP_ECDH_SIG_OFS = 0, + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, + MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, + MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, + MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, +}; + +typedef struct { + void *m_p; + size_t m_size, m_capacity; + mz_uint m_element_size; +} mz_zip_array; + +struct mz_zip_internal_state_tag { + mz_zip_array m_central_dir; + mz_zip_array m_central_dir_offsets; + mz_zip_array m_sorted_central_dir_offsets; + MZ_FILE *m_pFile; + void *m_pMem; + size_t m_mem_size; + size_t m_mem_capacity; +}; + +#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) \ + (array_ptr)->m_element_size = element_size +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \ + ((element_type *)((array_ptr)->m_p))[index] + +static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, + mz_zip_array *pArray) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); + memset(pArray, 0, sizeof(mz_zip_array)); +} + +static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t min_new_capacity, + mz_uint growing) { + void *pNew_p; + size_t new_capacity = min_new_capacity; + MZ_ASSERT(pArray->m_element_size); + if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; + if (growing) { + new_capacity = MZ_MAX(1, pArray->m_capacity); + while (new_capacity < min_new_capacity) new_capacity *= 2; + } + if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, + pArray->m_element_size, new_capacity))) + return MZ_FALSE; + pArray->m_p = pNew_p; + pArray->m_capacity = new_capacity; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t new_capacity, + mz_uint growing) { + if (new_capacity > pArray->m_capacity) { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) + return MZ_FALSE; + } + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t new_size, + mz_uint growing) { + if (new_size > pArray->m_capacity) { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) + return MZ_FALSE; + } + pArray->m_size = new_size; + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t n) { + return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); +} + +static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, + mz_zip_array *pArray, + const void *pElements, + size_t n) { + size_t orig_size = pArray->m_size; + if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) + return MZ_FALSE; + memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, + pElements, n * pArray->m_element_size); + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) { + struct tm tm; + memset(&tm, 0, sizeof(tm)); + tm.tm_isdst = -1; + tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; + tm.tm_mon = ((dos_date >> 5) & 15) - 1; + tm.tm_mday = dos_date & 31; + tm.tm_hour = (dos_time >> 11) & 31; + tm.tm_min = (dos_time >> 5) & 63; + tm.tm_sec = (dos_time << 1) & 62; + return mktime(&tm); +} + +static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, + mz_uint16 *pDOS_date) { +#ifdef _MSC_VER + struct tm tm_struct; + struct tm *tm = &tm_struct; + errno_t err = localtime_s(tm, &time); + if (err) { + *pDOS_date = 0; + *pDOS_time = 0; + return; + } +#else + struct tm *tm = localtime(&time); +#endif + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + + ((tm->tm_sec) >> 1)); + *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +} +#endif + +#ifndef MINIZ_NO_STDIO +static mz_bool mz_zip_get_file_modified_time(const char *pFilename, + mz_uint16 *pDOS_time, + mz_uint16 *pDOS_date) { +#ifdef MINIZ_NO_TIME + (void)pFilename; + *pDOS_date = *pDOS_time = 0; +#else + struct MZ_FILE_STAT_STRUCT file_stat; + // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 + // bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. + if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; + mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); +#endif // #ifdef MINIZ_NO_TIME + return MZ_TRUE; +} + +#ifndef MINIZ_NO_TIME +static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, + time_t modified_time) { + struct utimbuf t; + t.actime = access_time; + t.modtime = modified_time; + return !utime(pFilename, &t); +} +#endif // #ifndef MINIZ_NO_TIME +#endif // #ifndef MINIZ_NO_STDIO + +static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, + mz_uint32 flags) { + (void)flags; + if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; + + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + + pZip->m_zip_mode = MZ_ZIP_MODE_READING; + pZip->m_archive_size = 0; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, + sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, + sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, + sizeof(mz_uint32)); + return MZ_TRUE; +} + +static MZ_FORCEINLINE mz_bool +mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, + const mz_zip_array *pCentral_dir_offsets, + mz_uint l_index, mz_uint r_index) { + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT( + pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, + l_index)), + *pE; + const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT( + pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), + r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; + pL++; + pR++; + } + return (pL == pE) ? (l_len < r_len) : (l < r); +} + +#define MZ_SWAP_UINT32(a, b) \ + do { \ + mz_uint32 t = a; \ + a = b; \ + b = t; \ + } \ + MZ_MACRO_END + +// Heap sort of lowercased filenames, used to help accelerate plain central +// directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), +// but it could allocate memory.) +static void mz_zip_reader_sort_central_dir_offsets_by_filename( + mz_zip_archive *pZip) { + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT( + &pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + int start = (size - 2) >> 1, end; + while (start >= 0) { + int child, root = start; + for (;;) { + if ((child = (root << 1) + 1) >= size) break; + child += + (((child + 1) < size) && + (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[child], pIndices[child + 1]))); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + start--; + } + + end = size - 1; + while (end > 0) { + int child, root = 0; + MZ_SWAP_UINT32(pIndices[end], pIndices[0]); + for (;;) { + if ((child = (root << 1) + 1) >= end) break; + child += + (((child + 1) < end) && + mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[child], pIndices[child + 1])); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[root], pIndices[child])) + break; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; + } + end--; + } +} + +static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, + mz_uint32 flags) { + mz_uint cdir_size, num_this_disk, cdir_disk_index; + mz_uint64 cdir_ofs; + mz_int64 cur_file_ofs; + const mz_uint8 *p; + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + mz_bool sort_central_dir = + ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); + // Basic sanity checks - reject files which are too small, and check the first + // 4 bytes of the file to make sure a local header is there. + if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + // Find the end of central directory record by scanning the file from the end + // towards the beginning. + cur_file_ofs = + MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); + for (;;) { + int i, + n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) + return MZ_FALSE; + for (i = n - 4; i >= 0; --i) + if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) break; + if (i >= 0) { + cur_file_ofs += i; + break; + } + if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= + (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) + return MZ_FALSE; + cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); + } + // Read and verify the end of central directory record. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || + ((pZip->m_total_files = + MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != + MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) + return MZ_FALSE; + + num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); + cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); + if (((num_this_disk | cdir_disk_index) != 0) && + ((num_this_disk != 1) || (cdir_disk_index != 1))) + return MZ_FALSE; + + if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < + pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + return MZ_FALSE; + + cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); + if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return MZ_FALSE; + + pZip->m_central_directory_file_ofs = cdir_ofs; + + if (pZip->m_total_files) { + mz_uint i, n; + + // Read the entire central directory into a heap block, and allocate another + // heap block to hold the unsorted central dir file record offsets, and + // another to hold the sorted indices. + if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, + MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, + pZip->m_total_files, MZ_FALSE))) + return MZ_FALSE; + + if (sort_central_dir) { + if (!mz_zip_array_resize(pZip, + &pZip->m_pState->m_sorted_central_dir_offsets, + pZip->m_total_files, MZ_FALSE)) + return MZ_FALSE; + } + + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, + pZip->m_pState->m_central_dir.m_p, + cdir_size) != cdir_size) + return MZ_FALSE; + + // Now create an index into the central directory file records, do some + // basic sanity checking on each record, and check for zip64 entries (which + // are not yet supported). + p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; + for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) { + mz_uint total_header_size, comp_size, decomp_size, disk_index; + if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || + (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) + return MZ_FALSE; + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, + i) = + (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + if (sort_central_dir) + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, + mz_uint32, i) = i; + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && + (decomp_size != comp_size)) || + (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || + (comp_size == 0xFFFFFFFF)) + return MZ_FALSE; + disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); + if ((disk_index != num_this_disk) && (disk_index != 1)) return MZ_FALSE; + if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) + return MZ_FALSE; + if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > + n) + return MZ_FALSE; + n -= total_header_size; + p += total_header_size; + } + } + + if (sort_central_dir) + mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); + + return MZ_TRUE; +} + +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, + mz_uint32 flags) { + if ((!pZip) || (!pZip->m_pRead)) return MZ_FALSE; + if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; + pZip->m_archive_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} + +static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, + void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + size_t s = (file_ofs >= pZip->m_archive_size) + ? 0 + : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); + memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); + return s; +} + +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, + size_t size, mz_uint32 flags) { + if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; + pZip->m_archive_size = size; + pZip->m_pRead = mz_zip_mem_read_func; + pZip->m_pIO_opaque = pZip; +#ifdef __cplusplus + pZip->m_pState->m_pMem = const_cast(pMem); +#else + pZip->m_pState->m_pMem = (void *)pMem; +#endif + pZip->m_pState->m_mem_size = size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, + void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || + (((cur_ofs != (mz_int64)file_ofs)) && + (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint32 flags) { + mz_uint64 file_size; + MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb"); + if (!pFile) return MZ_FALSE; + if (MZ_FSEEK64(pFile, 0, SEEK_END)) { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + file_size = MZ_FTELL64(pFile); + if (!mz_zip_reader_init_internal(pZip, flags)) { + MZ_FCLOSE(pFile); + return MZ_FALSE; + } + pZip->m_pRead = mz_zip_file_read_func; + pZip->m_pIO_opaque = pZip; + pZip->m_pState->m_pFile = pFile; + pZip->m_archive_size = file_size; + if (!mz_zip_reader_read_central_dir(pZip, flags)) { + mz_zip_reader_end(pZip); + return MZ_FALSE; + } + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) { + return pZip ? pZip->m_total_files : 0; +} + +static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh( + mz_zip_archive *pZip, mz_uint file_index) { + if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || + (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return NULL; + return &MZ_ZIP_ARRAY_ELEMENT( + &pZip->m_pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, + file_index)); +} + +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, + mz_uint file_index) { + mz_uint m_bit_flag; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) return MZ_FALSE; + m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + return (m_bit_flag & 1); +} + +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, + mz_uint file_index) { + mz_uint filename_len, external_attr; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) return MZ_FALSE; + + // First see if the filename ends with a '/' character. + filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_len) { + if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') + return MZ_TRUE; + } + + // Bugfix: This code was also checking if the internal attribute was non-zero, + // which wasn't correct. + // Most/all zip writers (hopefully) set DOS file/directory attributes in the + // low 16-bits, so check for the DOS directory flag and ignore the source OS + // ID in the created by field. + // FIXME: Remove this check? Is it necessary - we already check the filename. + external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + if ((external_attr & 0x10) != 0) return MZ_TRUE; + + return MZ_FALSE; +} + +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, + mz_zip_archive_file_stat *pStat) { + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if ((!p) || (!pStat)) return MZ_FALSE; + + // Unpack the central directory record. + pStat->m_file_index = file_index; + pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT( + &pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); + pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); + pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); + pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); + pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); +#ifndef MINIZ_NO_TIME + pStat->m_time = + mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), + MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); +#endif + pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); + pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); + pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); + pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + + // Copy as much of the filename and comment as possible. + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); + memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pStat->m_filename[n] = '\0'; + + n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); + pStat->m_comment_size = n; + memcpy(pStat->m_comment, + p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), + n); + pStat->m_comment[n] = '\0'; + + return MZ_TRUE; +} + +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, + char *pFilename, mz_uint filename_buf_size) { + mz_uint n; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + if (!p) { + if (filename_buf_size) pFilename[0] = '\0'; + return 0; + } + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + if (filename_buf_size) { + n = MZ_MIN(n, filename_buf_size - 1); + memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pFilename[n] = '\0'; + } + return n + 1; +} + +static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, + const char *pB, + mz_uint len, + mz_uint flags) { + mz_uint i; + if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len); + for (i = 0; i < len; ++i) + if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) return MZ_FALSE; + return MZ_TRUE; +} + +static MZ_FORCEINLINE int mz_zip_reader_filename_compare( + const mz_zip_array *pCentral_dir_array, + const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, + mz_uint r_len) { + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT( + pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, + l_index)), + *pE; + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); + mz_uint8 l = 0, r = 0; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pE = pL + MZ_MIN(l_len, r_len); + while (pL < pE) { + if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; + pL++; + pR++; + } + return (pL == pE) ? (int)(l_len - r_len) : (l - r); +} + +static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, + const char *pFilename) { + mz_zip_internal_state *pState = pZip->m_pState; + const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; + const mz_zip_array *pCentral_dir = &pState->m_central_dir; + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT( + &pState->m_sorted_central_dir_offsets, mz_uint32, 0); + const int size = pZip->m_total_files; + const mz_uint filename_len = (mz_uint)strlen(pFilename); + int l = 0, h = size - 1; + while (l <= h) { + int m = (l + h) >> 1, file_index = pIndices[m], + comp = + mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, + file_index, pFilename, filename_len); + if (!comp) + return file_index; + else if (comp < 0) + l = m + 1; + else + h = m - 1; + } + return -1; +} + +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, + const char *pComment, mz_uint flags) { + mz_uint file_index; + size_t name_len, comment_len; + if ((!pZip) || (!pZip->m_pState) || (!pName) || + (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return -1; + if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && + (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) + return mz_zip_reader_locate_file_binary_search(pZip, pName); + name_len = strlen(pName); + if (name_len > 0xFFFF) return -1; + comment_len = pComment ? strlen(pComment) : 0; + if (comment_len > 0xFFFF) return -1; + for (file_index = 0; file_index < pZip->m_total_files; file_index++) { + const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT( + &pZip->m_pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, + file_index)); + mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); + const char *pFilename = + (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + if (filename_len < name_len) continue; + if (comment_len) { + mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), + file_comment_len = + MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); + const char *pFile_comment = pFilename + filename_len + file_extra_len; + if ((file_comment_len != comment_len) || + (!mz_zip_reader_string_equal(pComment, pFile_comment, + file_comment_len, flags))) + continue; + } + if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) { + int ofs = filename_len - 1; + do { + if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || + (pFilename[ofs] == ':')) + break; + } while (--ofs >= 0); + ofs++; + pFilename += ofs; + filename_len -= ofs; + } + if ((filename_len == name_len) && + (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) + return file_index; + } + return -1; +} + +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, + mz_uint file_index, void *pBuf, + size_t buf_size, mz_uint flags, + void *pUser_read_buf, + size_t user_read_buf_size) { + int status = TINFL_STATUS_DONE; + mz_uint64 needed_size, cur_file_ofs, comp_remaining, + out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; + mz_zip_archive_file_stat file_stat; + void *pRead_buf; + mz_uint32 + local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / + sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + tinfl_decompressor inflator; + + if ((buf_size) && (!pBuf)) return MZ_FALSE; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; + + // Empty file, or a directory (but not always a directory - I've seen odd zips + // with directories that have compressed data which inflates to 0 bytes) + if (!file_stat.m_comp_size) return MZ_TRUE; + + // Entry is a subdirectory (I've seen old zips with dir entries which have + // compressed deflate data which inflates to 0 bytes, but these entries claim + // to uncompress to 512 bytes in the headers). + // I'm torn how to handle this case - should it fail instead? + if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; + + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE; + + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && + (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; + + // Ensure supplied output buffer is large enough. + needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size + : file_stat.m_uncomp_size; + if (buf_size < needed_size) return MZ_FALSE; + + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, + (size_t)needed_size) != needed_size) + return MZ_FALSE; + return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || + (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, + (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); + } + + // Decompress the file either directly from memory or from a file input + // buffer. + tinfl_init(&inflator); + + if (pZip->m_pState->m_pMem) { + // Read directly from the archive in memory. + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } else if (pUser_read_buf) { + // Use a user provided read buffer. + if (!user_read_buf_size) return MZ_FALSE; + pRead_buf = (mz_uint8 *)pUser_read_buf; + read_buf_size = user_read_buf_size; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } else { + // Temporarily allocate a read buffer. + read_buf_size = + MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE); +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && + (read_buf_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) +#endif + return MZ_FALSE; + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + do { + size_t in_buf_size, + out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress( + &inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, + (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | + (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + out_buf_ofs += out_buf_size; + } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); + + if (status == TINFL_STATUS_DONE) { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || + (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, + (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } + + if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc( + mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, + mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) return MZ_FALSE; + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, + flags, pUser_read_buf, + user_read_buf_size); +} + +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, + void *pBuf, size_t buf_size, + mz_uint flags) { + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, + flags, NULL, 0); +} + +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, + const char *pFilename, void *pBuf, + size_t buf_size, mz_uint flags) { + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, + buf_size, flags, NULL, 0); +} + +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, + size_t *pSize, mz_uint flags) { + mz_uint64 comp_size, uncomp_size, alloc_size; + const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); + void *pBuf; + + if (pSize) *pSize = 0; + if (!p) return NULL; + + comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); + + alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) +#endif + return NULL; + if (NULL == + (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) + return NULL; + + if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, + flags)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return NULL; + } + + if (pSize) *pSize = (size_t)alloc_size; + return pBuf; +} + +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, + const char *pFilename, size_t *pSize, + mz_uint flags) { + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) { + if (pSize) *pSize = 0; + return MZ_FALSE; + } + return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); +} + +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, + mz_uint file_index, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags) { + int status = TINFL_STATUS_DONE; + mz_uint file_crc32 = MZ_CRC32_INIT; + mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, + out_buf_ofs = 0, cur_file_ofs; + mz_zip_archive_file_stat file_stat; + void *pRead_buf = NULL; + void *pWrite_buf = NULL; + mz_uint32 + local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / + sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; + + // Empty file, or a directory (but not always a directory - I've seen odd zips + // with directories that have compressed data which inflates to 0 bytes) + if (!file_stat.m_comp_size) return MZ_TRUE; + + // Entry is a subdirectory (I've seen old zips with dir entries which have + // compressed deflate data which inflates to 0 bytes, but these entries claim + // to uncompress to 512 bytes in the headers). + // I'm torn how to handle this case - should it fail instead? + if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; + + // Encryption and patch files are not supported. + if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE; + + // This function only supports stored and deflate. + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && + (file_stat.m_method != MZ_DEFLATED)) + return MZ_FALSE; + + // Read and parse the local directory entry. + cur_file_ofs = file_stat.m_local_header_ofs; + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) + return MZ_FALSE; + + // Decompress the file either directly from memory or from a file input + // buffer. + if (pZip->m_pState->m_pMem) { + pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; + read_buf_size = read_buf_avail = file_stat.m_comp_size; + comp_remaining = 0; + } else { + read_buf_size = + MZ_MIN(file_stat.m_comp_size, (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE); + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + (size_t)read_buf_size))) + return MZ_FALSE; + read_buf_avail = 0; + comp_remaining = file_stat.m_comp_size; + } + + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { + // The file is stored or the caller has requested the compressed data. + if (pZip->m_pState->m_pMem) { +#ifdef _MSC_VER + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && + (file_stat.m_comp_size > 0xFFFFFFFF)) +#else + if (((sizeof(size_t) == sizeof(mz_uint32))) && + (file_stat.m_comp_size > 0xFFFFFFFF)) +#endif + return MZ_FALSE; + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, + (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) + status = TINFL_STATUS_FAILED; + else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = + (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, + (size_t)file_stat.m_comp_size); + cur_file_ofs += file_stat.m_comp_size; + out_buf_ofs += file_stat.m_comp_size; + comp_remaining = 0; + } else { + while (comp_remaining) { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + + if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) + file_crc32 = (mz_uint32)mz_crc32( + file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); + + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + out_buf_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + } + } + } else { + tinfl_decompressor inflator; + tinfl_init(&inflator); + + if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + TINFL_LZ_DICT_SIZE))) + status = TINFL_STATUS_FAILED; + else { + do { + mz_uint8 *pWrite_buf_cur = + (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + size_t in_buf_size, + out_buf_size = + TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { + read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { + status = TINFL_STATUS_FAILED; + break; + } + cur_file_ofs += read_buf_avail; + comp_remaining -= read_buf_avail; + read_buf_ofs = 0; + } + + in_buf_size = (size_t)read_buf_avail; + status = tinfl_decompress( + &inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, + (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, + comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + read_buf_avail -= in_buf_size; + read_buf_ofs += in_buf_size; + + if (out_buf_size) { + if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != + out_buf_size) { + status = TINFL_STATUS_FAILED; + break; + } + file_crc32 = + (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); + if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) { + status = TINFL_STATUS_FAILED; + break; + } + } + } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || + (status == TINFL_STATUS_HAS_MORE_OUTPUT)); + } + } + + if ((status == TINFL_STATUS_DONE) && + (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { + // Make sure the entire file was decompressed, and check its CRC. + if ((out_buf_ofs != file_stat.m_uncomp_size) || + (file_crc32 != file_stat.m_crc32)) + status = TINFL_STATUS_FAILED; + } + + if (!pZip->m_pState->m_pMem) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + if (pWrite_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); + + return status == TINFL_STATUS_DONE; +} + +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, + const char *pFilename, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags) { + int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); + if (file_index < 0) return MZ_FALSE; + return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, + flags); +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, + const void *pBuf, size_t n) { + (void)ofs; + return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); +} + +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, + const char *pDst_filename, + mz_uint flags) { + mz_bool status; + mz_zip_archive_file_stat file_stat; + MZ_FILE *pFile; + if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; + pFile = MZ_FOPEN(pDst_filename, "wb"); + if (!pFile) return MZ_FALSE; + status = mz_zip_reader_extract_to_callback( + pZip, file_index, mz_zip_file_write_callback, pFile, flags); + if (MZ_FCLOSE(pFile) == EOF) return MZ_FALSE; +#ifndef MINIZ_NO_TIME + if (status) + mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); +#endif + return status; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_reader_end(mz_zip_archive *pZip) { + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || + (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return MZ_FALSE; + + if (pZip->m_pState) { + mz_zip_internal_state *pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + } + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, + const char *pArchive_filename, + const char *pDst_filename, + mz_uint flags) { + int file_index = + mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); + if (file_index < 0) return MZ_FALSE; + return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); +} +#endif + +// ------------------- .ZIP archive writing + +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); +} +static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); + p[2] = (mz_uint8)(v >> 16); + p[3] = (mz_uint8)(v >> 24); +} +#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) +#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) + +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) { + if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || + (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) + return MZ_FALSE; + + if (pZip->m_file_offset_alignment) { + // Ensure user specified file offset alignment is a power of 2. + if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) + return MZ_FALSE; + } + + if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_archive_size = existing_size; + pZip->m_central_directory_file_ofs = 0; + pZip->m_total_files = 0; + + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + return MZ_FALSE; + memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, + sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, + sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, + sizeof(mz_uint32)); + return MZ_TRUE; +} + +static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, + const void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); +#ifdef _MSC_VER + if ((!n) || + ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#else + if ((!n) || + ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) +#endif + return 0; + if (new_size > pState->m_mem_capacity) { + void *pNew_block; + size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + while (new_capacity < new_size) new_capacity *= 2; + if (NULL == (pNew_block = pZip->m_pRealloc( + pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) + return 0; + pState->m_pMem = pNew_block; + pState->m_mem_capacity = new_capacity; + } + memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); + pState->m_mem_size = (size_t)new_size; + return n; +} + +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, + size_t size_to_reserve_at_beginning, + size_t initial_allocation_size) { + pZip->m_pWrite = mz_zip_heap_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; + if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, + size_to_reserve_at_beginning))) { + if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, initial_allocation_size))) { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_mem_capacity = initial_allocation_size; + } + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, + const void *pBuf, size_t n) { + mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; + mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); + if (((mz_int64)file_ofs < 0) || + (((cur_ofs != (mz_int64)file_ofs)) && + (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + return 0; + return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); +} + +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint64 size_to_reserve_at_beginning) { + MZ_FILE *pFile; + pZip->m_pWrite = mz_zip_file_write_func; + pZip->m_pIO_opaque = pZip; + if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; + if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + pZip->m_pState->m_pFile = pFile; + if (size_to_reserve_at_beginning) { + mz_uint64 cur_ofs = 0; + char buf[4096]; + MZ_CLEAR_OBJ(buf); + do { + size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) { + mz_zip_writer_end(pZip); + return MZ_FALSE; + } + cur_ofs += n; + size_to_reserve_at_beginning -= n; + } while (size_to_reserve_at_beginning); + } + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, + const char *pFilename) { + mz_zip_internal_state *pState; + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) + return MZ_FALSE; + // No sense in trying to write to an archive that's already at the support max + // size + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + pState = pZip->m_pState; + + if (pState->m_pFile) { +#ifdef MINIZ_NO_STDIO + pFilename; + return MZ_FALSE; +#else + // Archive is being read from stdio - try to reopen as writable. + if (pZip->m_pIO_opaque != pZip) return MZ_FALSE; + if (!pFilename) return MZ_FALSE; + pZip->m_pWrite = mz_zip_file_write_func; + if (NULL == + (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) { + // The mz_zip_archive is now in a bogus state because pState->m_pFile is + // NULL, so just close it. + mz_zip_reader_end(pZip); + return MZ_FALSE; + } +#endif // #ifdef MINIZ_NO_STDIO + } else if (pState->m_pMem) { + // Archive lives in a memory block. Assume it's from the heap that we can + // resize using the realloc callback. + if (pZip->m_pIO_opaque != pZip) return MZ_FALSE; + pState->m_mem_capacity = pState->m_mem_size; + pZip->m_pWrite = mz_zip_heap_write_func; + } + // Archive is being read via a user provided read function - make sure the + // user has specified a write function too. + else if (!pZip->m_pWrite) + return MZ_FALSE; + + // Start writing new files at the archive's current central directory + // location. + pZip->m_archive_size = pZip->m_central_directory_file_ofs; + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; + pZip->m_central_directory_file_ofs = 0; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, + const void *pBuf, size_t buf_size, + mz_uint level_and_flags) { + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, + level_and_flags, 0, 0); +} + +typedef struct { + mz_zip_archive *m_pZip; + mz_uint64 m_cur_archive_file_ofs; + mz_uint64 m_comp_size; +} mz_zip_writer_add_state; + +static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, + void *pUser) { + mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; + if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, + pState->m_cur_archive_file_ofs, pBuf, + len) != len) + return MZ_FALSE; + pState->m_cur_archive_file_ofs += len; + pState->m_comp_size += len; + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_local_dir_header( + mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, + mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, + mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, + mz_uint16 dos_time, mz_uint16 dos_date) { + (void)pZip; + memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_create_central_dir_header( + mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, + mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, + mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, + mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, + mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { + (void)pZip; + memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); + MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_add_to_central_dir( + mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, + const void *pExtra, mz_uint16 extra_size, const void *pComment, + mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, + mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, + mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, + mz_uint32 ext_attributes) { + mz_zip_internal_state *pState = pZip->m_pState; + mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; + size_t orig_central_dir_size = pState->m_central_dir.m_size; + mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + + // No zip64 support yet + if ((local_header_ofs > 0xFFFFFFFF) || + (((mz_uint64)pState->m_central_dir.m_size + + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + + comment_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_central_dir_header( + pZip, central_dir_header, filename_size, extra_size, comment_size, + uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, + dos_date, local_header_ofs, ext_attributes)) + return MZ_FALSE; + + if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, + filename_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, + extra_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, + comment_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, + ¢ral_dir_ofs, 1))) { + // Try to push the central directory array back into its original state. + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, + MZ_FALSE); + return MZ_FALSE; + } + + return MZ_TRUE; +} + +static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) { + // Basic ZIP archive filename validity checks: Valid filenames cannot start + // with a forward slash, cannot contain a drive letter, and cannot use + // DOS-style backward slashes. + if (*pArchive_name == '/') return MZ_FALSE; + while (*pArchive_name) { + if ((*pArchive_name == '\\') || (*pArchive_name == ':')) return MZ_FALSE; + pArchive_name++; + } + return MZ_TRUE; +} + +static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment( + mz_zip_archive *pZip) { + mz_uint32 n; + if (!pZip->m_file_offset_alignment) return 0; + n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); + return (pZip->m_file_offset_alignment - n) & + (pZip->m_file_offset_alignment - 1); +} + +static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, + mz_uint64 cur_file_ofs, mz_uint32 n) { + char buf[4096]; + memset(buf, 0, MZ_MIN(sizeof(buf), n)); + while (n) { + mz_uint32 s = MZ_MIN(sizeof(buf), n); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) + return MZ_FALSE; + cur_file_ofs += s; + n -= s; + } + return MZ_TRUE; +} + +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, + const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, + mz_uint16 comment_size, + mz_uint level_and_flags, mz_uint64 uncomp_size, + mz_uint32 uncomp_crc32) { + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, + cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + tdefl_compressor *pComp = NULL; + mz_bool store_data_uncompressed; + mz_zip_internal_state *pState; + + if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + store_data_uncompressed = + ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + + if ((!pZip) || (!pZip->m_pState) || + (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || + (!pArchive_name) || ((comment_size) && (!pComment)) || + (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + + pState = pZip->m_pState; + + if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) + return MZ_FALSE; + // No zip64 support yet + if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; + +#ifndef MINIZ_NO_TIME + { + time_t cur_time; + time(&cur_time); + mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); + } +#endif // #ifndef MINIZ_NO_TIME + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) return MZ_FALSE; + + num_alignment_padding_bytes = + mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + comment_size + archive_name_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) { + // Set DOS Subdirectory attribute bit. + ext_attributes |= 0x10; + // Subdirectories cannot contain data. + if ((buf_size) || (uncomp_size)) return MZ_FALSE; + } + + // Try to do any allocations before writing to the archive, so if an + // allocation fails the file remains unmodified. (A good idea if we're doing + // an in-place modification.) + if ((!mz_zip_array_ensure_room( + pZip, &pState->m_central_dir, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || + (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) + return MZ_FALSE; + + if ((!store_data_uncompressed) && (buf_size)) { + if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) + return MZ_FALSE; + } + + if (!mz_zip_writer_write_zeros( + pZip, cur_archive_file_ofs, + num_alignment_padding_bytes + sizeof(local_dir_header))) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == + 0); + } + cur_archive_file_ofs += + num_alignment_padding_bytes + sizeof(local_dir_header); + + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, + archive_name_size) != archive_name_size) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + + if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { + uncomp_crc32 = + (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); + uncomp_size = buf_size; + if (uncomp_size <= 3) { + level = 0; + store_data_uncompressed = MZ_TRUE; + } + } + + if (store_data_uncompressed) { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, + buf_size) != buf_size) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + cur_archive_file_ofs += buf_size; + comp_size = buf_size; + + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) method = MZ_DEFLATED; + } else if (buf_size) { + mz_zip_writer_add_state state; + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, + tdefl_create_comp_flags_from_zip_params( + level, -15, MZ_DEFAULT_STRATEGY)) != + TDEFL_STATUS_OKAY) || + (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != + TDEFL_STATUS_DONE)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + + method = MZ_DEFLATED; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pComp = NULL; + + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_local_dir_header( + pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, + comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, + sizeof(local_dir_header)) != sizeof(local_dir_header)) + return MZ_FALSE; + + if (!mz_zip_writer_add_to_central_dir( + pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, + dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, + const char *pSrc_filename, const void *pComment, + mz_uint16 comment_size, + mz_uint level_and_flags) { + mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; + mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; + mz_uint64 local_dir_header_ofs = pZip->m_archive_size, + cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, + comp_size = 0; + size_t archive_name_size; + mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + MZ_FILE *pSrc_file = NULL; + + if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; + level = level_and_flags & 0xF; + + if ((!pZip) || (!pZip->m_pState) || + (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || + ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; + + archive_name_size = strlen(pArchive_name); + if (archive_name_size > 0xFFFF) return MZ_FALSE; + + num_alignment_padding_bytes = + mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + comment_size + archive_name_size) > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) + return MZ_FALSE; + + pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); + if (!pSrc_file) return MZ_FALSE; + MZ_FSEEK64(pSrc_file, 0, SEEK_END); + uncomp_size = MZ_FTELL64(pSrc_file); + MZ_FSEEK64(pSrc_file, 0, SEEK_SET); + + if (uncomp_size > 0xFFFFFFFF) { + // No zip64 support yet + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + if (uncomp_size <= 3) level = 0; + + if (!mz_zip_writer_write_zeros( + pZip, cur_archive_file_ofs, + num_alignment_padding_bytes + sizeof(local_dir_header))) { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + local_dir_header_ofs += num_alignment_padding_bytes; + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == + 0); + } + cur_archive_file_ofs += + num_alignment_padding_bytes + sizeof(local_dir_header); + + MZ_CLEAR_OBJ(local_dir_header); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, + archive_name_size) != archive_name_size) { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + cur_archive_file_ofs += archive_name_size; + + if (uncomp_size) { + mz_uint64 uncomp_remaining = uncomp_size; + void *pRead_buf = + pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); + if (!pRead_buf) { + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + if (!level) { + while (uncomp_remaining) { + mz_uint n = + (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); + if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || + (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, + n) != n)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + uncomp_crc32 = + (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + uncomp_remaining -= n; + cur_archive_file_ofs += n; + } + comp_size = uncomp_size; + } else { + mz_bool result = MZ_FALSE; + mz_zip_writer_add_state state; + tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + state.m_pZip = pZip; + state.m_cur_archive_file_ofs = cur_archive_file_ofs; + state.m_comp_size = 0; + + if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, + tdefl_create_comp_flags_from_zip_params( + level, -15, MZ_DEFAULT_STRATEGY)) != + TDEFL_STATUS_OKAY) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + for (;;) { + size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, + (mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE); + tdefl_status status; + + if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) + break; + + uncomp_crc32 = (mz_uint32)mz_crc32( + uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); + uncomp_remaining -= in_buf_size; + + status = tdefl_compress_buffer( + pComp, pRead_buf, in_buf_size, + uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); + if (status == TDEFL_STATUS_DONE) { + result = MZ_TRUE; + break; + } else if (status != TDEFL_STATUS_OKAY) + break; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); + + if (!result) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + MZ_FCLOSE(pSrc_file); + return MZ_FALSE; + } + + comp_size = state.m_comp_size; + cur_archive_file_ofs = state.m_cur_archive_file_ofs; + + method = MZ_DEFLATED; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); + } + + MZ_FCLOSE(pSrc_file); + pSrc_file = NULL; + + // no zip64 support yet + if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) + return MZ_FALSE; + + if (!mz_zip_writer_create_local_dir_header( + pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, + comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + return MZ_FALSE; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, + sizeof(local_dir_header)) != sizeof(local_dir_header)) + return MZ_FALSE; + + if (!mz_zip_writer_add_to_central_dir( + pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, + dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + return MZ_FALSE; + + pZip->m_total_files++; + pZip->m_archive_size = cur_archive_file_ofs; + + return MZ_TRUE; +} +#endif // #ifndef MINIZ_NO_STDIO + +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, + mz_zip_archive *pSource_zip, + mz_uint file_index) { + mz_uint n, bit_flags, num_alignment_padding_bytes; + mz_uint64 comp_bytes_remaining, local_dir_header_ofs; + mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; + mz_uint32 + local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / + sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; + size_t orig_central_dir_size; + mz_zip_internal_state *pState; + void *pBuf; + const mz_uint8 *pSrc_central_header; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; + if (NULL == + (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) + return MZ_FALSE; + pState = pZip->m_pState; + + num_alignment_padding_bytes = + mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + + // no zip64 support yet + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > + 0xFFFFFFFF)) + return MZ_FALSE; + + cur_src_file_ofs = + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + cur_dst_file_ofs = pZip->m_archive_size; + + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, + pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) + return MZ_FALSE; + cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, + num_alignment_padding_bytes)) + return MZ_FALSE; + cur_dst_file_ofs += num_alignment_padding_bytes; + local_dir_header_ofs = cur_dst_file_ofs; + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == + 0); + } + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + return MZ_FALSE; + cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; + + n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + comp_bytes_remaining = + n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + + if (NULL == (pBuf = pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, + (size_t)MZ_MAX(sizeof(mz_uint32) * 4, + MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, + comp_bytes_remaining))))) + return MZ_FALSE; + + while (comp_bytes_remaining) { + n = (mz_uint)MZ_MIN((mz_uint)MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, + n) != n) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_src_file_ofs += n; + + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + cur_dst_file_ofs += n; + + comp_bytes_remaining -= n; + } + + bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); + if (bit_flags & 8) { + // Copy data descriptor + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, + sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + + n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + return MZ_FALSE; + } + + cur_src_file_ofs += n; + cur_dst_file_ofs += n; + } + pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); + + // no zip64 support yet + if (cur_dst_file_ofs > 0xFFFFFFFF) return MZ_FALSE; + + orig_central_dir_size = pState->m_central_dir.m_size; + + memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); + MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, + local_dir_header_ofs); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + return MZ_FALSE; + + n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); + if (!mz_zip_array_push_back( + pZip, &pState->m_central_dir, + pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, + MZ_FALSE); + return MZ_FALSE; + } + + if (pState->m_central_dir.m_size > 0xFFFFFFFF) return MZ_FALSE; + n = (mz_uint32)orig_central_dir_size; + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, + MZ_FALSE); + return MZ_FALSE; + } + + pZip->m_total_files++; + pZip->m_archive_size = cur_dst_file_ofs; + + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { + mz_zip_internal_state *pState; + mz_uint64 central_dir_ofs, central_dir_size; + mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; + + if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) + return MZ_FALSE; + + pState = pZip->m_pState; + + // no zip64 support yet + if ((pZip->m_total_files > 0xFFFF) || + ((pZip->m_archive_size + pState->m_central_dir.m_size + + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + return MZ_FALSE; + + central_dir_ofs = 0; + central_dir_size = 0; + if (pZip->m_total_files) { + // Write central directory + central_dir_ofs = pZip->m_archive_size; + central_dir_size = pState->m_central_dir.m_size; + pZip->m_central_directory_file_ofs = central_dir_ofs; + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, + pState->m_central_dir.m_p, + (size_t)central_dir_size) != central_dir_size) + return MZ_FALSE; + pZip->m_archive_size += central_dir_size; + } + + // Write end of central directory record + MZ_CLEAR_OBJ(hdr); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, + pZip->m_total_files); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); + + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, + sizeof(hdr)) != sizeof(hdr)) + return MZ_FALSE; +#ifndef MINIZ_NO_STDIO + if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) return MZ_FALSE; +#endif // #ifndef MINIZ_NO_STDIO + + pZip->m_archive_size += sizeof(hdr); + + pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, + size_t *pSize) { + if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) return MZ_FALSE; + if (pZip->m_pWrite != mz_zip_heap_write_func) return MZ_FALSE; + if (!mz_zip_writer_finalize_archive(pZip)) return MZ_FALSE; + + *pBuf = pZip->m_pState->m_pMem; + *pSize = pZip->m_pState->m_mem_size; + pZip->m_pState->m_pMem = NULL; + pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; + return MZ_TRUE; +} + +mz_bool mz_zip_writer_end(mz_zip_archive *pZip) { + mz_zip_internal_state *pState; + mz_bool status = MZ_TRUE; + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || + ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && + (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) + return MZ_FALSE; + + pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + +#ifndef MINIZ_NO_STDIO + if (pState->m_pFile) { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } +#endif // #ifndef MINIZ_NO_STDIO + + if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { + pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); + pState->m_pMem = NULL; + } + + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; + return status; +} + +#ifndef MINIZ_NO_STDIO +mz_bool mz_zip_add_mem_to_archive_file_in_place( + const char *pZip_filename, const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, mz_uint16 comment_size, + mz_uint level_and_flags) { + mz_bool status, created_new_archive = MZ_FALSE; + mz_zip_archive zip_archive; + struct MZ_FILE_STAT_STRUCT file_stat; + MZ_CLEAR_OBJ(zip_archive); + if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; + if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || + ((comment_size) && (!pComment)) || + ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; + if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) { + // Create a new archive. + if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) + return MZ_FALSE; + created_new_archive = MZ_TRUE; + } else { + // Append to an existing archive. + if (!mz_zip_reader_init_file( + &zip_archive, pZip_filename, + level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return MZ_FALSE; + if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) { + mz_zip_reader_end(&zip_archive); + return MZ_FALSE; + } + } + status = + mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, + pComment, comment_size, level_and_flags, 0, 0); + // Always finalize, even if adding failed for some reason, so we have a valid + // central directory. (This may not always succeed, but we can try.) + if (!mz_zip_writer_finalize_archive(&zip_archive)) status = MZ_FALSE; + if (!mz_zip_writer_end(&zip_archive)) status = MZ_FALSE; + if ((!status) && (created_new_archive)) { + // It's a new archive and something went wrong, so just delete it. + int ignoredStatus = MZ_DELETE_FILE(pZip_filename); + (void)ignoredStatus; + } + return status; +} + +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, + const char *pArchive_name, + size_t *pSize, mz_uint flags) { + int file_index; + mz_zip_archive zip_archive; + void *p = NULL; + + if (pSize) *pSize = 0; + + if ((!pZip_filename) || (!pArchive_name)) return NULL; + + MZ_CLEAR_OBJ(zip_archive); + if (!mz_zip_reader_init_file( + &zip_archive, pZip_filename, + flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + return NULL; + + if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, + flags)) >= 0) + p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); + + mz_zip_reader_end(&zip_archive); + return p; +} + +#endif // #ifndef MINIZ_NO_STDIO + +#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS + +#endif // #ifndef MINIZ_NO_ARCHIVE_APIS + +#ifdef __cplusplus +} +#endif + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#endif // MINIZ_HEADER_FILE_ONLY + +/* + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to +*/ + +// ---------------------- end of miniz ---------------------------------------- + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +} // namespace miniz +#else + +// Reuse MINIZ_LITTE_ENDIAN macro + +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \ + defined(__i386) || defined(__i486__) || defined(__i486) || \ + defined(i386) || defined(__ia64__) || defined(__x86_64__) +// MINIZ_X86_OR_X64_CPU is only used to help set the below macros. +#define MINIZ_X86_OR_X64_CPU 1 +#endif + +#if defined(__sparcv9) +// Big endian +#else +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. +#define MINIZ_LITTLE_ENDIAN 1 +#endif +#endif + +#endif // TINYEXR_USE_MINIZ + +// static bool IsBigEndian(void) { +// union { +// unsigned int i; +// char c[4]; +// } bint = {0x01020304}; +// +// return bint.c[0] == 1; +//} + +static void SetErrorMessage(const std::string &msg, const char **err) { + if (err) { +#ifdef _WIN32 + (*err) = _strdup(msg.c_str()); +#else + (*err) = strdup(msg.c_str()); +#endif + } +} + +static const int kEXRVersionSize = 8; + +static void cpy2(unsigned short *dst_val, const unsigned short *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; +} + +static void swap2(unsigned short *val) { +#ifdef MINIZ_LITTLE_ENDIAN + (void)val; +#else + unsigned short tmp = *val; + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[1]; + dst[1] = src[0]; +#endif +} + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif +static void cpy4(int *dst_val, const int *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} + +static void cpy4(unsigned int *dst_val, const unsigned int *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} + +static void cpy4(float *dst_val, const float *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +static void swap4(unsigned int *val) { +#ifdef MINIZ_LITTLE_ENDIAN + (void)val; +#else + unsigned int tmp = *val; + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; +#endif +} + +static void swap4(int *val) { +#ifdef MINIZ_LITTLE_ENDIAN + (void)val; +#else + int tmp = *val; + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; +#endif +} + +static void swap4(float *val) { +#ifdef MINIZ_LITTLE_ENDIAN + (void)val; +#else + float tmp = *val; + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; +#endif +} + +#if 0 +static void cpy8(tinyexr::tinyexr_uint64 *dst_val, const tinyexr::tinyexr_uint64 *src_val) { + unsigned char *dst = reinterpret_cast(dst_val); + const unsigned char *src = reinterpret_cast(src_val); + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; +} +#endif + +static void swap8(tinyexr::tinyexr_uint64 *val) { +#ifdef MINIZ_LITTLE_ENDIAN + (void)val; +#else + tinyexr::tinyexr_uint64 tmp = (*val); + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[7]; + dst[1] = src[6]; + dst[2] = src[5]; + dst[3] = src[4]; + dst[4] = src[3]; + dst[5] = src[2]; + dst[6] = src[1]; + dst[7] = src[0]; +#endif +} + +// https://gist.github.com/rygorous/2156668 +// Reuse MINIZ_LITTLE_ENDIAN flag from miniz. +union FP32 { + unsigned int u; + float f; + struct { +#if MINIZ_LITTLE_ENDIAN + unsigned int Mantissa : 23; + unsigned int Exponent : 8; + unsigned int Sign : 1; +#else + unsigned int Sign : 1; + unsigned int Exponent : 8; + unsigned int Mantissa : 23; +#endif + } s; +}; + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +union FP16 { + unsigned short u; + struct { +#if MINIZ_LITTLE_ENDIAN + unsigned int Mantissa : 10; + unsigned int Exponent : 5; + unsigned int Sign : 1; +#else + unsigned int Sign : 1; + unsigned int Exponent : 5; + unsigned int Mantissa : 10; +#endif + } s; +}; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +static FP32 half_to_float(FP16 h) { + static const FP32 magic = {113 << 23}; + static const unsigned int shifted_exp = 0x7c00 + << 13; // exponent mask after shift + FP32 o; + + o.u = (h.u & 0x7fffU) << 13U; // exponent/mantissa bits + unsigned int exp_ = shifted_exp & o.u; // just the exponent + o.u += (127 - 15) << 23; // exponent adjust + + // handle exponent special cases + if (exp_ == shifted_exp) // Inf/NaN? + o.u += (128 - 16) << 23; // extra exp adjust + else if (exp_ == 0) // Zero/Denormal? + { + o.u += 1 << 23; // extra exp adjust + o.f -= magic.f; // renormalize + } + + o.u |= (h.u & 0x8000U) << 16U; // sign bit + return o; +} + +static FP16 float_to_half_full(FP32 f) { + FP16 o = {0}; + + // Based on ISPC reference code (with minor modifications) + if (f.s.Exponent == 0) // Signed zero/denormal (which will underflow) + o.s.Exponent = 0; + else if (f.s.Exponent == 255) // Inf or NaN (all exponent bits set) + { + o.s.Exponent = 31; + o.s.Mantissa = f.s.Mantissa ? 0x200 : 0; // NaN->qNaN and Inf->Inf + } else // Normalized number + { + // Exponent unbias the single, then bias the halfp + int newexp = f.s.Exponent - 127 + 15; + if (newexp >= 31) // Overflow, return signed infinity + o.s.Exponent = 31; + else if (newexp <= 0) // Underflow + { + if ((14 - newexp) <= 24) // Mantissa might be non-zero + { + unsigned int mant = f.s.Mantissa | 0x800000; // Hidden 1 bit + o.s.Mantissa = mant >> (14 - newexp); + if ((mant >> (13 - newexp)) & 1) // Check for rounding + o.u++; // Round, might overflow into exp bit, but this is OK + } + } else { + o.s.Exponent = static_cast(newexp); + o.s.Mantissa = f.s.Mantissa >> 13; + if (f.s.Mantissa & 0x1000) // Check for rounding + o.u++; // Round, might overflow to inf, this is OK + } + } + + o.s.Sign = f.s.Sign; + return o; +} + +// NOTE: From OpenEXR code +// #define IMF_INCREASING_Y 0 +// #define IMF_DECREASING_Y 1 +// #define IMF_RAMDOM_Y 2 +// +// #define IMF_NO_COMPRESSION 0 +// #define IMF_RLE_COMPRESSION 1 +// #define IMF_ZIPS_COMPRESSION 2 +// #define IMF_ZIP_COMPRESSION 3 +// #define IMF_PIZ_COMPRESSION 4 +// #define IMF_PXR24_COMPRESSION 5 +// #define IMF_B44_COMPRESSION 6 +// #define IMF_B44A_COMPRESSION 7 + +#ifdef __clang__ +#pragma clang diagnostic push + +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + +#endif + +static const char *ReadString(std::string *s, const char *ptr, size_t len) { + // Read untile NULL(\0). + const char *p = ptr; + const char *q = ptr; + while ((size_t(q - ptr) < len) && (*q) != 0) { + q++; + } + + if (size_t(q - ptr) >= len) { + (*s) = std::string(); + return NULL; + } + + (*s) = std::string(p, q); + + return q + 1; // skip '\0' +} + +static bool ReadAttribute(std::string *name, std::string *type, + std::vector *data, size_t *marker_size, + const char *marker, size_t size) { + size_t name_len = strnlen(marker, size); + if (name_len == size) { + // String does not have a terminating character. + return false; + } + *name = std::string(marker, name_len); + + marker += name_len + 1; + size -= name_len + 1; + + size_t type_len = strnlen(marker, size); + if (type_len == size) { + return false; + } + *type = std::string(marker, type_len); + + marker += type_len + 1; + size -= type_len + 1; + + if (size < sizeof(uint32_t)) { + return false; + } + + uint32_t data_len; + memcpy(&data_len, marker, sizeof(uint32_t)); + tinyexr::swap4(reinterpret_cast(&data_len)); + + if (data_len == 0) { + if ((*type).compare("string") == 0) { + // Accept empty string attribute. + + marker += sizeof(uint32_t); + size -= sizeof(uint32_t); + + *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t); + + data->resize(1); + (*data)[0] = '\0'; + + return true; + } else { + return false; + } + } + + marker += sizeof(uint32_t); + size -= sizeof(uint32_t); + + if (size < data_len) { + return false; + } + + data->resize(static_cast(data_len)); + memcpy(&data->at(0), marker, static_cast(data_len)); + + *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t) + data_len; + return true; +} + +static void WriteAttributeToMemory(std::vector *out, + const char *name, const char *type, + const unsigned char *data, int len) { + out->insert(out->end(), name, name + strlen(name) + 1); + out->insert(out->end(), type, type + strlen(type) + 1); + + int outLen = len; + tinyexr::swap4(&outLen); + out->insert(out->end(), reinterpret_cast(&outLen), + reinterpret_cast(&outLen) + sizeof(int)); + out->insert(out->end(), data, data + len); +} + +typedef struct { + std::string name; // less than 255 bytes long + int pixel_type; + int x_sampling; + int y_sampling; + unsigned char p_linear; + unsigned char pad[3]; +} ChannelInfo; + +typedef struct { + int min_x; + int min_y; + int max_x; + int max_y; +} Box2iInfo; + +struct HeaderInfo { + std::vector channels; + std::vector attributes; + + Box2iInfo data_window; + int line_order; + Box2iInfo display_window; + float screen_window_center[2]; + float screen_window_width; + float pixel_aspect_ratio; + + int chunk_count; + + // Tiled format + int tiled; // Non-zero if the part is tiled. + int tile_size_x; + int tile_size_y; + int tile_level_mode; + int tile_rounding_mode; + + unsigned int header_len; + + int compression_type; + + // required for multi-part or non-image files + std::string name; + // required for multi-part or non-image files + std::string type; + + void clear() { + channels.clear(); + attributes.clear(); + + data_window.min_x = 0; + data_window.min_y = 0; + data_window.max_x = 0; + data_window.max_y = 0; + line_order = 0; + display_window.min_x = 0; + display_window.min_y = 0; + display_window.max_x = 0; + display_window.max_y = 0; + screen_window_center[0] = 0.0f; + screen_window_center[1] = 0.0f; + screen_window_width = 0.0f; + pixel_aspect_ratio = 0.0f; + + chunk_count = 0; + + // Tiled format + tiled = 0; + tile_size_x = 0; + tile_size_y = 0; + tile_level_mode = 0; + tile_rounding_mode = 0; + + header_len = 0; + compression_type = 0; + + name.clear(); + type.clear(); + } +}; + +static bool ReadChannelInfo(std::vector &channels, + const std::vector &data) { + const char *p = reinterpret_cast(&data.at(0)); + + for (;;) { + if ((*p) == 0) { + break; + } + ChannelInfo info; + + tinyexr_int64 data_len = static_cast(data.size()) - + (p - reinterpret_cast(data.data())); + if (data_len < 0) { + return false; + } + + p = ReadString(&info.name, p, size_t(data_len)); + if ((p == NULL) && (info.name.empty())) { + // Buffer overrun. Issue #51. + return false; + } + + const unsigned char *data_end = + reinterpret_cast(p) + 16; + if (data_end >= (data.data() + data.size())) { + return false; + } + + memcpy(&info.pixel_type, p, sizeof(int)); + p += 4; + info.p_linear = static_cast(p[0]); // uchar + p += 1 + 3; // reserved: uchar[3] + memcpy(&info.x_sampling, p, sizeof(int)); // int + p += 4; + memcpy(&info.y_sampling, p, sizeof(int)); // int + p += 4; + + tinyexr::swap4(&info.pixel_type); + tinyexr::swap4(&info.x_sampling); + tinyexr::swap4(&info.y_sampling); + + channels.push_back(info); + } + + return true; +} + +static void WriteChannelInfo(std::vector &data, + const std::vector &channels) { + size_t sz = 0; + + // Calculate total size. + for (size_t c = 0; c < channels.size(); c++) { + sz += strlen(channels[c].name.c_str()) + 1; // +1 for \0 + sz += 16; // 4 * int + } + data.resize(sz + 1); + + unsigned char *p = &data.at(0); + + for (size_t c = 0; c < channels.size(); c++) { + memcpy(p, channels[c].name.c_str(), strlen(channels[c].name.c_str())); + p += strlen(channels[c].name.c_str()); + (*p) = '\0'; + p++; + + int pixel_type = channels[c].pixel_type; + int x_sampling = channels[c].x_sampling; + int y_sampling = channels[c].y_sampling; + tinyexr::swap4(&pixel_type); + tinyexr::swap4(&x_sampling); + tinyexr::swap4(&y_sampling); + + memcpy(p, &pixel_type, sizeof(int)); + p += sizeof(int); + + (*p) = channels[c].p_linear; + p += 4; + + memcpy(p, &x_sampling, sizeof(int)); + p += sizeof(int); + + memcpy(p, &y_sampling, sizeof(int)); + p += sizeof(int); + } + + (*p) = '\0'; +} + +static void CompressZip(unsigned char *dst, + tinyexr::tinyexr_uint64 &compressedSize, + const unsigned char *src, unsigned long src_size) { + std::vector tmpBuf(src_size); + + // + // Apply EXR-specific? postprocess. Grabbed from OpenEXR's + // ImfZipCompressor.cpp + // + + // + // Reorder the pixel data. + // + + const char *srcPtr = reinterpret_cast(src); + + { + char *t1 = reinterpret_cast(&tmpBuf.at(0)); + char *t2 = reinterpret_cast(&tmpBuf.at(0)) + (src_size + 1) / 2; + const char *stop = srcPtr + src_size; + + for (;;) { + if (srcPtr < stop) + *(t1++) = *(srcPtr++); + else + break; + + if (srcPtr < stop) + *(t2++) = *(srcPtr++); + else + break; + } + } + + // + // Predictor. + // + + { + unsigned char *t = &tmpBuf.at(0) + 1; + unsigned char *stop = &tmpBuf.at(0) + src_size; + int p = t[-1]; + + while (t < stop) { + int d = int(t[0]) - p + (128 + 256); + p = t[0]; + t[0] = static_cast(d); + ++t; + } + } + +#if TINYEXR_USE_MINIZ + // + // Compress the data using miniz + // + + miniz::mz_ulong outSize = miniz::mz_compressBound(src_size); + int ret = miniz::mz_compress( + dst, &outSize, static_cast(&tmpBuf.at(0)), + src_size); + assert(ret == miniz::MZ_OK); + (void)ret; + + compressedSize = outSize; +#else + uLong outSize = compressBound(static_cast(src_size)); + int ret = compress(dst, &outSize, static_cast(&tmpBuf.at(0)), + src_size); + assert(ret == Z_OK); + + compressedSize = outSize; +#endif + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if (compressedSize >= src_size) { + compressedSize = src_size; + memcpy(dst, src, src_size); + } +} + +static bool DecompressZip(unsigned char *dst, + unsigned long *uncompressed_size /* inout */, + const unsigned char *src, unsigned long src_size) { + if ((*uncompressed_size) == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + return true; + } + std::vector tmpBuf(*uncompressed_size); + +#if TINYEXR_USE_MINIZ + int ret = + miniz::mz_uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size); + if (miniz::MZ_OK != ret) { + return false; + } +#else + int ret = uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size); + if (Z_OK != ret) { + return false; + } +#endif + + // + // Apply EXR-specific? postprocess. Grabbed from OpenEXR's + // ImfZipCompressor.cpp + // + + // Predictor. + { + unsigned char *t = &tmpBuf.at(0) + 1; + unsigned char *stop = &tmpBuf.at(0) + (*uncompressed_size); + + while (t < stop) { + int d = int(t[-1]) + int(t[0]) - 128; + t[0] = static_cast(d); + ++t; + } + } + + // Reorder the pixel data. + { + const char *t1 = reinterpret_cast(&tmpBuf.at(0)); + const char *t2 = reinterpret_cast(&tmpBuf.at(0)) + + (*uncompressed_size + 1) / 2; + char *s = reinterpret_cast(dst); + char *stop = s + (*uncompressed_size); + + for (;;) { + if (s < stop) + *(s++) = *(t1++); + else + break; + + if (s < stop) + *(s++) = *(t2++); + else + break; + } + } + + return true; +} + +// RLE code from OpenEXR -------------------------------------- + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsign-conversion" +#if __has_warning("-Wextra-semi-stmt") +#pragma clang diagnostic ignored "-Wextra-semi-stmt" +#endif +#endif + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4204) // nonstandard extension used : non-constant + // aggregate initializer (also supported by GNU + // C and C99, so no big deal) +#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to + // 'int', possible loss of data +#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is + // deprecated. Instead, use the ISO C and C++ + // conformant name: _strdup. +#endif + +const int MIN_RUN_LENGTH = 3; +const int MAX_RUN_LENGTH = 127; + +// +// Compress an array of bytes, using run-length encoding, +// and return the length of the compressed data. +// + +static int rleCompress(int inLength, const char in[], signed char out[]) { + const char *inEnd = in + inLength; + const char *runStart = in; + const char *runEnd = in + 1; + signed char *outWrite = out; + + while (runStart < inEnd) { + while (runEnd < inEnd && *runStart == *runEnd && + runEnd - runStart - 1 < MAX_RUN_LENGTH) { + ++runEnd; + } + + if (runEnd - runStart >= MIN_RUN_LENGTH) { + // + // Compressible run + // + + *outWrite++ = static_cast(runEnd - runStart) - 1; + *outWrite++ = *(reinterpret_cast(runStart)); + runStart = runEnd; + } else { + // + // Uncompressable run + // + + while (runEnd < inEnd && + ((runEnd + 1 >= inEnd || *runEnd != *(runEnd + 1)) || + (runEnd + 2 >= inEnd || *(runEnd + 1) != *(runEnd + 2))) && + runEnd - runStart < MAX_RUN_LENGTH) { + ++runEnd; + } + + *outWrite++ = static_cast(runStart - runEnd); + + while (runStart < runEnd) { + *outWrite++ = *(reinterpret_cast(runStart++)); + } + } + + ++runEnd; + } + + return static_cast(outWrite - out); +} + +// +// Uncompress an array of bytes compressed with rleCompress(). +// Returns the length of the oncompressed data, or 0 if the +// length of the uncompressed data would be more than maxLength. +// + +static int rleUncompress(int inLength, int maxLength, const signed char in[], + char out[]) { + char *outStart = out; + + while (inLength > 0) { + if (*in < 0) { + int count = -(static_cast(*in++)); + inLength -= count + 1; + + // Fixes #116: Add bounds check to in buffer. + if ((0 > (maxLength -= count)) || (inLength < 0)) return 0; + + memcpy(out, in, count); + out += count; + in += count; + } else { + int count = *in++; + inLength -= 2; + + if (0 > (maxLength -= count + 1)) return 0; + + memset(out, *reinterpret_cast(in), count + 1); + out += count + 1; + + in++; + } + } + + return static_cast(out - outStart); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// End of RLE code from OpenEXR ----------------------------------- + +static void CompressRle(unsigned char *dst, + tinyexr::tinyexr_uint64 &compressedSize, + const unsigned char *src, unsigned long src_size) { + std::vector tmpBuf(src_size); + + // + // Apply EXR-specific? postprocess. Grabbed from OpenEXR's + // ImfRleCompressor.cpp + // + + // + // Reorder the pixel data. + // + + const char *srcPtr = reinterpret_cast(src); + + { + char *t1 = reinterpret_cast(&tmpBuf.at(0)); + char *t2 = reinterpret_cast(&tmpBuf.at(0)) + (src_size + 1) / 2; + const char *stop = srcPtr + src_size; + + for (;;) { + if (srcPtr < stop) + *(t1++) = *(srcPtr++); + else + break; + + if (srcPtr < stop) + *(t2++) = *(srcPtr++); + else + break; + } + } + + // + // Predictor. + // + + { + unsigned char *t = &tmpBuf.at(0) + 1; + unsigned char *stop = &tmpBuf.at(0) + src_size; + int p = t[-1]; + + while (t < stop) { + int d = int(t[0]) - p + (128 + 256); + p = t[0]; + t[0] = static_cast(d); + ++t; + } + } + + // outSize will be (srcSiz * 3) / 2 at max. + int outSize = rleCompress(static_cast(src_size), + reinterpret_cast(&tmpBuf.at(0)), + reinterpret_cast(dst)); + assert(outSize > 0); + + compressedSize = static_cast(outSize); + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if (compressedSize >= src_size) { + compressedSize = src_size; + memcpy(dst, src, src_size); + } +} + +static bool DecompressRle(unsigned char *dst, + const unsigned long uncompressed_size, + const unsigned char *src, unsigned long src_size) { + if (uncompressed_size == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + return true; + } + + // Workaround for issue #112. + // TODO(syoyo): Add more robust out-of-bounds check in `rleUncompress`. + if (src_size <= 2) { + return false; + } + + std::vector tmpBuf(uncompressed_size); + + int ret = rleUncompress(static_cast(src_size), + static_cast(uncompressed_size), + reinterpret_cast(src), + reinterpret_cast(&tmpBuf.at(0))); + if (ret != static_cast(uncompressed_size)) { + return false; + } + + // + // Apply EXR-specific? postprocess. Grabbed from OpenEXR's + // ImfRleCompressor.cpp + // + + // Predictor. + { + unsigned char *t = &tmpBuf.at(0) + 1; + unsigned char *stop = &tmpBuf.at(0) + uncompressed_size; + + while (t < stop) { + int d = int(t[-1]) + int(t[0]) - 128; + t[0] = static_cast(d); + ++t; + } + } + + // Reorder the pixel data. + { + const char *t1 = reinterpret_cast(&tmpBuf.at(0)); + const char *t2 = reinterpret_cast(&tmpBuf.at(0)) + + (uncompressed_size + 1) / 2; + char *s = reinterpret_cast(dst); + char *stop = s + uncompressed_size; + + for (;;) { + if (s < stop) + *(s++) = *(t1++); + else + break; + + if (s < stop) + *(s++) = *(t2++); + else + break; + } + } + + return true; +} + +#if TINYEXR_USE_PIZ + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wc++11-extensions" +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" + +#if __has_warning("-Wcast-qual") +#pragma clang diagnostic ignored "-Wcast-qual" +#endif + +#if __has_warning("-Wextra-semi-stmt") +#pragma clang diagnostic ignored "-Wextra-semi-stmt" +#endif + +#endif + +// +// PIZ compress/uncompress, based on OpenEXR's ImfPizCompressor.cpp +// +// ----------------------------------------------------------------- +// Copyright (c) 2004, Industrial Light & Magic, a division of Lucas +// Digital Ltd. LLC) +// (3 clause BSD license) +// + +struct PIZChannelData { + unsigned short *start; + unsigned short *end; + int nx; + int ny; + int ys; + int size; +}; + +//----------------------------------------------------------------------------- +// +// 16-bit Haar Wavelet encoding and decoding +// +// The source code in this file is derived from the encoding +// and decoding routines written by Christian Rouet for his +// PIZ image file format. +// +//----------------------------------------------------------------------------- + +// +// Wavelet basis functions without modulo arithmetic; they produce +// the best compression ratios when the wavelet-transformed data are +// Huffman-encoded, but the wavelet transform works only for 14-bit +// data (untransformed data values must be less than (1 << 14)). +// + +inline void wenc14(unsigned short a, unsigned short b, unsigned short &l, + unsigned short &h) { + short as = static_cast(a); + short bs = static_cast(b); + + short ms = (as + bs) >> 1; + short ds = as - bs; + + l = static_cast(ms); + h = static_cast(ds); +} + +inline void wdec14(unsigned short l, unsigned short h, unsigned short &a, + unsigned short &b) { + short ls = static_cast(l); + short hs = static_cast(h); + + int hi = hs; + int ai = ls + (hi & 1) + (hi >> 1); + + short as = static_cast(ai); + short bs = static_cast(ai - hi); + + a = static_cast(as); + b = static_cast(bs); +} + +// +// Wavelet basis functions with modulo arithmetic; they work with full +// 16-bit data, but Huffman-encoding the wavelet-transformed data doesn't +// compress the data quite as well. +// + +const int NBITS = 16; +const int A_OFFSET = 1 << (NBITS - 1); +const int M_OFFSET = 1 << (NBITS - 1); +const int MOD_MASK = (1 << NBITS) - 1; + +inline void wenc16(unsigned short a, unsigned short b, unsigned short &l, + unsigned short &h) { + int ao = (a + A_OFFSET) & MOD_MASK; + int m = ((ao + b) >> 1); + int d = ao - b; + + if (d < 0) m = (m + M_OFFSET) & MOD_MASK; + + d &= MOD_MASK; + + l = static_cast(m); + h = static_cast(d); +} + +inline void wdec16(unsigned short l, unsigned short h, unsigned short &a, + unsigned short &b) { + int m = l; + int d = h; + int bb = (m - (d >> 1)) & MOD_MASK; + int aa = (d + bb - A_OFFSET) & MOD_MASK; + b = static_cast(bb); + a = static_cast(aa); +} + +// +// 2D Wavelet encoding: +// + +static void wav2Encode( + unsigned short *in, // io: values are transformed in place + int nx, // i : x size + int ox, // i : x offset + int ny, // i : y size + int oy, // i : y offset + unsigned short mx) // i : maximum in[x][y] value +{ + bool w14 = (mx < (1 << 14)); + int n = (nx > ny) ? ny : nx; + int p = 1; // == 1 << level + int p2 = 2; // == 1 << (level+1) + + // + // Hierarchical loop on smaller dimension n + // + + while (p2 <= n) { + unsigned short *py = in; + unsigned short *ey = in + oy * (ny - p2); + int oy1 = oy * p; + int oy2 = oy * p2; + int ox1 = ox * p; + int ox2 = ox * p2; + unsigned short i00, i01, i10, i11; + + // + // Y loop + // + + for (; py <= ey; py += oy2) { + unsigned short *px = py; + unsigned short *ex = py + ox * (nx - p2); + + // + // X loop + // + + for (; px <= ex; px += ox2) { + unsigned short *p01 = px + ox1; + unsigned short *p10 = px + oy1; + unsigned short *p11 = p10 + ox1; + + // + // 2D wavelet encoding + // + + if (w14) { + wenc14(*px, *p01, i00, i01); + wenc14(*p10, *p11, i10, i11); + wenc14(i00, i10, *px, *p10); + wenc14(i01, i11, *p01, *p11); + } else { + wenc16(*px, *p01, i00, i01); + wenc16(*p10, *p11, i10, i11); + wenc16(i00, i10, *px, *p10); + wenc16(i01, i11, *p01, *p11); + } + } + + // + // Encode (1D) odd column (still in Y loop) + // + + if (nx & p) { + unsigned short *p10 = px + oy1; + + if (w14) + wenc14(*px, *p10, i00, *p10); + else + wenc16(*px, *p10, i00, *p10); + + *px = i00; + } + } + + // + // Encode (1D) odd line (must loop in X) + // + + if (ny & p) { + unsigned short *px = py; + unsigned short *ex = py + ox * (nx - p2); + + for (; px <= ex; px += ox2) { + unsigned short *p01 = px + ox1; + + if (w14) + wenc14(*px, *p01, i00, *p01); + else + wenc16(*px, *p01, i00, *p01); + + *px = i00; + } + } + + // + // Next level + // + + p = p2; + p2 <<= 1; + } +} + +// +// 2D Wavelet decoding: +// + +static void wav2Decode( + unsigned short *in, // io: values are transformed in place + int nx, // i : x size + int ox, // i : x offset + int ny, // i : y size + int oy, // i : y offset + unsigned short mx) // i : maximum in[x][y] value +{ + bool w14 = (mx < (1 << 14)); + int n = (nx > ny) ? ny : nx; + int p = 1; + int p2; + + // + // Search max level + // + + while (p <= n) p <<= 1; + + p >>= 1; + p2 = p; + p >>= 1; + + // + // Hierarchical loop on smaller dimension n + // + + while (p >= 1) { + unsigned short *py = in; + unsigned short *ey = in + oy * (ny - p2); + int oy1 = oy * p; + int oy2 = oy * p2; + int ox1 = ox * p; + int ox2 = ox * p2; + unsigned short i00, i01, i10, i11; + + // + // Y loop + // + + for (; py <= ey; py += oy2) { + unsigned short *px = py; + unsigned short *ex = py + ox * (nx - p2); + + // + // X loop + // + + for (; px <= ex; px += ox2) { + unsigned short *p01 = px + ox1; + unsigned short *p10 = px + oy1; + unsigned short *p11 = p10 + ox1; + + // + // 2D wavelet decoding + // + + if (w14) { + wdec14(*px, *p10, i00, i10); + wdec14(*p01, *p11, i01, i11); + wdec14(i00, i01, *px, *p01); + wdec14(i10, i11, *p10, *p11); + } else { + wdec16(*px, *p10, i00, i10); + wdec16(*p01, *p11, i01, i11); + wdec16(i00, i01, *px, *p01); + wdec16(i10, i11, *p10, *p11); + } + } + + // + // Decode (1D) odd column (still in Y loop) + // + + if (nx & p) { + unsigned short *p10 = px + oy1; + + if (w14) + wdec14(*px, *p10, i00, *p10); + else + wdec16(*px, *p10, i00, *p10); + + *px = i00; + } + } + + // + // Decode (1D) odd line (must loop in X) + // + + if (ny & p) { + unsigned short *px = py; + unsigned short *ex = py + ox * (nx - p2); + + for (; px <= ex; px += ox2) { + unsigned short *p01 = px + ox1; + + if (w14) + wdec14(*px, *p01, i00, *p01); + else + wdec16(*px, *p01, i00, *p01); + + *px = i00; + } + } + + // + // Next level + // + + p2 = p; + p >>= 1; + } +} + +//----------------------------------------------------------------------------- +// +// 16-bit Huffman compression and decompression. +// +// The source code in this file is derived from the 8-bit +// Huffman compression and decompression routines written +// by Christian Rouet for his PIZ image file format. +// +//----------------------------------------------------------------------------- + +// Adds some modification for tinyexr. + +const int HUF_ENCBITS = 16; // literal (value) bit length +const int HUF_DECBITS = 14; // decoding bit size (>= 8) + +const int HUF_ENCSIZE = (1 << HUF_ENCBITS) + 1; // encoding table size +const int HUF_DECSIZE = 1 << HUF_DECBITS; // decoding table size +const int HUF_DECMASK = HUF_DECSIZE - 1; + +struct HufDec { // short code long code + //------------------------------- + unsigned int len : 8; // code length 0 + unsigned int lit : 24; // lit p size + unsigned int *p; // 0 lits +}; + +inline long long hufLength(long long code) { return code & 63; } + +inline long long hufCode(long long code) { return code >> 6; } + +inline void outputBits(int nBits, long long bits, long long &c, int &lc, + char *&out) { + c <<= nBits; + lc += nBits; + + c |= bits; + + while (lc >= 8) *out++ = static_cast((c >> (lc -= 8))); +} + +inline long long getBits(int nBits, long long &c, int &lc, const char *&in) { + while (lc < nBits) { + c = (c << 8) | *(reinterpret_cast(in++)); + lc += 8; + } + + lc -= nBits; + return (c >> lc) & ((1 << nBits) - 1); +} + +// +// ENCODING TABLE BUILDING & (UN)PACKING +// + +// +// Build a "canonical" Huffman code table: +// - for each (uncompressed) symbol, hcode contains the length +// of the corresponding code (in the compressed data) +// - canonical codes are computed and stored in hcode +// - the rules for constructing canonical codes are as follows: +// * shorter codes (if filled with zeroes to the right) +// have a numerically higher value than longer codes +// * for codes with the same length, numerical values +// increase with numerical symbol values +// - because the canonical code table can be constructed from +// symbol lengths alone, the code table can be transmitted +// without sending the actual code values +// - see http://www.compressconsult.com/huffman/ +// + +static void hufCanonicalCodeTable(long long hcode[HUF_ENCSIZE]) { + long long n[59]; + + // + // For each i from 0 through 58, count the + // number of different codes of length i, and + // store the count in n[i]. + // + + for (int i = 0; i <= 58; ++i) n[i] = 0; + + for (int i = 0; i < HUF_ENCSIZE; ++i) n[hcode[i]] += 1; + + // + // For each i from 58 through 1, compute the + // numerically lowest code with length i, and + // store that code in n[i]. + // + + long long c = 0; + + for (int i = 58; i > 0; --i) { + long long nc = ((c + n[i]) >> 1); + n[i] = c; + c = nc; + } + + // + // hcode[i] contains the length, l, of the + // code for symbol i. Assign the next available + // code of length l to the symbol and store both + // l and the code in hcode[i]. + // + + for (int i = 0; i < HUF_ENCSIZE; ++i) { + int l = static_cast(hcode[i]); + + if (l > 0) hcode[i] = l | (n[l]++ << 6); + } +} + +// +// Compute Huffman codes (based on frq input) and store them in frq: +// - code structure is : [63:lsb - 6:msb] | [5-0: bit length]; +// - max code length is 58 bits; +// - codes outside the range [im-iM] have a null length (unused values); +// - original frequencies are destroyed; +// - encoding tables are used by hufEncode() and hufBuildDecTable(); +// + +struct FHeapCompare { + bool operator()(long long *a, long long *b) { return *a > *b; } +}; + +static void hufBuildEncTable( + long long *frq, // io: input frequencies [HUF_ENCSIZE], output table + int *im, // o: min frq index + int *iM) // o: max frq index +{ + // + // This function assumes that when it is called, array frq + // indicates the frequency of all possible symbols in the data + // that are to be Huffman-encoded. (frq[i] contains the number + // of occurrences of symbol i in the data.) + // + // The loop below does three things: + // + // 1) Finds the minimum and maximum indices that point + // to non-zero entries in frq: + // + // frq[im] != 0, and frq[i] == 0 for all i < im + // frq[iM] != 0, and frq[i] == 0 for all i > iM + // + // 2) Fills array fHeap with pointers to all non-zero + // entries in frq. + // + // 3) Initializes array hlink such that hlink[i] == i + // for all array entries. + // + + std::vector hlink(HUF_ENCSIZE); + std::vector fHeap(HUF_ENCSIZE); + + *im = 0; + + while (!frq[*im]) (*im)++; + + int nf = 0; + + for (int i = *im; i < HUF_ENCSIZE; i++) { + hlink[i] = i; + + if (frq[i]) { + fHeap[nf] = &frq[i]; + nf++; + *iM = i; + } + } + + // + // Add a pseudo-symbol, with a frequency count of 1, to frq; + // adjust the fHeap and hlink array accordingly. Function + // hufEncode() uses the pseudo-symbol for run-length encoding. + // + + (*iM)++; + frq[*iM] = 1; + fHeap[nf] = &frq[*iM]; + nf++; + + // + // Build an array, scode, such that scode[i] contains the number + // of bits assigned to symbol i. Conceptually this is done by + // constructing a tree whose leaves are the symbols with non-zero + // frequency: + // + // Make a heap that contains all symbols with a non-zero frequency, + // with the least frequent symbol on top. + // + // Repeat until only one symbol is left on the heap: + // + // Take the two least frequent symbols off the top of the heap. + // Create a new node that has first two nodes as children, and + // whose frequency is the sum of the frequencies of the first + // two nodes. Put the new node back into the heap. + // + // The last node left on the heap is the root of the tree. For each + // leaf node, the distance between the root and the leaf is the length + // of the code for the corresponding symbol. + // + // The loop below doesn't actually build the tree; instead we compute + // the distances of the leaves from the root on the fly. When a new + // node is added to the heap, then that node's descendants are linked + // into a single linear list that starts at the new node, and the code + // lengths of the descendants (that is, their distance from the root + // of the tree) are incremented by one. + // + + std::make_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); + + std::vector scode(HUF_ENCSIZE); + memset(scode.data(), 0, sizeof(long long) * HUF_ENCSIZE); + + while (nf > 1) { + // + // Find the indices, mm and m, of the two smallest non-zero frq + // values in fHeap, add the smallest frq to the second-smallest + // frq, and remove the smallest frq value from fHeap. + // + + int mm = fHeap[0] - frq; + std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); + --nf; + + int m = fHeap[0] - frq; + std::pop_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); + + frq[m] += frq[mm]; + std::push_heap(&fHeap[0], &fHeap[nf], FHeapCompare()); + + // + // The entries in scode are linked into lists with the + // entries in hlink serving as "next" pointers and with + // the end of a list marked by hlink[j] == j. + // + // Traverse the lists that start at scode[m] and scode[mm]. + // For each element visited, increment the length of the + // corresponding code by one bit. (If we visit scode[j] + // during the traversal, then the code for symbol j becomes + // one bit longer.) + // + // Merge the lists that start at scode[m] and scode[mm] + // into a single list that starts at scode[m]. + // + + // + // Add a bit to all codes in the first list. + // + + for (int j = m;; j = hlink[j]) { + scode[j]++; + + assert(scode[j] <= 58); + + if (hlink[j] == j) { + // + // Merge the two lists. + // + + hlink[j] = mm; + break; + } + } + + // + // Add a bit to all codes in the second list + // + + for (int j = mm;; j = hlink[j]) { + scode[j]++; + + assert(scode[j] <= 58); + + if (hlink[j] == j) break; + } + } + + // + // Build a canonical Huffman code table, replacing the code + // lengths in scode with (code, code length) pairs. Copy the + // code table from scode into frq. + // + + hufCanonicalCodeTable(scode.data()); + memcpy(frq, scode.data(), sizeof(long long) * HUF_ENCSIZE); +} + +// +// Pack an encoding table: +// - only code lengths, not actual codes, are stored +// - runs of zeroes are compressed as follows: +// +// unpacked packed +// -------------------------------- +// 1 zero 0 (6 bits) +// 2 zeroes 59 +// 3 zeroes 60 +// 4 zeroes 61 +// 5 zeroes 62 +// n zeroes (6 or more) 63 n-6 (6 + 8 bits) +// + +const int SHORT_ZEROCODE_RUN = 59; +const int LONG_ZEROCODE_RUN = 63; +const int SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN; +const int LONGEST_LONG_RUN = 255 + SHORTEST_LONG_RUN; + +static void hufPackEncTable( + const long long *hcode, // i : encoding table [HUF_ENCSIZE] + int im, // i : min hcode index + int iM, // i : max hcode index + char **pcode) // o: ptr to packed table (updated) +{ + char *p = *pcode; + long long c = 0; + int lc = 0; + + for (; im <= iM; im++) { + int l = hufLength(hcode[im]); + + if (l == 0) { + int zerun = 1; + + while ((im < iM) && (zerun < LONGEST_LONG_RUN)) { + if (hufLength(hcode[im + 1]) > 0) break; + im++; + zerun++; + } + + if (zerun >= 2) { + if (zerun >= SHORTEST_LONG_RUN) { + outputBits(6, LONG_ZEROCODE_RUN, c, lc, p); + outputBits(8, zerun - SHORTEST_LONG_RUN, c, lc, p); + } else { + outputBits(6, SHORT_ZEROCODE_RUN + zerun - 2, c, lc, p); + } + continue; + } + } + + outputBits(6, l, c, lc, p); + } + + if (lc > 0) *p++ = (unsigned char)(c << (8 - lc)); + + *pcode = p; +} + +// +// Unpack an encoding table packed by hufPackEncTable(): +// + +static bool hufUnpackEncTable( + const char **pcode, // io: ptr to packed table (updated) + int ni, // i : input size (in bytes) + int im, // i : min hcode index + int iM, // i : max hcode index + long long *hcode) // o: encoding table [HUF_ENCSIZE] +{ + memset(hcode, 0, sizeof(long long) * HUF_ENCSIZE); + + const char *p = *pcode; + long long c = 0; + int lc = 0; + + for (; im <= iM; im++) { + if (p - *pcode >= ni) { + return false; + } + + long long l = hcode[im] = getBits(6, c, lc, p); // code length + + if (l == (long long)LONG_ZEROCODE_RUN) { + if (p - *pcode > ni) { + return false; + } + + int zerun = getBits(8, c, lc, p) + SHORTEST_LONG_RUN; + + if (im + zerun > iM + 1) { + return false; + } + + while (zerun--) hcode[im++] = 0; + + im--; + } else if (l >= (long long)SHORT_ZEROCODE_RUN) { + int zerun = l - SHORT_ZEROCODE_RUN + 2; + + if (im + zerun > iM + 1) { + return false; + } + + while (zerun--) hcode[im++] = 0; + + im--; + } + } + + *pcode = const_cast(p); + + hufCanonicalCodeTable(hcode); + + return true; +} + +// +// DECODING TABLE BUILDING +// + +// +// Clear a newly allocated decoding table so that it contains only zeroes. +// + +static void hufClearDecTable(HufDec *hdecod) // io: (allocated by caller) +// decoding table [HUF_DECSIZE] +{ + for (int i = 0; i < HUF_DECSIZE; i++) { + hdecod[i].len = 0; + hdecod[i].lit = 0; + hdecod[i].p = NULL; + } + // memset(hdecod, 0, sizeof(HufDec) * HUF_DECSIZE); +} + +// +// Build a decoding hash table based on the encoding table hcode: +// - short codes (<= HUF_DECBITS) are resolved with a single table access; +// - long code entry allocations are not optimized, because long codes are +// unfrequent; +// - decoding tables are used by hufDecode(); +// + +static bool hufBuildDecTable(const long long *hcode, // i : encoding table + int im, // i : min index in hcode + int iM, // i : max index in hcode + HufDec *hdecod) // o: (allocated by caller) +// decoding table [HUF_DECSIZE] +{ + // + // Init hashtable & loop on all codes. + // Assumes that hufClearDecTable(hdecod) has already been called. + // + + for (; im <= iM; im++) { + long long c = hufCode(hcode[im]); + int l = hufLength(hcode[im]); + + if (c >> l) { + // + // Error: c is supposed to be an l-bit code, + // but c contains a value that is greater + // than the largest l-bit number. + // + + // invalidTableEntry(); + return false; + } + + if (l > HUF_DECBITS) { + // + // Long code: add a secondary entry + // + + HufDec *pl = hdecod + (c >> (l - HUF_DECBITS)); + + if (pl->len) { + // + // Error: a short code has already + // been stored in table entry *pl. + // + + // invalidTableEntry(); + return false; + } + + pl->lit++; + + if (pl->p) { + unsigned int *p = pl->p; + pl->p = new unsigned int[pl->lit]; + + for (int i = 0; i < pl->lit - 1; ++i) pl->p[i] = p[i]; + + delete[] p; + } else { + pl->p = new unsigned int[1]; + } + + pl->p[pl->lit - 1] = im; + } else if (l) { + // + // Short code: init all primary entries + // + + HufDec *pl = hdecod + (c << (HUF_DECBITS - l)); + + for (long long i = 1ULL << (HUF_DECBITS - l); i > 0; i--, pl++) { + if (pl->len || pl->p) { + // + // Error: a short code or a long code has + // already been stored in table entry *pl. + // + + // invalidTableEntry(); + return false; + } + + pl->len = l; + pl->lit = im; + } + } + } + + return true; +} + +// +// Free the long code entries of a decoding table built by hufBuildDecTable() +// + +static void hufFreeDecTable(HufDec *hdecod) // io: Decoding table +{ + for (int i = 0; i < HUF_DECSIZE; i++) { + if (hdecod[i].p) { + delete[] hdecod[i].p; + hdecod[i].p = 0; + } + } +} + +// +// ENCODING +// + +inline void outputCode(long long code, long long &c, int &lc, char *&out) { + outputBits(hufLength(code), hufCode(code), c, lc, out); +} + +inline void sendCode(long long sCode, int runCount, long long runCode, + long long &c, int &lc, char *&out) { + // + // Output a run of runCount instances of the symbol sCount. + // Output the symbols explicitly, or if that is shorter, output + // the sCode symbol once followed by a runCode symbol and runCount + // expressed as an 8-bit number. + // + + if (hufLength(sCode) + hufLength(runCode) + 8 < hufLength(sCode) * runCount) { + outputCode(sCode, c, lc, out); + outputCode(runCode, c, lc, out); + outputBits(8, runCount, c, lc, out); + } else { + while (runCount-- >= 0) outputCode(sCode, c, lc, out); + } +} + +// +// Encode (compress) ni values based on the Huffman encoding table hcode: +// + +static int hufEncode // return: output size (in bits) + (const long long *hcode, // i : encoding table + const unsigned short *in, // i : uncompressed input buffer + const int ni, // i : input buffer size (in bytes) + int rlc, // i : rl code + char *out) // o: compressed output buffer +{ + char *outStart = out; + long long c = 0; // bits not yet written to out + int lc = 0; // number of valid bits in c (LSB) + int s = in[0]; + int cs = 0; + + // + // Loop on input values + // + + for (int i = 1; i < ni; i++) { + // + // Count same values or send code + // + + if (s == in[i] && cs < 255) { + cs++; + } else { + sendCode(hcode[s], cs, hcode[rlc], c, lc, out); + cs = 0; + } + + s = in[i]; + } + + // + // Send remaining code + // + + sendCode(hcode[s], cs, hcode[rlc], c, lc, out); + + if (lc) *out = (c << (8 - lc)) & 0xff; + + return (out - outStart) * 8 + lc; +} + +// +// DECODING +// + +// +// In order to force the compiler to inline them, +// getChar() and getCode() are implemented as macros +// instead of "inline" functions. +// + +#define getChar(c, lc, in) \ + { \ + c = (c << 8) | *(unsigned char *)(in++); \ + lc += 8; \ + } + +#if 0 +#define getCode(po, rlc, c, lc, in, out, ob, oe) \ + { \ + if (po == rlc) { \ + if (lc < 8) getChar(c, lc, in); \ + \ + lc -= 8; \ + \ + unsigned char cs = (c >> lc); \ + \ + if (out + cs > oe) return false; \ + \ + /* TinyEXR issue 78 */ \ + unsigned short s = out[-1]; \ + \ + while (cs-- > 0) *out++ = s; \ + } else if (out < oe) { \ + *out++ = po; \ + } else { \ + return false; \ + } \ + } +#else +static bool getCode(int po, int rlc, long long &c, int &lc, const char *&in, + const char *in_end, unsigned short *&out, + const unsigned short *ob, const unsigned short *oe) { + (void)ob; + if (po == rlc) { + if (lc < 8) { + /* TinyEXR issue 78 */ + if ((in + 1) >= in_end) { + return false; + } + + getChar(c, lc, in); + } + + lc -= 8; + + unsigned char cs = (c >> lc); + + if (out + cs > oe) return false; + + // Bounds check for safety + // Issue 100. + if ((out - 1) < ob) return false; + unsigned short s = out[-1]; + + while (cs-- > 0) *out++ = s; + } else if (out < oe) { + *out++ = po; + } else { + return false; + } + return true; +} +#endif + +// +// Decode (uncompress) ni bits based on encoding & decoding tables: +// + +static bool hufDecode(const long long *hcode, // i : encoding table + const HufDec *hdecod, // i : decoding table + const char *in, // i : compressed input buffer + int ni, // i : input size (in bits) + int rlc, // i : run-length code + int no, // i : expected output size (in bytes) + unsigned short *out) // o: uncompressed output buffer +{ + long long c = 0; + int lc = 0; + unsigned short *outb = out; // begin + unsigned short *oe = out + no; // end + const char *ie = in + (ni + 7) / 8; // input byte size + + // + // Loop on input bytes + // + + while (in < ie) { + getChar(c, lc, in); + + // + // Access decoding table + // + + while (lc >= HUF_DECBITS) { + const HufDec pl = hdecod[(c >> (lc - HUF_DECBITS)) & HUF_DECMASK]; + + if (pl.len) { + // + // Get short code + // + + lc -= pl.len; + // std::cout << "lit = " << pl.lit << std::endl; + // std::cout << "rlc = " << rlc << std::endl; + // std::cout << "c = " << c << std::endl; + // std::cout << "lc = " << lc << std::endl; + // std::cout << "in = " << in << std::endl; + // std::cout << "out = " << out << std::endl; + // std::cout << "oe = " << oe << std::endl; + if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) { + return false; + } + } else { + if (!pl.p) { + return false; + } + // invalidCode(); // wrong code + + // + // Search long code + // + + int j; + + for (j = 0; j < pl.lit; j++) { + int l = hufLength(hcode[pl.p[j]]); + + while (lc < l && in < ie) // get more bits + getChar(c, lc, in); + + if (lc >= l) { + if (hufCode(hcode[pl.p[j]]) == + ((c >> (lc - l)) & (((long long)(1) << l) - 1))) { + // + // Found : get long code + // + + lc -= l; + if (!getCode(pl.p[j], rlc, c, lc, in, ie, out, outb, oe)) { + return false; + } + break; + } + } + } + + if (j == pl.lit) { + return false; + // invalidCode(); // Not found + } + } + } + } + + // + // Get remaining (short) codes + // + + int i = (8 - ni) & 7; + c >>= i; + lc -= i; + + while (lc > 0) { + const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK]; + + if (pl.len) { + lc -= pl.len; + if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) { + return false; + } + } else { + return false; + // invalidCode(); // wrong (long) code + } + } + + if (out - outb != no) { + return false; + } + // notEnoughData (); + + return true; +} + +static void countFrequencies(std::vector &freq, + const unsigned short data[/*n*/], int n) { + for (int i = 0; i < HUF_ENCSIZE; ++i) freq[i] = 0; + + for (int i = 0; i < n; ++i) ++freq[data[i]]; +} + +static void writeUInt(char buf[4], unsigned int i) { + unsigned char *b = (unsigned char *)buf; + + b[0] = i; + b[1] = i >> 8; + b[2] = i >> 16; + b[3] = i >> 24; +} + +static unsigned int readUInt(const char buf[4]) { + const unsigned char *b = (const unsigned char *)buf; + + return (b[0] & 0x000000ff) | ((b[1] << 8) & 0x0000ff00) | + ((b[2] << 16) & 0x00ff0000) | ((b[3] << 24) & 0xff000000); +} + +// +// EXTERNAL INTERFACE +// + +static int hufCompress(const unsigned short raw[], int nRaw, + char compressed[]) { + if (nRaw == 0) return 0; + + std::vector freq(HUF_ENCSIZE); + + countFrequencies(freq, raw, nRaw); + + int im = 0; + int iM = 0; + hufBuildEncTable(freq.data(), &im, &iM); + + char *tableStart = compressed + 20; + char *tableEnd = tableStart; + hufPackEncTable(freq.data(), im, iM, &tableEnd); + int tableLength = tableEnd - tableStart; + + char *dataStart = tableEnd; + int nBits = hufEncode(freq.data(), raw, nRaw, iM, dataStart); + int data_length = (nBits + 7) / 8; + + writeUInt(compressed, im); + writeUInt(compressed + 4, iM); + writeUInt(compressed + 8, tableLength); + writeUInt(compressed + 12, nBits); + writeUInt(compressed + 16, 0); // room for future extensions + + return dataStart + data_length - compressed; +} + +static bool hufUncompress(const char compressed[], int nCompressed, + std::vector *raw) { + if (nCompressed == 0) { + if (raw->size() != 0) return false; + + return false; + } + + int im = readUInt(compressed); + int iM = readUInt(compressed + 4); + // int tableLength = readUInt (compressed + 8); + int nBits = readUInt(compressed + 12); + + if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE) return false; + + const char *ptr = compressed + 20; + + // + // Fast decoder needs at least 2x64-bits of compressed data, and + // needs to be run-able on this platform. Otherwise, fall back + // to the original decoder + // + + // if (FastHufDecoder::enabled() && nBits > 128) + //{ + // FastHufDecoder fhd (ptr, nCompressed - (ptr - compressed), im, iM, iM); + // fhd.decode ((unsigned char*)ptr, nBits, raw, nRaw); + //} + // else + { + std::vector freq(HUF_ENCSIZE); + std::vector hdec(HUF_DECSIZE); + + hufClearDecTable(&hdec.at(0)); + + hufUnpackEncTable(&ptr, nCompressed - (ptr - compressed), im, iM, + &freq.at(0)); + + { + if (nBits > 8 * (nCompressed - (ptr - compressed))) { + return false; + } + + hufBuildDecTable(&freq.at(0), im, iM, &hdec.at(0)); + hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, raw->size(), + raw->data()); + } + // catch (...) + //{ + // hufFreeDecTable (hdec); + // throw; + //} + + hufFreeDecTable(&hdec.at(0)); + } + + return true; +} + +// +// Functions to compress the range of values in the pixel data +// + +const int USHORT_RANGE = (1 << 16); +const int BITMAP_SIZE = (USHORT_RANGE >> 3); + +static void bitmapFromData(const unsigned short data[/*nData*/], int nData, + unsigned char bitmap[BITMAP_SIZE], + unsigned short &minNonZero, + unsigned short &maxNonZero) { + for (int i = 0; i < BITMAP_SIZE; ++i) bitmap[i] = 0; + + for (int i = 0; i < nData; ++i) bitmap[data[i] >> 3] |= (1 << (data[i] & 7)); + + bitmap[0] &= ~1; // zero is not explicitly stored in + // the bitmap; we assume that the + // data always contain zeroes + minNonZero = BITMAP_SIZE - 1; + maxNonZero = 0; + + for (int i = 0; i < BITMAP_SIZE; ++i) { + if (bitmap[i]) { + if (minNonZero > i) minNonZero = i; + if (maxNonZero < i) maxNonZero = i; + } + } +} + +static unsigned short forwardLutFromBitmap( + const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) { + int k = 0; + + for (int i = 0; i < USHORT_RANGE; ++i) { + if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) + lut[i] = k++; + else + lut[i] = 0; + } + + return k - 1; // maximum value stored in lut[], +} // i.e. number of ones in bitmap minus 1 + +static unsigned short reverseLutFromBitmap( + const unsigned char bitmap[BITMAP_SIZE], unsigned short lut[USHORT_RANGE]) { + int k = 0; + + for (int i = 0; i < USHORT_RANGE; ++i) { + if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) lut[k++] = i; + } + + int n = k - 1; + + while (k < USHORT_RANGE) lut[k++] = 0; + + return n; // maximum k where lut[k] is non-zero, +} // i.e. number of ones in bitmap minus 1 + +static void applyLut(const unsigned short lut[USHORT_RANGE], + unsigned short data[/*nData*/], int nData) { + for (int i = 0; i < nData; ++i) data[i] = lut[data[i]]; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif // __clang__ + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize, + const unsigned char *inPtr, size_t inSize, + const std::vector &channelInfo, + int data_width, int num_lines) { + std::vector bitmap(BITMAP_SIZE); + unsigned short minNonZero; + unsigned short maxNonZero; + +#if !MINIZ_LITTLE_ENDIAN + // @todo { PIZ compression on BigEndian architecture. } + assert(0); + return false; +#endif + + // Assume `inSize` is multiple of 2 or 4. + std::vector tmpBuffer(inSize / sizeof(unsigned short)); + + std::vector channelData(channelInfo.size()); + unsigned short *tmpBufferEnd = &tmpBuffer.at(0); + + for (size_t c = 0; c < channelData.size(); c++) { + PIZChannelData &cd = channelData[c]; + + cd.start = tmpBufferEnd; + cd.end = cd.start; + + cd.nx = data_width; + cd.ny = num_lines; + // cd.ys = c.channel().ySampling; + + size_t pixelSize = sizeof(int); // UINT and FLOAT + if (channelInfo[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + pixelSize = sizeof(short); + } + + cd.size = static_cast(pixelSize / sizeof(short)); + + tmpBufferEnd += cd.nx * cd.ny * cd.size; + } + + const unsigned char *ptr = inPtr; + for (int y = 0; y < num_lines; ++y) { + for (size_t i = 0; i < channelData.size(); ++i) { + PIZChannelData &cd = channelData[i]; + + // if (modp (y, cd.ys) != 0) + // continue; + + size_t n = static_cast(cd.nx * cd.size); + memcpy(cd.end, ptr, n * sizeof(unsigned short)); + ptr += n * sizeof(unsigned short); + cd.end += n; + } + } + + bitmapFromData(&tmpBuffer.at(0), static_cast(tmpBuffer.size()), + bitmap.data(), minNonZero, maxNonZero); + + std::vector lut(USHORT_RANGE); + unsigned short maxValue = forwardLutFromBitmap(bitmap.data(), lut.data()); + applyLut(lut.data(), &tmpBuffer.at(0), static_cast(tmpBuffer.size())); + + // + // Store range compression info in _outBuffer + // + + char *buf = reinterpret_cast(outPtr); + + memcpy(buf, &minNonZero, sizeof(unsigned short)); + buf += sizeof(unsigned short); + memcpy(buf, &maxNonZero, sizeof(unsigned short)); + buf += sizeof(unsigned short); + + if (minNonZero <= maxNonZero) { + memcpy(buf, reinterpret_cast(&bitmap[0] + minNonZero), + maxNonZero - minNonZero + 1); + buf += maxNonZero - minNonZero + 1; + } + + // + // Apply wavelet encoding + // + + for (size_t i = 0; i < channelData.size(); ++i) { + PIZChannelData &cd = channelData[i]; + + for (int j = 0; j < cd.size; ++j) { + wav2Encode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size, + maxValue); + } + } + + // + // Apply Huffman encoding; append the result to _outBuffer + // + + // length header(4byte), then huff data. Initialize length header with zero, + // then later fill it by `length`. + char *lengthPtr = buf; + int zero = 0; + memcpy(buf, &zero, sizeof(int)); + buf += sizeof(int); + + int length = + hufCompress(&tmpBuffer.at(0), static_cast(tmpBuffer.size()), buf); + memcpy(lengthPtr, &length, sizeof(int)); + + (*outSize) = static_cast( + (reinterpret_cast(buf) - outPtr) + + static_cast(length)); + + // Use uncompressed data when compressed data is larger than uncompressed. + // (Issue 40) + if ((*outSize) >= inSize) { + (*outSize) = static_cast(inSize); + memcpy(outPtr, inPtr, inSize); + } + return true; +} + +static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr, + size_t tmpBufSize, size_t inLen, int num_channels, + const EXRChannelInfo *channels, int data_width, + int num_lines) { + if (inLen == tmpBufSize) { + // Data is not compressed(Issue 40). + memcpy(outPtr, inPtr, inLen); + return true; + } + + std::vector bitmap(BITMAP_SIZE); + unsigned short minNonZero; + unsigned short maxNonZero; + +#if !MINIZ_LITTLE_ENDIAN + // @todo { PIZ compression on BigEndian architecture. } + assert(0); + return false; +#endif + + memset(bitmap.data(), 0, BITMAP_SIZE); + + const unsigned char *ptr = inPtr; + // minNonZero = *(reinterpret_cast(ptr)); + tinyexr::cpy2(&minNonZero, reinterpret_cast(ptr)); + // maxNonZero = *(reinterpret_cast(ptr + 2)); + tinyexr::cpy2(&maxNonZero, reinterpret_cast(ptr + 2)); + ptr += 4; + + if (maxNonZero >= BITMAP_SIZE) { + return false; + } + + if (minNonZero <= maxNonZero) { + memcpy(reinterpret_cast(&bitmap[0] + minNonZero), ptr, + maxNonZero - minNonZero + 1); + ptr += maxNonZero - minNonZero + 1; + } + + std::vector lut(USHORT_RANGE); + memset(lut.data(), 0, sizeof(unsigned short) * USHORT_RANGE); + unsigned short maxValue = reverseLutFromBitmap(bitmap.data(), lut.data()); + + // + // Huffman decoding + // + + int length; + + // length = *(reinterpret_cast(ptr)); + tinyexr::cpy4(&length, reinterpret_cast(ptr)); + ptr += sizeof(int); + + if (size_t((ptr - inPtr) + length) > inLen) { + return false; + } + + std::vector tmpBuffer(tmpBufSize); + hufUncompress(reinterpret_cast(ptr), length, &tmpBuffer); + + // + // Wavelet decoding + // + + std::vector channelData(static_cast(num_channels)); + + unsigned short *tmpBufferEnd = &tmpBuffer.at(0); + + for (size_t i = 0; i < static_cast(num_channels); ++i) { + const EXRChannelInfo &chan = channels[i]; + + size_t pixelSize = sizeof(int); // UINT and FLOAT + if (chan.pixel_type == TINYEXR_PIXELTYPE_HALF) { + pixelSize = sizeof(short); + } + + channelData[i].start = tmpBufferEnd; + channelData[i].end = channelData[i].start; + channelData[i].nx = data_width; + channelData[i].ny = num_lines; + // channelData[i].ys = 1; + channelData[i].size = static_cast(pixelSize / sizeof(short)); + + tmpBufferEnd += channelData[i].nx * channelData[i].ny * channelData[i].size; + } + + for (size_t i = 0; i < channelData.size(); ++i) { + PIZChannelData &cd = channelData[i]; + + for (int j = 0; j < cd.size; ++j) { + wav2Decode(cd.start + j, cd.nx, cd.size, cd.ny, cd.nx * cd.size, + maxValue); + } + } + + // + // Expand the pixel data to their original range + // + + applyLut(lut.data(), &tmpBuffer.at(0), static_cast(tmpBufSize)); + + for (int y = 0; y < num_lines; y++) { + for (size_t i = 0; i < channelData.size(); ++i) { + PIZChannelData &cd = channelData[i]; + + // if (modp (y, cd.ys) != 0) + // continue; + + size_t n = static_cast(cd.nx * cd.size); + memcpy(outPtr, cd.end, static_cast(n * sizeof(unsigned short))); + outPtr += n * sizeof(unsigned short); + cd.end += n; + } + } + + return true; +} +#endif // TINYEXR_USE_PIZ + +#if TINYEXR_USE_ZFP + +struct ZFPCompressionParam { + double rate; + unsigned int precision; + unsigned int __pad0; + double tolerance; + int type; // TINYEXR_ZFP_COMPRESSIONTYPE_* + unsigned int __pad1; + + ZFPCompressionParam() { + type = TINYEXR_ZFP_COMPRESSIONTYPE_RATE; + rate = 2.0; + precision = 0; + tolerance = 0.0; + } +}; + +static bool FindZFPCompressionParam(ZFPCompressionParam *param, + const EXRAttribute *attributes, + int num_attributes, std::string *err) { + bool foundType = false; + + for (int i = 0; i < num_attributes; i++) { + if ((strcmp(attributes[i].name, "zfpCompressionType") == 0)) { + if (attributes[i].size == 1) { + param->type = static_cast(attributes[i].value[0]); + foundType = true; + break; + } else { + if (err) { + (*err) += + "zfpCompressionType attribute must be uchar(1 byte) type.\n"; + } + return false; + } + } + } + + if (!foundType) { + if (err) { + (*err) += "`zfpCompressionType` attribute not found.\n"; + } + return false; + } + + if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) { + for (int i = 0; i < num_attributes; i++) { + if ((strcmp(attributes[i].name, "zfpCompressionRate") == 0) && + (attributes[i].size == 8)) { + param->rate = *(reinterpret_cast(attributes[i].value)); + return true; + } + } + + if (err) { + (*err) += "`zfpCompressionRate` attribute not found.\n"; + } + + } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) { + for (int i = 0; i < num_attributes; i++) { + if ((strcmp(attributes[i].name, "zfpCompressionPrecision") == 0) && + (attributes[i].size == 4)) { + param->rate = *(reinterpret_cast(attributes[i].value)); + return true; + } + } + + if (err) { + (*err) += "`zfpCompressionPrecision` attribute not found.\n"; + } + + } else if (param->type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) { + for (int i = 0; i < num_attributes; i++) { + if ((strcmp(attributes[i].name, "zfpCompressionTolerance") == 0) && + (attributes[i].size == 8)) { + param->tolerance = *(reinterpret_cast(attributes[i].value)); + return true; + } + } + + if (err) { + (*err) += "`zfpCompressionTolerance` attribute not found.\n"; + } + } else { + if (err) { + (*err) += "Unknown value specified for `zfpCompressionType`.\n"; + } + } + + return false; +} + +// Assume pixel format is FLOAT for all channels. +static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines, + size_t num_channels, const unsigned char *src, + unsigned long src_size, + const ZFPCompressionParam ¶m) { + size_t uncompressed_size = + size_t(dst_width) * size_t(dst_num_lines) * num_channels; + + if (uncompressed_size == src_size) { + // Data is not compressed(Issue 40). + memcpy(dst, src, src_size); + } + + zfp_stream *zfp = NULL; + zfp_field *field = NULL; + + assert((dst_width % 4) == 0); + assert((dst_num_lines % 4) == 0); + + if ((size_t(dst_width) & 3U) || (size_t(dst_num_lines) & 3U)) { + return false; + } + + field = + zfp_field_2d(reinterpret_cast(const_cast(src)), + zfp_type_float, static_cast(dst_width), + static_cast(dst_num_lines) * + static_cast(num_channels)); + zfp = zfp_stream_open(NULL); + + if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) { + zfp_stream_set_rate(zfp, param.rate, zfp_type_float, /* dimension */ 2, + /* write random access */ 0); + } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) { + zfp_stream_set_precision(zfp, param.precision); + } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) { + zfp_stream_set_accuracy(zfp, param.tolerance); + } else { + assert(0); + } + + size_t buf_size = zfp_stream_maximum_size(zfp, field); + std::vector buf(buf_size); + memcpy(&buf.at(0), src, src_size); + + bitstream *stream = stream_open(&buf.at(0), buf_size); + zfp_stream_set_bit_stream(zfp, stream); + zfp_stream_rewind(zfp); + + size_t image_size = size_t(dst_width) * size_t(dst_num_lines); + + for (size_t c = 0; c < size_t(num_channels); c++) { + // decompress 4x4 pixel block. + for (size_t y = 0; y < size_t(dst_num_lines); y += 4) { + for (size_t x = 0; x < size_t(dst_width); x += 4) { + float fblock[16]; + zfp_decode_block_float_2(zfp, fblock); + for (size_t j = 0; j < 4; j++) { + for (size_t i = 0; i < 4; i++) { + dst[c * image_size + ((y + j) * size_t(dst_width) + (x + i))] = + fblock[j * 4 + i]; + } + } + } + } + } + + zfp_field_free(field); + zfp_stream_close(zfp); + stream_close(stream); + + return true; +} + +// Assume pixel format is FLOAT for all channels. +static bool CompressZfp(std::vector *outBuf, + unsigned int *outSize, const float *inPtr, int width, + int num_lines, int num_channels, + const ZFPCompressionParam ¶m) { + zfp_stream *zfp = NULL; + zfp_field *field = NULL; + + assert((width % 4) == 0); + assert((num_lines % 4) == 0); + + if ((size_t(width) & 3U) || (size_t(num_lines) & 3U)) { + return false; + } + + // create input array. + field = zfp_field_2d(reinterpret_cast(const_cast(inPtr)), + zfp_type_float, static_cast(width), + static_cast(num_lines * num_channels)); + + zfp = zfp_stream_open(NULL); + + if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_RATE) { + zfp_stream_set_rate(zfp, param.rate, zfp_type_float, 2, 0); + } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_PRECISION) { + zfp_stream_set_precision(zfp, param.precision); + } else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) { + zfp_stream_set_accuracy(zfp, param.tolerance); + } else { + assert(0); + } + + size_t buf_size = zfp_stream_maximum_size(zfp, field); + + outBuf->resize(buf_size); + + bitstream *stream = stream_open(&outBuf->at(0), buf_size); + zfp_stream_set_bit_stream(zfp, stream); + zfp_field_free(field); + + size_t image_size = size_t(width) * size_t(num_lines); + + for (size_t c = 0; c < size_t(num_channels); c++) { + // compress 4x4 pixel block. + for (size_t y = 0; y < size_t(num_lines); y += 4) { + for (size_t x = 0; x < size_t(width); x += 4) { + float fblock[16]; + for (size_t j = 0; j < 4; j++) { + for (size_t i = 0; i < 4; i++) { + fblock[j * 4 + i] = + inPtr[c * image_size + ((y + j) * size_t(width) + (x + i))]; + } + } + zfp_encode_block_float_2(zfp, fblock); + } + } + } + + zfp_stream_flush(zfp); + (*outSize) = static_cast(zfp_stream_compressed_size(zfp)); + + zfp_stream_close(zfp); + + return true; +} + +#endif + +// +// ----------------------------------------------------------------- +// + +// heuristics +#define TINYEXR_DIMENSION_THRESHOLD (1024 * 8192) + +// TODO(syoyo): Refactor function arguments. +static bool DecodePixelData(/* out */ unsigned char **out_images, + const int *requested_pixel_types, + const unsigned char *data_ptr, size_t data_len, + int compression_type, int line_order, int width, + int height, int x_stride, int y, int line_no, + int num_lines, size_t pixel_data_size, + size_t num_attributes, + const EXRAttribute *attributes, size_t num_channels, + const EXRChannelInfo *channels, + const std::vector &channel_offset_list) { + if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { // PIZ +#if TINYEXR_USE_PIZ + if ((width == 0) || (num_lines == 0) || (pixel_data_size == 0)) { + // Invalid input #90 + return false; + } + + // Allocate original data size. + std::vector outBuf(static_cast( + static_cast(width * num_lines) * pixel_data_size)); + size_t tmpBufLen = outBuf.size(); + + bool ret = tinyexr::DecompressPiz( + reinterpret_cast(&outBuf.at(0)), data_ptr, tmpBufLen, + data_len, static_cast(num_channels), channels, width, num_lines); + + if (!ret) { + return false; + } + + // For PIZ_COMPRESSION: + // pixel sample data for channel 0 for scanline 0 + // pixel sample data for channel 1 for scanline 0 + // pixel sample data for channel ... for scanline 0 + // pixel sample data for channel n for scanline 0 + // pixel sample data for channel 0 for scanline 1 + // pixel sample data for channel 1 for scanline 1 + // pixel sample data for channel ... for scanline 1 + // pixel sample data for channel n for scanline 1 + // ... + for (size_t c = 0; c < static_cast(num_channels); c++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned short *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + FP16 hf; + + // hf.u = line_ptr[u]; + // use `cpy` to avoid unaligned memory access when compiler's + // optimization is on. + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + unsigned short *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += static_cast( + (height - 1 - (line_no + static_cast(v)))) * + static_cast(x_stride) + + u; + } + *image = hf.u; + } else { // HALF -> FLOAT + FP32 f32 = half_to_float(hf); + float *image = reinterpret_cast(out_images)[c]; + size_t offset = 0; + if (line_order == 0) { + offset = (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + offset = static_cast( + (height - 1 - (line_no + static_cast(v)))) * + static_cast(x_stride) + + u; + } + image += offset; + *image = f32.f; + } + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT); + + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned int *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + unsigned int val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(&val); + + unsigned int *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += static_cast( + (height - 1 - (line_no + static_cast(v)))) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); + for (size_t v = 0; v < static_cast(num_lines); v++) { + const float *line_ptr = reinterpret_cast(&outBuf.at( + v * pixel_data_size * static_cast(x_stride) + + channel_offset_list[c] * static_cast(x_stride))); + for (size_t u = 0; u < static_cast(width); u++) { + float val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += static_cast( + (height - 1 - (line_no + static_cast(v)))) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else { + assert(0); + } + } +#else + assert(0 && "PIZ is enabled in this build"); + return false; +#endif + + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS || + compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + // Allocate original data size. + std::vector outBuf(static_cast(width) * + static_cast(num_lines) * + pixel_data_size); + + unsigned long dstLen = static_cast(outBuf.size()); + assert(dstLen > 0); + if (!tinyexr::DecompressZip( + reinterpret_cast(&outBuf.at(0)), &dstLen, data_ptr, + static_cast(data_len))) { + return false; + } + + // For ZIP_COMPRESSION: + // pixel sample data for channel 0 for scanline 0 + // pixel sample data for channel 1 for scanline 0 + // pixel sample data for channel ... for scanline 0 + // pixel sample data for channel n for scanline 0 + // pixel sample data for channel 0 for scanline 1 + // pixel sample data for channel 1 for scanline 1 + // pixel sample data for channel ... for scanline 1 + // pixel sample data for channel n for scanline 1 + // ... + for (size_t c = 0; c < static_cast(num_channels); c++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned short *line_ptr = reinterpret_cast( + &outBuf.at(v * static_cast(pixel_data_size) * + static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + tinyexr::FP16 hf; + + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + unsigned short *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = hf.u; + } else { // HALF -> FLOAT + tinyexr::FP32 f32 = half_to_float(hf); + float *image = reinterpret_cast(out_images)[c]; + size_t offset = 0; + if (line_order == 0) { + offset = (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + offset = (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + image += offset; + + *image = f32.f; + } + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT); + + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned int *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + unsigned int val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(&val); + + unsigned int *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); + for (size_t v = 0; v < static_cast(num_lines); v++) { + const float *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + float val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else { + assert(0); + return false; + } + } + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) { + // Allocate original data size. + std::vector outBuf(static_cast(width) * + static_cast(num_lines) * + pixel_data_size); + + unsigned long dstLen = static_cast(outBuf.size()); + if (dstLen == 0) { + return false; + } + + if (!tinyexr::DecompressRle( + reinterpret_cast(&outBuf.at(0)), dstLen, data_ptr, + static_cast(data_len))) { + return false; + } + + // For RLE_COMPRESSION: + // pixel sample data for channel 0 for scanline 0 + // pixel sample data for channel 1 for scanline 0 + // pixel sample data for channel ... for scanline 0 + // pixel sample data for channel n for scanline 0 + // pixel sample data for channel 0 for scanline 1 + // pixel sample data for channel 1 for scanline 1 + // pixel sample data for channel ... for scanline 1 + // pixel sample data for channel n for scanline 1 + // ... + for (size_t c = 0; c < static_cast(num_channels); c++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned short *line_ptr = reinterpret_cast( + &outBuf.at(v * static_cast(pixel_data_size) * + static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + tinyexr::FP16 hf; + + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + unsigned short *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = hf.u; + } else { // HALF -> FLOAT + tinyexr::FP32 f32 = half_to_float(hf); + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = f32.f; + } + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT); + + for (size_t v = 0; v < static_cast(num_lines); v++) { + const unsigned int *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + unsigned int val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(&val); + + unsigned int *image = + reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); + for (size_t v = 0; v < static_cast(num_lines); v++) { + const float *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + float val; + // val = line_ptr[u]; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else { + assert(0); + return false; + } + } + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { +#if TINYEXR_USE_ZFP + tinyexr::ZFPCompressionParam zfp_compression_param; + std::string e; + if (!tinyexr::FindZFPCompressionParam(&zfp_compression_param, attributes, + int(num_attributes), &e)) { + // This code path should not be reachable. + assert(0); + return false; + } + + // Allocate original data size. + std::vector outBuf(static_cast(width) * + static_cast(num_lines) * + pixel_data_size); + + unsigned long dstLen = outBuf.size(); + assert(dstLen > 0); + tinyexr::DecompressZfp(reinterpret_cast(&outBuf.at(0)), width, + num_lines, num_channels, data_ptr, + static_cast(data_len), + zfp_compression_param); + + // For ZFP_COMPRESSION: + // pixel sample data for channel 0 for scanline 0 + // pixel sample data for channel 1 for scanline 0 + // pixel sample data for channel ... for scanline 0 + // pixel sample data for channel n for scanline 0 + // pixel sample data for channel 0 for scanline 1 + // pixel sample data for channel 1 for scanline 1 + // pixel sample data for channel ... for scanline 1 + // pixel sample data for channel n for scanline 1 + // ... + for (size_t c = 0; c < static_cast(num_channels); c++) { + assert(channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT); + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT); + for (size_t v = 0; v < static_cast(num_lines); v++) { + const float *line_ptr = reinterpret_cast( + &outBuf.at(v * pixel_data_size * static_cast(width) + + channel_offset_list[c] * static_cast(width))); + for (size_t u = 0; u < static_cast(width); u++) { + float val; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + float *image = reinterpret_cast(out_images)[c]; + if (line_order == 0) { + image += (static_cast(line_no) + v) * + static_cast(x_stride) + + u; + } else { + image += (static_cast(height) - 1U - + (static_cast(line_no) + v)) * + static_cast(x_stride) + + u; + } + *image = val; + } + } + } else { + assert(0); + return false; + } + } +#else + (void)attributes; + (void)num_attributes; + (void)num_channels; + assert(0); + return false; +#endif + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) { + for (size_t c = 0; c < num_channels; c++) { + for (size_t v = 0; v < static_cast(num_lines); v++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + const unsigned short *line_ptr = + reinterpret_cast( + data_ptr + v * pixel_data_size * size_t(width) + + channel_offset_list[c] * static_cast(width)); + + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + unsigned short *outLine = + reinterpret_cast(out_images[c]); + if (line_order == 0) { + outLine += (size_t(y) + v) * size_t(x_stride); + } else { + outLine += + (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); + } + + for (int u = 0; u < width; u++) { + tinyexr::FP16 hf; + + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + outLine[u] = hf.u; + } + } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + float *outLine = reinterpret_cast(out_images[c]); + if (line_order == 0) { + outLine += (size_t(y) + v) * size_t(x_stride); + } else { + outLine += + (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); + } + + if (reinterpret_cast(line_ptr + width) > + (data_ptr + data_len)) { + // Insufficient data size + return false; + } + + for (int u = 0; u < width; u++) { + tinyexr::FP16 hf; + + // address may not be aliged. use byte-wise copy for safety.#76 + // hf.u = line_ptr[u]; + tinyexr::cpy2(&(hf.u), line_ptr + u); + + tinyexr::swap2(reinterpret_cast(&hf.u)); + + tinyexr::FP32 f32 = half_to_float(hf); + + outLine[u] = f32.f; + } + } else { + assert(0); + return false; + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + const float *line_ptr = reinterpret_cast( + data_ptr + v * pixel_data_size * size_t(width) + + channel_offset_list[c] * static_cast(width)); + + float *outLine = reinterpret_cast(out_images[c]); + if (line_order == 0) { + outLine += (size_t(y) + v) * size_t(x_stride); + } else { + outLine += + (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); + } + + if (reinterpret_cast(line_ptr + width) > + (data_ptr + data_len)) { + // Insufficient data size + return false; + } + + for (int u = 0; u < width; u++) { + float val; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + outLine[u] = val; + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + const unsigned int *line_ptr = reinterpret_cast( + data_ptr + v * pixel_data_size * size_t(width) + + channel_offset_list[c] * static_cast(width)); + + unsigned int *outLine = + reinterpret_cast(out_images[c]); + if (line_order == 0) { + outLine += (size_t(y) + v) * size_t(x_stride); + } else { + outLine += + (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride); + } + + for (int u = 0; u < width; u++) { + if (reinterpret_cast(line_ptr + u) >= + (data_ptr + data_len)) { + // Corrupsed data? + return false; + } + + unsigned int val; + tinyexr::cpy4(&val, line_ptr + u); + + tinyexr::swap4(reinterpret_cast(&val)); + + outLine[u] = val; + } + } + } + } + } + + return true; +} + +static bool DecodeTiledPixelData( + unsigned char **out_images, int *width, int *height, + const int *requested_pixel_types, const unsigned char *data_ptr, + size_t data_len, int compression_type, int line_order, int data_width, + int data_height, int tile_offset_x, int tile_offset_y, int tile_size_x, + int tile_size_y, size_t pixel_data_size, size_t num_attributes, + const EXRAttribute *attributes, size_t num_channels, + const EXRChannelInfo *channels, + const std::vector &channel_offset_list) { + // Here, data_width and data_height are the dimensions of the current (sub)level. + if (tile_size_x * tile_offset_x > data_width || + tile_size_y * tile_offset_y > data_height) { + return false; + } + + // Compute actual image size in a tile. + if ((tile_offset_x + 1) * tile_size_x >= data_width) { + (*width) = data_width - (tile_offset_x * tile_size_x); + } else { + (*width) = tile_size_x; + } + + if ((tile_offset_y + 1) * tile_size_y >= data_height) { + (*height) = data_height - (tile_offset_y * tile_size_y); + } else { + (*height) = tile_size_y; + } + + // Image size = tile size. + return DecodePixelData(out_images, requested_pixel_types, data_ptr, data_len, + compression_type, line_order, (*width), tile_size_y, + /* stride */ tile_size_x, /* y */ 0, /* line_no */ 0, + (*height), pixel_data_size, num_attributes, attributes, + num_channels, channels, channel_offset_list); +} + +static bool ComputeChannelLayout(std::vector *channel_offset_list, + int *pixel_data_size, size_t *channel_offset, + int num_channels, + const EXRChannelInfo *channels) { + channel_offset_list->resize(static_cast(num_channels)); + + (*pixel_data_size) = 0; + (*channel_offset) = 0; + + for (size_t c = 0; c < static_cast(num_channels); c++) { + (*channel_offset_list)[c] = (*channel_offset); + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + (*pixel_data_size) += sizeof(unsigned short); + (*channel_offset) += sizeof(unsigned short); + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + (*pixel_data_size) += sizeof(float); + (*channel_offset) += sizeof(float); + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + (*pixel_data_size) += sizeof(unsigned int); + (*channel_offset) += sizeof(unsigned int); + } else { + // ??? + return false; + } + } + return true; +} + +static unsigned char **AllocateImage(int num_channels, + const EXRChannelInfo *channels, + const int *requested_pixel_types, + int data_width, int data_height) { + unsigned char **images = + reinterpret_cast(static_cast( + malloc(sizeof(float *) * static_cast(num_channels)))); + + for (size_t c = 0; c < static_cast(num_channels); c++) { + size_t data_len = + static_cast(data_width) * static_cast(data_height); + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + // pixel_data_size += sizeof(unsigned short); + // channel_offset += sizeof(unsigned short); + // Alloc internal image for half type. + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + images[c] = + reinterpret_cast(static_cast( + malloc(sizeof(unsigned short) * data_len))); + } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + images[c] = reinterpret_cast( + static_cast(malloc(sizeof(float) * data_len))); + } else { + assert(0); + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + // pixel_data_size += sizeof(float); + // channel_offset += sizeof(float); + images[c] = reinterpret_cast( + static_cast(malloc(sizeof(float) * data_len))); + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + // pixel_data_size += sizeof(unsigned int); + // channel_offset += sizeof(unsigned int); + images[c] = reinterpret_cast( + static_cast(malloc(sizeof(unsigned int) * data_len))); + } else { + assert(0); + } + } + + return images; +} + +#ifdef _WIN32 +static inline std::wstring UTF8ToWchar(const std::string &str) { + int wstr_size = + MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), NULL, 0); + std::wstring wstr(wstr_size, 0); + MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &wstr[0], + (int)wstr.size()); + return wstr; +} +#endif + + +static int ParseEXRHeader(HeaderInfo *info, bool *empty_header, + const EXRVersion *version, std::string *err, + const unsigned char *buf, size_t size) { + const char *marker = reinterpret_cast(&buf[0]); + + if (empty_header) { + (*empty_header) = false; + } + + if (version->multipart) { + if (size > 0 && marker[0] == '\0') { + // End of header list. + if (empty_header) { + (*empty_header) = true; + } + return TINYEXR_SUCCESS; + } + } + + // According to the spec, the header of every OpenEXR file must contain at + // least the following attributes: + // + // channels chlist + // compression compression + // dataWindow box2i + // displayWindow box2i + // lineOrder lineOrder + // pixelAspectRatio float + // screenWindowCenter v2f + // screenWindowWidth float + bool has_channels = false; + bool has_compression = false; + bool has_data_window = false; + bool has_display_window = false; + bool has_line_order = false; + bool has_pixel_aspect_ratio = false; + bool has_screen_window_center = false; + bool has_screen_window_width = false; + bool has_name = false; + bool has_type = false; + + info->name.clear(); + info->type.clear(); + + info->data_window.min_x = 0; + info->data_window.min_y = 0; + info->data_window.max_x = 0; + info->data_window.max_y = 0; + info->line_order = 0; // @fixme + info->display_window.min_x = 0; + info->display_window.min_y = 0; + info->display_window.max_x = 0; + info->display_window.max_y = 0; + info->screen_window_center[0] = 0.0f; + info->screen_window_center[1] = 0.0f; + info->screen_window_width = -1.0f; + info->pixel_aspect_ratio = -1.0f; + + info->tiled = 0; + info->tile_size_x = -1; + info->tile_size_y = -1; + info->tile_level_mode = -1; + info->tile_rounding_mode = -1; + + info->attributes.clear(); + + // Read attributes + size_t orig_size = size; + for (size_t nattr = 0; nattr < TINYEXR_MAX_HEADER_ATTRIBUTES; nattr++) { + if (0 == size) { + if (err) { + (*err) += "Insufficient data size for attributes.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } else if (marker[0] == '\0') { + size--; + break; + } + + std::string attr_name; + std::string attr_type; + std::vector data; + size_t marker_size; + if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size, + marker, size)) { + if (err) { + (*err) += "Failed to read attribute.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + marker += marker_size; + size -= marker_size; + + // For a multipart file, the version field 9th bit is 0. + if ((version->tiled || version->multipart || version->non_image) && attr_name.compare("tiles") == 0) { + unsigned int x_size, y_size; + unsigned char tile_mode; + assert(data.size() == 9); + memcpy(&x_size, &data.at(0), sizeof(int)); + memcpy(&y_size, &data.at(4), sizeof(int)); + tile_mode = data[8]; + tinyexr::swap4(&x_size); + tinyexr::swap4(&y_size); + + if (x_size > static_cast(std::numeric_limits::max()) || + y_size > static_cast(std::numeric_limits::max())) { + if (err) { + (*err) = "Tile sizes were invalid."; + } + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + info->tile_size_x = static_cast(x_size); + info->tile_size_y = static_cast(y_size); + + // mode = levelMode + roundingMode * 16 + info->tile_level_mode = tile_mode & 0x3; + info->tile_rounding_mode = (tile_mode >> 4) & 0x1; + info->tiled = 1; + } else if (attr_name.compare("compression") == 0) { + bool ok = false; + if (data[0] < TINYEXR_COMPRESSIONTYPE_PIZ) { + ok = true; + } + + if (data[0] == TINYEXR_COMPRESSIONTYPE_PIZ) { +#if TINYEXR_USE_PIZ + ok = true; +#else + if (err) { + (*err) = "PIZ compression is not supported."; + } + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; +#endif + } + + if (data[0] == TINYEXR_COMPRESSIONTYPE_ZFP) { +#if TINYEXR_USE_ZFP + ok = true; +#else + if (err) { + (*err) = "ZFP compression is not supported."; + } + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; +#endif + } + + if (!ok) { + if (err) { + (*err) = "Unknown compression type."; + } + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + info->compression_type = static_cast(data[0]); + has_compression = true; + + } else if (attr_name.compare("channels") == 0) { + // name: zero-terminated string, from 1 to 255 bytes long + // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2 + // pLinear: unsigned char, possible values are 0 and 1 + // reserved: three chars, should be zero + // xSampling: int + // ySampling: int + + if (!ReadChannelInfo(info->channels, data)) { + if (err) { + (*err) += "Failed to parse channel info.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + if (info->channels.size() < 1) { + if (err) { + (*err) += "# of channels is zero.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + has_channels = true; + + } else if (attr_name.compare("dataWindow") == 0) { + if (data.size() >= 16) { + memcpy(&info->data_window.min_x, &data.at(0), sizeof(int)); + memcpy(&info->data_window.min_y, &data.at(4), sizeof(int)); + memcpy(&info->data_window.max_x, &data.at(8), sizeof(int)); + memcpy(&info->data_window.max_y, &data.at(12), sizeof(int)); + tinyexr::swap4(&info->data_window.min_x); + tinyexr::swap4(&info->data_window.min_y); + tinyexr::swap4(&info->data_window.max_x); + tinyexr::swap4(&info->data_window.max_y); + has_data_window = true; + } + } else if (attr_name.compare("displayWindow") == 0) { + if (data.size() >= 16) { + memcpy(&info->display_window.min_x, &data.at(0), sizeof(int)); + memcpy(&info->display_window.min_y, &data.at(4), sizeof(int)); + memcpy(&info->display_window.max_x, &data.at(8), sizeof(int)); + memcpy(&info->display_window.max_y, &data.at(12), sizeof(int)); + tinyexr::swap4(&info->display_window.min_x); + tinyexr::swap4(&info->display_window.min_y); + tinyexr::swap4(&info->display_window.max_x); + tinyexr::swap4(&info->display_window.max_y); + + has_display_window = true; + } + } else if (attr_name.compare("lineOrder") == 0) { + if (data.size() >= 1) { + info->line_order = static_cast(data[0]); + has_line_order = true; + } + } else if (attr_name.compare("pixelAspectRatio") == 0) { + if (data.size() >= sizeof(float)) { + memcpy(&info->pixel_aspect_ratio, &data.at(0), sizeof(float)); + tinyexr::swap4(&info->pixel_aspect_ratio); + has_pixel_aspect_ratio = true; + } + } else if (attr_name.compare("screenWindowCenter") == 0) { + if (data.size() >= 8) { + memcpy(&info->screen_window_center[0], &data.at(0), sizeof(float)); + memcpy(&info->screen_window_center[1], &data.at(4), sizeof(float)); + tinyexr::swap4(&info->screen_window_center[0]); + tinyexr::swap4(&info->screen_window_center[1]); + has_screen_window_center = true; + } + } else if (attr_name.compare("screenWindowWidth") == 0) { + if (data.size() >= sizeof(float)) { + memcpy(&info->screen_window_width, &data.at(0), sizeof(float)); + tinyexr::swap4(&info->screen_window_width); + + has_screen_window_width = true; + } + } else if (attr_name.compare("chunkCount") == 0) { + if (data.size() >= sizeof(int)) { + memcpy(&info->chunk_count, &data.at(0), sizeof(int)); + tinyexr::swap4(&info->chunk_count); + } + } else if (attr_name.compare("name") == 0) { + if (!data.empty() && data[0]) { + data.push_back(0); + size_t len = strlen(reinterpret_cast(&data[0])); + info->name.resize(len); + info->name.assign(reinterpret_cast(&data[0]), len); + has_name = true; + } + } else if (attr_name.compare("type") == 0) { + if (!data.empty() && data[0]) { + data.push_back(0); + size_t len = strlen(reinterpret_cast(&data[0])); + info->type.resize(len); + info->type.assign(reinterpret_cast(&data[0]), len); + has_type = true; + } + } else { + // Custom attribute(up to TINYEXR_MAX_CUSTOM_ATTRIBUTES) + if (info->attributes.size() < TINYEXR_MAX_CUSTOM_ATTRIBUTES) { + EXRAttribute attrib; +#ifdef _MSC_VER + strncpy_s(attrib.name, attr_name.c_str(), 255); + strncpy_s(attrib.type, attr_type.c_str(), 255); +#else + strncpy(attrib.name, attr_name.c_str(), 255); + strncpy(attrib.type, attr_type.c_str(), 255); +#endif + attrib.name[255] = '\0'; + attrib.type[255] = '\0'; + attrib.size = static_cast(data.size()); + attrib.value = static_cast(malloc(data.size())); + memcpy(reinterpret_cast(attrib.value), &data.at(0), + data.size()); + info->attributes.push_back(attrib); + } + } + } + + // Check if required attributes exist + { + std::stringstream ss_err; + + if (!has_compression) { + ss_err << "\"compression\" attribute not found in the header." + << std::endl; + } + + if (!has_channels) { + ss_err << "\"channels\" attribute not found in the header." << std::endl; + } + + if (!has_line_order) { + ss_err << "\"lineOrder\" attribute not found in the header." << std::endl; + } + + if (!has_display_window) { + ss_err << "\"displayWindow\" attribute not found in the header." + << std::endl; + } + + if (!has_data_window) { + ss_err << "\"dataWindow\" attribute not found in the header or invalid." + << std::endl; + } + + if (!has_pixel_aspect_ratio) { + ss_err << "\"pixelAspectRatio\" attribute not found in the header." + << std::endl; + } + + if (!has_screen_window_width) { + ss_err << "\"screenWindowWidth\" attribute not found in the header." + << std::endl; + } + + if (!has_screen_window_center) { + ss_err << "\"screenWindowCenter\" attribute not found in the header." + << std::endl; + } + + if (version->multipart || version->non_image) { + if (!has_name) { + ss_err << "\"name\" attribute not found in the header." + << std::endl; + } + if (!has_type) { + ss_err << "\"type\" attribute not found in the header." + << std::endl; + } + } + + if (!(ss_err.str().empty())) { + if (err) { + (*err) += ss_err.str(); + } + return TINYEXR_ERROR_INVALID_HEADER; + } + } + + info->header_len = static_cast(orig_size - size); + + return TINYEXR_SUCCESS; +} + +// C++ HeaderInfo to C EXRHeader conversion. +static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) { + exr_header->pixel_aspect_ratio = info.pixel_aspect_ratio; + exr_header->screen_window_center[0] = info.screen_window_center[0]; + exr_header->screen_window_center[1] = info.screen_window_center[1]; + exr_header->screen_window_width = info.screen_window_width; + exr_header->chunk_count = info.chunk_count; + exr_header->display_window.min_x = info.display_window.min_x; + exr_header->display_window.min_y = info.display_window.min_y; + exr_header->display_window.max_x = info.display_window.max_x; + exr_header->display_window.max_y = info.display_window.max_y; + exr_header->data_window.min_x = info.data_window.min_x; + exr_header->data_window.min_y = info.data_window.min_y; + exr_header->data_window.max_x = info.data_window.max_x; + exr_header->data_window.max_y = info.data_window.max_y; + exr_header->line_order = info.line_order; + exr_header->compression_type = info.compression_type; + exr_header->tiled = info.tiled; + exr_header->tile_size_x = info.tile_size_x; + exr_header->tile_size_y = info.tile_size_y; + exr_header->tile_level_mode = info.tile_level_mode; + exr_header->tile_rounding_mode = info.tile_rounding_mode; + + EXRSetNameAttr(exr_header, info.name.c_str()); + + if (!info.type.empty()) { + if (info.type == "scanlineimage") { + assert(!exr_header->tiled); + } else if (info.type == "tiledimage") { + assert(exr_header->tiled); + } else if (info.type == "deeptile") { + exr_header->non_image = 1; + assert(exr_header->tiled); + } else if (info.type == "deepscanline") { + exr_header->non_image = 1; + assert(!exr_header->tiled); + } else { + assert(false); + } + } + + exr_header->num_channels = static_cast(info.channels.size()); + + exr_header->channels = static_cast(malloc( + sizeof(EXRChannelInfo) * static_cast(exr_header->num_channels))); + for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { +#ifdef _MSC_VER + strncpy_s(exr_header->channels[c].name, info.channels[c].name.c_str(), 255); +#else + strncpy(exr_header->channels[c].name, info.channels[c].name.c_str(), 255); +#endif + // manually add '\0' for safety. + exr_header->channels[c].name[255] = '\0'; + + exr_header->channels[c].pixel_type = info.channels[c].pixel_type; + exr_header->channels[c].p_linear = info.channels[c].p_linear; + exr_header->channels[c].x_sampling = info.channels[c].x_sampling; + exr_header->channels[c].y_sampling = info.channels[c].y_sampling; + } + + exr_header->pixel_types = static_cast( + malloc(sizeof(int) * static_cast(exr_header->num_channels))); + for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { + exr_header->pixel_types[c] = info.channels[c].pixel_type; + } + + // Initially fill with values of `pixel_types` + exr_header->requested_pixel_types = static_cast( + malloc(sizeof(int) * static_cast(exr_header->num_channels))); + for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { + exr_header->requested_pixel_types[c] = info.channels[c].pixel_type; + } + + exr_header->num_custom_attributes = static_cast(info.attributes.size()); + + if (exr_header->num_custom_attributes > 0) { + // TODO(syoyo): Report warning when # of attributes exceeds + // `TINYEXR_MAX_CUSTOM_ATTRIBUTES` + if (exr_header->num_custom_attributes > TINYEXR_MAX_CUSTOM_ATTRIBUTES) { + exr_header->num_custom_attributes = TINYEXR_MAX_CUSTOM_ATTRIBUTES; + } + + exr_header->custom_attributes = static_cast(malloc( + sizeof(EXRAttribute) * size_t(exr_header->num_custom_attributes))); + + for (size_t i = 0; i < info.attributes.size(); i++) { + memcpy(exr_header->custom_attributes[i].name, info.attributes[i].name, + 256); + memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type, + 256); + exr_header->custom_attributes[i].size = info.attributes[i].size; + // Just copy pointer + exr_header->custom_attributes[i].value = info.attributes[i].value; + } + + } else { + exr_header->custom_attributes = NULL; + } + + exr_header->header_len = info.header_len; +} + +struct OffsetData { + OffsetData() : num_x_levels(0), num_y_levels(0) {} + std::vector > > offsets; + int num_x_levels; + int num_y_levels; +}; + +int LevelIndex(int lx, int ly, int tile_level_mode, int num_x_levels) { + switch (tile_level_mode) { + case TINYEXR_TILE_ONE_LEVEL: + return 0; + + case TINYEXR_TILE_MIPMAP_LEVELS: + return lx; + + case TINYEXR_TILE_RIPMAP_LEVELS: + return lx + ly * num_x_levels; + + default: + assert(false); + } + return 0; +} + +static int LevelSize(int toplevel_size, int level, int tile_rounding_mode) { + assert(level >= 0); + + int b = (int)(1u << (unsigned)level); + int level_size = toplevel_size / b; + + if (tile_rounding_mode == TINYEXR_TILE_ROUND_UP && level_size * b < toplevel_size) + level_size += 1; + + return std::max(level_size, 1); +} + +static int DecodeTiledLevel(EXRImage* exr_image, const EXRHeader* exr_header, + const OffsetData& offset_data, + const std::vector& channel_offset_list, + int pixel_data_size, + const unsigned char* head, const size_t size, + std::string* err) { + int num_channels = exr_header->num_channels; + + int level_index = LevelIndex(exr_image->level_x, exr_image->level_y, exr_header->tile_level_mode, offset_data.num_x_levels); + int num_y_tiles = (int)offset_data.offsets[level_index].size(); + assert(num_y_tiles); + int num_x_tiles = (int)offset_data.offsets[level_index][0].size(); + assert(num_x_tiles); + int num_tiles = num_x_tiles * num_y_tiles; + + int err_code = TINYEXR_SUCCESS; + + enum { + EF_SUCCESS = 0, + EF_INVALID_DATA = 1, + EF_INSUFFICIENT_DATA = 2, + EF_FAILED_TO_DECODE = 4 + }; +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::atomic error_flag(EF_SUCCESS); +#else + unsigned error_flag(EF_SUCCESS); +#endif + + // Although the spec says : "...the data window is subdivided into an array of smaller rectangles...", + // the IlmImf library allows the dimensions of the tile to be larger (or equal) than the dimensions of the data window. +#if 0 + if ((exr_header->tile_size_x > exr_image->width || exr_header->tile_size_y > exr_image->height) && + exr_image->level_x == 0 && exr_image->level_y == 0) { + if (err) { + (*err) += "Failed to decode tile data.\n"; + } + err_code = TINYEXR_ERROR_INVALID_DATA; + } +#endif + exr_image->tiles = static_cast( + calloc(sizeof(EXRTile), static_cast(num_tiles))); + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::vector workers; + std::atomic tile_count(0); + + int num_threads = std::max(1, int(std::thread::hardware_concurrency())); + if (num_threads > int(num_tiles)) { + num_threads = int(num_tiles); + } + + for (int t = 0; t < num_threads; t++) { + workers.emplace_back(std::thread([&]() + { + int tile_idx = 0; + while ((tile_idx = tile_count++) < num_tiles) { + +#else +#if TINYEXR_USE_OPENMP +#pragma omp parallel for +#endif + for (int tile_idx = 0; tile_idx < num_tiles; tile_idx++) { +#endif + // Allocate memory for each tile. + exr_image->tiles[tile_idx].images = tinyexr::AllocateImage( + num_channels, exr_header->channels, + exr_header->requested_pixel_types, exr_header->tile_size_x, + exr_header->tile_size_y); + + int x_tile = tile_idx % num_x_tiles; + int y_tile = tile_idx / num_x_tiles; + // 16 byte: tile coordinates + // 4 byte : data size + // ~ : data(uncompressed or compressed) + tinyexr::tinyexr_uint64 offset = offset_data.offsets[level_index][y_tile][x_tile]; + if (offset + sizeof(int) * 5 > size) { + // Insufficient data size. + error_flag |= EF_INSUFFICIENT_DATA; + continue; + } + + size_t data_size = + size_t(size - (offset + sizeof(int) * 5)); + const unsigned char* data_ptr = + reinterpret_cast(head + offset); + + int tile_coordinates[4]; + memcpy(tile_coordinates, data_ptr, sizeof(int) * 4); + tinyexr::swap4(&tile_coordinates[0]); + tinyexr::swap4(&tile_coordinates[1]); + tinyexr::swap4(&tile_coordinates[2]); + tinyexr::swap4(&tile_coordinates[3]); + + if (tile_coordinates[2] != exr_image->level_x) { + // Invalid data. + error_flag |= EF_INVALID_DATA; + continue; + } + if (tile_coordinates[3] != exr_image->level_y) { + // Invalid data. + error_flag |= EF_INVALID_DATA; + continue; + } + + int data_len; + memcpy(&data_len, data_ptr + 16, + sizeof(int)); // 16 = sizeof(tile_coordinates) + tinyexr::swap4(&data_len); + + if (data_len < 2 || size_t(data_len) > data_size) { + // Insufficient data size. + error_flag |= EF_INSUFFICIENT_DATA; + continue; + } + + // Move to data addr: 20 = 16 + 4; + data_ptr += 20; + bool ret = tinyexr::DecodeTiledPixelData( + exr_image->tiles[tile_idx].images, + &(exr_image->tiles[tile_idx].width), + &(exr_image->tiles[tile_idx].height), + exr_header->requested_pixel_types, data_ptr, + static_cast(data_len), exr_header->compression_type, + exr_header->line_order, + exr_image->width, exr_image->height, + tile_coordinates[0], tile_coordinates[1], exr_header->tile_size_x, + exr_header->tile_size_y, static_cast(pixel_data_size), + static_cast(exr_header->num_custom_attributes), + exr_header->custom_attributes, + static_cast(exr_header->num_channels), + exr_header->channels, channel_offset_list); + + if (!ret) { + // Failed to decode tile data. + error_flag |= EF_FAILED_TO_DECODE; + } + + exr_image->tiles[tile_idx].offset_x = tile_coordinates[0]; + exr_image->tiles[tile_idx].offset_y = tile_coordinates[1]; + exr_image->tiles[tile_idx].level_x = tile_coordinates[2]; + exr_image->tiles[tile_idx].level_y = tile_coordinates[3]; + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + } + })); + } // num_thread loop + + for (auto& t : workers) { + t.join(); + } + +#else + } // parallel for +#endif + + // Even in the event of an error, the reserved memory may be freed. + exr_image->num_channels = num_channels; + exr_image->num_tiles = static_cast(num_tiles); + + if (error_flag) err_code = TINYEXR_ERROR_INVALID_DATA; + if (err) { + if (error_flag & EF_INSUFFICIENT_DATA) { + (*err) += "Insufficient data length.\n"; + } + if (error_flag & EF_FAILED_TO_DECODE) { + (*err) += "Failed to decode tile data.\n"; + } + } + return err_code; +} + +static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header, + const OffsetData& offset_data, + const unsigned char *head, const size_t size, + std::string *err) { + int num_channels = exr_header->num_channels; + + int num_scanline_blocks = 1; + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + num_scanline_blocks = 16; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + num_scanline_blocks = 32; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + num_scanline_blocks = 16; + +#if TINYEXR_USE_ZFP + tinyexr::ZFPCompressionParam zfp_compression_param; + if (!FindZFPCompressionParam(&zfp_compression_param, + exr_header->custom_attributes, + int(exr_header->num_custom_attributes), err)) { + return TINYEXR_ERROR_INVALID_HEADER; + } +#endif + } + + if (exr_header->data_window.max_x < exr_header->data_window.min_x || + exr_header->data_window.max_y < exr_header->data_window.min_y) { + if (err) { + (*err) += "Invalid data window.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + int data_width = + exr_header->data_window.max_x - exr_header->data_window.min_x + 1; + int data_height = + exr_header->data_window.max_y - exr_header->data_window.min_y + 1; + + // Do not allow too large data_width and data_height. header invalid? + { + if ((data_width > TINYEXR_DIMENSION_THRESHOLD) || (data_height > TINYEXR_DIMENSION_THRESHOLD)) { + if (err) { + std::stringstream ss; + ss << "data_with or data_height too large. data_width: " << data_width + << ", " + << "data_height = " << data_height << std::endl; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_DATA; + } + if (exr_header->tiled) { + if ((exr_header->tile_size_x > TINYEXR_DIMENSION_THRESHOLD) || (exr_header->tile_size_y > TINYEXR_DIMENSION_THRESHOLD)) { + if (err) { + std::stringstream ss; + ss << "tile with or tile height too large. tile width: " << exr_header->tile_size_x + << ", " + << "tile height = " << exr_header->tile_size_y << std::endl; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_DATA; + } + } + } + + const std::vector& offsets = offset_data.offsets[0][0]; + size_t num_blocks = offsets.size(); + + std::vector channel_offset_list; + int pixel_data_size = 0; + size_t channel_offset = 0; + if (!tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size, + &channel_offset, num_channels, + exr_header->channels)) { + if (err) { + (*err) += "Failed to compute channel layout.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::atomic invalid_data(false); +#else + bool invalid_data(false); +#endif + + if (exr_header->tiled) { + // value check + if (exr_header->tile_size_x < 0) { + if (err) { + std::stringstream ss; + ss << "Invalid tile size x : " << exr_header->tile_size_x << "\n"; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_HEADER; + } + + if (exr_header->tile_size_y < 0) { + if (err) { + std::stringstream ss; + ss << "Invalid tile size y : " << exr_header->tile_size_y << "\n"; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_HEADER; + } + if (exr_header->tile_level_mode != TINYEXR_TILE_RIPMAP_LEVELS) { + EXRImage* level_image = NULL; + for (int level = 0; level < offset_data.num_x_levels; ++level) { + if (!level_image) { + level_image = exr_image; + } else { + level_image->next_level = new EXRImage; + InitEXRImage(level_image->next_level); + level_image = level_image->next_level; + } + level_image->width = + LevelSize(exr_header->data_window.max_x - exr_header->data_window.min_x + 1, level, exr_header->tile_rounding_mode); + level_image->height = + LevelSize(exr_header->data_window.max_y - exr_header->data_window.min_y + 1, level, exr_header->tile_rounding_mode); + level_image->level_x = level; + level_image->level_y = level; + + int ret = DecodeTiledLevel(level_image, exr_header, + offset_data, + channel_offset_list, + pixel_data_size, + head, size, + err); + if (ret != TINYEXR_SUCCESS) return ret; + } + } else { + EXRImage* level_image = NULL; + for (int level_y = 0; level_y < offset_data.num_y_levels; ++level_y) + for (int level_x = 0; level_x < offset_data.num_x_levels; ++level_x) { + if (!level_image) { + level_image = exr_image; + } else { + level_image->next_level = new EXRImage; + InitEXRImage(level_image->next_level); + level_image = level_image->next_level; + } + + level_image->width = + LevelSize(exr_header->data_window.max_x - exr_header->data_window.min_x + 1, level_x, exr_header->tile_rounding_mode); + level_image->height = + LevelSize(exr_header->data_window.max_y - exr_header->data_window.min_y + 1, level_y, exr_header->tile_rounding_mode); + level_image->level_x = level_x; + level_image->level_y = level_y; + + int ret = DecodeTiledLevel(level_image, exr_header, + offset_data, + channel_offset_list, + pixel_data_size, + head, size, + err); + if (ret != TINYEXR_SUCCESS) return ret; + } + } + } else { // scanline format + // Don't allow too large image(256GB * pixel_data_size or more). Workaround + // for #104. + size_t total_data_len = + size_t(data_width) * size_t(data_height) * size_t(num_channels); + const bool total_data_len_overflown = + sizeof(void *) == 8 ? (total_data_len >= 0x4000000000) : false; + if ((total_data_len == 0) || total_data_len_overflown) { + if (err) { + std::stringstream ss; + ss << "Image data size is zero or too large: width = " << data_width + << ", height = " << data_height << ", channels = " << num_channels + << std::endl; + (*err) += ss.str(); + } + return TINYEXR_ERROR_INVALID_DATA; + } + + exr_image->images = tinyexr::AllocateImage( + num_channels, exr_header->channels, exr_header->requested_pixel_types, + data_width, data_height); + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::vector workers; + std::atomic y_count(0); + + int num_threads = std::max(1, int(std::thread::hardware_concurrency())); + if (num_threads > int(num_blocks)) { + num_threads = int(num_blocks); + } + + for (int t = 0; t < num_threads; t++) { + workers.emplace_back(std::thread([&]() { + int y = 0; + while ((y = y_count++) < int(num_blocks)) { + +#else + +#if TINYEXR_USE_OPENMP +#pragma omp parallel for +#endif + for (int y = 0; y < static_cast(num_blocks); y++) { + +#endif + size_t y_idx = static_cast(y); + + if (offsets[y_idx] + sizeof(int) * 2 > size) { + invalid_data = true; + } else { + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(uncompressed or compressed) + size_t data_size = + size_t(size - (offsets[y_idx] + sizeof(int) * 2)); + const unsigned char *data_ptr = + reinterpret_cast(head + offsets[y_idx]); + + int line_no; + memcpy(&line_no, data_ptr, sizeof(int)); + int data_len; + memcpy(&data_len, data_ptr + 4, sizeof(int)); + tinyexr::swap4(&line_no); + tinyexr::swap4(&data_len); + + if (size_t(data_len) > data_size) { + invalid_data = true; + + } else if ((line_no > (2 << 20)) || (line_no < -(2 << 20))) { + // Too large value. Assume this is invalid + // 2**20 = 1048576 = heuristic value. + invalid_data = true; + } else if (data_len == 0) { + // TODO(syoyo): May be ok to raise the threshold for example + // `data_len < 4` + invalid_data = true; + } else { + // line_no may be negative. + int end_line_no = (std::min)(line_no + num_scanline_blocks, + (exr_header->data_window.max_y + 1)); + + int num_lines = end_line_no - line_no; + + if (num_lines <= 0) { + invalid_data = true; + } else { + // Move to data addr: 8 = 4 + 4; + data_ptr += 8; + + // Adjust line_no with data_window.bmin.y + + // overflow check + tinyexr_int64 lno = + static_cast(line_no) - + static_cast(exr_header->data_window.min_y); + if (lno > std::numeric_limits::max()) { + line_no = -1; // invalid + } else if (lno < -std::numeric_limits::max()) { + line_no = -1; // invalid + } else { + line_no -= exr_header->data_window.min_y; + } + + if (line_no < 0) { + invalid_data = true; + } else { + if (!tinyexr::DecodePixelData( + exr_image->images, exr_header->requested_pixel_types, + data_ptr, static_cast(data_len), + exr_header->compression_type, exr_header->line_order, + data_width, data_height, data_width, y, line_no, + num_lines, static_cast(pixel_data_size), + static_cast( + exr_header->num_custom_attributes), + exr_header->custom_attributes, + static_cast(exr_header->num_channels), + exr_header->channels, channel_offset_list)) { + invalid_data = true; + } + } + } + } + } + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + } + })); + } + + for (auto &t : workers) { + t.join(); + } +#else + } // omp parallel +#endif + } + + if (invalid_data) { + if (err) { + std::stringstream ss; + (*err) += "Invalid data found when decoding pixels.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + // Overwrite `pixel_type` with `requested_pixel_type`. + { + for (int c = 0; c < exr_header->num_channels; c++) { + exr_header->pixel_types[c] = exr_header->requested_pixel_types[c]; + } + } + + { + exr_image->num_channels = num_channels; + + exr_image->width = data_width; + exr_image->height = data_height; + } + + return TINYEXR_SUCCESS; +} + +static bool ReconstructLineOffsets( + std::vector *offsets, size_t n, + const unsigned char *head, const unsigned char *marker, const size_t size) { + assert(head < marker); + assert(offsets->size() == n); + + for (size_t i = 0; i < n; i++) { + size_t offset = static_cast(marker - head); + // Offset should not exceed whole EXR file/data size. + if ((offset + sizeof(tinyexr::tinyexr_uint64)) >= size) { + return false; + } + + int y; + unsigned int data_len; + + memcpy(&y, marker, sizeof(int)); + memcpy(&data_len, marker + 4, sizeof(unsigned int)); + + if (data_len >= size) { + return false; + } + + tinyexr::swap4(&y); + tinyexr::swap4(&data_len); + + (*offsets)[i] = offset; + + marker += data_len + 8; // 8 = 4 bytes(y) + 4 bytes(data_len) + } + + return true; +} + + +static int FloorLog2(unsigned x) { + // + // For x > 0, floorLog2(y) returns floor(log(x)/log(2)). + // + int y = 0; + while (x > 1) { + y += 1; + x >>= 1u; + } + return y; +} + + +static int CeilLog2(unsigned x) { + // + // For x > 0, ceilLog2(y) returns ceil(log(x)/log(2)). + // + int y = 0; + int r = 0; + while (x > 1) { + if (x & 1) + r = 1; + + y += 1; + x >>= 1u; + } + return y + r; +} + +static int RoundLog2(int x, int tile_rounding_mode) { + return (tile_rounding_mode == TINYEXR_TILE_ROUND_DOWN) ? FloorLog2(static_cast(x)) : CeilLog2(static_cast(x)); +} + +static int CalculateNumXLevels(const EXRHeader* exr_header) { + int min_x = exr_header->data_window.min_x; + int max_x = exr_header->data_window.max_x; + int min_y = exr_header->data_window.min_y; + int max_y = exr_header->data_window.max_y; + + int num = 0; + switch (exr_header->tile_level_mode) { + case TINYEXR_TILE_ONE_LEVEL: + + num = 1; + break; + + case TINYEXR_TILE_MIPMAP_LEVELS: + + { + int w = max_x - min_x + 1; + int h = max_y - min_y + 1; + num = RoundLog2(std::max(w, h), exr_header->tile_rounding_mode) + 1; + } + break; + + case TINYEXR_TILE_RIPMAP_LEVELS: + + { + int w = max_x - min_x + 1; + num = RoundLog2(w, exr_header->tile_rounding_mode) + 1; + } + break; + + default: + + assert(false); + } + + return num; +} + +static int CalculateNumYLevels(const EXRHeader* exr_header) { + int min_x = exr_header->data_window.min_x; + int max_x = exr_header->data_window.max_x; + int min_y = exr_header->data_window.min_y; + int max_y = exr_header->data_window.max_y; + int num = 0; + + switch (exr_header->tile_level_mode) { + case TINYEXR_TILE_ONE_LEVEL: + + num = 1; + break; + + case TINYEXR_TILE_MIPMAP_LEVELS: + + { + int w = max_x - min_x + 1; + int h = max_y - min_y + 1; + num = RoundLog2(std::max(w, h), exr_header->tile_rounding_mode) + 1; + } + break; + + case TINYEXR_TILE_RIPMAP_LEVELS: + + { + int h = max_y - min_y + 1; + num = RoundLog2(h, exr_header->tile_rounding_mode) + 1; + } + break; + + default: + + assert(false); + } + + return num; +} + +static void CalculateNumTiles(std::vector& numTiles, + int toplevel_size, + int size, + int tile_rounding_mode) { + for (unsigned i = 0; i < numTiles.size(); i++) { + int l = LevelSize(toplevel_size, i, tile_rounding_mode); + assert(l <= std::numeric_limits::max() - size + 1); + + numTiles[i] = (l + size - 1) / size; + } +} + +static void PrecalculateTileInfo(std::vector& num_x_tiles, + std::vector& num_y_tiles, + const EXRHeader* exr_header) { + int min_x = exr_header->data_window.min_x; + int max_x = exr_header->data_window.max_x; + int min_y = exr_header->data_window.min_y; + int max_y = exr_header->data_window.max_y; + + int num_x_levels = CalculateNumXLevels(exr_header); + int num_y_levels = CalculateNumYLevels(exr_header); + + num_x_tiles.resize(num_x_levels); + num_y_tiles.resize(num_y_levels); + + CalculateNumTiles(num_x_tiles, + max_x - min_x + 1, + exr_header->tile_size_x, + exr_header->tile_rounding_mode); + + CalculateNumTiles(num_y_tiles, + max_y - min_y + 1, + exr_header->tile_size_y, + exr_header->tile_rounding_mode); +} + +static void InitSingleResolutionOffsets(OffsetData& offset_data, size_t num_blocks) { + offset_data.offsets.resize(1); + offset_data.offsets[0].resize(1); + offset_data.offsets[0][0].resize(num_blocks); + offset_data.num_x_levels = 1; + offset_data.num_y_levels = 1; +} + +// Return sum of tile blocks. +static int InitTileOffsets(OffsetData& offset_data, + const EXRHeader* exr_header, + const std::vector& num_x_tiles, + const std::vector& num_y_tiles) { + int num_tile_blocks = 0; + offset_data.num_x_levels = static_cast(num_x_tiles.size()); + offset_data.num_y_levels = static_cast(num_y_tiles.size()); + switch (exr_header->tile_level_mode) { + case TINYEXR_TILE_ONE_LEVEL: + case TINYEXR_TILE_MIPMAP_LEVELS: + assert(offset_data.num_x_levels == offset_data.num_y_levels); + offset_data.offsets.resize(offset_data.num_x_levels); + + for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) { + offset_data.offsets[l].resize(num_y_tiles[l]); + + for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) { + offset_data.offsets[l][dy].resize(num_x_tiles[l]); + num_tile_blocks += num_x_tiles[l]; + } + } + break; + + case TINYEXR_TILE_RIPMAP_LEVELS: + + offset_data.offsets.resize(static_cast(offset_data.num_x_levels) * static_cast(offset_data.num_y_levels)); + + for (int ly = 0; ly < offset_data.num_y_levels; ++ly) { + for (int lx = 0; lx < offset_data.num_x_levels; ++lx) { + int l = ly * offset_data.num_x_levels + lx; + offset_data.offsets[l].resize(num_y_tiles[ly]); + + for (size_t dy = 0; dy < offset_data.offsets[l].size(); ++dy) { + offset_data.offsets[l][dy].resize(num_x_tiles[lx]); + num_tile_blocks += num_x_tiles[lx]; + } + } + } + break; + + default: + assert(false); + } + return num_tile_blocks; +} + +static bool IsAnyOffsetsAreInvalid(const OffsetData& offset_data) { + for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) + for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) + for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) + if (reinterpret_cast(offset_data.offsets[l][dy][dx]) <= 0) + return true; + + return false; +} + +static bool isValidTile(const EXRHeader* exr_header, + const OffsetData& offset_data, + int dx, int dy, int lx, int ly) { + if (lx < 0 || ly < 0 || dx < 0 || dy < 0) return false; + int num_x_levels = offset_data.num_x_levels; + int num_y_levels = offset_data.num_y_levels; + switch (exr_header->tile_level_mode) { + case TINYEXR_TILE_ONE_LEVEL: + + if (lx == 0 && + ly == 0 && + offset_data.offsets.size() > 0 && + offset_data.offsets[0].size() > static_cast(dy) && + offset_data.offsets[0][dy].size() > static_cast(dx)) { + return true; + } + + break; + + case TINYEXR_TILE_MIPMAP_LEVELS: + + if (lx < num_x_levels && + ly < num_y_levels && + offset_data.offsets.size() > static_cast(lx) && + offset_data.offsets[lx].size() > static_cast(dy) && + offset_data.offsets[lx][dy].size() > static_cast(dx)) { + return true; + } + + break; + + case TINYEXR_TILE_RIPMAP_LEVELS: + { + size_t idx = static_cast(lx) + static_cast(ly)* static_cast(num_x_levels); + if (lx < num_x_levels && + ly < num_y_levels && + (offset_data.offsets.size() > idx) && + offset_data.offsets[idx].size() > static_cast(dy) && + offset_data.offsets[idx][dy].size() > static_cast(dx)) { + return true; + } + } + + break; + + default: + + return false; + } + + return false; +} + +static void ReconstructTileOffsets(OffsetData& offset_data, + const EXRHeader* exr_header, + const unsigned char* head, const unsigned char* marker, const size_t size, + bool isMultiPartFile, + bool isDeep) { + int numXLevels = offset_data.num_x_levels; + for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) { + for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) { + for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) { + tinyexr::tinyexr_uint64 tileOffset = marker - head; + + if (isMultiPartFile) { + //int partNumber; + marker += sizeof(int); + } + + int tileX; + memcpy(&tileX, marker, sizeof(int)); + tinyexr::swap4(&tileX); + marker += sizeof(int); + + int tileY; + memcpy(&tileY, marker, sizeof(int)); + tinyexr::swap4(&tileY); + marker += sizeof(int); + + int levelX; + memcpy(&levelX, marker, sizeof(int)); + tinyexr::swap4(&levelX); + marker += sizeof(int); + + int levelY; + memcpy(&levelY, marker, sizeof(int)); + tinyexr::swap4(&levelY); + marker += sizeof(int); + + if (isDeep) { + tinyexr::tinyexr_int64 packed_offset_table_size; + memcpy(&packed_offset_table_size, marker, sizeof(tinyexr::tinyexr_int64)); + tinyexr::swap8(reinterpret_cast(&packed_offset_table_size)); + marker += sizeof(tinyexr::tinyexr_int64); + + tinyexr::tinyexr_int64 packed_sample_size; + memcpy(&packed_sample_size, marker, sizeof(tinyexr::tinyexr_int64)); + tinyexr::swap8(reinterpret_cast(&packed_sample_size)); + marker += sizeof(tinyexr::tinyexr_int64); + + // next Int64 is unpacked sample size - skip that too + marker += packed_offset_table_size + packed_sample_size + 8; + + } else { + + int dataSize; + memcpy(&dataSize, marker, sizeof(int)); + tinyexr::swap4(&dataSize); + marker += sizeof(int); + marker += dataSize; + } + + if (!isValidTile(exr_header, offset_data, + tileX, tileY, levelX, levelY)) + return; + + int level_idx = LevelIndex(levelX, levelY, exr_header->tile_level_mode, numXLevels); + offset_data.offsets[level_idx][tileY][tileX] = tileOffset; + } + } + } +} + +// marker output is also +static int ReadOffsets(OffsetData& offset_data, + const unsigned char* head, + const unsigned char*& marker, + const size_t size, + const char** err) { + for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) { + for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) { + for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) { + tinyexr::tinyexr_uint64 offset; + if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) { + tinyexr::SetErrorMessage("Insufficient data size in offset table.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64)); + tinyexr::swap8(&offset); + if (offset >= size) { + tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + marker += sizeof(tinyexr::tinyexr_uint64); // = 8 + offset_data.offsets[l][dy][dx] = offset; + } + } + } + return TINYEXR_SUCCESS; +} + +static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header, + const unsigned char *head, + const unsigned char *marker, const size_t size, + const char **err) { + if (exr_image == NULL || exr_header == NULL || head == NULL || + marker == NULL || (size <= tinyexr::kEXRVersionSize)) { + tinyexr::SetErrorMessage("Invalid argument for DecodeEXRImage().", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + int num_scanline_blocks = 1; + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + num_scanline_blocks = 16; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + num_scanline_blocks = 32; + } else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + num_scanline_blocks = 16; + } + + if (exr_header->data_window.max_x < exr_header->data_window.min_x || + exr_header->data_window.max_x - exr_header->data_window.min_x == + std::numeric_limits::max()) { + // Issue 63 + tinyexr::SetErrorMessage("Invalid data width value", err); + return TINYEXR_ERROR_INVALID_DATA; + } + int data_width = + exr_header->data_window.max_x - exr_header->data_window.min_x + 1; + + if (exr_header->data_window.max_y < exr_header->data_window.min_y || + exr_header->data_window.max_y - exr_header->data_window.min_y == + std::numeric_limits::max()) { + tinyexr::SetErrorMessage("Invalid data height value", err); + return TINYEXR_ERROR_INVALID_DATA; + } + int data_height = + exr_header->data_window.max_y - exr_header->data_window.min_y + 1; + + // Do not allow too large data_width and data_height. header invalid? + { + if (data_width > TINYEXR_DIMENSION_THRESHOLD) { + tinyexr::SetErrorMessage("data width too large.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + if (data_height > TINYEXR_DIMENSION_THRESHOLD) { + tinyexr::SetErrorMessage("data height too large.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + + if (exr_header->tiled) { + if (exr_header->tile_size_x > TINYEXR_DIMENSION_THRESHOLD) { + tinyexr::SetErrorMessage("tile width too large.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + if (exr_header->tile_size_y > TINYEXR_DIMENSION_THRESHOLD) { + tinyexr::SetErrorMessage("tile height too large.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + + // Read offset tables. + OffsetData offset_data; + size_t num_blocks = 0; + // For a multi-resolution image, the size of the offset table will be calculated from the other attributes of the header. + // If chunk_count > 0 then chunk_count must be equal to the calculated tile count. + if (exr_header->tiled) { + { + std::vector num_x_tiles, num_y_tiles; + PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_header); + num_blocks = InitTileOffsets(offset_data, exr_header, num_x_tiles, num_y_tiles); + if (exr_header->chunk_count > 0) { + if (exr_header->chunk_count != num_blocks) { + tinyexr::SetErrorMessage("Invalid offset table size.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + } + + int ret = ReadOffsets(offset_data, head, marker, size, err); + if (ret != TINYEXR_SUCCESS) return ret; + if (IsAnyOffsetsAreInvalid(offset_data)) { + ReconstructTileOffsets(offset_data, exr_header, + head, marker, size, + exr_header->multipart, exr_header->non_image); + } + } else if (exr_header->chunk_count > 0) { + // Use `chunkCount` attribute. + num_blocks = static_cast(exr_header->chunk_count); + InitSingleResolutionOffsets(offset_data, num_blocks); + } else { + num_blocks = static_cast(data_height) / + static_cast(num_scanline_blocks); + if (num_blocks * static_cast(num_scanline_blocks) < + static_cast(data_height)) { + num_blocks++; + } + + InitSingleResolutionOffsets(offset_data, num_blocks); + } + + if (!exr_header->tiled) { + std::vector& offsets = offset_data.offsets[0][0]; + for (size_t y = 0; y < num_blocks; y++) { + tinyexr::tinyexr_uint64 offset; + // Issue #81 + if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) { + tinyexr::SetErrorMessage("Insufficient data size in offset table.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64)); + tinyexr::swap8(&offset); + if (offset >= size) { + tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + marker += sizeof(tinyexr::tinyexr_uint64); // = 8 + offsets[y] = offset; + } + + // If line offsets are invalid, we try to reconstruct it. + // See OpenEXR/IlmImf/ImfScanLineInputFile.cpp::readLineOffsets() for details. + for (size_t y = 0; y < num_blocks; y++) { + if (offsets[y] <= 0) { + // TODO(syoyo) Report as warning? + // if (err) { + // stringstream ss; + // ss << "Incomplete lineOffsets." << std::endl; + // (*err) += ss.str(); + //} + bool ret = + ReconstructLineOffsets(&offsets, num_blocks, head, marker, size); + if (ret) { + // OK + break; + } else { + tinyexr::SetErrorMessage( + "Cannot reconstruct lineOffset table in DecodeEXRImage.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + } + } + + { + std::string e; + int ret = DecodeChunk(exr_image, exr_header, offset_data, head, size, &e); + + if (ret != TINYEXR_SUCCESS) { + if (!e.empty()) { + tinyexr::SetErrorMessage(e, err); + } + +#if 1 + FreeEXRImage(exr_image); +#else + // release memory(if exists) + if ((exr_header->num_channels > 0) && exr_image && exr_image->images) { + for (size_t c = 0; c < size_t(exr_header->num_channels); c++) { + if (exr_image->images[c]) { + free(exr_image->images[c]); + exr_image->images[c] = NULL; + } + } + free(exr_image->images); + exr_image->images = NULL; + } +#endif + } + + return ret; + } +} + +static void GetLayers(const EXRHeader &exr_header, + std::vector &layer_names) { + // Naive implementation + // Group channels by layers + // go over all channel names, split by periods + // collect unique names + layer_names.clear(); + for (int c = 0; c < exr_header.num_channels; c++) { + std::string full_name(exr_header.channels[c].name); + const size_t pos = full_name.find_last_of('.'); + if (pos != std::string::npos && pos != 0 && pos + 1 < full_name.size()) { + full_name.erase(pos); + if (std::find(layer_names.begin(), layer_names.end(), full_name) == + layer_names.end()) + layer_names.push_back(full_name); + } + } +} + +struct LayerChannel { + explicit LayerChannel(size_t i, std::string n) : index(i), name(n) {} + size_t index; + std::string name; +}; + +static void ChannelsInLayer(const EXRHeader &exr_header, + const std::string layer_name, + std::vector &channels) { + channels.clear(); + for (int c = 0; c < exr_header.num_channels; c++) { + std::string ch_name(exr_header.channels[c].name); + if (layer_name.empty()) { + const size_t pos = ch_name.find_last_of('.'); + if (pos != std::string::npos && pos < ch_name.size()) { + ch_name = ch_name.substr(pos + 1); + } + } else { + const size_t pos = ch_name.find(layer_name + '.'); + if (pos == std::string::npos) continue; + if (pos == 0) { + ch_name = ch_name.substr(layer_name.size() + 1); + } + } + LayerChannel ch(size_t(c), ch_name); + channels.push_back(ch); + } +} + +} // namespace tinyexr + +int EXRLayers(const char *filename, const char **layer_names[], int *num_layers, + const char **err) { + EXRVersion exr_version; + EXRHeader exr_header; + InitEXRHeader(&exr_header); + + { + int ret = ParseEXRVersionFromFile(&exr_version, filename); + if (ret != TINYEXR_SUCCESS) { + tinyexr::SetErrorMessage("Invalid EXR header.", err); + return ret; + } + + if (exr_version.multipart || exr_version.non_image) { + tinyexr::SetErrorMessage( + "Loading multipart or DeepImage is not supported in LoadEXR() API", + err); + return TINYEXR_ERROR_INVALID_DATA; // @fixme. + } + } + + int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err); + if (ret != TINYEXR_SUCCESS) { + FreeEXRHeader(&exr_header); + return ret; + } + + std::vector layer_vec; + tinyexr::GetLayers(exr_header, layer_vec); + + (*num_layers) = int(layer_vec.size()); + (*layer_names) = static_cast( + malloc(sizeof(const char *) * static_cast(layer_vec.size()))); + for (size_t c = 0; c < static_cast(layer_vec.size()); c++) { +#ifdef _MSC_VER + (*layer_names)[c] = _strdup(layer_vec[c].c_str()); +#else + (*layer_names)[c] = strdup(layer_vec[c].c_str()); +#endif + } + + FreeEXRHeader(&exr_header); + return TINYEXR_SUCCESS; +} + +int LoadEXR(float **out_rgba, int *width, int *height, const char *filename, + const char **err) { + return LoadEXRWithLayer(out_rgba, width, height, filename, + /* layername */ NULL, err); +} + +int LoadEXRWithLayer(float **out_rgba, int *width, int *height, + const char *filename, const char *layername, + const char **err) { + if (out_rgba == NULL) { + tinyexr::SetErrorMessage("Invalid argument for LoadEXR()", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + EXRVersion exr_version; + EXRImage exr_image; + EXRHeader exr_header; + InitEXRHeader(&exr_header); + InitEXRImage(&exr_image); + + { + int ret = ParseEXRVersionFromFile(&exr_version, filename); + if (ret != TINYEXR_SUCCESS) { + std::stringstream ss; + ss << "Failed to open EXR file or read version info from EXR file. code(" + << ret << ")"; + tinyexr::SetErrorMessage(ss.str(), err); + return ret; + } + + if (exr_version.multipart || exr_version.non_image) { + tinyexr::SetErrorMessage( + "Loading multipart or DeepImage is not supported in LoadEXR() API", + err); + return TINYEXR_ERROR_INVALID_DATA; // @fixme. + } + } + + { + int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err); + if (ret != TINYEXR_SUCCESS) { + FreeEXRHeader(&exr_header); + return ret; + } + } + + // Read HALF channel as FLOAT. + for (int i = 0; i < exr_header.num_channels; i++) { + if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) { + exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; + } + } + + // TODO: Probably limit loading to layers (channels) selected by layer index + { + int ret = LoadEXRImageFromFile(&exr_image, &exr_header, filename, err); + if (ret != TINYEXR_SUCCESS) { + FreeEXRHeader(&exr_header); + return ret; + } + } + + // RGBA + int idxR = -1; + int idxG = -1; + int idxB = -1; + int idxA = -1; + + std::vector layer_names; + tinyexr::GetLayers(exr_header, layer_names); + + std::vector channels; + tinyexr::ChannelsInLayer( + exr_header, layername == NULL ? "" : std::string(layername), channels); + + if (channels.size() < 1) { + tinyexr::SetErrorMessage("Layer Not Found", err); + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + return TINYEXR_ERROR_LAYER_NOT_FOUND; + } + + size_t ch_count = channels.size() < 4 ? channels.size() : 4; + for (size_t c = 0; c < ch_count; c++) { + const tinyexr::LayerChannel &ch = channels[c]; + + if (ch.name == "R") { + idxR = int(ch.index); + } else if (ch.name == "G") { + idxG = int(ch.index); + } else if (ch.name == "B") { + idxB = int(ch.index); + } else if (ch.name == "A") { + idxA = int(ch.index); + } + } + + if (channels.size() == 1) { + int chIdx = int(channels.front().index); + // Grayscale channel only. + + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + + if (exr_header.tiled) { + for (int it = 0; it < exr_image.num_tiles; it++) { + for (int j = 0; j < exr_header.tile_size_y; j++) { + for (int i = 0; i < exr_header.tile_size_x; i++) { + const int ii = exr_image.tiles[it].offset_x * + static_cast(exr_header.tile_size_x) + + i; + const int jj = exr_image.tiles[it].offset_y * + static_cast(exr_header.tile_size_y) + + j; + const int idx = ii + jj * static_cast(exr_image.width); + + // out of region check. + if (ii >= exr_image.width) { + continue; + } + if (jj >= exr_image.height) { + continue; + } + const int srcIdx = i + j * exr_header.tile_size_x; + unsigned char **src = exr_image.tiles[it].images; + (*out_rgba)[4 * idx + 0] = + reinterpret_cast(src)[chIdx][srcIdx]; + (*out_rgba)[4 * idx + 1] = + reinterpret_cast(src)[chIdx][srcIdx]; + (*out_rgba)[4 * idx + 2] = + reinterpret_cast(src)[chIdx][srcIdx]; + (*out_rgba)[4 * idx + 3] = + reinterpret_cast(src)[chIdx][srcIdx]; + } + } + } + } else { + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + const float val = + reinterpret_cast(exr_image.images)[chIdx][i]; + (*out_rgba)[4 * i + 0] = val; + (*out_rgba)[4 * i + 1] = val; + (*out_rgba)[4 * i + 2] = val; + (*out_rgba)[4 * i + 3] = val; + } + } + } else { + // Assume RGB(A) + + if (idxR == -1) { + tinyexr::SetErrorMessage("R channel not found", err); + + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + return TINYEXR_ERROR_INVALID_DATA; + } + + if (idxG == -1) { + tinyexr::SetErrorMessage("G channel not found", err); + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + return TINYEXR_ERROR_INVALID_DATA; + } + + if (idxB == -1) { + tinyexr::SetErrorMessage("B channel not found", err); + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + return TINYEXR_ERROR_INVALID_DATA; + } + + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + if (exr_header.tiled) { + for (int it = 0; it < exr_image.num_tiles; it++) { + for (int j = 0; j < exr_header.tile_size_y; j++) { + for (int i = 0; i < exr_header.tile_size_x; i++) { + const int ii = + exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; + const int jj = + exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; + const int idx = ii + jj * exr_image.width; + + // out of region check. + if (ii >= exr_image.width) { + continue; + } + if (jj >= exr_image.height) { + continue; + } + const int srcIdx = i + j * exr_header.tile_size_x; + unsigned char **src = exr_image.tiles[it].images; + (*out_rgba)[4 * idx + 0] = + reinterpret_cast(src)[idxR][srcIdx]; + (*out_rgba)[4 * idx + 1] = + reinterpret_cast(src)[idxG][srcIdx]; + (*out_rgba)[4 * idx + 2] = + reinterpret_cast(src)[idxB][srcIdx]; + if (idxA != -1) { + (*out_rgba)[4 * idx + 3] = + reinterpret_cast(src)[idxA][srcIdx]; + } else { + (*out_rgba)[4 * idx + 3] = 1.0; + } + } + } + } + } else { + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + (*out_rgba)[4 * i + 0] = + reinterpret_cast(exr_image.images)[idxR][i]; + (*out_rgba)[4 * i + 1] = + reinterpret_cast(exr_image.images)[idxG][i]; + (*out_rgba)[4 * i + 2] = + reinterpret_cast(exr_image.images)[idxB][i]; + if (idxA != -1) { + (*out_rgba)[4 * i + 3] = + reinterpret_cast(exr_image.images)[idxA][i]; + } else { + (*out_rgba)[4 * i + 3] = 1.0; + } + } + } + } + + (*width) = exr_image.width; + (*height) = exr_image.height; + + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + + return TINYEXR_SUCCESS; +} + +int IsEXR(const char *filename) { + EXRVersion exr_version; + + int ret = ParseEXRVersionFromFile(&exr_version, filename); + if (ret != TINYEXR_SUCCESS) { + return ret; + } + + return TINYEXR_SUCCESS; +} + +int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version, + const unsigned char *memory, size_t size, + const char **err) { + if (memory == NULL || exr_header == NULL) { + tinyexr::SetErrorMessage( + "Invalid argument. `memory` or `exr_header` argument is null in " + "ParseEXRHeaderFromMemory()", + err); + + // Invalid argument + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (size < tinyexr::kEXRVersionSize) { + tinyexr::SetErrorMessage("Insufficient header/data size.\n", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + const unsigned char *marker = memory + tinyexr::kEXRVersionSize; + size_t marker_size = size - tinyexr::kEXRVersionSize; + + tinyexr::HeaderInfo info; + info.clear(); + + std::string err_str; + int ret = ParseEXRHeader(&info, NULL, version, &err_str, marker, marker_size); + + if (ret != TINYEXR_SUCCESS) { + if (err && !err_str.empty()) { + tinyexr::SetErrorMessage(err_str, err); + } + } + + ConvertHeader(exr_header, info); + + exr_header->multipart = version->multipart ? 1 : 0; + exr_header->non_image = version->non_image ? 1 : 0; + + return ret; +} + +int LoadEXRFromMemory(float **out_rgba, int *width, int *height, + const unsigned char *memory, size_t size, + const char **err) { + if (out_rgba == NULL || memory == NULL) { + tinyexr::SetErrorMessage("Invalid argument for LoadEXRFromMemory", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + EXRVersion exr_version; + EXRImage exr_image; + EXRHeader exr_header; + + InitEXRHeader(&exr_header); + + int ret = ParseEXRVersionFromMemory(&exr_version, memory, size); + if (ret != TINYEXR_SUCCESS) { + std::stringstream ss; + ss << "Failed to parse EXR version. code(" << ret << ")"; + tinyexr::SetErrorMessage(ss.str(), err); + return ret; + } + + ret = ParseEXRHeaderFromMemory(&exr_header, &exr_version, memory, size, err); + if (ret != TINYEXR_SUCCESS) { + return ret; + } + + // Read HALF channel as FLOAT. + for (int i = 0; i < exr_header.num_channels; i++) { + if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) { + exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT; + } + } + + InitEXRImage(&exr_image); + ret = LoadEXRImageFromMemory(&exr_image, &exr_header, memory, size, err); + if (ret != TINYEXR_SUCCESS) { + return ret; + } + + // RGBA + int idxR = -1; + int idxG = -1; + int idxB = -1; + int idxA = -1; + for (int c = 0; c < exr_header.num_channels; c++) { + if (strcmp(exr_header.channels[c].name, "R") == 0) { + idxR = c; + } else if (strcmp(exr_header.channels[c].name, "G") == 0) { + idxG = c; + } else if (strcmp(exr_header.channels[c].name, "B") == 0) { + idxB = c; + } else if (strcmp(exr_header.channels[c].name, "A") == 0) { + idxA = c; + } + } + + // TODO(syoyo): Refactor removing same code as used in LoadEXR(). + if (exr_header.num_channels == 1) { + // Grayscale channel only. + + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + + if (exr_header.tiled) { + for (int it = 0; it < exr_image.num_tiles; it++) { + for (int j = 0; j < exr_header.tile_size_y; j++) { + for (int i = 0; i < exr_header.tile_size_x; i++) { + const int ii = + exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; + const int jj = + exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; + const int idx = ii + jj * exr_image.width; + + // out of region check. + if (ii >= exr_image.width) { + continue; + } + if (jj >= exr_image.height) { + continue; + } + const int srcIdx = i + j * exr_header.tile_size_x; + unsigned char **src = exr_image.tiles[it].images; + (*out_rgba)[4 * idx + 0] = + reinterpret_cast(src)[0][srcIdx]; + (*out_rgba)[4 * idx + 1] = + reinterpret_cast(src)[0][srcIdx]; + (*out_rgba)[4 * idx + 2] = + reinterpret_cast(src)[0][srcIdx]; + (*out_rgba)[4 * idx + 3] = + reinterpret_cast(src)[0][srcIdx]; + } + } + } + } else { + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + const float val = reinterpret_cast(exr_image.images)[0][i]; + (*out_rgba)[4 * i + 0] = val; + (*out_rgba)[4 * i + 1] = val; + (*out_rgba)[4 * i + 2] = val; + (*out_rgba)[4 * i + 3] = val; + } + } + + } else { + // TODO(syoyo): Support non RGBA image. + + if (idxR == -1) { + tinyexr::SetErrorMessage("R channel not found", err); + + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; + } + + if (idxG == -1) { + tinyexr::SetErrorMessage("G channel not found", err); + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; + } + + if (idxB == -1) { + tinyexr::SetErrorMessage("B channel not found", err); + // @todo { free exr_image } + return TINYEXR_ERROR_INVALID_DATA; + } + + (*out_rgba) = reinterpret_cast( + malloc(4 * sizeof(float) * static_cast(exr_image.width) * + static_cast(exr_image.height))); + + if (exr_header.tiled) { + for (int it = 0; it < exr_image.num_tiles; it++) { + for (int j = 0; j < exr_header.tile_size_y; j++) + for (int i = 0; i < exr_header.tile_size_x; i++) { + const int ii = + exr_image.tiles[it].offset_x * exr_header.tile_size_x + i; + const int jj = + exr_image.tiles[it].offset_y * exr_header.tile_size_y + j; + const int idx = ii + jj * exr_image.width; + + // out of region check. + if (ii >= exr_image.width) { + continue; + } + if (jj >= exr_image.height) { + continue; + } + const int srcIdx = i + j * exr_header.tile_size_x; + unsigned char **src = exr_image.tiles[it].images; + (*out_rgba)[4 * idx + 0] = + reinterpret_cast(src)[idxR][srcIdx]; + (*out_rgba)[4 * idx + 1] = + reinterpret_cast(src)[idxG][srcIdx]; + (*out_rgba)[4 * idx + 2] = + reinterpret_cast(src)[idxB][srcIdx]; + if (idxA != -1) { + (*out_rgba)[4 * idx + 3] = + reinterpret_cast(src)[idxA][srcIdx]; + } else { + (*out_rgba)[4 * idx + 3] = 1.0; + } + } + } + } else { + for (int i = 0; i < exr_image.width * exr_image.height; i++) { + (*out_rgba)[4 * i + 0] = + reinterpret_cast(exr_image.images)[idxR][i]; + (*out_rgba)[4 * i + 1] = + reinterpret_cast(exr_image.images)[idxG][i]; + (*out_rgba)[4 * i + 2] = + reinterpret_cast(exr_image.images)[idxB][i]; + if (idxA != -1) { + (*out_rgba)[4 * i + 3] = + reinterpret_cast(exr_image.images)[idxA][i]; + } else { + (*out_rgba)[4 * i + 3] = 1.0; + } + } + } + } + + (*width) = exr_image.width; + (*height) = exr_image.height; + + FreeEXRHeader(&exr_header); + FreeEXRImage(&exr_image); + + return TINYEXR_SUCCESS; +} + +int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header, + const char *filename, const char **err) { + if (exr_image == NULL) { + tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromFile", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + // TODO(syoyo): return wfopen_s erro code + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "rb"); +#endif +#else + fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + if (filesize < 16) { + tinyexr::SetErrorMessage("File size too short " + std::string(filename), + err); + return TINYEXR_ERROR_INVALID_FILE; + } + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + fclose(fp); + (void)ret; + } + + return LoadEXRImageFromMemory(exr_image, exr_header, &buf.at(0), filesize, + err); +} + +int LoadEXRImageFromMemory(EXRImage *exr_image, const EXRHeader *exr_header, + const unsigned char *memory, const size_t size, + const char **err) { + if (exr_image == NULL || memory == NULL || + (size < tinyexr::kEXRVersionSize)) { + tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromMemory", + err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (exr_header->header_len == 0) { + tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + const unsigned char *head = memory; + const unsigned char *marker = reinterpret_cast( + memory + exr_header->header_len + + 8); // +8 for magic number + version header. + return tinyexr::DecodeEXRImage(exr_image, exr_header, head, marker, size, + err); +} + +namespace tinyexr +{ + +// out_data must be allocated initially with the block-header size +// of the current image(-part) type +static bool EncodePixelData(/* out */ std::vector& out_data, + const unsigned char* const* images, + const int* requested_pixel_types, + int compression_type, + int line_order, + int width, // for tiled : tile.width + int height, // for tiled : header.tile_size_y + int x_stride, // for tiled : header.tile_size_x + int line_no, // for tiled : 0 + int num_lines, // for tiled : tile.height + size_t pixel_data_size, + const std::vector& channels, + const std::vector& channel_offset_list, + const void* compression_param = 0) // zfp compression param +{ + size_t buf_size = static_cast(width) * + static_cast(num_lines) * + static_cast(pixel_data_size); + //int last2bit = (buf_size & 3); + // buf_size must be multiple of four + //if(last2bit) buf_size += 4 - last2bit; + std::vector buf(buf_size); + + size_t start_y = static_cast(line_no); + for (size_t c = 0; c < channels.size(); c++) { + if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) { + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + for (int y = 0; y < num_lines; y++) { + // Assume increasing Y + float *line_ptr = reinterpret_cast(&buf.at( + static_cast(pixel_data_size * y * width) + + channel_offset_list[c] * + static_cast(width))); + for (int x = 0; x < width; x++) { + tinyexr::FP16 h16; + h16.u = reinterpret_cast( + images)[c][(y + start_y) * x_stride + x]; + + tinyexr::FP32 f32 = half_to_float(h16); + + tinyexr::swap4(&f32.f); + + // line_ptr[x] = f32.f; + tinyexr::cpy4(line_ptr + x, &(f32.f)); + } + } + } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + for (int y = 0; y < num_lines; y++) { + // Assume increasing Y + unsigned short *line_ptr = reinterpret_cast( + &buf.at(static_cast(pixel_data_size * y * + width) + + channel_offset_list[c] * + static_cast(width))); + for (int x = 0; x < width; x++) { + unsigned short val = reinterpret_cast( + images)[c][(y + start_y) * x_stride + x]; + + tinyexr::swap2(&val); + + // line_ptr[x] = val; + tinyexr::cpy2(line_ptr + x, &val); + } + } + } else { + assert(0); + } + + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) { + if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + for (int y = 0; y < num_lines; y++) { + // Assume increasing Y + unsigned short *line_ptr = reinterpret_cast( + &buf.at(static_cast(pixel_data_size * y * + width) + + channel_offset_list[c] * + static_cast(width))); + for (int x = 0; x < width; x++) { + tinyexr::FP32 f32; + f32.f = reinterpret_cast( + images)[c][(y + start_y) * x_stride + x]; + + tinyexr::FP16 h16; + h16 = float_to_half_full(f32); + + tinyexr::swap2(reinterpret_cast(&h16.u)); + + // line_ptr[x] = h16.u; + tinyexr::cpy2(line_ptr + x, &(h16.u)); + } + } + } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) { + for (int y = 0; y < num_lines; y++) { + // Assume increasing Y + float *line_ptr = reinterpret_cast(&buf.at( + static_cast(pixel_data_size * y * width) + + channel_offset_list[c] * + static_cast(width))); + for (int x = 0; x < width; x++) { + float val = reinterpret_cast( + images)[c][(y + start_y) * x_stride + x]; + + tinyexr::swap4(&val); + + // line_ptr[x] = val; + tinyexr::cpy4(line_ptr + x, &val); + } + } + } else { + assert(0); + } + } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) { + for (int y = 0; y < num_lines; y++) { + // Assume increasing Y + unsigned int *line_ptr = reinterpret_cast(&buf.at( + static_cast(pixel_data_size * y * width) + + channel_offset_list[c] * static_cast(width))); + for (int x = 0; x < width; x++) { + unsigned int val = reinterpret_cast( + images)[c][(y + start_y) * x_stride + x]; + + tinyexr::swap4(&val); + + // line_ptr[x] = val; + tinyexr::cpy4(line_ptr + x, &val); + } + } + } + } + + if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) { + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(uncompressed) + out_data.insert(out_data.end(), buf.begin(), buf.end()); + + } else if ((compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) { +#if TINYEXR_USE_MINIZ + std::vector block(tinyexr::miniz::mz_compressBound( + static_cast(buf.size()))); +#else + std::vector block( + compressBound(static_cast(buf.size()))); +#endif + tinyexr::tinyexr_uint64 outSize = block.size(); + + tinyexr::CompressZip(&block.at(0), outSize, + reinterpret_cast(&buf.at(0)), + static_cast(buf.size())); + + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(compressed) + unsigned int data_len = static_cast(outSize); // truncate + + out_data.insert(out_data.end(), block.begin(), block.begin() + data_len); + + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) { + // (buf.size() * 3) / 2 would be enough. + std::vector block((buf.size() * 3) / 2); + + tinyexr::tinyexr_uint64 outSize = block.size(); + + tinyexr::CompressRle(&block.at(0), outSize, + reinterpret_cast(&buf.at(0)), + static_cast(buf.size())); + + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(compressed) + unsigned int data_len = static_cast(outSize); // truncate + out_data.insert(out_data.end(), block.begin(), block.begin() + data_len); + + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { +#if TINYEXR_USE_PIZ + unsigned int bufLen = + 8192 + static_cast( + 2 * static_cast( + buf.size())); // @fixme { compute good bound. } + std::vector block(bufLen); + unsigned int outSize = static_cast(block.size()); + + CompressPiz(&block.at(0), &outSize, + reinterpret_cast(&buf.at(0)), + buf.size(), channels, width, num_lines); + + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(compressed) + unsigned int data_len = outSize; + out_data.insert(out_data.end(), block.begin(), block.begin() + data_len); + +#else + assert(0); +#endif + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { +#if TINYEXR_USE_ZFP + const ZFPCompressionParam* zfp_compression_param = reinterpret_cast(compression_param); + std::vector block; + unsigned int outSize; + + tinyexr::CompressZfp( + &block, &outSize, reinterpret_cast(&buf.at(0)), + width, num_lines, static_cast(channels.size()), *zfp_compression_param); + + // 4 byte: scan line + // 4 byte: data size + // ~ : pixel data(compressed) + unsigned int data_len = outSize; + out_data.insert(out_data.end(), block.begin(), block.begin() + data_len); + +#else + assert(0); +#endif + } else { + assert(0); + return false; + } + + return true; +} + +static int EncodeTiledLevel(const EXRImage* level_image, const EXRHeader* exr_header, + const std::vector& channels, + std::vector >& data_list, + size_t start_index, // for data_list + int num_x_tiles, int num_y_tiles, + const std::vector& channel_offset_list, + int pixel_data_size, + const void* compression_param, // must be set if zfp compression is enabled + std::string* err) { + int num_tiles = num_x_tiles * num_y_tiles; + assert(num_tiles == level_image->num_tiles); + + if ((exr_header->tile_size_x > level_image->width || exr_header->tile_size_y > level_image->height) && + level_image->level_x == 0 && level_image->level_y == 0) { + if (err) { + (*err) += "Failed to encode tile data.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::atomic invalid_data(false); +#else + bool invalid_data(false); +#endif + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::vector workers; + std::atomic tile_count(0); + + int num_threads = std::max(1, int(std::thread::hardware_concurrency())); + if (num_threads > int(num_tiles)) { + num_threads = int(num_tiles); + } + + for (int t = 0; t < num_threads; t++) { + workers.emplace_back(std::thread([&]() { + int i = 0; + while ((i = tile_count++) < num_tiles) { + +#else + // Use signed int since some OpenMP compiler doesn't allow unsigned type for + // `parallel for` +#if TINYEXR_USE_OPENMP +#pragma omp parallel for +#endif + for (int i = 0; i < num_tiles; i++) { + +#endif + size_t tile_idx = static_cast(i); + size_t data_idx = tile_idx + start_index; + + int x_tile = i % num_x_tiles; + int y_tile = i / num_x_tiles; + + EXRTile& tile = level_image->tiles[tile_idx]; + + const unsigned char* const* images = + static_cast(tile.images); + + data_list[data_idx].resize(5*sizeof(int)); + size_t data_header_size = data_list[data_idx].size(); + bool ret = EncodePixelData(data_list[data_idx], + images, + exr_header->requested_pixel_types, + exr_header->compression_type, + 0, // increasing y + tile.width, + exr_header->tile_size_y, + exr_header->tile_size_x, + 0, + tile.height, + pixel_data_size, + channels, + channel_offset_list, + compression_param); + if (!ret) { + invalid_data = true; + continue; + } + assert(data_list[data_idx].size() > data_header_size); + int data_len = static_cast(data_list[data_idx].size() - data_header_size); + //tileX, tileY, levelX, levelY // pixel_data_size(int) + memcpy(&data_list[data_idx][0], &x_tile, sizeof(int)); + memcpy(&data_list[data_idx][4], &y_tile, sizeof(int)); + memcpy(&data_list[data_idx][8], &level_image->level_x, sizeof(int)); + memcpy(&data_list[data_idx][12], &level_image->level_y, sizeof(int)); + memcpy(&data_list[data_idx][16], &data_len, sizeof(int)); + + swap4(reinterpret_cast(&data_list[data_idx][0])); + swap4(reinterpret_cast(&data_list[data_idx][4])); + swap4(reinterpret_cast(&data_list[data_idx][8])); + swap4(reinterpret_cast(&data_list[data_idx][12])); + swap4(reinterpret_cast(&data_list[data_idx][16])); + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + } +})); + } + + for (auto &t : workers) { + t.join(); + } +#else + } // omp parallel +#endif + + if (invalid_data) { + if (err) { + (*err) += "Failed to encode tile data.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + return TINYEXR_SUCCESS; +} + +static int NumScanlines(int compression_type) { + int num_scanlines = 1; + if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + num_scanlines = 16; + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + num_scanlines = 32; + } else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + num_scanlines = 16; + } + return num_scanlines; +} + +static int EncodeChunk(const EXRImage* exr_image, const EXRHeader* exr_header, + const std::vector& channels, + int num_blocks, + tinyexr_uint64 chunk_offset, // starting offset of current chunk + bool is_multipart, + OffsetData& offset_data, // output block offsets, must be initialized + std::vector >& data_list, // output + tinyexr_uint64& total_size, // output: ending offset of current chunk + std::string* err) { + int num_scanlines = NumScanlines(exr_header->compression_type); + + data_list.resize(num_blocks); + + std::vector channel_offset_list( + static_cast(exr_header->num_channels)); + + int pixel_data_size = 0; + { + size_t channel_offset = 0; + for (size_t c = 0; c < static_cast(exr_header->num_channels); c++) { + channel_offset_list[c] = channel_offset; + if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) { + pixel_data_size += sizeof(unsigned short); + channel_offset += sizeof(unsigned short); + } else if (exr_header->requested_pixel_types[c] == + TINYEXR_PIXELTYPE_FLOAT) { + pixel_data_size += sizeof(float); + channel_offset += sizeof(float); + } else if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT) { + pixel_data_size += sizeof(unsigned int); + channel_offset += sizeof(unsigned int); + } else { + assert(0); + } + } + } + + const void* compression_param = 0; +#if TINYEXR_USE_ZFP + tinyexr::ZFPCompressionParam zfp_compression_param; + + // Use ZFP compression parameter from custom attributes(if such a parameter + // exists) + { + std::string e; + bool ret = tinyexr::FindZFPCompressionParam( + &zfp_compression_param, exr_header->custom_attributes, + exr_header->num_custom_attributes, &e); + + if (!ret) { + // Use predefined compression parameter. + zfp_compression_param.type = 0; + zfp_compression_param.rate = 2; + } + compression_param = &zfp_compression_param; + } +#endif + + tinyexr_uint64 offset = chunk_offset; + tinyexr_uint64 doffset = is_multipart ? 4u : 0u; + + if (exr_image->tiles) { + const EXRImage* level_image = exr_image; + size_t block_idx = 0; + tinyexr::tinyexr_uint64 block_data_size = 0; + int num_levels = (exr_header->tile_level_mode != TINYEXR_TILE_RIPMAP_LEVELS) ? + offset_data.num_x_levels : (offset_data.num_x_levels * offset_data.num_y_levels); + for (int level_index = 0; level_index < num_levels; ++level_index) { + if (!level_image) { + if (err) { + (*err) += "Invalid number of tiled levels for EncodeChunk\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + int level_index_from_image = LevelIndex(level_image->level_x, level_image->level_y, + exr_header->tile_level_mode, offset_data.num_x_levels); + if (level_index_from_image != level_index) { + if (err) { + (*err) += "Incorrect level ordering in tiled image\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + int num_y_tiles = (int)offset_data.offsets[level_index].size(); + assert(num_y_tiles); + int num_x_tiles = (int)offset_data.offsets[level_index][0].size(); + assert(num_x_tiles); + + std::string e; + int ret = EncodeTiledLevel(level_image, + exr_header, + channels, + data_list, + block_idx, + num_x_tiles, + num_y_tiles, + channel_offset_list, + pixel_data_size, + compression_param, + &e); + if (ret != TINYEXR_SUCCESS) { + if (!e.empty() && err) { + (*err) += e; + } + return ret; + } + + for (size_t j = 0; j < static_cast(num_y_tiles); ++j) + for (size_t i = 0; i < static_cast(num_x_tiles); ++i) { + offset_data.offsets[level_index][j][i] = offset; + swap8(reinterpret_cast(&offset_data.offsets[level_index][j][i])); + offset += data_list[block_idx].size() + doffset; + block_data_size += data_list[block_idx].size(); + ++block_idx; + } + level_image = level_image->next_level; + } + assert(block_idx == num_blocks); + total_size = offset; + } else { // scanlines + std::vector& offsets = offset_data.offsets[0][0]; + +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + std::atomic invalid_data(false); + std::vector workers; + std::atomic block_count(0); + + int num_threads = std::min(std::max(1, int(std::thread::hardware_concurrency())), num_blocks); + + for (int t = 0; t < num_threads; t++) { + workers.emplace_back(std::thread([&]() { + int i = 0; + while ((i = block_count++) < num_blocks) { + +#else + bool invalid_data(false); +#if TINYEXR_USE_OPENMP +#pragma omp parallel for +#endif + for (int i = 0; i < num_blocks; i++) { + +#endif + int start_y = num_scanlines * i; + int end_Y = (std::min)(num_scanlines * (i + 1), exr_image->height); + int num_lines = end_Y - start_y; + + const unsigned char* const* images = + static_cast(exr_image->images); + + data_list[i].resize(2*sizeof(int)); + size_t data_header_size = data_list[i].size(); + + bool ret = EncodePixelData(data_list[i], + images, + exr_header->requested_pixel_types, + exr_header->compression_type, + 0, // increasing y + exr_image->width, + exr_image->height, + exr_image->width, + start_y, + num_lines, + pixel_data_size, + channels, + channel_offset_list, + compression_param); + if (!ret) { + invalid_data = true; + continue; // "break" cannot be used with OpenMP + } + assert(data_list[i].size() > data_header_size); + int data_len = static_cast(data_list[i].size() - data_header_size); + memcpy(&data_list[i][0], &start_y, sizeof(int)); + memcpy(&data_list[i][4], &data_len, sizeof(int)); + + swap4(reinterpret_cast(&data_list[i][0])); + swap4(reinterpret_cast(&data_list[i][4])); +#if TINYEXR_HAS_CXX11 && (TINYEXR_USE_THREAD > 0) + } + })); + } + + for (auto &t : workers) { + t.join(); + } +#else + } // omp parallel +#endif + + if (invalid_data) { + if (err) { + (*err) += "Failed to encode scanline data.\n"; + } + return TINYEXR_ERROR_INVALID_DATA; + } + + for (size_t i = 0; i < static_cast(num_blocks); i++) { + offsets[i] = offset; + tinyexr::swap8(reinterpret_cast(&offsets[i])); + offset += data_list[i].size() + doffset; + } + + total_size = static_cast(offset); + } + return TINYEXR_SUCCESS; +} + +// can save a single or multi-part image (no deep* formats) +static size_t SaveEXRNPartImageToMemory(const EXRImage* exr_images, + const EXRHeader** exr_headers, + unsigned int num_parts, + unsigned char** memory_out, const char** err) { + if (exr_images == NULL || exr_headers == NULL || num_parts == 0 || + memory_out == NULL) { + SetErrorMessage("Invalid argument for SaveEXRNPartImageToMemory", + err); + return 0; + } + { + for (unsigned int i = 0; i < num_parts; ++i) { + if (exr_headers[i]->compression_type < 0) { + SetErrorMessage("Invalid argument for SaveEXRNPartImageToMemory", + err); + return 0; + } +#if !TINYEXR_USE_PIZ + if (exr_headers[i]->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + SetErrorMessage("PIZ compression is not supported in this build", + err); + return 0; + } +#endif +#if !TINYEXR_USE_ZFP + if (exr_headers[i]->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + SetErrorMessage("ZFP compression is not supported in this build", + err); + return 0; + } +#else + for (int c = 0; c < exr_header->num_channels; ++c) { + if (exr_headers[i]->requested_pixel_types[c] != TINYEXR_PIXELTYPE_FLOAT) { + SetErrorMessage("Pixel type must be FLOAT for ZFP compression", + err); + return 0; + } + } +#endif + } + } + + std::vector memory; + + // Header + { + const char header[] = { 0x76, 0x2f, 0x31, 0x01 }; + memory.insert(memory.end(), header, header + 4); + } + + // Version + // using value from the first header + int long_name = exr_headers[0]->long_name; + { + char marker[] = { 2, 0, 0, 0 }; + /* @todo + if (exr_header->non_image) { + marker[1] |= 0x8; + } + */ + // tiled + if (num_parts == 1 && exr_images[0].tiles) { + marker[1] |= 0x2; + } + // long_name + if (long_name) { + marker[1] |= 0x4; + } + // multipart + if (num_parts > 1) { + marker[1] |= 0x10; + } + memory.insert(memory.end(), marker, marker + 4); + } + + int total_chunk_count = 0; + std::vector chunk_count(num_parts); + std::vector offset_data(num_parts); + for (unsigned int i = 0; i < num_parts; ++i) { + if (!exr_images[i].tiles) { + int num_scanlines = NumScanlines(exr_headers[i]->compression_type); + chunk_count[i] = + (exr_images[i].height + num_scanlines - 1) / num_scanlines; + InitSingleResolutionOffsets(offset_data[i], chunk_count[i]); + total_chunk_count += chunk_count[i]; + } else { + { + std::vector num_x_tiles, num_y_tiles; + PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_headers[i]); + chunk_count[i] = + InitTileOffsets(offset_data[i], exr_headers[i], num_x_tiles, num_y_tiles); + total_chunk_count += chunk_count[i]; + } + } + } + // Write attributes to memory buffer. + std::vector< std::vector > channels(num_parts); + { + std::set partnames; + for (unsigned int i = 0; i < num_parts; ++i) { + //channels + { + std::vector data; + + for (int c = 0; c < exr_headers[i]->num_channels; c++) { + tinyexr::ChannelInfo info; + info.p_linear = 0; + info.pixel_type = exr_headers[i]->requested_pixel_types[c]; + info.x_sampling = 1; + info.y_sampling = 1; + info.name = std::string(exr_headers[i]->channels[c].name); + channels[i].push_back(info); + } + + tinyexr::WriteChannelInfo(data, channels[i]); + + tinyexr::WriteAttributeToMemory(&memory, "channels", "chlist", &data.at(0), + static_cast(data.size())); + } + + { + int comp = exr_headers[i]->compression_type; + swap4(&comp); + WriteAttributeToMemory( + &memory, "compression", "compression", + reinterpret_cast(&comp), 1); + } + + { + int data[4] = { 0, 0, exr_images[i].width - 1, exr_images[i].height - 1 }; + swap4(&data[0]); + swap4(&data[1]); + swap4(&data[2]); + swap4(&data[3]); + WriteAttributeToMemory( + &memory, "dataWindow", "box2i", + reinterpret_cast(data), sizeof(int) * 4); + + int data0[4] = { 0, 0, exr_images[0].width - 1, exr_images[0].height - 1 }; + swap4(&data0[0]); + swap4(&data0[1]); + swap4(&data0[2]); + swap4(&data0[3]); + // Note: must be the same across parts (currently, using value from the first header) + WriteAttributeToMemory( + &memory, "displayWindow", "box2i", + reinterpret_cast(data0), sizeof(int) * 4); + } + + { + unsigned char line_order = 0; // @fixme { read line_order from EXRHeader } + WriteAttributeToMemory(&memory, "lineOrder", "lineOrder", + &line_order, 1); + } + + { + // Note: must be the same across parts + float aspectRatio = 1.0f; + swap4(&aspectRatio); + WriteAttributeToMemory( + &memory, "pixelAspectRatio", "float", + reinterpret_cast(&aspectRatio), sizeof(float)); + } + + { + float center[2] = { 0.0f, 0.0f }; + swap4(¢er[0]); + swap4(¢er[1]); + WriteAttributeToMemory( + &memory, "screenWindowCenter", "v2f", + reinterpret_cast(center), 2 * sizeof(float)); + } + + { + float w = 1.0f; + swap4(&w); + WriteAttributeToMemory(&memory, "screenWindowWidth", "float", + reinterpret_cast(&w), + sizeof(float)); + } + + if (exr_images[i].tiles) { + unsigned char tile_mode = static_cast(exr_headers[i]->tile_level_mode & 0x3); + if (exr_headers[i]->tile_rounding_mode) tile_mode |= (1u << 4u); + //unsigned char data[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + unsigned int datai[3] = { 0, 0, 0 }; + unsigned char* data = reinterpret_cast(&datai[0]); + datai[0] = static_cast(exr_headers[i]->tile_size_x); + datai[1] = static_cast(exr_headers[i]->tile_size_y); + data[8] = tile_mode; + swap4(reinterpret_cast(&data[0])); + swap4(reinterpret_cast(&data[4])); + WriteAttributeToMemory( + &memory, "tiles", "tiledesc", + reinterpret_cast(data), 9); + } + + // must be present for multi-part files - according to spec. + if (num_parts > 1) { + // name + { + size_t len = 0; + if ((len = strlen(exr_headers[i]->name)) > 0) { + partnames.insert(std::string(exr_headers[i]->name)); + if (partnames.size() != i + 1) { + SetErrorMessage("'name' attributes must be unique for a multi-part file", err); + return 0; + } + WriteAttributeToMemory( + &memory, "name", "string", + reinterpret_cast(exr_headers[i]->name), + static_cast(len)); + } else { + SetErrorMessage("Invalid 'name' attribute for a multi-part file", err); + return 0; + } + } + // type + { + const char* type = "scanlineimage"; + if (exr_images[i].tiles) type = "tiledimage"; + WriteAttributeToMemory( + &memory, "type", "string", + reinterpret_cast(type), + static_cast(strlen(type))); + } + // chunkCount + { + WriteAttributeToMemory( + &memory, "chunkCount", "int", + reinterpret_cast(&chunk_count[i]), + 4); + } + } + + // Custom attributes + if (exr_headers[i]->num_custom_attributes > 0) { + for (int j = 0; j < exr_headers[i]->num_custom_attributes; j++) { + tinyexr::WriteAttributeToMemory( + &memory, exr_headers[i]->custom_attributes[j].name, + exr_headers[i]->custom_attributes[j].type, + reinterpret_cast( + exr_headers[i]->custom_attributes[j].value), + exr_headers[i]->custom_attributes[j].size); + } + } + + { // end of header + memory.push_back(0); + } + } + } + if (num_parts > 1) { + // end of header list + memory.push_back(0); + } + + tinyexr_uint64 chunk_offset = memory.size() + size_t(total_chunk_count) * sizeof(tinyexr_uint64); + + tinyexr_uint64 total_size = 0; + std::vector< std::vector< std::vector > > data_lists(num_parts); + for (unsigned int i = 0; i < num_parts; ++i) { + std::string e; + int ret = EncodeChunk(&exr_images[i], exr_headers[i], + channels[i], + chunk_count[i], + // starting offset of current chunk after part-number + chunk_offset, + num_parts > 1, + offset_data[i], // output: block offsets, must be initialized + data_lists[i], // output + total_size, // output + &e); + if (ret != TINYEXR_SUCCESS) { + if (!e.empty()) { + tinyexr::SetErrorMessage(e, err); + } + return 0; + } + chunk_offset = total_size; + } + + // Allocating required memory + if (total_size == 0) { // something went wrong + tinyexr::SetErrorMessage("Output memory size is zero", err); + return 0; + } + (*memory_out) = static_cast(malloc(total_size)); + + // Writing header + memcpy((*memory_out), &memory[0], memory.size()); + unsigned char* memory_ptr = *memory_out + memory.size(); + size_t sum = memory.size(); + + // Writing offset data for chunks + for (unsigned int i = 0; i < num_parts; ++i) { + if (exr_images[i].tiles) { + const EXRImage* level_image = &exr_images[i]; + int num_levels = (exr_headers[i]->tile_level_mode != TINYEXR_TILE_RIPMAP_LEVELS) ? + offset_data[i].num_x_levels : (offset_data[i].num_x_levels * offset_data[i].num_y_levels); + for (int level_index = 0; level_index < num_levels; ++level_index) { + for (size_t j = 0; j < offset_data[i].offsets[level_index].size(); ++j) { + size_t num_bytes = sizeof(tinyexr_uint64) * offset_data[i].offsets[level_index][j].size(); + sum += num_bytes; + assert(sum <= total_size); + memcpy(memory_ptr, + reinterpret_cast(&offset_data[i].offsets[level_index][j][0]), + num_bytes); + memory_ptr += num_bytes; + } + level_image = level_image->next_level; + } + } else { + size_t num_bytes = sizeof(tinyexr::tinyexr_uint64) * static_cast(chunk_count[i]); + sum += num_bytes; + assert(sum <= total_size); + std::vector& offsets = offset_data[i].offsets[0][0]; + memcpy(memory_ptr, reinterpret_cast(&offsets[0]), num_bytes); + memory_ptr += num_bytes; + } + } + + // Writing chunk data + for (unsigned int i = 0; i < num_parts; ++i) { + for (size_t j = 0; j < static_cast(chunk_count[i]); ++j) { + if (num_parts > 1) { + sum += 4; + assert(sum <= total_size); + unsigned int part_number = i; + swap4(&part_number); + memcpy(memory_ptr, &part_number, 4); + memory_ptr += 4; + } + sum += data_lists[i][j].size(); + assert(sum <= total_size); + memcpy(memory_ptr, &data_lists[i][j][0], data_lists[i][j].size()); + memory_ptr += data_lists[i][j].size(); + } + } + assert(sum == total_size); + return total_size; // OK +} + +} // tinyexr + +size_t SaveEXRImageToMemory(const EXRImage* exr_image, + const EXRHeader* exr_header, + unsigned char** memory_out, const char** err) { + return tinyexr::SaveEXRNPartImageToMemory(exr_image, &exr_header, 1, memory_out, err); +} + +int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header, + const char *filename, const char **err) { + if (exr_image == NULL || filename == NULL || + exr_header->compression_type < 0) { + tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToFile", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + +#if !TINYEXR_USE_PIZ + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { + tinyexr::SetErrorMessage("PIZ compression is not supported in this build", + err); + return TINYEXR_ERROR_UNSUPPORTED_FEATURE; + } +#endif + +#if !TINYEXR_USE_ZFP + if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) { + tinyexr::SetErrorMessage("ZFP compression is not supported in this build", + err); + return TINYEXR_ERROR_UNSUPPORTED_FEATURE; + } +#endif + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"wb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot write a file: " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "wb"); +#endif +#else + fp = fopen(filename, "wb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot write a file: " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } + + unsigned char *mem = NULL; + size_t mem_size = SaveEXRImageToMemory(exr_image, exr_header, &mem, err); + if (mem_size == 0) { + return TINYEXR_ERROR_SERIALZATION_FAILED; + } + + size_t written_size = 0; + if ((mem_size > 0) && mem) { + written_size = fwrite(mem, 1, mem_size, fp); + } + free(mem); + + fclose(fp); + + if (written_size != mem_size) { + tinyexr::SetErrorMessage("Cannot write a file", err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } + + return TINYEXR_SUCCESS; +} + +size_t SaveEXRMultipartImageToMemory(const EXRImage* exr_images, + const EXRHeader** exr_headers, + unsigned int num_parts, + unsigned char** memory_out, const char** err) { + if (exr_images == NULL || exr_headers == NULL || num_parts < 2 || + memory_out == NULL) { + tinyexr::SetErrorMessage("Invalid argument for SaveEXRNPartImageToMemory", + err); + return 0; + } + return tinyexr::SaveEXRNPartImageToMemory(exr_images, exr_headers, num_parts, memory_out, err); +} + +int SaveEXRMultipartImageToFile(const EXRImage* exr_images, + const EXRHeader** exr_headers, + unsigned int num_parts, + const char* filename, + const char** err) { + if (exr_images == NULL || exr_headers == NULL || num_parts < 2) { + tinyexr::SetErrorMessage("Invalid argument for SaveEXRMultipartImageToFile", + err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"wb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot write a file: " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "wb"); +#endif +#else + fp = fopen(filename, "wb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot write a file: " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } + + unsigned char *mem = NULL; + size_t mem_size = SaveEXRMultipartImageToMemory(exr_images, exr_headers, num_parts, &mem, err); + if (mem_size == 0) { + return TINYEXR_ERROR_SERIALZATION_FAILED; + } + + size_t written_size = 0; + if ((mem_size > 0) && mem) { + written_size = fwrite(mem, 1, mem_size, fp); + } + free(mem); + + fclose(fp); + + if (written_size != mem_size) { + tinyexr::SetErrorMessage("Cannot write a file", err); + return TINYEXR_ERROR_CANT_WRITE_FILE; + } + + return TINYEXR_SUCCESS; +} + +int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) { + if (deep_image == NULL) { + tinyexr::SetErrorMessage("Invalid argument for LoadDeepEXR", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + +#ifdef _WIN32 + FILE *fp = NULL; +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#else + FILE *fp = fopen(filename, "rb"); + if (!fp) { + tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename), + err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#endif + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + if (filesize == 0) { + fclose(fp); + tinyexr::SetErrorMessage("File size is zero : " + std::string(filename), + err); + return TINYEXR_ERROR_INVALID_FILE; + } + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + (void)ret; + } + fclose(fp); + + const char *head = &buf[0]; + const char *marker = &buf[0]; + + // Header check. + { + const char header[] = {0x76, 0x2f, 0x31, 0x01}; + + if (memcmp(marker, header, 4) != 0) { + tinyexr::SetErrorMessage("Invalid magic number", err); + return TINYEXR_ERROR_INVALID_MAGIC_NUMBER; + } + marker += 4; + } + + // Version, scanline. + { + // ver 2.0, scanline, deep bit on(0x800) + // must be [2, 0, 0, 0] + if (marker[0] != 2 || marker[1] != 8 || marker[2] != 0 || marker[3] != 0) { + tinyexr::SetErrorMessage("Unsupported version or scanline", err); + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + marker += 4; + } + + int dx = -1; + int dy = -1; + int dw = -1; + int dh = -1; + int num_scanline_blocks = 1; // 16 for ZIP compression. + int compression_type = -1; + int num_channels = -1; + std::vector channels; + + // Read attributes + size_t size = filesize - tinyexr::kEXRVersionSize; + for (;;) { + if (0 == size) { + return TINYEXR_ERROR_INVALID_DATA; + } else if (marker[0] == '\0') { + marker++; + size--; + break; + } + + std::string attr_name; + std::string attr_type; + std::vector data; + size_t marker_size; + if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size, + marker, size)) { + std::stringstream ss; + ss << "Failed to parse attribute\n"; + tinyexr::SetErrorMessage(ss.str(), err); + return TINYEXR_ERROR_INVALID_DATA; + } + marker += marker_size; + size -= marker_size; + + if (attr_name.compare("compression") == 0) { + compression_type = data[0]; + if (compression_type > TINYEXR_COMPRESSIONTYPE_PIZ) { + std::stringstream ss; + ss << "Unsupported compression type : " << compression_type; + tinyexr::SetErrorMessage(ss.str(), err); + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) { + num_scanline_blocks = 16; + } + + } else if (attr_name.compare("channels") == 0) { + // name: zero-terminated string, from 1 to 255 bytes long + // pixel type: int, possible values are: UINT = 0 HALF = 1 FLOAT = 2 + // pLinear: unsigned char, possible values are 0 and 1 + // reserved: three chars, should be zero + // xSampling: int + // ySampling: int + + if (!tinyexr::ReadChannelInfo(channels, data)) { + tinyexr::SetErrorMessage("Failed to parse channel info", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + num_channels = static_cast(channels.size()); + + if (num_channels < 1) { + tinyexr::SetErrorMessage("Invalid channels format", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + } else if (attr_name.compare("dataWindow") == 0) { + memcpy(&dx, &data.at(0), sizeof(int)); + memcpy(&dy, &data.at(4), sizeof(int)); + memcpy(&dw, &data.at(8), sizeof(int)); + memcpy(&dh, &data.at(12), sizeof(int)); + tinyexr::swap4(&dx); + tinyexr::swap4(&dy); + tinyexr::swap4(&dw); + tinyexr::swap4(&dh); + + } else if (attr_name.compare("displayWindow") == 0) { + int x; + int y; + int w; + int h; + memcpy(&x, &data.at(0), sizeof(int)); + memcpy(&y, &data.at(4), sizeof(int)); + memcpy(&w, &data.at(8), sizeof(int)); + memcpy(&h, &data.at(12), sizeof(int)); + tinyexr::swap4(&x); + tinyexr::swap4(&y); + tinyexr::swap4(&w); + tinyexr::swap4(&h); + } + } + + assert(dx >= 0); + assert(dy >= 0); + assert(dw >= 0); + assert(dh >= 0); + assert(num_channels >= 1); + + int data_width = dw - dx + 1; + int data_height = dh - dy + 1; + + std::vector image( + static_cast(data_width * data_height * 4)); // 4 = RGBA + + // Read offset tables. + int num_blocks = data_height / num_scanline_blocks; + if (num_blocks * num_scanline_blocks < data_height) { + num_blocks++; + } + + std::vector offsets(static_cast(num_blocks)); + + for (size_t y = 0; y < static_cast(num_blocks); y++) { + tinyexr::tinyexr_int64 offset; + memcpy(&offset, marker, sizeof(tinyexr::tinyexr_int64)); + tinyexr::swap8(reinterpret_cast(&offset)); + marker += sizeof(tinyexr::tinyexr_int64); // = 8 + offsets[y] = offset; + } + +#if TINYEXR_USE_PIZ + if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) || + (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP) || + (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ)) { +#else + if ((compression_type == TINYEXR_COMPRESSIONTYPE_NONE) || + (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS) || + (compression_type == TINYEXR_COMPRESSIONTYPE_ZIP)) { +#endif + // OK + } else { + tinyexr::SetErrorMessage("Unsupported compression format", err); + return TINYEXR_ERROR_UNSUPPORTED_FORMAT; + } + + deep_image->image = static_cast( + malloc(sizeof(float **) * static_cast(num_channels))); + for (int c = 0; c < num_channels; c++) { + deep_image->image[c] = static_cast( + malloc(sizeof(float *) * static_cast(data_height))); + for (int y = 0; y < data_height; y++) { + } + } + + deep_image->offset_table = static_cast( + malloc(sizeof(int *) * static_cast(data_height))); + for (int y = 0; y < data_height; y++) { + deep_image->offset_table[y] = static_cast( + malloc(sizeof(int) * static_cast(data_width))); + } + + for (size_t y = 0; y < static_cast(num_blocks); y++) { + const unsigned char *data_ptr = + reinterpret_cast(head + offsets[y]); + + // int: y coordinate + // int64: packed size of pixel offset table + // int64: packed size of sample data + // int64: unpacked size of sample data + // compressed pixel offset table + // compressed sample data + int line_no; + tinyexr::tinyexr_int64 packedOffsetTableSize; + tinyexr::tinyexr_int64 packedSampleDataSize; + tinyexr::tinyexr_int64 unpackedSampleDataSize; + memcpy(&line_no, data_ptr, sizeof(int)); + memcpy(&packedOffsetTableSize, data_ptr + 4, + sizeof(tinyexr::tinyexr_int64)); + memcpy(&packedSampleDataSize, data_ptr + 12, + sizeof(tinyexr::tinyexr_int64)); + memcpy(&unpackedSampleDataSize, data_ptr + 20, + sizeof(tinyexr::tinyexr_int64)); + + tinyexr::swap4(&line_no); + tinyexr::swap8( + reinterpret_cast(&packedOffsetTableSize)); + tinyexr::swap8( + reinterpret_cast(&packedSampleDataSize)); + tinyexr::swap8( + reinterpret_cast(&unpackedSampleDataSize)); + + std::vector pixelOffsetTable(static_cast(data_width)); + + // decode pixel offset table. + { + unsigned long dstLen = + static_cast(pixelOffsetTable.size() * sizeof(int)); + if (!tinyexr::DecompressZip( + reinterpret_cast(&pixelOffsetTable.at(0)), + &dstLen, data_ptr + 28, + static_cast(packedOffsetTableSize))) { + return false; + } + + assert(dstLen == pixelOffsetTable.size() * sizeof(int)); + for (size_t i = 0; i < static_cast(data_width); i++) { + deep_image->offset_table[y][i] = pixelOffsetTable[i]; + } + } + + std::vector sample_data( + static_cast(unpackedSampleDataSize)); + + // decode sample data. + { + unsigned long dstLen = static_cast(unpackedSampleDataSize); + if (dstLen) { + if (!tinyexr::DecompressZip( + reinterpret_cast(&sample_data.at(0)), &dstLen, + data_ptr + 28 + packedOffsetTableSize, + static_cast(packedSampleDataSize))) { + return false; + } + assert(dstLen == static_cast(unpackedSampleDataSize)); + } + } + + // decode sample + int sampleSize = -1; + std::vector channel_offset_list(static_cast(num_channels)); + { + int channel_offset = 0; + for (size_t i = 0; i < static_cast(num_channels); i++) { + channel_offset_list[i] = channel_offset; + if (channels[i].pixel_type == TINYEXR_PIXELTYPE_UINT) { // UINT + channel_offset += 4; + } else if (channels[i].pixel_type == TINYEXR_PIXELTYPE_HALF) { // half + channel_offset += 2; + } else if (channels[i].pixel_type == + TINYEXR_PIXELTYPE_FLOAT) { // float + channel_offset += 4; + } else { + assert(0); + } + } + sampleSize = channel_offset; + } + assert(sampleSize >= 2); + + assert(static_cast( + pixelOffsetTable[static_cast(data_width - 1)] * + sampleSize) == sample_data.size()); + int samples_per_line = static_cast(sample_data.size()) / sampleSize; + + // + // Alloc memory + // + + // + // pixel data is stored as image[channels][pixel_samples] + // + { + tinyexr::tinyexr_uint64 data_offset = 0; + for (size_t c = 0; c < static_cast(num_channels); c++) { + deep_image->image[c][y] = static_cast( + malloc(sizeof(float) * static_cast(samples_per_line))); + + if (channels[c].pixel_type == 0) { // UINT + for (size_t x = 0; x < static_cast(samples_per_line); x++) { + unsigned int ui; + unsigned int *src_ptr = reinterpret_cast( + &sample_data.at(size_t(data_offset) + x * sizeof(int))); + tinyexr::cpy4(&ui, src_ptr); + deep_image->image[c][y][x] = static_cast(ui); // @fixme + } + data_offset += + sizeof(unsigned int) * static_cast(samples_per_line); + } else if (channels[c].pixel_type == 1) { // half + for (size_t x = 0; x < static_cast(samples_per_line); x++) { + tinyexr::FP16 f16; + const unsigned short *src_ptr = reinterpret_cast( + &sample_data.at(size_t(data_offset) + x * sizeof(short))); + tinyexr::cpy2(&(f16.u), src_ptr); + tinyexr::FP32 f32 = half_to_float(f16); + deep_image->image[c][y][x] = f32.f; + } + data_offset += sizeof(short) * static_cast(samples_per_line); + } else { // float + for (size_t x = 0; x < static_cast(samples_per_line); x++) { + float f; + const float *src_ptr = reinterpret_cast( + &sample_data.at(size_t(data_offset) + x * sizeof(float))); + tinyexr::cpy4(&f, src_ptr); + deep_image->image[c][y][x] = f; + } + data_offset += sizeof(float) * static_cast(samples_per_line); + } + } + } + } // y + + deep_image->width = data_width; + deep_image->height = data_height; + + deep_image->channel_names = static_cast( + malloc(sizeof(const char *) * static_cast(num_channels))); + for (size_t c = 0; c < static_cast(num_channels); c++) { +#ifdef _WIN32 + deep_image->channel_names[c] = _strdup(channels[c].name.c_str()); +#else + deep_image->channel_names[c] = strdup(channels[c].name.c_str()); +#endif + } + deep_image->num_channels = num_channels; + + return TINYEXR_SUCCESS; +} + +void InitEXRImage(EXRImage *exr_image) { + if (exr_image == NULL) { + return; + } + + exr_image->width = 0; + exr_image->height = 0; + exr_image->num_channels = 0; + + exr_image->images = NULL; + exr_image->tiles = NULL; + exr_image->next_level = NULL; + exr_image->level_x = 0; + exr_image->level_y = 0; + + exr_image->num_tiles = 0; +} + +void FreeEXRErrorMessage(const char *msg) { + if (msg) { + free(reinterpret_cast(const_cast(msg))); + } + return; +} + +void InitEXRHeader(EXRHeader *exr_header) { + if (exr_header == NULL) { + return; + } + + memset(exr_header, 0, sizeof(EXRHeader)); +} + +int FreeEXRHeader(EXRHeader *exr_header) { + if (exr_header == NULL) { + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (exr_header->channels) { + free(exr_header->channels); + } + + if (exr_header->pixel_types) { + free(exr_header->pixel_types); + } + + if (exr_header->requested_pixel_types) { + free(exr_header->requested_pixel_types); + } + + for (int i = 0; i < exr_header->num_custom_attributes; i++) { + if (exr_header->custom_attributes[i].value) { + free(exr_header->custom_attributes[i].value); + } + } + + if (exr_header->custom_attributes) { + free(exr_header->custom_attributes); + } + + EXRSetNameAttr(exr_header, NULL); + + return TINYEXR_SUCCESS; +} + +void EXRSetNameAttr(EXRHeader* exr_header, const char* name) { + if (exr_header == NULL) { + return; + } + memset(exr_header->name, 0, 256); + if (name != NULL) { + size_t len = std::min(strlen(name), (size_t)255); + if (len) { + memcpy(exr_header->name, name, len); + } + } +} + +int EXRNumLevels(const EXRImage* exr_image) { + if (exr_image == NULL) return 0; + if(exr_image->images) return 1; // scanlines + int levels = 1; + const EXRImage* level_image = exr_image; + while((level_image = level_image->next_level)) ++levels; + return levels; +} + +int FreeEXRImage(EXRImage *exr_image) { + if (exr_image == NULL) { + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (exr_image->next_level) { + FreeEXRImage(exr_image->next_level); + delete exr_image->next_level; + } + + for (int i = 0; i < exr_image->num_channels; i++) { + if (exr_image->images && exr_image->images[i]) { + free(exr_image->images[i]); + } + } + + if (exr_image->images) { + free(exr_image->images); + } + + if (exr_image->tiles) { + for (int tid = 0; tid < exr_image->num_tiles; tid++) { + for (int i = 0; i < exr_image->num_channels; i++) { + if (exr_image->tiles[tid].images && exr_image->tiles[tid].images[i]) { + free(exr_image->tiles[tid].images[i]); + } + } + if (exr_image->tiles[tid].images) { + free(exr_image->tiles[tid].images); + } + } + free(exr_image->tiles); + } + + return TINYEXR_SUCCESS; +} + +int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version, + const char *filename, const char **err) { + if (exr_header == NULL || exr_version == NULL || filename == NULL) { + tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile", + err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_INVALID_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "rb"); +#endif +#else + fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + fclose(fp); + + if (ret != filesize) { + tinyexr::SetErrorMessage("fread() error on " + std::string(filename), + err); + return TINYEXR_ERROR_INVALID_FILE; + } + } + + return ParseEXRHeaderFromMemory(exr_header, exr_version, &buf.at(0), filesize, + err); +} + +int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers, + int *num_headers, + const EXRVersion *exr_version, + const unsigned char *memory, size_t size, + const char **err) { + if (memory == NULL || exr_headers == NULL || num_headers == NULL || + exr_version == NULL) { + // Invalid argument + tinyexr::SetErrorMessage( + "Invalid argument for ParseEXRMultipartHeaderFromMemory", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (size < tinyexr::kEXRVersionSize) { + tinyexr::SetErrorMessage("Data size too short", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + const unsigned char *marker = memory + tinyexr::kEXRVersionSize; + size_t marker_size = size - tinyexr::kEXRVersionSize; + + std::vector infos; + + for (;;) { + tinyexr::HeaderInfo info; + info.clear(); + + std::string err_str; + bool empty_header = false; + int ret = ParseEXRHeader(&info, &empty_header, exr_version, &err_str, + marker, marker_size); + + if (ret != TINYEXR_SUCCESS) { + tinyexr::SetErrorMessage(err_str, err); + return ret; + } + + if (empty_header) { + marker += 1; // skip '\0' + break; + } + + // `chunkCount` must exist in the header. + if (info.chunk_count == 0) { + tinyexr::SetErrorMessage( + "`chunkCount' attribute is not found in the header.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + + infos.push_back(info); + + // move to next header. + marker += info.header_len; + size -= info.header_len; + } + + // allocate memory for EXRHeader and create array of EXRHeader pointers. + (*exr_headers) = + static_cast(malloc(sizeof(EXRHeader *) * infos.size())); + for (size_t i = 0; i < infos.size(); i++) { + EXRHeader *exr_header = static_cast(malloc(sizeof(EXRHeader))); + memset(exr_header, 0, sizeof(EXRHeader)); + + ConvertHeader(exr_header, infos[i]); + + exr_header->multipart = exr_version->multipart ? 1 : 0; + + (*exr_headers)[i] = exr_header; + } + + (*num_headers) = static_cast(infos.size()); + + return TINYEXR_SUCCESS; +} + +int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers, + const EXRVersion *exr_version, + const char *filename, const char **err) { + if (exr_headers == NULL || num_headers == NULL || exr_version == NULL || + filename == NULL) { + tinyexr::SetErrorMessage( + "Invalid argument for ParseEXRMultipartHeaderFromFile()", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_INVALID_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "rb"); +#endif +#else + fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + fclose(fp); + + if (ret != filesize) { + tinyexr::SetErrorMessage("`fread' error. file may be corrupted.", err); + return TINYEXR_ERROR_INVALID_FILE; + } + } + + return ParseEXRMultipartHeaderFromMemory( + exr_headers, num_headers, exr_version, &buf.at(0), filesize, err); +} + +int ParseEXRVersionFromMemory(EXRVersion *version, const unsigned char *memory, + size_t size) { + if (version == NULL || memory == NULL) { + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + if (size < tinyexr::kEXRVersionSize) { + return TINYEXR_ERROR_INVALID_DATA; + } + + const unsigned char *marker = memory; + + // Header check. + { + const char header[] = {0x76, 0x2f, 0x31, 0x01}; + + if (memcmp(marker, header, 4) != 0) { + return TINYEXR_ERROR_INVALID_MAGIC_NUMBER; + } + marker += 4; + } + + version->tiled = false; + version->long_name = false; + version->non_image = false; + version->multipart = false; + + // Parse version header. + { + // must be 2 + if (marker[0] != 2) { + return TINYEXR_ERROR_INVALID_EXR_VERSION; + } + + if (version == NULL) { + return TINYEXR_SUCCESS; // May OK + } + + version->version = 2; + + if (marker[1] & 0x2) { // 9th bit + version->tiled = true; + } + if (marker[1] & 0x4) { // 10th bit + version->long_name = true; + } + if (marker[1] & 0x8) { // 11th bit + version->non_image = true; // (deep image) + } + if (marker[1] & 0x10) { // 12th bit + version->multipart = true; + } + } + + return TINYEXR_SUCCESS; +} + +int ParseEXRVersionFromFile(EXRVersion *version, const char *filename) { + if (filename == NULL) { + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t err = _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb"); + if (err != 0) { + // TODO(syoyo): return wfopen_s erro code + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "rb"); +#endif +#else + fp = fopen(filename, "rb"); +#endif + if (!fp) { + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t file_size; + // Compute size + fseek(fp, 0, SEEK_END); + file_size = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + if (file_size < tinyexr::kEXRVersionSize) { + return TINYEXR_ERROR_INVALID_FILE; + } + + unsigned char buf[tinyexr::kEXRVersionSize]; + size_t ret = fread(&buf[0], 1, tinyexr::kEXRVersionSize, fp); + fclose(fp); + + if (ret != tinyexr::kEXRVersionSize) { + return TINYEXR_ERROR_INVALID_FILE; + } + + return ParseEXRVersionFromMemory(version, buf, tinyexr::kEXRVersionSize); +} + +int LoadEXRMultipartImageFromMemory(EXRImage *exr_images, + const EXRHeader **exr_headers, + unsigned int num_parts, + const unsigned char *memory, + const size_t size, const char **err) { + if (exr_images == NULL || exr_headers == NULL || num_parts == 0 || + memory == NULL || (size <= tinyexr::kEXRVersionSize)) { + tinyexr::SetErrorMessage( + "Invalid argument for LoadEXRMultipartImageFromMemory()", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + // compute total header size. + size_t total_header_size = 0; + for (unsigned int i = 0; i < num_parts; i++) { + if (exr_headers[i]->header_len == 0) { + tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + total_header_size += exr_headers[i]->header_len; + } + + const char *marker = reinterpret_cast( + memory + total_header_size + 4 + + 4); // +8 for magic number and version header. + + marker += 1; // Skip empty header. + + // NOTE 1: + // In multipart image, There is 'part number' before chunk data. + // 4 byte : part number + // 4+ : chunk + // + // NOTE 2: + // EXR spec says 'part number' is 'unsigned long' but actually this is + // 'unsigned int(4 bytes)' in OpenEXR implementation... + // http://www.openexr.com/openexrfilelayout.pdf + + // Load chunk offset table. + std::vector chunk_offset_table_list; + chunk_offset_table_list.reserve(num_parts); + for (size_t i = 0; i < static_cast(num_parts); i++) { + chunk_offset_table_list.resize(chunk_offset_table_list.size() + 1); + tinyexr::OffsetData& offset_data = chunk_offset_table_list.back(); + if (!exr_headers[i]->tiled || exr_headers[i]->tile_level_mode == TINYEXR_TILE_ONE_LEVEL) { + tinyexr::InitSingleResolutionOffsets(offset_data, exr_headers[i]->chunk_count); + std::vector& offset_table = offset_data.offsets[0][0]; + + for (size_t c = 0; c < offset_table.size(); c++) { + tinyexr::tinyexr_uint64 offset; + memcpy(&offset, marker, 8); + tinyexr::swap8(&offset); + + if (offset >= size) { + tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.", + err); + return TINYEXR_ERROR_INVALID_DATA; + } + + offset_table[c] = offset + 4; // +4 to skip 'part number' + marker += 8; + } + } else { + { + std::vector num_x_tiles, num_y_tiles; + tinyexr::PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_headers[i]); + int num_blocks = InitTileOffsets(offset_data, exr_headers[i], num_x_tiles, num_y_tiles); + if (num_blocks != exr_headers[i]->chunk_count) { + tinyexr::SetErrorMessage("Invalid offset table size.", err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) { + for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) { + for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) { + tinyexr::tinyexr_uint64 offset; + memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64)); + tinyexr::swap8(&offset); + if (offset >= size) { + tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.", + err); + return TINYEXR_ERROR_INVALID_DATA; + } + offset_data.offsets[l][dy][dx] = offset + 4; // +4 to skip 'part number' + marker += sizeof(tinyexr::tinyexr_uint64); // = 8 + } + } + } + } + } + + // Decode image. + for (size_t i = 0; i < static_cast(num_parts); i++) { + tinyexr::OffsetData &offset_data = chunk_offset_table_list[i]; + + // First check 'part number' is identitical to 'i' + for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) + for (unsigned int dy = 0; dy < offset_data.offsets[l].size(); ++dy) + for (unsigned int dx = 0; dx < offset_data.offsets[l][dy].size(); ++dx) { + + const unsigned char *part_number_addr = + memory + offset_data.offsets[l][dy][dx] - 4; // -4 to move to 'part number' field. + unsigned int part_no; + memcpy(&part_no, part_number_addr, sizeof(unsigned int)); // 4 + tinyexr::swap4(&part_no); + + if (part_no != i) { + tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.", + err); + return TINYEXR_ERROR_INVALID_DATA; + } + } + + std::string e; + int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_data, + memory, size, &e); + if (ret != TINYEXR_SUCCESS) { + if (!e.empty()) { + tinyexr::SetErrorMessage(e, err); + } + return ret; + } + } + + return TINYEXR_SUCCESS; +} + +int LoadEXRMultipartImageFromFile(EXRImage *exr_images, + const EXRHeader **exr_headers, + unsigned int num_parts, const char *filename, + const char **err) { + if (exr_images == NULL || exr_headers == NULL || num_parts == 0) { + tinyexr::SetErrorMessage( + "Invalid argument for LoadEXRMultipartImageFromFile", err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + FILE *fp = NULL; +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(__MINGW32__) // MSVC, MinGW gcc or clang + errno_t errcode = + _wfopen_s(&fp, tinyexr::UTF8ToWchar(filename).c_str(), L"rb"); + if (errcode != 0) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } +#else + // Unknown compiler + fp = fopen(filename, "rb"); +#endif +#else + fp = fopen(filename, "rb"); +#endif + if (!fp) { + tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err); + return TINYEXR_ERROR_CANT_OPEN_FILE; + } + + size_t filesize; + // Compute size + fseek(fp, 0, SEEK_END); + filesize = static_cast(ftell(fp)); + fseek(fp, 0, SEEK_SET); + + std::vector buf(filesize); // @todo { use mmap } + { + size_t ret; + ret = fread(&buf[0], 1, filesize, fp); + assert(ret == filesize); + fclose(fp); + (void)ret; + } + + return LoadEXRMultipartImageFromMemory(exr_images, exr_headers, num_parts, + &buf.at(0), filesize, err); +} + +int SaveEXR(const float *data, int width, int height, int components, + const int save_as_fp16, const char *outfilename, const char **err) { + if ((components == 1) || components == 3 || components == 4) { + // OK + } else { + std::stringstream ss; + ss << "Unsupported component value : " << components << std::endl; + + tinyexr::SetErrorMessage(ss.str(), err); + return TINYEXR_ERROR_INVALID_ARGUMENT; + } + + EXRHeader header; + InitEXRHeader(&header); + + if ((width < 16) && (height < 16)) { + // No compression for small image. + header.compression_type = TINYEXR_COMPRESSIONTYPE_NONE; + } else { + header.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP; + } + + EXRImage image; + InitEXRImage(&image); + + image.num_channels = components; + + std::vector images[4]; + + if (components == 1) { + images[0].resize(static_cast(width * height)); + memcpy(images[0].data(), data, sizeof(float) * size_t(width * height)); + } else { + images[0].resize(static_cast(width * height)); + images[1].resize(static_cast(width * height)); + images[2].resize(static_cast(width * height)); + images[3].resize(static_cast(width * height)); + + // Split RGB(A)RGB(A)RGB(A)... into R, G and B(and A) layers + for (size_t i = 0; i < static_cast(width * height); i++) { + images[0][i] = data[static_cast(components) * i + 0]; + images[1][i] = data[static_cast(components) * i + 1]; + images[2][i] = data[static_cast(components) * i + 2]; + if (components == 4) { + images[3][i] = data[static_cast(components) * i + 3]; + } + } + } + + float *image_ptr[4] = {0, 0, 0, 0}; + if (components == 4) { + image_ptr[0] = &(images[3].at(0)); // A + image_ptr[1] = &(images[2].at(0)); // B + image_ptr[2] = &(images[1].at(0)); // G + image_ptr[3] = &(images[0].at(0)); // R + } else if (components == 3) { + image_ptr[0] = &(images[2].at(0)); // B + image_ptr[1] = &(images[1].at(0)); // G + image_ptr[2] = &(images[0].at(0)); // R + } else if (components == 1) { + image_ptr[0] = &(images[0].at(0)); // A + } + + image.images = reinterpret_cast(image_ptr); + image.width = width; + image.height = height; + + header.num_channels = components; + header.channels = static_cast(malloc( + sizeof(EXRChannelInfo) * static_cast(header.num_channels))); + // Must be (A)BGR order, since most of EXR viewers expect this channel order. + if (components == 4) { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "A", 255); + strncpy_s(header.channels[1].name, "B", 255); + strncpy_s(header.channels[2].name, "G", 255); + strncpy_s(header.channels[3].name, "R", 255); +#else + strncpy(header.channels[0].name, "A", 255); + strncpy(header.channels[1].name, "B", 255); + strncpy(header.channels[2].name, "G", 255); + strncpy(header.channels[3].name, "R", 255); +#endif + header.channels[0].name[strlen("A")] = '\0'; + header.channels[1].name[strlen("B")] = '\0'; + header.channels[2].name[strlen("G")] = '\0'; + header.channels[3].name[strlen("R")] = '\0'; + } else if (components == 3) { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "B", 255); + strncpy_s(header.channels[1].name, "G", 255); + strncpy_s(header.channels[2].name, "R", 255); +#else + strncpy(header.channels[0].name, "B", 255); + strncpy(header.channels[1].name, "G", 255); + strncpy(header.channels[2].name, "R", 255); +#endif + header.channels[0].name[strlen("B")] = '\0'; + header.channels[1].name[strlen("G")] = '\0'; + header.channels[2].name[strlen("R")] = '\0'; + } else { +#ifdef _MSC_VER + strncpy_s(header.channels[0].name, "A", 255); +#else + strncpy(header.channels[0].name, "A", 255); +#endif + header.channels[0].name[strlen("A")] = '\0'; + } + + header.pixel_types = static_cast( + malloc(sizeof(int) * static_cast(header.num_channels))); + header.requested_pixel_types = static_cast( + malloc(sizeof(int) * static_cast(header.num_channels))); + for (int i = 0; i < header.num_channels; i++) { + header.pixel_types[i] = + TINYEXR_PIXELTYPE_FLOAT; // pixel type of input image + + if (save_as_fp16 > 0) { + header.requested_pixel_types[i] = + TINYEXR_PIXELTYPE_HALF; // save with half(fp16) pixel format + } else { + header.requested_pixel_types[i] = + TINYEXR_PIXELTYPE_FLOAT; // save with float(fp32) pixel format(i.e. + // no precision reduction) + } + } + + int ret = SaveEXRImageToFile(&image, &header, outfilename, err); + if (ret != TINYEXR_SUCCESS) { + return ret; + } + + free(header.channels); + free(header.pixel_types); + free(header.requested_pixel_types); + + return ret; +} + +#ifdef __clang__ +// zero-as-null-ppinter-constant +#pragma clang diagnostic pop +#endif + +#endif // TINYEXR_IMPLEMENTATION_DEFINED +#endif // TINYEXR_IMPLEMENTATION diff --git a/libs/anari_viewer/windows/LightsEditor.cpp b/libs/anari_viewer/windows/LightsEditor.cpp index 32101135..2bdbaf24 100644 --- a/libs/anari_viewer/windows/LightsEditor.cpp +++ b/libs/anari_viewer/windows/LightsEditor.cpp @@ -2,6 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 #include "LightsEditor.h" +#include "../HDRImage.h" +// anari_viewer +#include "nfd.h" // std #include @@ -16,6 +19,8 @@ static const char *lightToType(Light::LightType type) return "point"; case Light::SPOT: return "spot"; + case Light::HDRI: + return "hdri"; default: return nullptr; } @@ -59,6 +64,9 @@ void LightsEditor::buildUI() ImGui::SameLine(); if (ImGui::Button("spot")) addNewLight(Light::SPOT); + ImGui::SameLine(); + if (ImGui::Button("hdri")) + addNewLight(Light::HDRI); Light *lightToRemove = nullptr; @@ -70,9 +78,12 @@ void LightsEditor::buildUI() bool update = false; - update |= ImGui::DragFloat("intensity", &l.intensity, 0.001f, 0.f, 1000.f); + if (l.type != Light::HDRI) { + update |= + ImGui::DragFloat("intensity", &l.intensity, 0.001f, 0.f, 1000.f); - update |= ImGui::ColorEdit3("color", &l.color.x); + update |= ImGui::ColorEdit3("color", &l.color.x); + } if (l.type == Light::DIRECTIONAL || l.type == Light::SPOT) { auto maintainUnitCircle = [](float inDegrees) -> float { @@ -104,6 +115,44 @@ void LightsEditor::buildUI() update = true; } + if (l.type == Light::HDRI) { + const void *value = l.hdriRadiance.data(); + + constexpr int MAX_LENGTH = 2000; + l.hdriRadiance.reserve(MAX_LENGTH); + + if (ImGui::Button("...")) { + nfdchar_t *outPath = nullptr; + nfdfilteritem_t filterItem[1] = {{"HDR Image Files", "exr,hdr"}}; + nfdresult_t result = NFD_OpenDialog(&outPath, filterItem, 1, nullptr); + if (result == NFD_OKAY) { + l.hdriRadiance = std::string(outPath).c_str(); + NFD_FreePath(outPath); + } else { + printf("NFD Error: %s\n", NFD_GetError()); + } + } + + ImGui::SameLine(); + + auto text_cb = [](ImGuiInputTextCallbackData *cbd) { + auto &l = *(Light *)cbd->UserData; + l.hdriRadiance.resize(cbd->BufTextLen); + return 0; + }; + + ImGui::InputText("fileName", + (char *)value, + MAX_LENGTH, + ImGuiInputTextFlags_CallbackEdit, + text_cb, + &l); + + ImGui::DragFloat("scale", &l.scale, 0.01f, 10.f); + + update = ImGui::Button("update"); + } + if (ImGui::Button("remove")) lightToRemove = &l; @@ -193,6 +242,46 @@ void LightsEditor::updateLight(const Light &l) if (l.type == Light::SPOT) { anari::setParameter(device, light, "openingAngle", l.openingAngle); } + if (l.type == Light::HDRI) { + std::vector pixel; + unsigned width = 0, height = 0; + importers::HDRImage hdrImg; + if (hdrImg.load(l.hdriRadiance)) { + pixel.resize(hdrImg.width * hdrImg.height * 3); + width = hdrImg.width; + height = hdrImg.height; + if (hdrImg.numComponents == 3) { + std::copy(hdrImg.pixel.begin(), hdrImg.pixel.end(), pixel.begin()); + } else if (hdrImg.numComponents == 4) { + for (size_t i = 0; i < hdrImg.pixel.size(); i += 4) { + size_t i3 = i / 4 * 3; + pixel[i3] = hdrImg.pixel[i]; + pixel[i3 + 1] = hdrImg.pixel[i + 1]; + pixel[i3 + 2] = hdrImg.pixel[i + 2]; + } + } else { + printf("Error loading HDR image, unsupported num. components: %u\n", + hdrImg.numComponents); + pixel.clear(); + width = height = 0; + } + } + + if (pixel.empty()) { + // Fill with dummy data: + pixel.resize(6, 1.f); + width = 2; + height = 1; + } + + ANARIArray2D radiance = anariNewArray2D( + device, pixel.data(), 0, 0, ANARI_FLOAT32_VEC3, width, height); + + anari::setParameter(device, light, "radiance", radiance); + anari::setParameter(device, light, "scale", l.scale); + + anariRelease(device, radiance); + } anari::commitParameters(device, light); } @@ -221,4 +310,4 @@ void LightsEditor::updateLightsArray() } } -} // namespace windows \ No newline at end of file +} // namespace windows diff --git a/libs/anari_viewer/windows/LightsEditor.h b/libs/anari_viewer/windows/LightsEditor.h index 43521d78..6aeb820e 100644 --- a/libs/anari_viewer/windows/LightsEditor.h +++ b/libs/anari_viewer/windows/LightsEditor.h @@ -7,6 +7,7 @@ #include #include // std +#include #include #include "Window.h" @@ -19,7 +20,8 @@ struct Light { DIRECTIONAL, POINT, - SPOT + SPOT, + HDRI }; LightType type{DIRECTIONAL}; float intensity{1.f}; @@ -27,6 +29,8 @@ struct Light anari::float3 color{1.f}; anari::float2 directionalAZEL{0.f, 345.f}; anari::float3 pointPosition{0.f}; + std::string hdriRadiance; + float scale{1.f}; std::vector handles; }; From e6eda49ed3ffbbce03a2b264235e5a8cc99ed339 Mon Sep 17 00:00:00 2001 From: Stefan Zellmann Date: Sun, 17 Sep 2023 23:56:51 +0200 Subject: [PATCH 05/34] Simplify --- libs/anari_viewer/HDRImage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/anari_viewer/HDRImage.cpp b/libs/anari_viewer/HDRImage.cpp index cbf04ce6..62663b31 100644 --- a/libs/anari_viewer/HDRImage.cpp +++ b/libs/anari_viewer/HDRImage.cpp @@ -23,10 +23,10 @@ bool HDRImage::load(std::string fileName) std::addressof(extension[0]), [](unsigned char c) { return std::tolower(c); }); - if (extension.compare(".hdr") != 0 && extension.compare(".exr") != 0) + if (extension != ".hdr" && extension != ".exr") return false; - if (extension.compare(".hdr") == 0) { + if (extension == ".hdr") { int w, h, n; float *imgData = stbi_loadf(fileName.c_str(), &w, &h, &n, STBI_rgb); width = w; From 71883e4f31593e342ad1ec11fa7d986c6598f5c0 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Wed, 27 Sep 2023 12:58:45 -0500 Subject: [PATCH 06/34] add advanced CMake option for allowing anariViewer to be installed --- CMakeLists.txt | 2 ++ examples/viewer/CMakeLists.txt | 4 ++++ libs/anari_viewer/external/nativefiledialog/CMakeLists.txt | 1 + 3 files changed, 7 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ed60b71b..3aaf493e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,8 @@ cmake_dependent_option(INSTALL_VIEWER_LIBRARY "BUILD_EXAMPLES;BUILD_VIEWER" OFF ) +option(INSTALL_VIEWER "Install anariViewer app" OFF) +mark_as_advanced(INSTALL_VIEWER) ## The generate_all targets collects all offline code generation targets diff --git a/examples/viewer/CMakeLists.txt b/examples/viewer/CMakeLists.txt index 759770f7..05dbb97b 100644 --- a/examples/viewer/CMakeLists.txt +++ b/examples/viewer/CMakeLists.txt @@ -11,3 +11,7 @@ endif() project_add_executable(main.cpp ui_layout.cpp) project_link_libraries(PRIVATE anari::anari_viewer) + +if (INSTALL_VIEWER) + install(TARGETS ${PROJECT_NAME} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif() diff --git a/libs/anari_viewer/external/nativefiledialog/CMakeLists.txt b/libs/anari_viewer/external/nativefiledialog/CMakeLists.txt index 25c3e0c3..5856faac 100644 --- a/libs/anari_viewer/external/nativefiledialog/CMakeLists.txt +++ b/libs/anari_viewer/external/nativefiledialog/CMakeLists.txt @@ -3,6 +3,7 @@ project(anari_viewer_nfd VERSION ${PROJECT_VERSION} LANGUAGES CXX) +set(BUILD_SHARED_LIBS OFF) anari_sdk_fetch_project( NAME ${PROJECT_NAME} URL https://github.com/btzy/nativefiledialog-extended/archive/refs/tags/v1.0.3.zip From 7af86080b160ea9284724c0bf71aa12e3f2ffbfd Mon Sep 17 00:00:00 2001 From: Stefan Zellmann Date: Tue, 26 Sep 2023 23:24:32 +0200 Subject: [PATCH 07/34] Implement object and parameter info queries --- libs/remote_device/Device.cpp | 225 +++++++++++++++++++++++++++++++++- libs/remote_device/Device.h | 60 +++++++++ libs/remote_device/Server.cpp | 164 +++++++++++++++++++++++++ libs/remote_device/common.h | 4 + 4 files changed, 451 insertions(+), 2 deletions(-) diff --git a/libs/remote_device/Device.cpp b/libs/remote_device/Device.cpp index a5723be7..5e14f783 100644 --- a/libs/remote_device/Device.cpp +++ b/libs/remote_device/Device.cpp @@ -488,7 +488,44 @@ const void* Device::getObjectInfo(ANARIDataType objectType, const char* infoName, ANARIDataType infoType) { - return nullptr; + auto it = std::find_if(objectInfos.begin(), + objectInfos.end(), + [objectType, objectSubtype, infoName, infoType](const ObjectInfo &oi) { + return oi.objectType == objectType + && oi.objectSubtype == std::string(objectSubtype) + && oi.info.name == std::string(infoName) + && oi.info.type == infoType; + }); + if (it != objectInfos.end()) { + return it->info.data(); + } + + auto buf = std::make_shared(); + buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); + buf->write((const char *)&objectType, sizeof(objectType)); + uint64_t len = strlen(objectSubtype); + buf->write((const char *)&len, sizeof(len)); + buf->write(objectSubtype, len); + len = strlen(infoName); + buf->write((const char *)&len, sizeof(len)); + buf->write(infoName, len); + buf->write((const char *)&infoType, sizeof(infoType)); + write(MessageType::GetObjectInfo, buf); + + std::unique_lock l(syncObjectInfo.mtx); + syncObjectInfo.cv.wait(l, [this, &it, objectType, objectSubtype, infoName, infoType]() { + it = std::find_if(objectInfos.begin(), + objectInfos.end(), + [&it, objectType, objectSubtype, infoName, infoType](const ObjectInfo &oi) { + return oi.objectType == objectType + && oi.objectSubtype == std::string(objectSubtype) + && oi.info.name == std::string(infoName) + && oi.info.type == infoType; + }); + return it != objectInfos.end(); + }); + + return it->info.data(); } const void* Device::getParameterInfo(ANARIDataType objectType, @@ -498,7 +535,52 @@ const void* Device::getParameterInfo(ANARIDataType objectType, const char* infoName, ANARIDataType infoType) { - return nullptr; + auto it = std::find_if(parameterInfos.begin(), + parameterInfos.end(), + [objectType, objectSubtype, parameterName, parameterType, infoName, infoType](const ParameterInfo &pi) { + return pi.objectType == objectType + && pi.objectSubtype == std::string(objectSubtype) + && pi.parameterName == std::string(parameterName) + && pi.parameterType == parameterType + && pi.info.name == std::string(infoName) + && pi.info.type == infoType; + }); + if (it != parameterInfos.end()) { + return it->info.data(); + } + + auto buf = std::make_shared(); + buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); + buf->write((const char *)&objectType, sizeof(objectType)); + uint64_t len = strlen(objectSubtype); + buf->write((const char *)&len, sizeof(len)); + buf->write(objectSubtype, len); + len = strlen(parameterName); + buf->write((const char *)&len, sizeof(len)); + buf->write(parameterName, len); + buf->write((const char *)¶meterType, sizeof(parameterType)); + len = strlen(infoName); + buf->write((const char *)&len, sizeof(len)); + buf->write(infoName, len); + buf->write((const char *)&infoType, sizeof(infoType)); + write(MessageType::GetParameterInfo, buf); + + std::unique_lock l(syncParameterInfo.mtx); + syncParameterInfo.cv.wait(l, [this, &it, objectType, objectSubtype, parameterName, parameterType, infoName, infoType]() { + it = std::find_if(parameterInfos.begin(), + parameterInfos.end(), + [&it, objectType, objectSubtype, parameterName, parameterType, infoName, infoType](const ParameterInfo &pi) { + return pi.objectType == objectType + && pi.objectSubtype == std::string(objectSubtype) + && pi.parameterName == std::string(parameterName) + && pi.parameterType == parameterType + && pi.info.name == std::string(infoName) + && pi.info.type == infoType; + }); + return it != parameterInfos.end(); + }); + + return it->info.data(); } //--- FrameBuffer Manipulation ------------------------ @@ -668,6 +750,18 @@ Device::~Device() delete[] objectSubtypes[i].value[j]; } } + + for (size_t i = 0; i < objectInfos.size(); ++i) { + for (size_t j = 0; j < objectInfos[i].info.asStringList.size(); ++j) { + delete[] objectInfos[i].info.asStringList[j]; + } + } + + for (size_t i = 0; i < parameterInfos.size(); ++i) { + for (size_t j = 0; j < parameterInfos[i].info.asStringList.size(); ++j) { + delete[] parameterInfos[i].info.asStringList[j]; + } + } } ANARIObject Device::registerNewObject(ANARIDataType type, std::string subtype) @@ -971,6 +1065,133 @@ void Device::handleMessage(async::connection::reason reason, l.unlock(); syncObjectSubtypes.cv.notify_all(); + } else if (message->type() == MessageType::ObjectInfo) { + std::unique_lock l(syncObjectInfo.mtx); + + Buffer buf; + buf.write(message->data(), message->size()); + buf.seek(0); + + ObjectInfo oi; + + buf.read((char *)&oi.objectType, sizeof(oi.objectType)); + uint64_t len; + buf.read((char *)&len, sizeof(len)); + std::vector bytesToString(len); + buf.read(bytesToString.data(), len); + oi.objectSubtype = std::string(bytesToString.data(), len); + buf.read((char *)&len, sizeof(len)); + bytesToString.resize(len); + buf.read(bytesToString.data(), len); + oi.info.name = std::string(bytesToString.data(), len); + buf.read((char *)&oi.info.type, sizeof(oi.info.type)); + if (oi.info.type == ANARI_STRING) { + uint64_t strLen; + buf.read((char *)&strLen, sizeof(strLen)); + oi.info.asString.resize(strLen + 1); + buf.read(oi.info.asString.data(), strLen); + oi.info.asString[strLen] = '\0'; + } else if (oi.info.type == ANARI_STRING_LIST) { + while (!buf.eof()) { + uint64_t strLen; + buf.read((char *)&strLen, sizeof(strLen)); + + char *str = new char[strLen + 1]; + buf.read(str, strLen); + str[strLen] = '\0'; + oi.info.asStringList.push_back(str); + } + oi.info.asStringList.push_back(nullptr); + } else if (oi.info.type == ANARI_PARAMETER_LIST) { + while (!buf.eof()) { + uint64_t len; + buf.read((char *)&len, sizeof(len)); + char *name = new char[len + 1]; + buf.read(name, len); + name[len] = '\0'; + + ANARIDataType type; + buf.read((char *)&type, sizeof(type)); + oi.info.asParameterList.push_back({name, type}); + } + oi.info.asParameterList.push_back({nullptr, 0}); + } else { + if (!buf.eof()) { + oi.info.asOther.resize(anari::sizeOf(oi.info.type)); + buf.read(oi.info.asOther.data(), anari::sizeOf(oi.info.type)); + } + } + + objectInfos.push_back(oi); + + l.unlock(); + syncObjectInfo.cv.notify_all(); + } else if (message->type() == MessageType::ParameterInfo) { + std::unique_lock l(syncParameterInfo.mtx); + + Buffer buf; + buf.write(message->data(), message->size()); + buf.seek(0); + + ParameterInfo pi; + + buf.read((char *)&pi.objectType, sizeof(pi.objectType)); + uint64_t len; + buf.read((char *)&len, sizeof(len)); + std::vector bytesToString(len); + buf.read(bytesToString.data(), len); + pi.objectSubtype = std::string(bytesToString.data(), len); + buf.read((char *)&len, sizeof(len)); + bytesToString.resize(len); + buf.read(bytesToString.data(), len); + pi.parameterName = std::string(bytesToString.data(), len); + buf.read((char *)&pi.parameterType, sizeof(pi.parameterType)); + buf.read((char *)&len, sizeof(len)); + bytesToString.resize(len); + buf.read(bytesToString.data(), len); + pi.info.name = std::string(bytesToString.data(), len); + buf.read((char *)&pi.info.type, sizeof(pi.info.type)); + if (pi.info.type == ANARI_STRING) { + uint64_t strLen; + buf.read((char *)&strLen, sizeof(strLen)); + pi.info.asString.resize(strLen + 1); + buf.read(pi.info.asString.data(), strLen); + pi.info.asString[strLen] = '\0'; + } else if (pi.info.type == ANARI_STRING_LIST) { + while (!buf.eof()) { + uint64_t strLen; + buf.read((char *)&strLen, sizeof(strLen)); + + char *str = new char[strLen + 1]; + buf.read(str, strLen); + str[strLen] = '\0'; + pi.info.asStringList.push_back(str); + } + pi.info.asStringList.push_back(nullptr); + } else if (pi.info.type == ANARI_PARAMETER_LIST) { + while (!buf.eof()) { + uint64_t len; + buf.read((char *)&len, sizeof(len)); + char *name = new char[len + 1]; + buf.read(name, len); + name[len] = '\0'; + + ANARIDataType type; + buf.read((char *)&type, sizeof(type)); + pi.info.asParameterList.push_back({name, type}); + } + pi.info.asParameterList.push_back({nullptr, 0}); + } else { + if (!buf.eof()) { + pi.info.asOther.resize(anari::sizeOf(pi.info.type)); + buf.read(pi.info.asOther.data(), anari::sizeOf(pi.info.type)); + } + } + + parameterInfos.push_back(pi); + + l.unlock(); + syncParameterInfo.cv.notify_all(); } else if (message->type() == MessageType::ChannelColor || message->type() == MessageType::ChannelDepth) { size_t off = 0; diff --git a/libs/remote_device/Device.h b/libs/remote_device/Device.h index 6d4a0ce5..c2c8d62d 100644 --- a/libs/remote_device/Device.h +++ b/libs/remote_device/Device.h @@ -220,6 +220,18 @@ struct Device : anari::DeviceImpl, helium::ParameterizedObject std::condition_variable cv; } syncObjectSubtypes; + struct + { + std::mutex mtx; + std::condition_variable cv; + } syncObjectInfo; + + struct + { + std::mutex mtx; + std::condition_variable cv; + } syncParameterInfo; + ANARIDevice remoteDevice{nullptr}; std::string remoteSubtype = "default"; @@ -254,6 +266,54 @@ struct Device : anari::DeviceImpl, helium::ParameterizedObject }; std::vector objectSubtypes; + struct Parameter + { + char *name; + ANARIDataType type; + }; + + struct Info + { + std::string name; + ANARIDataType type; + std::string asString; + std::vector asStringList; + std::vector asParameterList; + std::vector asOther; + + const void *data() const { + if (type == ANARI_STRING) + return asString.data(); + else if (type == ANARI_STRING_LIST) + return asStringList.data(); + else if (type == ANARI_PARAMETER_LIST) + return asParameterList.data(); + else + return asOther.data(); + } + }; + + // Cache for "object infos" + struct ObjectInfo + { + ANARIDataType objectType; + std::string objectSubtype; + std::string infoName; + Info info; + }; + std::vector objectInfos; + + // Cache for "parameter infos" + struct ParameterInfo + { + ANARIDataType objectType; + std::string objectSubtype; + std::string parameterName; + ANARIDataType parameterType; + Info info; + }; + std::vector parameterInfos; + std::map frames; struct ArrayData { diff --git a/libs/remote_device/Server.cpp b/libs/remote_device/Server.cpp index 71ca7ffc..b1276e62 100644 --- a/libs/remote_device/Server.cpp +++ b/libs/remote_device/Server.cpp @@ -1031,6 +1031,170 @@ struct Server } } write(MessageType::ObjectSubtypes, outbuf); + } else if (message->type() == MessageType::GetObjectInfo) { + LOG(logging::Level::Info) << "Message: GetObjectInfo, message size: " + << prettyBytes(message->size()); + + Buffer buf; + buf.write(message->data(), message->size()); + buf.seek(0); + + Handle deviceHandle; + buf.read((char *)&deviceHandle, sizeof(deviceHandle)); + + ANARIDataType objectType; + buf.read((char *)&objectType, sizeof(objectType)); + + uint64_t len; + buf.read((char *)&len, sizeof(len)); + std::vector objectSubtype(len + 1); + buf.read(objectSubtype.data(), len); + objectSubtype[len] = '\0'; + + buf.read((char *)&len, sizeof(len)); + std::vector infoName(len + 1); + buf.read(infoName.data(), len); + infoName[len] = '\0'; + + ANARIDataType infoType; + buf.read((char *)&infoType, sizeof(infoType)); + + ANARIDevice dev = resourceManager.getDevice(deviceHandle); + + if (!dev) { + LOG(logging::Level::Error) + << "Server: invalid device: " << deviceHandle; + // manager->stop(); // legal? + return; + } + + auto outbuf = std::make_shared(); + outbuf->write((const char *)&objectType, sizeof(objectType)); + len = objectSubtype.size()-1; + outbuf->write((const char *)&len, sizeof(len)); + outbuf->write(objectSubtype.data(), len); + len = infoName.size()-1; + outbuf->write((const char *)&len, sizeof(len)); + outbuf->write(infoName.data(), len); + outbuf->write((const char *)&infoType, sizeof(infoType)); + + const void *info = anariGetObjectInfo(dev, objectType, objectSubtype.data(), + infoName.data(), infoType); + + if (info != nullptr) { + if (infoType == ANARI_STRING) { + auto *str = (const char *)info; + uint64_t strLen = strlen(str); + outbuf->write((const char *)&strLen, sizeof(strLen)); + outbuf->write(str, strLen); + } else if (infoType == ANARI_STRING_LIST) { + const auto **strings = (const char **)info; + while (const char *str = *strings++) { + uint64_t strLen = strlen(str); + outbuf->write((const char *)&strLen, sizeof(strLen)); + outbuf->write(str, strLen); + } + } else if (infoType == ANARI_PARAMETER_LIST) { + auto *parameter = (const ANARIParameter *)info; + for (; parameter && parameter->name != nullptr; parameter++) { + uint64_t len = strlen(parameter->name); + outbuf->write((const char *)&len, sizeof(len)); + outbuf->write(parameter->name, len); + outbuf->write((const char *)¶meter->type, sizeof(parameter->type)); + } + } else { + outbuf->write((const char *)info, anari::sizeOf(infoType)); + } + } + write(MessageType::ObjectInfo, outbuf); + } else if (message->type() == MessageType::GetParameterInfo) { + LOG(logging::Level::Info) << "Message: GetParameterInfo, message size: " + << prettyBytes(message->size()); + + Buffer buf; + buf.write(message->data(), message->size()); + buf.seek(0); + + Handle deviceHandle; + buf.read((char *)&deviceHandle, sizeof(deviceHandle)); + + ANARIDataType objectType; + buf.read((char *)&objectType, sizeof(objectType)); + + uint64_t len; + buf.read((char *)&len, sizeof(len)); + std::vector objectSubtype(len + 1); + buf.read(objectSubtype.data(), len); + objectSubtype[len] = '\0'; + + buf.read((char *)&len, sizeof(len)); + std::vector parameterName(len + 1); + buf.read(parameterName.data(), len); + parameterName[len] = '\0'; + + ANARIDataType parameterType; + buf.read((char *)¶meterType, sizeof(parameterType)); + + buf.read((char *)&len, sizeof(len)); + std::vector infoName(len + 1); + buf.read(infoName.data(), len); + infoName[len] = '\0'; + + ANARIDataType infoType; + buf.read((char *)&infoType, sizeof(infoType)); + + ANARIDevice dev = resourceManager.getDevice(deviceHandle); + + if (!dev) { + LOG(logging::Level::Error) + << "Server: invalid device: " << deviceHandle; + // manager->stop(); // legal? + return; + } + + auto outbuf = std::make_shared(); + outbuf->write((const char *)&objectType, sizeof(objectType)); + len = objectSubtype.size()-1; + outbuf->write((const char *)&len, sizeof(len)); + outbuf->write(objectSubtype.data(), len); + len = parameterName.size()-1; + outbuf->write((const char *)&len, sizeof(len)); + outbuf->write(parameterName.data(), len); + outbuf->write((const char *)¶meterType, sizeof(parameterType)); + len = infoName.size()-1; + outbuf->write((const char *)&len, sizeof(len)); + outbuf->write(infoName.data(), len); + outbuf->write((const char *)&infoType, sizeof(infoType)); + + const void *info = anariGetParameterInfo(dev, objectType, objectSubtype.data(), + parameterName.data(), parameterType, infoName.data(), infoType); + + if (info != nullptr) { + if (infoType == ANARI_STRING) { + auto *str = (const char *)info; + uint64_t strLen = strlen(str); + outbuf->write((const char *)&strLen, sizeof(strLen)); + outbuf->write(str, strLen); + } else if (infoType == ANARI_STRING_LIST) { + const auto **strings = (const char **)info; + while (const char *str = *strings++) { + uint64_t strLen = strlen(str); + outbuf->write((const char *)&strLen, sizeof(strLen)); + outbuf->write(str, strLen); + } + } else if (infoType == ANARI_PARAMETER_LIST) { + auto *parameter = (const ANARIParameter *)info; + for (; parameter && parameter->name != nullptr; parameter++) { + uint64_t len = strlen(parameter->name); + outbuf->write((const char *)&len, sizeof(len)); + outbuf->write(parameter->name, len); + outbuf->write((const char *)¶meter->type, sizeof(parameter->type)); + } + } else { + outbuf->write((const char *)info, anari::sizeOf(infoType)); + } + } + write(MessageType::ParameterInfo, outbuf); } else { LOG(logging::Level::Warning) << "Unhandled message of size: " << message->size(); diff --git a/libs/remote_device/common.h b/libs/remote_device/common.h index 1834e604..80154763 100644 --- a/libs/remote_device/common.h +++ b/libs/remote_device/common.h @@ -43,6 +43,10 @@ struct MessageType Property, GetObjectSubtypes, ObjectSubtypes, + GetObjectInfo, + ObjectInfo, + GetParameterInfo, + ParameterInfo, ChannelColor, ChannelDepth, }; From 45537899ef4f7a65c619f1a3319b90561ca6c32e Mon Sep 17 00:00:00 2001 From: Stefan Zellmann Date: Wed, 27 Sep 2023 02:16:08 +0200 Subject: [PATCH 08/34] clang-format --- libs/remote_device/Device.cpp | 164 +++++++++++++++++++--------------- libs/remote_device/Device.h | 61 ++++++------- libs/remote_device/Server.cpp | 93 ++++++++++--------- 3 files changed, 176 insertions(+), 142 deletions(-) diff --git a/libs/remote_device/Device.cpp b/libs/remote_device/Device.cpp index 5e14f783..cb34ec42 100644 --- a/libs/remote_device/Device.cpp +++ b/libs/remote_device/Device.cpp @@ -109,14 +109,8 @@ ANARIArray1D Device::newArray1D(const void *appMemory, const ANARIDataType elementType, uint64_t numItems1) { - return (ANARIArray1D)registerNewArray(ANARI_ARRAY1D, - appMemory, - deleter, - userPtr, - elementType, - numItems1, - 0, - 0); + return (ANARIArray1D)registerNewArray( + ANARI_ARRAY1D, appMemory, deleter, userPtr, elementType, numItems1, 0, 0); } ANARIArray2D Device::newArray2D(const void *appMemory, @@ -163,9 +157,8 @@ void *Device::mapArray(ANARIArray array) std::unique_lock l(syncMapArray.mtx); ArrayData &data = arrays[array]; - syncMapArray.cv.wait(l, [&]() { - return (ssize_t)data.value.size() == data.bytesExpected; - }); + syncMapArray.cv.wait( + l, [&]() { return (ssize_t)data.value.size() == data.bytesExpected; }); l.unlock(); LOG(logging::Level::Info) << "Array mapped: " << array; @@ -269,14 +262,15 @@ void Device::setParameter( if (object == (ANARIObject)this) { if (strncmp(name, "server.hostname", 15) == 0) { if (remoteDevice != nullptr) { - LOG(logging::Level::Error) << "server.hostname must be set after device creation"; + LOG(logging::Level::Error) + << "server.hostname must be set after device creation"; return; } server.hostname = std::string((const char *)mem); } else if (strncmp(name, "server.port", 11) == 0) { - if (remoteDevice != nullptr) { - LOG(logging::Level::Error) << "server.port must be set after device creation"; + LOG(logging::Level::Error) + << "server.port must be set after device creation"; return; } server.port = *(unsigned short *)mem; @@ -454,13 +448,12 @@ int Device::getProperty(ANARIObject object, return result; } -const char ** Device::getObjectSubtypes(ANARIDataType objectType) +const char **Device::getObjectSubtypes(ANARIDataType objectType) { auto it = std::find_if(objectSubtypes.begin(), objectSubtypes.end(), - [objectType](const ObjectSubtypes &os) { - return os.objectType == objectType; - }); + [objectType]( + const ObjectSubtypes &os) { return os.objectType == objectType; }); if (it != objectSubtypes.end()) { return (const char **)it->value.data(); } @@ -473,19 +466,18 @@ const char ** Device::getObjectSubtypes(ANARIDataType objectType) std::unique_lock l(syncObjectSubtypes.mtx); syncObjectSubtypes.cv.wait(l, [this, &it, objectType]() { it = std::find_if(objectSubtypes.begin(), - objectSubtypes.end(), - [&it, objectType](const ObjectSubtypes &os) { - return os.objectType == objectType; - }); + objectSubtypes.end(), + [&it, objectType]( + const ObjectSubtypes &os) { return os.objectType == objectType; }); return it != objectSubtypes.end(); }); return (const char **)it->value.data(); } -const void* Device::getObjectInfo(ANARIDataType objectType, - const char* objectSubtype, - const char* infoName, +const void *Device::getObjectInfo(ANARIDataType objectType, + const char *objectSubtype, + const char *infoName, ANARIDataType infoType) { auto it = std::find_if(objectInfos.begin(), @@ -513,31 +505,38 @@ const void* Device::getObjectInfo(ANARIDataType objectType, write(MessageType::GetObjectInfo, buf); std::unique_lock l(syncObjectInfo.mtx); - syncObjectInfo.cv.wait(l, [this, &it, objectType, objectSubtype, infoName, infoType]() { - it = std::find_if(objectInfos.begin(), - objectInfos.end(), - [&it, objectType, objectSubtype, infoName, infoType](const ObjectInfo &oi) { - return oi.objectType == objectType - && oi.objectSubtype == std::string(objectSubtype) - && oi.info.name == std::string(infoName) - && oi.info.type == infoType; + syncObjectInfo.cv.wait( + l, [this, &it, objectType, objectSubtype, infoName, infoType]() { + it = std::find_if(objectInfos.begin(), + objectInfos.end(), + [&it, objectType, objectSubtype, infoName, infoType]( + const ObjectInfo &oi) { + return oi.objectType == objectType + && oi.objectSubtype == std::string(objectSubtype) + && oi.info.name == std::string(infoName) + && oi.info.type == infoType; + }); + return it != objectInfos.end(); }); - return it != objectInfos.end(); - }); return it->info.data(); } -const void* Device::getParameterInfo(ANARIDataType objectType, - const char* objectSubtype, - const char* parameterName, +const void *Device::getParameterInfo(ANARIDataType objectType, + const char *objectSubtype, + const char *parameterName, ANARIDataType parameterType, - const char* infoName, + const char *infoName, ANARIDataType infoType) { auto it = std::find_if(parameterInfos.begin(), parameterInfos.end(), - [objectType, objectSubtype, parameterName, parameterType, infoName, infoType](const ParameterInfo &pi) { + [objectType, + objectSubtype, + parameterName, + parameterType, + infoName, + infoType](const ParameterInfo &pi) { return pi.objectType == objectType && pi.objectSubtype == std::string(objectSubtype) && pi.parameterName == std::string(parameterName) @@ -566,19 +565,33 @@ const void* Device::getParameterInfo(ANARIDataType objectType, write(MessageType::GetParameterInfo, buf); std::unique_lock l(syncParameterInfo.mtx); - syncParameterInfo.cv.wait(l, [this, &it, objectType, objectSubtype, parameterName, parameterType, infoName, infoType]() { - it = std::find_if(parameterInfos.begin(), - parameterInfos.end(), - [&it, objectType, objectSubtype, parameterName, parameterType, infoName, infoType](const ParameterInfo &pi) { - return pi.objectType == objectType - && pi.objectSubtype == std::string(objectSubtype) - && pi.parameterName == std::string(parameterName) - && pi.parameterType == parameterType - && pi.info.name == std::string(infoName) - && pi.info.type == infoType; + syncParameterInfo.cv.wait(l, + [this, + &it, + objectType, + objectSubtype, + parameterName, + parameterType, + infoName, + infoType]() { + it = std::find_if(parameterInfos.begin(), + parameterInfos.end(), + [&it, + objectType, + objectSubtype, + parameterName, + parameterType, + infoName, + infoType](const ParameterInfo &pi) { + return pi.objectType == objectType + && pi.objectSubtype == std::string(objectSubtype) + && pi.parameterName == std::string(parameterName) + && pi.parameterType == parameterType + && pi.info.name == std::string(infoName) + && pi.info.type == infoType; + }); + return it != parameterInfos.end(); }); - return it != parameterInfos.end(); - }); return it->info.data(); } @@ -717,8 +730,8 @@ Device::Device(std::string subtype) : manager(async::make_connection_manager()) char *serverHostName = getenv("ANARI_REMOTE_SERVER_HOSTNAME"); if (serverHostName) { server.hostname = std::string(serverHostName); - LOG(logging::Level::Info) << "Server hostname specified via environment: " - << server.hostname; + LOG(logging::Level::Info) + << "Server hostname specified via environment: " << server.hostname; } char *serverPort = getenv("ANARI_REMOTE_SERVER_PORT"); @@ -726,11 +739,11 @@ Device::Device(std::string subtype) : manager(async::make_connection_manager()) int p = std::stoi(serverPort); if (p >= 0 && p <= USHRT_MAX) { server.port = (unsigned short)p; - LOG(logging::Level::Info) << "Server port specified via environment: " - << server.port; + LOG(logging::Level::Info) + << "Server port specified via environment: " << server.port; } else { LOG(logging::Level::Warning) - << "Server port specified via environment but ill-formed: " << p; + << "Server port specified via environment but ill-formed: " << p; } } @@ -810,11 +823,7 @@ ANARIArray Device::registerNewArray(ANARIDataType type, buf->write((const char *)&numItems2, sizeof(numItems2)); buf->write((const char *)&numItems3, sizeof(numItems3)); - ArrayInfo info(type, - elementType, - numItems1, - numItems2, - numItems3); + ArrayInfo info(type, elementType, numItems1, numItems2, numItems3); if (appMemory) buf->write((const char *)appMemory, info.getSizeInBytes()); @@ -846,8 +855,8 @@ void Device::initClient() buf->write((const char *)&remoteSubtypeLength, sizeof(remoteSubtypeLength)); buf->write(remoteSubtype.c_str(), remoteSubtype.length()); buf->write((const char *)&cf, sizeof(cf)); - //write(MessageType::NewDevice, buf); - // post to queue directly: write() would call initClient() recursively! + // write(MessageType::NewDevice, buf); + // post to queue directly: write() would call initClient() recursively! queue.post(std::bind(&Device::writeImpl, this, MessageType::NewDevice, buf)); // block till device ID was returned by remote @@ -861,8 +870,12 @@ void Device::connect(std::string host, unsigned short port) LOG(logging::Level::Info) << "ANARIDevice client connecting, host " << host << ", port " << port; - manager->connect( - host, port, std::bind(&Device::handleNewConnection, this, std::placeholders::_1, std::placeholders::_2)); + manager->connect(host, + port, + std::bind(&Device::handleNewConnection, + this, + std::placeholders::_1, + std::placeholders::_2)); } void Device::run() @@ -904,7 +917,11 @@ bool Device::handleNewConnection( // Accept and save this connection // and set the messange handler of the connection conn = new_conn; - conn->set_handler(std::bind(&Device::handleMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + conn->set_handler(std::bind(&Device::handleMessage, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3)); // Notify main thread about the connection established syncConnectionEstablished.cv.notify_all(); @@ -937,9 +954,10 @@ void Device::handleMessage(async::connection::reason reason, l.unlock(); syncDeviceHandleRemote.cv.notify_all(); LOG(logging::Level::Info) << "Got remote device handle: " << remoteDevice; - LOG(logging::Level::Info) << "Server has TurboJPEG: " - << server.compression.hasTurboJPEG; - LOG(logging::Level::Info) << "Server has SNAPPY: " << server.compression.hasSNAPPY; + LOG(logging::Level::Info) + << "Server has TurboJPEG: " << server.compression.hasTurboJPEG; + LOG(logging::Level::Info) + << "Server has SNAPPY: " << server.compression.hasSNAPPY; } else if (message->type() == MessageType::ArrayMapped) { std::unique_lock l(syncMapArray.mtx); @@ -1225,9 +1243,11 @@ void Device::handleMessage(async::connection::reason reason, if (message->type() == MessageType::ChannelColor) { frm.resizeColor(width, height, type); - bool compressionTurboJPEG = cf.hasTurboJPEG && server.compression.hasTurboJPEG; + bool compressionTurboJPEG = + cf.hasTurboJPEG && server.compression.hasTurboJPEG; - if (compressionTurboJPEG && type == ANARI_UFIXED8_RGBA_SRGB) { // TODO: more formats.. + if (compressionTurboJPEG + && type == ANARI_UFIXED8_RGBA_SRGB) { // TODO: more formats.. uint32_t jpegSize = *(uint32_t *)(message->data() + off); off += sizeof(jpegSize); diff --git a/libs/remote_device/Device.h b/libs/remote_device/Device.h index c2c8d62d..c643f64a 100644 --- a/libs/remote_device/Device.h +++ b/libs/remote_device/Device.h @@ -3,19 +3,19 @@ #pragma once -#include "Buffer.h" -#include "async/connection.h" -#include "async/connection_manager.h" -#include "async/work_queue.h" #include -#include "utility/IntrusivePtr.h" -#include "utility/ParameterizedObject.h" #include #include #include #include -#include "Frame.h" +#include "Buffer.h" #include "Compression.h" +#include "Frame.h" +#include "async/connection.h" +#include "async/connection_manager.h" +#include "async/work_queue.h" +#include "utility/IntrusivePtr.h" +#include "utility/ParameterizedObject.h" namespace remote { @@ -23,26 +23,25 @@ struct Device : anari::DeviceImpl, helium::ParameterizedObject { //--- Data Arrays --------------------------------- - void* mapParameterArray1D(ANARIObject o, - const char* name, + void *mapParameterArray1D(ANARIObject o, + const char *name, ANARIDataType dataType, uint64_t numElements1, uint64_t *elementStride) override; - void* mapParameterArray2D(ANARIObject o, - const char* name, + void *mapParameterArray2D(ANARIObject o, + const char *name, ANARIDataType dataType, uint64_t numElements1, uint64_t numElements2, uint64_t *elementStride) override; - void* mapParameterArray3D(ANARIObject o, - const char* name, + void *mapParameterArray3D(ANARIObject o, + const char *name, ANARIDataType dataType, uint64_t numElements1, uint64_t numElements2, uint64_t numElements3, uint64_t *elementStride) override; - void unmapParameterArray(ANARIObject o, - const char* name) override; + void unmapParameterArray(ANARIObject o, const char *name) override; ANARIArray1D newArray1D(const void *appMemory, ANARIMemoryDeleter deleter, @@ -125,16 +124,16 @@ struct Device : anari::DeviceImpl, helium::ParameterizedObject uint64_t size, ANARIWaitMask mask) override; - const char ** getObjectSubtypes(ANARIDataType objectType) override; - const void* getObjectInfo(ANARIDataType objectType, - const char* objectSubtype, - const char* infoName, + const char **getObjectSubtypes(ANARIDataType objectType) override; + const void *getObjectInfo(ANARIDataType objectType, + const char *objectSubtype, + const char *infoName, ANARIDataType infoType) override; - const void* getParameterInfo(ANARIDataType objectType, - const char* objectSubtype, - const char* parameterName, + const void *getParameterInfo(ANARIDataType objectType, + const char *objectSubtype, + const char *parameterName, ANARIDataType parameterType, - const char* infoName, + const char *infoName, ANARIDataType infoType) override; //--- FrameBuffer Manipulation -------------------- @@ -167,7 +166,8 @@ struct Device : anari::DeviceImpl, helium::ParameterizedObject void initClient(); uint64_t nextObjectID = 1; - struct { + struct + { std::string hostname = "localhost"; unsigned short port{31050}; CompressionFeatures compression; @@ -281,7 +281,8 @@ struct Device : anari::DeviceImpl, helium::ParameterizedObject std::vector asParameterList; std::vector asOther; - const void *data() const { + const void *data() const + { if (type == ANARI_STRING) return asString.data(); else if (type == ANARI_STRING_LIST) @@ -328,11 +329,11 @@ struct Device : anari::DeviceImpl, helium::ParameterizedObject { ANARIObject object{nullptr}; const char *name = ""; - bool operator<(const ParameterArray &other) const { - return object && object == other.object - && strlen(name) > 0 - && std::string(name) < std::string(other.name); - } + bool operator<(const ParameterArray &other) const + { + return object && object == other.object && strlen(name) > 0 + && std::string(name) < std::string(other.name); + } }; std::map parameterArrays; diff --git a/libs/remote_device/Server.cpp b/libs/remote_device/Server.cpp index b1276e62..cf3b5712 100644 --- a/libs/remote_device/Server.cpp +++ b/libs/remote_device/Server.cpp @@ -91,12 +91,8 @@ static ANARIArray newArray( { ANARIArray array = nullptr; if (info.type == ANARI_ARRAY1D) { - array = anariNewArray1D(dev, - nullptr, - nullptr, - nullptr, - info.elementType, - info.numItems1); + array = anariNewArray1D( + dev, nullptr, nullptr, nullptr, info.elementType, info.numItems1); } else if (info.type == ANARI_ARRAY2D) { array = anariNewArray2D(dev, nullptr, @@ -216,7 +212,8 @@ struct ResourceManager struct Server { // For now only one client: - struct { + struct + { CompressionFeatures compression; } client; @@ -242,7 +239,10 @@ struct Server { LOG(logging::Level::Info) << "Server: accepting..."; - manager->accept(std::bind(&Server::handleNewConnection, this, std::placeholders::_1, std::placeholders::_2)); + manager->accept(std::bind(&Server::handleNewConnection, + this, + std::placeholders::_1, + std::placeholders::_2)); } void run() @@ -266,18 +266,17 @@ struct Server conn->write(type, *buf); } - std::vector translateArrayData(Buffer &buf, ANARIDevice dev, ArrayInfo info) + std::vector translateArrayData( + Buffer &buf, ANARIDevice dev, ArrayInfo info) { std::vector arrayData(info.getSizeInBytes()); buf.read((char *)arrayData.data(), arrayData.size()); // Translate remote to device handles if (anari::isObject(info.elementType)) { - const auto &serverObjects = - resourceManager.serverObjects[(uint64_t)dev]; + const auto &serverObjects = resourceManager.serverObjects[(uint64_t)dev]; - size_t numObjects = info.numItems1 - * std::max(uint64_t(1), info.numItems2) + size_t numObjects = info.numItems1 * std::max(uint64_t(1), info.numItems2) * std::max(uint64_t(1), info.numItems3); // This only works b/c sizeof(ANARIObject)==sizeof(uint64_t)! @@ -307,7 +306,11 @@ struct Server // Accept and save this connection // and set the message handler of the connection conn = new_conn; - conn->set_handler(std::bind(&Server::handleMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + conn->set_handler(std::bind(&Server::handleMessage, + this, + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3)); // Accept new connections (TODO: the new connection // will overwrite the current one, so, store these @@ -357,10 +360,10 @@ struct Server LOG(logging::Level::Info) << "Creating new device, type: " << deviceType << ", device ID: " << deviceHandle << ", ANARI handle: " << dev; - LOG(logging::Level::Info) << "Client has TurboJPEG: " - << client.compression.hasTurboJPEG; - LOG(logging::Level::Info) << "Client has SNAPPY: " - << client.compression.hasSNAPPY; + LOG(logging::Level::Info) + << "Client has TurboJPEG: " << client.compression.hasTurboJPEG; + LOG(logging::Level::Info) + << "Client has SNAPPY: " << client.compression.hasSNAPPY; } else if (message->type() == MessageType::NewObject) { LOG(logging::Level::Info) << "Message: NewObject, message size: " << prettyBytes(message->size()); @@ -689,7 +692,8 @@ struct Server void *ptr = anariMapArray(dev, (ANARIArray)serverObj.handle); - const ArrayInfo &info = resourceManager.getArrayInfo(deviceHandle, objectHandle); + const ArrayInfo &info = + resourceManager.getArrayInfo(deviceHandle, objectHandle); uint64_t numBytes = info.getSizeInBytes(); @@ -699,8 +703,7 @@ struct Server outbuf->write((const char *)ptr, numBytes); write(MessageType::ArrayMapped, outbuf); - LOG(logging::Level::Info) - << "Mapped array. Handle: " << objectHandle; + LOG(logging::Level::Info) << "Mapped array. Handle: " << objectHandle; } else if (message->type() == MessageType::UnmapArray) { LOG(logging::Level::Info) << "Message: UnmapArray, message size: " << prettyBytes(message->size()); @@ -734,7 +737,8 @@ struct Server // Fetch data into separate buffer and copy std::vector arrayData; if (buf.pos < message->size()) { - ArrayInfo info = resourceManager.getArrayInfo(deviceHandle, objectHandle); + ArrayInfo info = + resourceManager.getArrayInfo(deviceHandle, objectHandle); arrayData = translateArrayData(buf, (ANARIDevice)deviceHandle, info); memcpy(ptr, arrayData.data(), arrayData.size()); } @@ -746,8 +750,7 @@ struct Server outbuf->write((const char *)&objectHandle, sizeof(objectHandle)); write(MessageType::ArrayUnmapped, outbuf); - LOG(logging::Level::Info) - << "Unmapped array. Handle: " << objectHandle; + LOG(logging::Level::Info) << "Unmapped array. Handle: " << objectHandle; } else if (message->type() == MessageType::RenderFrame) { LOG(logging::Level::Info) << "Message: RenderFrame, message size: " << prettyBytes(message->size()); @@ -792,9 +795,11 @@ struct Server outbuf->write((const char *)&height, sizeof(height)); outbuf->write((const char *)&type, sizeof(type)); - bool compressionTurboJPEG = cf.hasTurboJPEG && client.compression.hasTurboJPEG; + bool compressionTurboJPEG = + cf.hasTurboJPEG && client.compression.hasTurboJPEG; - if (compressionTurboJPEG && type == ANARI_UFIXED8_RGBA_SRGB) { // TODO: more formats.. + if (compressionTurboJPEG + && type == ANARI_UFIXED8_RGBA_SRGB) { // TODO: more formats.. TurboJPEGOptions options; options.width = width; options.height = height; @@ -996,8 +1001,9 @@ struct Server } write(MessageType::Property, outbuf); } else if (message->type() == MessageType::GetObjectSubtypes) { - LOG(logging::Level::Info) << "Message: GetObjectSubtypes, message size: " - << prettyBytes(message->size()); + LOG(logging::Level::Info) + << "Message: GetObjectSubtypes, message size: " + << prettyBytes(message->size()); Buffer buf; buf.write(message->data(), message->size()); @@ -1070,16 +1076,16 @@ struct Server auto outbuf = std::make_shared(); outbuf->write((const char *)&objectType, sizeof(objectType)); - len = objectSubtype.size()-1; + len = objectSubtype.size() - 1; outbuf->write((const char *)&len, sizeof(len)); outbuf->write(objectSubtype.data(), len); - len = infoName.size()-1; + len = infoName.size() - 1; outbuf->write((const char *)&len, sizeof(len)); outbuf->write(infoName.data(), len); outbuf->write((const char *)&infoType, sizeof(infoType)); - const void *info = anariGetObjectInfo(dev, objectType, objectSubtype.data(), - infoName.data(), infoType); + const void *info = anariGetObjectInfo( + dev, objectType, objectSubtype.data(), infoName.data(), infoType); if (info != nullptr) { if (infoType == ANARI_STRING) { @@ -1100,14 +1106,15 @@ struct Server uint64_t len = strlen(parameter->name); outbuf->write((const char *)&len, sizeof(len)); outbuf->write(parameter->name, len); - outbuf->write((const char *)¶meter->type, sizeof(parameter->type)); + outbuf->write( + (const char *)¶meter->type, sizeof(parameter->type)); } } else { outbuf->write((const char *)info, anari::sizeOf(infoType)); } } write(MessageType::ObjectInfo, outbuf); - } else if (message->type() == MessageType::GetParameterInfo) { + } else if (message->type() == MessageType::GetParameterInfo) { LOG(logging::Level::Info) << "Message: GetParameterInfo, message size: " << prettyBytes(message->size()); @@ -1154,20 +1161,25 @@ struct Server auto outbuf = std::make_shared(); outbuf->write((const char *)&objectType, sizeof(objectType)); - len = objectSubtype.size()-1; + len = objectSubtype.size() - 1; outbuf->write((const char *)&len, sizeof(len)); outbuf->write(objectSubtype.data(), len); - len = parameterName.size()-1; + len = parameterName.size() - 1; outbuf->write((const char *)&len, sizeof(len)); outbuf->write(parameterName.data(), len); outbuf->write((const char *)¶meterType, sizeof(parameterType)); - len = infoName.size()-1; + len = infoName.size() - 1; outbuf->write((const char *)&len, sizeof(len)); outbuf->write(infoName.data(), len); outbuf->write((const char *)&infoType, sizeof(infoType)); - const void *info = anariGetParameterInfo(dev, objectType, objectSubtype.data(), - parameterName.data(), parameterType, infoName.data(), infoType); + const void *info = anariGetParameterInfo(dev, + objectType, + objectSubtype.data(), + parameterName.data(), + parameterType, + infoName.data(), + infoType); if (info != nullptr) { if (infoType == ANARI_STRING) { @@ -1188,7 +1200,8 @@ struct Server uint64_t len = strlen(parameter->name); outbuf->write((const char *)&len, sizeof(len)); outbuf->write(parameter->name, len); - outbuf->write((const char *)¶meter->type, sizeof(parameter->type)); + outbuf->write( + (const char *)¶meter->type, sizeof(parameter->type)); } } else { outbuf->write((const char *)info, anari::sizeOf(infoType)); From d1e9a0a28e9694eaee4860f4a4249f351f59246a Mon Sep 17 00:00:00 2001 From: Stefan Zellmann Date: Wed, 27 Sep 2023 02:23:27 +0200 Subject: [PATCH 09/34] README update: remote server app's name has changed --- libs/remote_device/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/remote_device/README.md b/libs/remote_device/README.md index dce1c4de..4c10d746 100644 --- a/libs/remote_device/README.md +++ b/libs/remote_device/README.md @@ -1,7 +1,7 @@ # The Remote Device -The remote device and `anari-remote-server` application establish a TCP -connection. On the server side the `anari-remote-server` application connects +The remote device and `anariRemoteServer` application establish a TCP +connection. On the server side the `anariRemoteServer` application connects to an arbitrary ANARI device. ANARI commands from the client pass through the TCP connection; the server forwards the commands to the server-side device. Color and depth images are sent from the server to the client. These color and @@ -10,11 +10,11 @@ client and server implement TCP passthrough and remote rendering. ## Usage -On the server, run the `anari-remote-server` application with a ANARI library +On the server, run the `anariRemoteServer` application with a ANARI library configured; the server will listen for incoming connections, e.g.: ``` -ANARI_LIBRARY=helide anari-remote-server +ANARI_LIBRARY=helide anariRemoteServer ``` the server will wait for any incoming TCP connections. From 3d1581d0cfb84ed06d158877f4976a5cfd0e39c4 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Wed, 27 Sep 2023 16:11:42 -0500 Subject: [PATCH 10/34] implement prim/obj/inst ID frame channels in helide --- examples/simple/anariTutorial.cpp | 34 + libs/helide/HelideDeviceQueries.cpp | 1037 +++++++++++++++---------- libs/helide/HelideDeviceQueries.h | 2 +- libs/helide/frame/Frame.cpp | 48 +- libs/helide/frame/Frame.h | 9 +- libs/helide/helide_device.json | 3 + libs/helide/helide_math.h | 1 + libs/helide/renderer/Renderer.cpp | 23 +- libs/helide/renderer/Renderer.h | 3 + libs/helide/scene/Instance.cpp | 6 + libs/helide/scene/Instance.h | 3 + libs/helide/scene/World.cpp | 11 +- libs/helide/scene/World.h | 22 + libs/helide/scene/surface/Surface.cpp | 1 + libs/helide/scene/surface/Surface.h | 7 + libs/helide/scene/volume/Volume.cpp | 5 + libs/helide/scene/volume/Volume.h | 15 + 17 files changed, 802 insertions(+), 428 deletions(-) diff --git a/examples/simple/anariTutorial.cpp b/examples/simple/anariTutorial.cpp index e71889ac..656700a5 100644 --- a/examples/simple/anariTutorial.cpp +++ b/examples/simple/anariTutorial.cpp @@ -46,6 +46,12 @@ void statusFunc(const void *userData, } } +template +static T getPixelValue(uvec2 coord, int width, const T *buf) +{ + return buf[coord[1] * width + coord[0]]; +} + int main(int argc, const char **argv) { (void)argc; @@ -120,10 +126,12 @@ int main(int argc, const char **argv) auto surface = anari::newObject(d); anari::setAndReleaseParameter(d, surface, "geometry", mesh); anari::setAndReleaseParameter(d, surface, "material", mat); + anari::setParameter(d, surface, "id", 2u); anari::commitParameters(d, surface); // put the surface directly onto the world anari::setParameterArray1D(d, world, "surface", &surface, 1); + anari::setParameter(d, world, "id", 3u); anari::release(d, surface); anari::commitParameters(d, world); @@ -159,6 +167,9 @@ int main(int argc, const char **argv) auto frame = anari::newObject(d); anari::setParameter(d, frame, "size", imgSize); anari::setParameter(d, frame, "channel.color", ANARI_UFIXED8_RGBA_SRGB); + anari::setParameter(d, frame, "channel.primitiveId", ANARI_UINT32); + anari::setParameter(d, frame, "channel.objectId", ANARI_UINT32); + anari::setParameter(d, frame, "channel.instanceId", ANARI_UINT32); anari::setAndReleaseParameter(d, frame, "renderer", renderer); anari::setAndReleaseParameter(d, frame, "camera", camera); @@ -183,6 +194,29 @@ int main(int argc, const char **argv) anari::unmap(d, frame, "channel.color"); printf("done!\n"); + + // Check center pixel id buffers + auto fbPrimId = anari::map(d, frame, "channel.primitiveId"); + auto fbObjId = anari::map(d, frame, "channel.objectId"); + auto fbInstId = anari::map(d, frame, "channel.instanceId"); + + uvec2 queryPixel = {imgSize[0] / 2, imgSize[1] / 2}; + + printf("checking id buffers @ [%u, %u]:\n", queryPixel[0], queryPixel[1]); + + if (fbPrimId.pixelType == ANARI_UINT32) { + printf(" primId: %u\n", + getPixelValue(queryPixel, imgSize[0], fbPrimId.data)); + } + if (fbObjId.pixelType == ANARI_UINT32) { + printf(" objId: %u\n", + getPixelValue(queryPixel, imgSize[0], fbObjId.data)); + } + if (fbPrimId.pixelType == ANARI_UINT32) { + printf(" instId: %u\n", + getPixelValue(queryPixel, imgSize[0], fbInstId.data)); + } + printf("\ncleaning up objects..."); // final cleanups diff --git a/libs/helide/HelideDeviceQueries.cpp b/libs/helide/HelideDeviceQueries.cpp index bb774f69..0b6461cd 100644 --- a/libs/helide/HelideDeviceQueries.cpp +++ b/libs/helide/HelideDeviceQueries.cpp @@ -9,8 +9,8 @@ #include namespace helide { static int subtype_hash(const char *str) { - static const uint32_t table[] = {0x7a6f0012u,0x6665002bu,0x0u,0x0u,0x0u,0x0u,0x6e6d0032u,0x0u,0x0u,0x0u,0x6261003fu,0x0u,0x73720044u,0x73650050u,0x76750070u,0x0u,0x75700074u,0x7372008eu,0x6f6e001du,0x0u,0x0u,0x0u,0x0u,0x0u,0x73720020u,0x0u,0x0u,0x0u,0x6d6c0024u,0x6665001eu,0x100001fu,0x80000000u,0x77760021u,0x66650022u,0x1000023u,0x80000001u,0x6a690025u,0x6f6e0026u,0x65640027u,0x66650028u,0x73720029u,0x100002au,0x80000002u,0x6766002cu,0x6261002du,0x7675002eu,0x6d6c002fu,0x75740030u,0x1000031u,0x80000003u,0x62610033u,0x68670034u,0x66650035u,0x34310036u,0x45440039u,0x4544003bu,0x4544003du,0x100003au,0x80000004u,0x100003cu,0x80000005u,0x100003eu,0x80000006u,0x75740040u,0x75740041u,0x66650042u,0x1000043u,0x80000007u,0x75740045u,0x69680046u,0x706f0047u,0x68670048u,0x73720049u,0x6261004au,0x7170004bu,0x6968004cu,0x6a69004du,0x6463004eu,0x100004fu,0x80000008u,0x7372005eu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6a690068u,0x7473005fu,0x71700060u,0x66650061u,0x64630062u,0x75740063u,0x6a690064u,0x77760065u,0x66650066u,0x1000067u,0x80000009u,0x6e6d0069u,0x6a69006au,0x7574006bu,0x6a69006cu,0x7776006du,0x6665006eu,0x100006fu,0x8000000au,0x62610071u,0x65640072u,0x1000073u,0x8000000bu,0x69680079u,0x0u,0x0u,0x0u,0x7372007eu,0x6665007au,0x7372007bu,0x6665007cu,0x100007du,0x8000000cu,0x7675007fu,0x64630080u,0x75740081u,0x76750082u,0x73720083u,0x66650084u,0x65640085u,0x53520086u,0x66650087u,0x68670088u,0x76750089u,0x6d6c008au,0x6261008bu,0x7372008cu,0x100008du,0x8000000du,0x6a61008fu,0x6f6e0098u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x626100b5u,0x74730099u,0x6766009au,0x7065009bu,0x737200a6u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x737200b2u,0x474600a7u,0x767500a8u,0x6f6e00a9u,0x646300aau,0x757400abu,0x6a6900acu,0x706f00adu,0x6f6e00aeu,0x323100afu,0x454400b0u,0x10000b1u,0x8000000eu,0x6e6d00b3u,0x10000b4u,0x8000000fu,0x6f6e00b6u,0x686700b7u,0x6d6c00b8u,0x666500b9u,0x10000bau,0x80000010u}; - uint32_t cur = 0x75630000u; + static const uint32_t table[] = {0x80000000u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x7a6f0075u,0x6665008eu,0x0u,0x0u,0x0u,0x0u,0x6e6d0095u,0x0u,0x0u,0x0u,0x626100a2u,0x0u,0x737200a7u,0x736500b3u,0x767500d3u,0x0u,0x757000d7u,0x737200f1u,0x6f6e0080u,0x0u,0x0u,0x0u,0x0u,0x0u,0x73720083u,0x0u,0x0u,0x0u,0x6d6c0087u,0x66650081u,0x1000082u,0x80000001u,0x77760084u,0x66650085u,0x1000086u,0x80000002u,0x6a690088u,0x6f6e0089u,0x6564008au,0x6665008bu,0x7372008cu,0x100008du,0x80000003u,0x6766008fu,0x62610090u,0x76750091u,0x6d6c0092u,0x75740093u,0x1000094u,0x80000004u,0x62610096u,0x68670097u,0x66650098u,0x34310099u,0x4544009cu,0x4544009eu,0x454400a0u,0x100009du,0x80000005u,0x100009fu,0x80000006u,0x10000a1u,0x80000007u,0x757400a3u,0x757400a4u,0x666500a5u,0x10000a6u,0x80000008u,0x757400a8u,0x696800a9u,0x706f00aau,0x686700abu,0x737200acu,0x626100adu,0x717000aeu,0x696800afu,0x6a6900b0u,0x646300b1u,0x10000b2u,0x80000009u,0x737200c1u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6a6900cbu,0x747300c2u,0x717000c3u,0x666500c4u,0x646300c5u,0x757400c6u,0x6a6900c7u,0x777600c8u,0x666500c9u,0x10000cau,0x8000000au,0x6e6d00ccu,0x6a6900cdu,0x757400ceu,0x6a6900cfu,0x777600d0u,0x666500d1u,0x10000d2u,0x8000000bu,0x626100d4u,0x656400d5u,0x10000d6u,0x8000000cu,0x696800dcu,0x0u,0x0u,0x0u,0x737200e1u,0x666500ddu,0x737200deu,0x666500dfu,0x10000e0u,0x8000000du,0x767500e2u,0x646300e3u,0x757400e4u,0x767500e5u,0x737200e6u,0x666500e7u,0x656400e8u,0x535200e9u,0x666500eau,0x686700ebu,0x767500ecu,0x6d6c00edu,0x626100eeu,0x737200efu,0x10000f0u,0x8000000eu,0x6a6100f2u,0x6f6e00fbu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x62610118u,0x747300fcu,0x676600fdu,0x706500feu,0x73720109u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x73720115u,0x4746010au,0x7675010bu,0x6f6e010cu,0x6463010du,0x7574010eu,0x6a69010fu,0x706f0110u,0x6f6e0111u,0x32310112u,0x45440113u,0x1000114u,0x8000000fu,0x6e6d0116u,0x1000117u,0x80000010u,0x6f6e0119u,0x6867011au,0x6d6c011bu,0x6665011cu,0x100011du,0x80000011u}; + uint32_t cur = 0x75000000u; for(int i = 0;cur!=0;++i) { uint32_t idx = cur&0xFFFFu; uint32_t low = (cur>>16u)&0xFFu; @@ -31,7 +31,7 @@ static int subtype_hash(const char *str) { return -1; } static int param_hash(const char *str) { - static const uint32_t table[] = {0x746c0017u,0x62610065u,0x7061006fu,0x6a61009eu,0x0u,0x706100b2u,0x736500cbu,0x666500e4u,0x6f6d00eau,0x0u,0x0u,0x6a6901aeu,0x706101b3u,0x666101ccu,0x767001d7u,0x736f01feu,0x0u,0x6661024eu,0x7669025fu,0x737202e5u,0x716e02eeu,0x706102fdu,0x736f03c5u,0x716c001fu,0x6362004eu,0x0u,0x0u,0x0u,0x0u,0x7372005cu,0x71700060u,0x706f0024u,0x0u,0x0u,0x0u,0x69680037u,0x78770025u,0x4a490026u,0x6f6e0027u,0x77760028u,0x62610029u,0x6d6c002au,0x6a69002bu,0x6564002cu,0x4e4d002du,0x6261002eu,0x7574002fu,0x66650030u,0x73720031u,0x6a690032u,0x62610033u,0x6d6c0034u,0x74730035u,0x1000036u,0x80000000u,0x62610038u,0x4e430039u,0x76750044u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x706f004au,0x75740045u,0x706f0046u,0x67660047u,0x67660048u,0x1000049u,0x80000001u,0x6564004bu,0x6665004cu,0x100004du,0x80000002u,0x6a69004fu,0x66650050u,0x6f6e0051u,0x75740052u,0x53520053u,0x62610054u,0x65640055u,0x6a690056u,0x62610057u,0x6f6e0058u,0x64630059u,0x6665005au,0x100005bu,0x80000003u,0x6261005du,0x7a79005eu,0x100005fu,0x80000004u,0x66650061u,0x64630062u,0x75740063u,0x1000064u,0x80000005u,0x64630066u,0x6c6b0067u,0x68670068u,0x73720069u,0x706f006au,0x7675006bu,0x6f6e006cu,0x6564006du,0x100006eu,0x80000006u,0x716d007eu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x62610088u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6d6c009au,0x66650082u,0x0u,0x0u,0x74730086u,0x73720083u,0x62610084u,0x1000085u,0x80000007u,0x1000087u,0x80000008u,0x6f6e0089u,0x6f6e008au,0x6665008bu,0x6d6c008cu,0x2f2e008du,0x6563008eu,0x706f0090u,0x66650095u,0x6d6c0091u,0x706f0092u,0x73720093u,0x1000094u,0x80000009u,0x71700096u,0x75740097u,0x69680098u,0x1000099u,0x8000000au,0x706f009bu,0x7372009cu,0x100009du,0x8000000bu,0x757400a7u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x737200aau,0x626100a8u,0x10000a9u,0x8000000cu,0x666500abu,0x646300acu,0x757400adu,0x6a6900aeu,0x706f00afu,0x6f6e00b0u,0x10000b1u,0x8000000du,0x737200c1u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6d6c00c3u,0x0u,0x0u,0x0u,0x0u,0x0u,0x777600c8u,0x10000c2u,0x8000000eu,0x757400c4u,0x666500c5u,0x737200c6u,0x10000c7u,0x8000000fu,0x7a7900c9u,0x10000cau,0x80000010u,0x706f00d9u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x706f00e0u,0x6e6d00dau,0x666500dbu,0x757400dcu,0x737200ddu,0x7a7900deu,0x10000dfu,0x80000011u,0x767500e1u,0x717000e2u,0x10000e3u,0x80000012u,0x6a6900e5u,0x686700e6u,0x696800e7u,0x757400e8u,0x10000e9u,0x80000013u,0x626100ecu,0x77410148u,0x686700edu,0x666500eeu,0x530000efu,0x80000014u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x66650142u,0x68670143u,0x6a690144u,0x706f0145u,0x6f6e0146u,0x1000147u,0x80000015u,0x7574017eu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x67660187u,0x0u,0x0u,0x0u,0x0u,0x7372018du,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x75740196u,0x0u,0x0u,0x6261019cu,0x7574017fu,0x73720180u,0x6a690181u,0x63620182u,0x76750183u,0x75740184u,0x66650185u,0x1000186u,0x80000016u,0x67660188u,0x74730189u,0x6665018au,0x7574018bu,0x100018cu,0x80000017u,0x6261018eu,0x6f6e018fu,0x74730190u,0x67660191u,0x706f0192u,0x73720193u,0x6e6d0194u,0x1000195u,0x80000018u,0x62610197u,0x6f6e0198u,0x64630199u,0x6665019au,0x100019bu,0x80000019u,0x6d6c019du,0x6a69019eu,0x6564019fu,0x4e4d01a0u,0x626101a1u,0x757401a2u,0x666501a3u,0x737201a4u,0x6a6901a5u,0x626101a6u,0x6d6c01a7u,0x444301a8u,0x706f01a9u,0x6d6c01aau,0x706f01abu,0x737201acu,0x10001adu,0x8000001au,0x686701afu,0x696801b0u,0x757401b1u,0x10001b2u,0x8000001bu,0x757401c2u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x656401c9u,0x666501c3u,0x737201c4u,0x6a6901c5u,0x626101c6u,0x6d6c01c7u,0x10001c8u,0x8000001cu,0x666501cau,0x10001cbu,0x8000001du,0x6e6d01d1u,0x0u,0x0u,0x0u,0x626101d4u,0x666501d2u,0x10001d3u,0x8000001eu,0x737201d5u,0x10001d6u,0x8000001fu,0x626101ddu,0x0u,0x6a6901e3u,0x0u,0x0u,0x757401e8u,0x646301deu,0x6a6901dfu,0x757401e0u,0x7a7901e1u,0x10001e2u,0x80000020u,0x686701e4u,0x6a6901e5u,0x6f6e01e6u,0x10001e7u,0x80000021u,0x554f01e9u,0x676601efu,0x0u,0x0u,0x0u,0x0u,0x737201f5u,0x676601f0u,0x747301f1u,0x666501f2u,0x757401f3u,0x10001f4u,0x80000022u,0x626101f6u,0x6f6e01f7u,0x747301f8u,0x676601f9u,0x706f01fau,0x737201fbu,0x6e6d01fcu,0x10001fdu,0x80000023u,0x74730202u,0x0u,0x0u,0x6a690209u,0x6a690203u,0x75740204u,0x6a690205u,0x706f0206u,0x6f6e0207u,0x1000208u,0x80000024u,0x6e6d020au,0x6a69020bu,0x7574020cu,0x6a69020du,0x7776020eu,0x6665020fu,0x2f2e0210u,0x73610211u,0x75740223u,0x0u,0x706f0233u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6f640238u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x62610248u,0x75740224u,0x73720225u,0x6a690226u,0x63620227u,0x76750228u,0x75740229u,0x6665022au,0x3430022bu,0x100022fu,0x1000230u,0x1000231u,0x1000232u,0x80000025u,0x80000026u,0x80000027u,0x80000028u,0x6d6c0234u,0x706f0235u,0x73720236u,0x1000237u,0x80000029u,0x1000243u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x65640244u,0x8000002au,0x66650245u,0x79780246u,0x1000247u,0x8000002bu,0x65640249u,0x6a69024au,0x7675024bu,0x7473024cu,0x100024du,0x8000002cu,0x65640253u,0x0u,0x0u,0x0u,0x6f6e0258u,0x6a690254u,0x76750255u,0x74730256u,0x1000257u,0x8000002du,0x65640259u,0x6665025au,0x7372025bu,0x6665025cu,0x7372025du,0x100025eu,0x8000002eu,0x7b7a026cu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6261026fu,0x0u,0x0u,0x0u,0x62610275u,0x737202dfu,0x6665026du,0x100026eu,0x8000002fu,0x64630270u,0x6a690271u,0x6f6e0272u,0x68670273u,0x1000274u,0x80000030u,0x75740276u,0x76750277u,0x74730278u,0x44430279u,0x6261027au,0x6d6c027bu,0x6d6c027cu,0x6362027du,0x6261027eu,0x6463027fu,0x6c6b0280u,0x56000281u,0x80000031u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x747302d7u,0x666502d8u,0x737202d9u,0x454402dau,0x626102dbu,0x757402dcu,0x626102ddu,0x10002deu,0x80000032u,0x676602e0u,0x626102e1u,0x646302e2u,0x666502e3u,0x10002e4u,0x80000033u,0x626102e6u,0x6f6e02e7u,0x747302e8u,0x676602e9u,0x706f02eau,0x737202ebu,0x6e6d02ecu,0x10002edu,0x80000034u,0x6a6902f1u,0x0u,0x10002fcu,0x757402f2u,0x454402f3u,0x6a6902f4u,0x747302f5u,0x757402f6u,0x626102f7u,0x6f6e02f8u,0x646302f9u,0x666502fau,0x10002fbu,0x80000035u,0x80000036u,0x6d6c030cu,0x0u,0x0u,0x0u,0x73720367u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6d6c03c0u,0x7675030du,0x6665030eu,0x5300030fu,0x80000037u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x62610362u,0x6f6e0363u,0x68670364u,0x66650365u,0x1000366u,0x80000038u,0x75740368u,0x66650369u,0x7978036au,0x2f2e036bu,0x7561036cu,0x75740380u,0x0u,0x70610390u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x706f03a5u,0x0u,0x706f03abu,0x0u,0x626103b3u,0x0u,0x626103b9u,0x75740381u,0x73720382u,0x6a690383u,0x63620384u,0x76750385u,0x75740386u,0x66650387u,0x34300388u,0x100038cu,0x100038du,0x100038eu,0x100038fu,0x80000039u,0x8000003au,0x8000003bu,0x8000003cu,0x7170039fu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6d6c03a1u,0x10003a0u,0x8000003du,0x706f03a2u,0x737203a3u,0x10003a4u,0x8000003eu,0x737203a6u,0x6e6d03a7u,0x626103a8u,0x6d6c03a9u,0x10003aau,0x8000003fu,0x747303acu,0x6a6903adu,0x757403aeu,0x6a6903afu,0x706f03b0u,0x6f6e03b1u,0x10003b2u,0x80000040u,0x656403b4u,0x6a6903b5u,0x767503b6u,0x747303b7u,0x10003b8u,0x80000041u,0x6f6e03bau,0x686703bbu,0x666503bcu,0x6f6e03bdu,0x757403beu,0x10003bfu,0x80000042u,0x767503c1u,0x6e6d03c2u,0x666503c3u,0x10003c4u,0x80000043u,0x737203c9u,0x0u,0x0u,0x626103cdu,0x6d6c03cau,0x656403cbu,0x10003ccu,0x80000044u,0x717003ceu,0x4e4d03cfu,0x706f03d0u,0x656403d1u,0x666503d2u,0x343103d3u,0x10003d6u,0x10003d7u,0x10003d8u,0x80000045u,0x80000046u,0x80000047u}; + static const uint32_t table[] = {0x746c0017u,0x62610065u,0x7061006fu,0x6a6100c7u,0x0u,0x706100dbu,0x736500f4u,0x6665010du,0x6f640113u,0x0u,0x0u,0x6a6901e1u,0x706101e6u,0x666101ffu,0x7670020au,0x736f0231u,0x0u,0x66610281u,0x76690292u,0x73720318u,0x716e0321u,0x70610330u,0x736f03f8u,0x716c001fu,0x6362004eu,0x0u,0x0u,0x0u,0x0u,0x7372005cu,0x71700060u,0x706f0024u,0x0u,0x0u,0x0u,0x69680037u,0x78770025u,0x4a490026u,0x6f6e0027u,0x77760028u,0x62610029u,0x6d6c002au,0x6a69002bu,0x6564002cu,0x4e4d002du,0x6261002eu,0x7574002fu,0x66650030u,0x73720031u,0x6a690032u,0x62610033u,0x6d6c0034u,0x74730035u,0x1000036u,0x80000000u,0x62610038u,0x4e430039u,0x76750044u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x706f004au,0x75740045u,0x706f0046u,0x67660047u,0x67660048u,0x1000049u,0x80000001u,0x6564004bu,0x6665004cu,0x100004du,0x80000002u,0x6a69004fu,0x66650050u,0x6f6e0051u,0x75740052u,0x53520053u,0x62610054u,0x65640055u,0x6a690056u,0x62610057u,0x6f6e0058u,0x64630059u,0x6665005au,0x100005bu,0x80000003u,0x6261005du,0x7a79005eu,0x100005fu,0x80000004u,0x66650061u,0x64630062u,0x75740063u,0x1000064u,0x80000005u,0x64630066u,0x6c6b0067u,0x68670068u,0x73720069u,0x706f006au,0x7675006bu,0x6f6e006cu,0x6564006du,0x100006eu,0x80000006u,0x716d007eu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x62610088u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6d6c00c3u,0x66650082u,0x0u,0x0u,0x74730086u,0x73720083u,0x62610084u,0x1000085u,0x80000007u,0x1000087u,0x80000008u,0x6f6e0089u,0x6f6e008au,0x6665008bu,0x6d6c008cu,0x2f2e008du,0x7163008eu,0x706f009cu,0x666500a1u,0x0u,0x0u,0x0u,0x0u,0x6f6e00a6u,0x0u,0x0u,0x0u,0x0u,0x0u,0x636200b0u,0x737200b8u,0x6d6c009du,0x706f009eu,0x7372009fu,0x10000a0u,0x80000009u,0x717000a2u,0x757400a3u,0x696800a4u,0x10000a5u,0x8000000au,0x747300a7u,0x757400a8u,0x626100a9u,0x6f6e00aau,0x646300abu,0x666500acu,0x4a4900adu,0x656400aeu,0x10000afu,0x8000000bu,0x6b6a00b1u,0x666500b2u,0x646300b3u,0x757400b4u,0x4a4900b5u,0x656400b6u,0x10000b7u,0x8000000cu,0x6a6900b9u,0x6e6d00bau,0x6a6900bbu,0x757400bcu,0x6a6900bdu,0x777600beu,0x666500bfu,0x4a4900c0u,0x656400c1u,0x10000c2u,0x8000000du,0x706f00c4u,0x737200c5u,0x10000c6u,0x8000000eu,0x757400d0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x737200d3u,0x626100d1u,0x10000d2u,0x8000000fu,0x666500d4u,0x646300d5u,0x757400d6u,0x6a6900d7u,0x706f00d8u,0x6f6e00d9u,0x10000dau,0x80000010u,0x737200eau,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6d6c00ecu,0x0u,0x0u,0x0u,0x0u,0x0u,0x777600f1u,0x10000ebu,0x80000011u,0x757400edu,0x666500eeu,0x737200efu,0x10000f0u,0x80000012u,0x7a7900f2u,0x10000f3u,0x80000013u,0x706f0102u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x706f0109u,0x6e6d0103u,0x66650104u,0x75740105u,0x73720106u,0x7a790107u,0x1000108u,0x80000014u,0x7675010au,0x7170010bu,0x100010cu,0x80000015u,0x6a69010eu,0x6867010fu,0x69680110u,0x75740111u,0x1000112u,0x80000016u,0x100011eu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6261011fu,0x7741017bu,0x80000017u,0x68670120u,0x66650121u,0x53000122u,0x80000018u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x66650175u,0x68670176u,0x6a690177u,0x706f0178u,0x6f6e0179u,0x100017au,0x80000019u,0x757401b1u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x676601bau,0x0u,0x0u,0x0u,0x0u,0x737201c0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x757401c9u,0x0u,0x0u,0x626101cfu,0x757401b2u,0x737201b3u,0x6a6901b4u,0x636201b5u,0x767501b6u,0x757401b7u,0x666501b8u,0x10001b9u,0x8000001au,0x676601bbu,0x747301bcu,0x666501bdu,0x757401beu,0x10001bfu,0x8000001bu,0x626101c1u,0x6f6e01c2u,0x747301c3u,0x676601c4u,0x706f01c5u,0x737201c6u,0x6e6d01c7u,0x10001c8u,0x8000001cu,0x626101cau,0x6f6e01cbu,0x646301ccu,0x666501cdu,0x10001ceu,0x8000001du,0x6d6c01d0u,0x6a6901d1u,0x656401d2u,0x4e4d01d3u,0x626101d4u,0x757401d5u,0x666501d6u,0x737201d7u,0x6a6901d8u,0x626101d9u,0x6d6c01dau,0x444301dbu,0x706f01dcu,0x6d6c01ddu,0x706f01deu,0x737201dfu,0x10001e0u,0x8000001eu,0x686701e2u,0x696801e3u,0x757401e4u,0x10001e5u,0x8000001fu,0x757401f5u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x656401fcu,0x666501f6u,0x737201f7u,0x6a6901f8u,0x626101f9u,0x6d6c01fau,0x10001fbu,0x80000020u,0x666501fdu,0x10001feu,0x80000021u,0x6e6d0204u,0x0u,0x0u,0x0u,0x62610207u,0x66650205u,0x1000206u,0x80000022u,0x73720208u,0x1000209u,0x80000023u,0x62610210u,0x0u,0x6a690216u,0x0u,0x0u,0x7574021bu,0x64630211u,0x6a690212u,0x75740213u,0x7a790214u,0x1000215u,0x80000024u,0x68670217u,0x6a690218u,0x6f6e0219u,0x100021au,0x80000025u,0x554f021cu,0x67660222u,0x0u,0x0u,0x0u,0x0u,0x73720228u,0x67660223u,0x74730224u,0x66650225u,0x75740226u,0x1000227u,0x80000026u,0x62610229u,0x6f6e022au,0x7473022bu,0x6766022cu,0x706f022du,0x7372022eu,0x6e6d022fu,0x1000230u,0x80000027u,0x74730235u,0x0u,0x0u,0x6a69023cu,0x6a690236u,0x75740237u,0x6a690238u,0x706f0239u,0x6f6e023au,0x100023bu,0x80000028u,0x6e6d023du,0x6a69023eu,0x7574023fu,0x6a690240u,0x77760241u,0x66650242u,0x2f2e0243u,0x73610244u,0x75740256u,0x0u,0x706f0266u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6f64026bu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6261027bu,0x75740257u,0x73720258u,0x6a690259u,0x6362025au,0x7675025bu,0x7574025cu,0x6665025du,0x3430025eu,0x1000262u,0x1000263u,0x1000264u,0x1000265u,0x80000029u,0x8000002au,0x8000002bu,0x8000002cu,0x6d6c0267u,0x706f0268u,0x73720269u,0x100026au,0x8000002du,0x1000276u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x65640277u,0x8000002eu,0x66650278u,0x79780279u,0x100027au,0x8000002fu,0x6564027cu,0x6a69027du,0x7675027eu,0x7473027fu,0x1000280u,0x80000030u,0x65640286u,0x0u,0x0u,0x0u,0x6f6e028bu,0x6a690287u,0x76750288u,0x74730289u,0x100028au,0x80000031u,0x6564028cu,0x6665028du,0x7372028eu,0x6665028fu,0x73720290u,0x1000291u,0x80000032u,0x7b7a029fu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x626102a2u,0x0u,0x0u,0x0u,0x626102a8u,0x73720312u,0x666502a0u,0x10002a1u,0x80000033u,0x646302a3u,0x6a6902a4u,0x6f6e02a5u,0x686702a6u,0x10002a7u,0x80000034u,0x757402a9u,0x767502aau,0x747302abu,0x444302acu,0x626102adu,0x6d6c02aeu,0x6d6c02afu,0x636202b0u,0x626102b1u,0x646302b2u,0x6c6b02b3u,0x560002b4u,0x80000035u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x7473030au,0x6665030bu,0x7372030cu,0x4544030du,0x6261030eu,0x7574030fu,0x62610310u,0x1000311u,0x80000036u,0x67660313u,0x62610314u,0x64630315u,0x66650316u,0x1000317u,0x80000037u,0x62610319u,0x6f6e031au,0x7473031bu,0x6766031cu,0x706f031du,0x7372031eu,0x6e6d031fu,0x1000320u,0x80000038u,0x6a690324u,0x0u,0x100032fu,0x75740325u,0x45440326u,0x6a690327u,0x74730328u,0x75740329u,0x6261032au,0x6f6e032bu,0x6463032cu,0x6665032du,0x100032eu,0x80000039u,0x8000003au,0x6d6c033fu,0x0u,0x0u,0x0u,0x7372039au,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6d6c03f3u,0x76750340u,0x66650341u,0x53000342u,0x8000003bu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x62610395u,0x6f6e0396u,0x68670397u,0x66650398u,0x1000399u,0x8000003cu,0x7574039bu,0x6665039cu,0x7978039du,0x2f2e039eu,0x7561039fu,0x757403b3u,0x0u,0x706103c3u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x706f03d8u,0x0u,0x706f03deu,0x0u,0x626103e6u,0x0u,0x626103ecu,0x757403b4u,0x737203b5u,0x6a6903b6u,0x636203b7u,0x767503b8u,0x757403b9u,0x666503bau,0x343003bbu,0x10003bfu,0x10003c0u,0x10003c1u,0x10003c2u,0x8000003du,0x8000003eu,0x8000003fu,0x80000040u,0x717003d2u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x6d6c03d4u,0x10003d3u,0x80000041u,0x706f03d5u,0x737203d6u,0x10003d7u,0x80000042u,0x737203d9u,0x6e6d03dau,0x626103dbu,0x6d6c03dcu,0x10003ddu,0x80000043u,0x747303dfu,0x6a6903e0u,0x757403e1u,0x6a6903e2u,0x706f03e3u,0x6f6e03e4u,0x10003e5u,0x80000044u,0x656403e7u,0x6a6903e8u,0x767503e9u,0x747303eau,0x10003ebu,0x80000045u,0x6f6e03edu,0x686703eeu,0x666503efu,0x6f6e03f0u,0x757403f1u,0x10003f2u,0x80000046u,0x767503f4u,0x6e6d03f5u,0x666503f6u,0x10003f7u,0x80000047u,0x737203fcu,0x0u,0x0u,0x62610400u,0x6d6c03fdu,0x656403feu,0x10003ffu,0x80000048u,0x71700401u,0x4e4d0402u,0x706f0403u,0x65640404u,0x66650405u,0x34310406u,0x1000409u,0x100040au,0x100040bu,0x80000049u,0x8000004au,0x8000004bu}; uint32_t cur = 0x78610000u; for(int i = 0;cur!=0;++i) { uint32_t idx = cur&0xFFFFu; @@ -81,6 +81,9 @@ const char ** query_extensions() { "ANARI_KHR_INSTANCE_TRANSFORM", "ANARI_KHR_CAMERA_ORTHOGRAPHIC", "ANARI_KHR_CAMERA_PERSPECTIVE", + "ANARI_KHR_FRAME_CHANNEL_PRIMITIVE_ID", + "ANARI_KHR_FRAME_CHANNEL_OBJECT_ID", + "ANARI_KHR_FRAME_CHANNEL_INSTANCE_ID", "ANARI_KHR_GEOMETRY_CONE", "ANARI_KHR_GEOMETRY_CURVE", "ANARI_KHR_GEOMETRY_CYLINDER", @@ -116,6 +119,11 @@ const char ** query_object_types(ANARIDataType type) { static const char *ANARI_CAMERA_subtypes[] = {"orthographic", "perspective", 0}; return ANARI_CAMERA_subtypes; } + case ANARI_VOLUME: + { + static const char *ANARI_VOLUME_subtypes[] = {"", "transferFunction1D", 0}; + return ANARI_VOLUME_subtypes; + } case ANARI_GEOMETRY: { static const char *ANARI_GEOMETRY_subtypes[] = {"cone", "curve", "cylinder", "quad", "sphere", "triangle", 0}; @@ -136,11 +144,6 @@ const char ** query_object_types(ANARIDataType type) { static const char *ANARI_SPATIAL_FIELD_subtypes[] = {"structuredRegular", 0}; return ANARI_SPATIAL_FIELD_subtypes; } - case ANARI_VOLUME: - { - static const char *ANARI_VOLUME_subtypes[] = {"transferFunction1D", 0}; - return ANARI_VOLUME_subtypes; - } default: { static const char *none_subtypes[] = {0}; @@ -251,13 +254,13 @@ static const void * ANARI_DEVICE_param_info(const char *paramName, ANARIDataType switch(param_hash(paramName)) { case 0: return ANARI_DEVICE_allowInvalidMaterials_info(paramType, infoName, infoType); - case 26: - return ANARI_DEVICE_invalidMaterialColor_info(paramType, infoName, infoType); case 30: + return ANARI_DEVICE_invalidMaterialColor_info(paramType, infoName, infoType); + case 34: return ANARI_DEVICE_name_info(paramType, infoName, infoType); - case 49: + case 53: return ANARI_DEVICE_statusCallback_info(paramType, infoName, infoType); - case 50: + case 54: return ANARI_DEVICE_statusCallbackUserData_info(paramType, infoName, infoType); default: return nullptr; @@ -365,9 +368,9 @@ static const void * ANARI_RENDERER_default_param_info(const char *paramName, ANA return ANARI_RENDERER_default_background_info(paramType, infoName, infoType); case 3: return ANARI_RENDERER_default_ambientRadiance_info(paramType, infoName, infoType); - case 29: + case 33: return ANARI_RENDERER_default_mode_info(paramType, infoName, infoType); - case 30: + case 34: return ANARI_RENDERER_default_name_info(paramType, infoName, infoType); default: return nullptr; @@ -392,7 +395,7 @@ static const void * ANARI_ARRAY1D_name_info(ANARIDataType paramType, int infoNam } static const void * ANARI_ARRAY1D_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_ARRAY1D_name_info(paramType, infoName, infoType); default: return nullptr; @@ -417,7 +420,7 @@ static const void * ANARI_ARRAY2D_name_info(ANARIDataType paramType, int infoNam } static const void * ANARI_ARRAY2D_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_ARRAY2D_name_info(paramType, infoName, infoType); default: return nullptr; @@ -442,7 +445,7 @@ static const void * ANARI_ARRAY3D_name_info(ANARIDataType paramType, int infoNam } static const void * ANARI_ARRAY3D_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_ARRAY3D_name_info(paramType, infoName, infoType); default: return nullptr; @@ -581,22 +584,124 @@ static const void * ANARI_FRAME_channel_depth_info(ANARIDataType paramType, int default: return nullptr; } } +static const void * ANARI_FRAME_channel_primitiveId_info(ANARIDataType paramType, int infoName, ANARIDataType infoType) { + (void)paramType; + switch(infoName) { + case 0: // required + if(infoType == ANARI_BOOL) { + return &anari_false; + } else { + return nullptr; + } + case 4: // description + { + static const char *description = "enables mapping the primitiveId channel as the type specified"; + return description; + } + case 6: // value + if(paramType == ANARI_DATA_TYPE && infoType == ANARI_DATA_TYPE_LIST) { + static const ANARIDataType values[] = {ANARI_UINT32, ANARI_UNKNOWN}; + return values; + } else { + return nullptr; + } + case 7: // sourceExtension + if(infoType == ANARI_STRING) { + static const char *extension = "KHR_FRAME_CHANNEL_PRIMITIVE_ID"; + return extension; + } else if(infoType == ANARI_INT32) { + static const int32_t value = 3; + return &value; + } + default: return nullptr; + } +} +static const void * ANARI_FRAME_channel_objectId_info(ANARIDataType paramType, int infoName, ANARIDataType infoType) { + (void)paramType; + switch(infoName) { + case 0: // required + if(infoType == ANARI_BOOL) { + return &anari_false; + } else { + return nullptr; + } + case 4: // description + { + static const char *description = "enables mapping the objectId channel as the type specified"; + return description; + } + case 6: // value + if(paramType == ANARI_DATA_TYPE && infoType == ANARI_DATA_TYPE_LIST) { + static const ANARIDataType values[] = {ANARI_UINT32, ANARI_UNKNOWN}; + return values; + } else { + return nullptr; + } + case 7: // sourceExtension + if(infoType == ANARI_STRING) { + static const char *extension = "KHR_FRAME_CHANNEL_OBJECT_ID"; + return extension; + } else if(infoType == ANARI_INT32) { + static const int32_t value = 4; + return &value; + } + default: return nullptr; + } +} +static const void * ANARI_FRAME_channel_instanceId_info(ANARIDataType paramType, int infoName, ANARIDataType infoType) { + (void)paramType; + switch(infoName) { + case 0: // required + if(infoType == ANARI_BOOL) { + return &anari_false; + } else { + return nullptr; + } + case 4: // description + { + static const char *description = "enables mapping the instanceId channel as the type specified"; + return description; + } + case 6: // value + if(paramType == ANARI_DATA_TYPE && infoType == ANARI_DATA_TYPE_LIST) { + static const ANARIDataType values[] = {ANARI_UINT32, ANARI_UNKNOWN}; + return values; + } else { + return nullptr; + } + case 7: // sourceExtension + if(infoType == ANARI_STRING) { + static const char *extension = "KHR_FRAME_CHANNEL_INSTANCE_ID"; + return extension; + } else if(infoType == ANARI_INT32) { + static const int32_t value = 5; + return &value; + } + default: return nullptr; + } +} static const void * ANARI_FRAME_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_FRAME_name_info(paramType, infoName, infoType); - case 68: + case 72: return ANARI_FRAME_world_info(paramType, infoName, infoType); - case 46: + case 50: return ANARI_FRAME_renderer_info(paramType, infoName, infoType); case 7: return ANARI_FRAME_camera_info(paramType, infoName, infoType); - case 47: + case 51: return ANARI_FRAME_size_info(paramType, infoName, infoType); case 9: return ANARI_FRAME_channel_color_info(paramType, infoName, infoType); case 10: return ANARI_FRAME_channel_depth_info(paramType, infoName, infoType); + case 13: + return ANARI_FRAME_channel_primitiveId_info(paramType, infoName, infoType); + case 12: + return ANARI_FRAME_channel_objectId_info(paramType, infoName, infoType); + case 11: + return ANARI_FRAME_channel_instanceId_info(paramType, infoName, infoType); default: return nullptr; } @@ -692,13 +797,13 @@ static const void * ANARI_GROUP_light_info(ANARIDataType paramType, int infoName } static const void * ANARI_GROUP_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_GROUP_name_info(paramType, infoName, infoType); - case 51: + case 55: return ANARI_GROUP_surface_info(paramType, infoName, infoType); - case 67: + case 71: return ANARI_GROUP_volume_info(paramType, infoName, infoType); - case 27: + case 31: return ANARI_GROUP_light_info(paramType, infoName, infoType); default: return nullptr; @@ -819,15 +924,15 @@ static const void * ANARI_WORLD_light_info(ANARIDataType paramType, int infoName } static const void * ANARI_WORLD_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_WORLD_name_info(paramType, infoName, infoType); - case 25: + case 29: return ANARI_WORLD_instance_info(paramType, infoName, infoType); - case 51: + case 55: return ANARI_WORLD_surface_info(paramType, infoName, infoType); - case 67: + case 71: return ANARI_WORLD_volume_info(paramType, infoName, infoType); - case 27: + case 31: return ANARI_WORLD_light_info(paramType, infoName, infoType); default: return nullptr; @@ -884,14 +989,41 @@ static const void * ANARI_SURFACE_material_info(ANARIDataType paramType, int inf default: return nullptr; } } +static const void * ANARI_SURFACE_id_info(ANARIDataType paramType, int infoName, ANARIDataType infoType) { + (void)paramType; + switch(infoName) { + case 0: // required + if(infoType == ANARI_BOOL) { + return &anari_false; + } else { + return nullptr; + } + case 4: // description + { + static const char *description = "user id for objectId channel"; + return description; + } + case 7: // sourceExtension + if(infoType == ANARI_STRING) { + static const char *extension = "KHR_FRAME_CHANNEL_OBJECT_ID"; + return extension; + } else if(infoType == ANARI_INT32) { + static const int32_t value = 4; + return &value; + } + default: return nullptr; + } +} static const void * ANARI_SURFACE_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_SURFACE_name_info(paramType, infoName, infoType); - case 17: + case 20: return ANARI_SURFACE_geometry_info(paramType, infoName, infoType); - case 28: + case 32: return ANARI_SURFACE_material_info(paramType, infoName, infoType); + case 23: + return ANARI_SURFACE_id_info(paramType, infoName, infoType); default: return nullptr; } @@ -978,14 +1110,41 @@ static const void * ANARI_INSTANCE_transform_group_info(ANARIDataType paramType, default: return nullptr; } } +static const void * ANARI_INSTANCE_transform_id_info(ANARIDataType paramType, int infoName, ANARIDataType infoType) { + (void)paramType; + switch(infoName) { + case 0: // required + if(infoType == ANARI_BOOL) { + return &anari_false; + } else { + return nullptr; + } + case 4: // description + { + static const char *description = "user id for instanceId channel"; + return description; + } + case 7: // sourceExtension + if(infoType == ANARI_STRING) { + static const char *extension = "KHR_FRAME_CHANNEL_INSTANCE_ID"; + return extension; + } else if(infoType == ANARI_INT32) { + static const int32_t value = 5; + return &value; + } + default: return nullptr; + } +} static const void * ANARI_INSTANCE_transform_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_INSTANCE_transform_name_info(paramType, infoName, infoType); - case 52: + case 56: return ANARI_INSTANCE_transform_transform_info(paramType, infoName, infoType); - case 18: + case 21: return ANARI_INSTANCE_transform_group_info(paramType, infoName, infoType); + case 23: + return ANARI_INSTANCE_transform_id_info(paramType, infoName, infoType); default: return nullptr; } @@ -1277,23 +1436,23 @@ static const void * ANARI_CAMERA_orthographic_far_info(ANARIDataType paramType, } static const void * ANARI_CAMERA_orthographic_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_CAMERA_orthographic_name_info(paramType, infoName, infoType); - case 36: + case 40: return ANARI_CAMERA_orthographic_position_info(paramType, infoName, infoType); - case 13: + case 16: return ANARI_CAMERA_orthographic_direction_info(paramType, infoName, infoType); - case 54: + case 58: return ANARI_CAMERA_orthographic_up_info(paramType, infoName, infoType); - case 21: + case 25: return ANARI_CAMERA_orthographic_imageRegion_info(paramType, infoName, infoType); case 5: return ANARI_CAMERA_orthographic_aspect_info(paramType, infoName, infoType); - case 19: + case 22: return ANARI_CAMERA_orthographic_height_info(paramType, infoName, infoType); - case 31: + case 35: return ANARI_CAMERA_orthographic_near_info(paramType, infoName, infoType); - case 14: + case 17: return ANARI_CAMERA_orthographic_far_info(paramType, infoName, infoType); default: return nullptr; @@ -1586,28 +1745,61 @@ static const void * ANARI_CAMERA_perspective_far_info(ANARIDataType paramType, i } static const void * ANARI_CAMERA_perspective_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_CAMERA_perspective_name_info(paramType, infoName, infoType); - case 36: + case 40: return ANARI_CAMERA_perspective_position_info(paramType, infoName, infoType); - case 13: + case 16: return ANARI_CAMERA_perspective_direction_info(paramType, infoName, infoType); - case 54: + case 58: return ANARI_CAMERA_perspective_up_info(paramType, infoName, infoType); - case 21: + case 25: return ANARI_CAMERA_perspective_imageRegion_info(paramType, infoName, infoType); - case 16: + case 19: return ANARI_CAMERA_perspective_fovy_info(paramType, infoName, infoType); case 5: return ANARI_CAMERA_perspective_aspect_info(paramType, infoName, infoType); - case 31: + case 35: return ANARI_CAMERA_perspective_near_info(paramType, infoName, infoType); - case 14: + case 17: return ANARI_CAMERA_perspective_far_info(paramType, infoName, infoType); default: return nullptr; } } +static const void * ANARI_VOLUME__id_info(ANARIDataType paramType, int infoName, ANARIDataType infoType) { + (void)paramType; + switch(infoName) { + case 0: // required + if(infoType == ANARI_BOOL) { + return &anari_false; + } else { + return nullptr; + } + case 4: // description + { + static const char *description = "user id for objectId channel"; + return description; + } + case 7: // sourceExtension + if(infoType == ANARI_STRING) { + static const char *extension = "KHR_FRAME_CHANNEL_OBJECT_ID"; + return extension; + } else if(infoType == ANARI_INT32) { + static const int32_t value = 4; + return &value; + } + default: return nullptr; + } +} +static const void * ANARI_VOLUME__param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { + switch(param_hash(paramName)) { + case 23: + return ANARI_VOLUME__id_info(paramType, infoName, infoType); + default: + return nullptr; + } +} static const void * ANARI_GEOMETRY_cone_name_info(ANARIDataType paramType, int infoName, ANARIDataType infoType) { (void)paramType; switch(infoName) { @@ -1627,7 +1819,7 @@ static const void * ANARI_GEOMETRY_cone_name_info(ANARIDataType paramType, int i static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -1659,7 +1851,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_color_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -1691,7 +1883,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_attribute0_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -1723,7 +1915,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_attribute1_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -1755,7 +1947,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_attribute2_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -1787,7 +1979,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_attribute3_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -1819,7 +2011,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_id_info(ANARIDataType paramTyp static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -1851,7 +2043,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_position_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -1883,7 +2075,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_radius_info(ANARIDataType paramTy static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -1915,7 +2107,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_cap_info(ANARIDataType paramType, static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -1947,7 +2139,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_color_info(ANARIDataType paramTyp static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -1979,7 +2171,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_attribute0_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -2011,7 +2203,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_attribute1_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -2043,7 +2235,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_attribute2_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -2075,7 +2267,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_attribute3_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -2107,7 +2299,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_index_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -2146,7 +2338,7 @@ static const void * ANARI_GEOMETRY_cone_caps_info(ANARIDataType paramType, int i static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -2154,37 +2346,37 @@ static const void * ANARI_GEOMETRY_cone_caps_info(ANARIDataType paramType, int i } static const void * ANARI_GEOMETRY_cone_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_GEOMETRY_cone_name_info(paramType, infoName, infoType); - case 41: + case 45: return ANARI_GEOMETRY_cone_primitive_color_info(paramType, infoName, infoType); - case 37: + case 41: return ANARI_GEOMETRY_cone_primitive_attribute0_info(paramType, infoName, infoType); - case 38: + case 42: return ANARI_GEOMETRY_cone_primitive_attribute1_info(paramType, infoName, infoType); - case 39: + case 43: return ANARI_GEOMETRY_cone_primitive_attribute2_info(paramType, infoName, infoType); - case 40: + case 44: return ANARI_GEOMETRY_cone_primitive_attribute3_info(paramType, infoName, infoType); - case 42: + case 46: return ANARI_GEOMETRY_cone_primitive_id_info(paramType, infoName, infoType); - case 64: + case 68: return ANARI_GEOMETRY_cone_vertex_position_info(paramType, infoName, infoType); - case 65: + case 69: return ANARI_GEOMETRY_cone_vertex_radius_info(paramType, infoName, infoType); - case 61: + case 65: return ANARI_GEOMETRY_cone_vertex_cap_info(paramType, infoName, infoType); - case 62: + case 66: return ANARI_GEOMETRY_cone_vertex_color_info(paramType, infoName, infoType); - case 57: + case 61: return ANARI_GEOMETRY_cone_vertex_attribute0_info(paramType, infoName, infoType); - case 58: + case 62: return ANARI_GEOMETRY_cone_vertex_attribute1_info(paramType, infoName, infoType); - case 59: + case 63: return ANARI_GEOMETRY_cone_vertex_attribute2_info(paramType, infoName, infoType); - case 60: + case 64: return ANARI_GEOMETRY_cone_vertex_attribute3_info(paramType, infoName, infoType); - case 43: + case 47: return ANARI_GEOMETRY_cone_primitive_index_info(paramType, infoName, infoType); case 8: return ANARI_GEOMETRY_cone_caps_info(paramType, infoName, infoType); @@ -2211,7 +2403,7 @@ static const void * ANARI_GEOMETRY_curve_name_info(ANARIDataType paramType, int static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2243,7 +2435,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_color_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2275,7 +2467,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_attribute0_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2307,7 +2499,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_attribute1_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2339,7 +2531,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_attribute2_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2371,7 +2563,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_attribute3_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2403,7 +2595,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_id_info(ANARIDataType paramTy static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2435,7 +2627,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_position_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2467,7 +2659,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_radius_info(ANARIDataType paramT static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2499,7 +2691,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_color_info(ANARIDataType paramTy static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2531,7 +2723,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_attribute0_info(ANARIDataType pa static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2563,7 +2755,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_attribute1_info(ANARIDataType pa static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2595,7 +2787,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_attribute2_info(ANARIDataType pa static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2627,7 +2819,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_attribute3_info(ANARIDataType pa static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2659,7 +2851,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_index_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2684,7 +2876,7 @@ static const void * ANARI_GEOMETRY_curve_radius_info(ANARIDataType paramType, in static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2692,37 +2884,37 @@ static const void * ANARI_GEOMETRY_curve_radius_info(ANARIDataType paramType, in } static const void * ANARI_GEOMETRY_curve_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_GEOMETRY_curve_name_info(paramType, infoName, infoType); - case 41: + case 45: return ANARI_GEOMETRY_curve_primitive_color_info(paramType, infoName, infoType); - case 37: + case 41: return ANARI_GEOMETRY_curve_primitive_attribute0_info(paramType, infoName, infoType); - case 38: + case 42: return ANARI_GEOMETRY_curve_primitive_attribute1_info(paramType, infoName, infoType); - case 39: + case 43: return ANARI_GEOMETRY_curve_primitive_attribute2_info(paramType, infoName, infoType); - case 40: + case 44: return ANARI_GEOMETRY_curve_primitive_attribute3_info(paramType, infoName, infoType); - case 42: + case 46: return ANARI_GEOMETRY_curve_primitive_id_info(paramType, infoName, infoType); - case 64: + case 68: return ANARI_GEOMETRY_curve_vertex_position_info(paramType, infoName, infoType); - case 65: + case 69: return ANARI_GEOMETRY_curve_vertex_radius_info(paramType, infoName, infoType); - case 62: + case 66: return ANARI_GEOMETRY_curve_vertex_color_info(paramType, infoName, infoType); - case 57: + case 61: return ANARI_GEOMETRY_curve_vertex_attribute0_info(paramType, infoName, infoType); - case 58: + case 62: return ANARI_GEOMETRY_curve_vertex_attribute1_info(paramType, infoName, infoType); - case 59: + case 63: return ANARI_GEOMETRY_curve_vertex_attribute2_info(paramType, infoName, infoType); - case 60: + case 64: return ANARI_GEOMETRY_curve_vertex_attribute3_info(paramType, infoName, infoType); - case 43: + case 47: return ANARI_GEOMETRY_curve_primitive_index_info(paramType, infoName, infoType); - case 45: + case 49: return ANARI_GEOMETRY_curve_radius_info(paramType, infoName, infoType); default: return nullptr; @@ -2747,7 +2939,7 @@ static const void * ANARI_GEOMETRY_cylinder_name_info(ANARIDataType paramType, i static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2779,7 +2971,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_color_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2811,7 +3003,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_attribute0_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2843,7 +3035,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_attribute1_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2875,7 +3067,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_attribute2_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2907,7 +3099,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_attribute3_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2939,7 +3131,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_id_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2971,7 +3163,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_position_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -3003,7 +3195,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_cap_info(ANARIDataType paramT static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -3035,7 +3227,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_color_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -3067,7 +3259,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_attribute0_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -3099,7 +3291,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_attribute1_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -3131,7 +3323,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_attribute2_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -3163,7 +3355,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_attribute3_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -3195,7 +3387,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_index_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -3227,7 +3419,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_radius_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -3252,7 +3444,7 @@ static const void * ANARI_GEOMETRY_cylinder_radius_info(ANARIDataType paramType, static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -3291,7 +3483,7 @@ static const void * ANARI_GEOMETRY_cylinder_caps_info(ANARIDataType paramType, i static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -3299,39 +3491,39 @@ static const void * ANARI_GEOMETRY_cylinder_caps_info(ANARIDataType paramType, i } static const void * ANARI_GEOMETRY_cylinder_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_GEOMETRY_cylinder_name_info(paramType, infoName, infoType); - case 41: + case 45: return ANARI_GEOMETRY_cylinder_primitive_color_info(paramType, infoName, infoType); - case 37: + case 41: return ANARI_GEOMETRY_cylinder_primitive_attribute0_info(paramType, infoName, infoType); - case 38: + case 42: return ANARI_GEOMETRY_cylinder_primitive_attribute1_info(paramType, infoName, infoType); - case 39: + case 43: return ANARI_GEOMETRY_cylinder_primitive_attribute2_info(paramType, infoName, infoType); - case 40: + case 44: return ANARI_GEOMETRY_cylinder_primitive_attribute3_info(paramType, infoName, infoType); - case 42: + case 46: return ANARI_GEOMETRY_cylinder_primitive_id_info(paramType, infoName, infoType); - case 64: + case 68: return ANARI_GEOMETRY_cylinder_vertex_position_info(paramType, infoName, infoType); - case 61: + case 65: return ANARI_GEOMETRY_cylinder_vertex_cap_info(paramType, infoName, infoType); - case 62: + case 66: return ANARI_GEOMETRY_cylinder_vertex_color_info(paramType, infoName, infoType); - case 57: + case 61: return ANARI_GEOMETRY_cylinder_vertex_attribute0_info(paramType, infoName, infoType); - case 58: + case 62: return ANARI_GEOMETRY_cylinder_vertex_attribute1_info(paramType, infoName, infoType); - case 59: + case 63: return ANARI_GEOMETRY_cylinder_vertex_attribute2_info(paramType, infoName, infoType); - case 60: + case 64: return ANARI_GEOMETRY_cylinder_vertex_attribute3_info(paramType, infoName, infoType); - case 43: + case 47: return ANARI_GEOMETRY_cylinder_primitive_index_info(paramType, infoName, infoType); - case 44: + case 48: return ANARI_GEOMETRY_cylinder_primitive_radius_info(paramType, infoName, infoType); - case 45: + case 49: return ANARI_GEOMETRY_cylinder_radius_info(paramType, infoName, infoType); case 8: return ANARI_GEOMETRY_cylinder_caps_info(paramType, infoName, infoType); @@ -3358,7 +3550,7 @@ static const void * ANARI_GEOMETRY_quad_name_info(ANARIDataType paramType, int i static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3390,7 +3582,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_color_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3422,7 +3614,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_attribute0_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3454,7 +3646,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_attribute1_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3486,7 +3678,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_attribute2_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3518,7 +3710,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_attribute3_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3550,7 +3742,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_id_info(ANARIDataType paramTyp static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3582,7 +3774,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_position_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3614,7 +3806,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_normal_info(ANARIDataType paramTy static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3646,7 +3838,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_tangent_info(ANARIDataType paramT static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3678,7 +3870,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_color_info(ANARIDataType paramTyp static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3710,7 +3902,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_attribute0_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3742,7 +3934,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_attribute1_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3774,7 +3966,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_attribute2_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3806,7 +3998,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_attribute3_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3838,7 +4030,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_index_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3846,37 +4038,37 @@ static const void * ANARI_GEOMETRY_quad_primitive_index_info(ANARIDataType param } static const void * ANARI_GEOMETRY_quad_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_GEOMETRY_quad_name_info(paramType, infoName, infoType); - case 41: + case 45: return ANARI_GEOMETRY_quad_primitive_color_info(paramType, infoName, infoType); - case 37: + case 41: return ANARI_GEOMETRY_quad_primitive_attribute0_info(paramType, infoName, infoType); - case 38: + case 42: return ANARI_GEOMETRY_quad_primitive_attribute1_info(paramType, infoName, infoType); - case 39: + case 43: return ANARI_GEOMETRY_quad_primitive_attribute2_info(paramType, infoName, infoType); - case 40: + case 44: return ANARI_GEOMETRY_quad_primitive_attribute3_info(paramType, infoName, infoType); - case 42: + case 46: return ANARI_GEOMETRY_quad_primitive_id_info(paramType, infoName, infoType); - case 64: + case 68: return ANARI_GEOMETRY_quad_vertex_position_info(paramType, infoName, infoType); - case 63: + case 67: return ANARI_GEOMETRY_quad_vertex_normal_info(paramType, infoName, infoType); - case 66: + case 70: return ANARI_GEOMETRY_quad_vertex_tangent_info(paramType, infoName, infoType); - case 62: + case 66: return ANARI_GEOMETRY_quad_vertex_color_info(paramType, infoName, infoType); - case 57: + case 61: return ANARI_GEOMETRY_quad_vertex_attribute0_info(paramType, infoName, infoType); - case 58: + case 62: return ANARI_GEOMETRY_quad_vertex_attribute1_info(paramType, infoName, infoType); - case 59: + case 63: return ANARI_GEOMETRY_quad_vertex_attribute2_info(paramType, infoName, infoType); - case 60: + case 64: return ANARI_GEOMETRY_quad_vertex_attribute3_info(paramType, infoName, infoType); - case 43: + case 47: return ANARI_GEOMETRY_quad_primitive_index_info(paramType, infoName, infoType); default: return nullptr; @@ -3901,7 +4093,7 @@ static const void * ANARI_GEOMETRY_sphere_name_info(ANARIDataType paramType, int static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3933,7 +4125,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_color_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3965,7 +4157,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_attribute0_info(ANARIDataTyp static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3997,7 +4189,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_attribute1_info(ANARIDataTyp static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4029,7 +4221,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_attribute2_info(ANARIDataTyp static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4061,7 +4253,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_attribute3_info(ANARIDataTyp static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4093,7 +4285,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_id_info(ANARIDataType paramT static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4125,7 +4317,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_position_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4157,7 +4349,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_radius_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4189,7 +4381,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_color_info(ANARIDataType paramT static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4221,7 +4413,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_attribute0_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4253,7 +4445,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_attribute1_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4285,7 +4477,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_attribute2_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4317,7 +4509,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_attribute3_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4349,7 +4541,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_index_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4374,7 +4566,7 @@ static const void * ANARI_GEOMETRY_sphere_radius_info(ANARIDataType paramType, i static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4382,37 +4574,37 @@ static const void * ANARI_GEOMETRY_sphere_radius_info(ANARIDataType paramType, i } static const void * ANARI_GEOMETRY_sphere_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_GEOMETRY_sphere_name_info(paramType, infoName, infoType); - case 41: + case 45: return ANARI_GEOMETRY_sphere_primitive_color_info(paramType, infoName, infoType); - case 37: + case 41: return ANARI_GEOMETRY_sphere_primitive_attribute0_info(paramType, infoName, infoType); - case 38: + case 42: return ANARI_GEOMETRY_sphere_primitive_attribute1_info(paramType, infoName, infoType); - case 39: + case 43: return ANARI_GEOMETRY_sphere_primitive_attribute2_info(paramType, infoName, infoType); - case 40: + case 44: return ANARI_GEOMETRY_sphere_primitive_attribute3_info(paramType, infoName, infoType); - case 42: + case 46: return ANARI_GEOMETRY_sphere_primitive_id_info(paramType, infoName, infoType); - case 64: + case 68: return ANARI_GEOMETRY_sphere_vertex_position_info(paramType, infoName, infoType); - case 65: + case 69: return ANARI_GEOMETRY_sphere_vertex_radius_info(paramType, infoName, infoType); - case 62: + case 66: return ANARI_GEOMETRY_sphere_vertex_color_info(paramType, infoName, infoType); - case 57: + case 61: return ANARI_GEOMETRY_sphere_vertex_attribute0_info(paramType, infoName, infoType); - case 58: + case 62: return ANARI_GEOMETRY_sphere_vertex_attribute1_info(paramType, infoName, infoType); - case 59: + case 63: return ANARI_GEOMETRY_sphere_vertex_attribute2_info(paramType, infoName, infoType); - case 60: + case 64: return ANARI_GEOMETRY_sphere_vertex_attribute3_info(paramType, infoName, infoType); - case 43: + case 47: return ANARI_GEOMETRY_sphere_primitive_index_info(paramType, infoName, infoType); - case 45: + case 49: return ANARI_GEOMETRY_sphere_radius_info(paramType, infoName, infoType); default: return nullptr; @@ -4437,7 +4629,7 @@ static const void * ANARI_GEOMETRY_triangle_name_info(ANARIDataType paramType, i static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4469,7 +4661,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_color_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4501,7 +4693,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_attribute0_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4533,7 +4725,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_attribute1_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4565,7 +4757,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_attribute2_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4597,7 +4789,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_attribute3_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4629,7 +4821,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_id_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4661,7 +4853,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_position_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4693,7 +4885,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_normal_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4725,7 +4917,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_tangent_info(ANARIDataType pa static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4757,7 +4949,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_color_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4789,7 +4981,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_attribute0_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4821,7 +5013,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_attribute1_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4853,7 +5045,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_attribute2_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4885,7 +5077,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_attribute3_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4917,7 +5109,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_index_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4925,37 +5117,37 @@ static const void * ANARI_GEOMETRY_triangle_primitive_index_info(ANARIDataType p } static const void * ANARI_GEOMETRY_triangle_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_GEOMETRY_triangle_name_info(paramType, infoName, infoType); - case 41: + case 45: return ANARI_GEOMETRY_triangle_primitive_color_info(paramType, infoName, infoType); - case 37: + case 41: return ANARI_GEOMETRY_triangle_primitive_attribute0_info(paramType, infoName, infoType); - case 38: + case 42: return ANARI_GEOMETRY_triangle_primitive_attribute1_info(paramType, infoName, infoType); - case 39: + case 43: return ANARI_GEOMETRY_triangle_primitive_attribute2_info(paramType, infoName, infoType); - case 40: + case 44: return ANARI_GEOMETRY_triangle_primitive_attribute3_info(paramType, infoName, infoType); - case 42: + case 46: return ANARI_GEOMETRY_triangle_primitive_id_info(paramType, infoName, infoType); - case 64: + case 68: return ANARI_GEOMETRY_triangle_vertex_position_info(paramType, infoName, infoType); - case 63: + case 67: return ANARI_GEOMETRY_triangle_vertex_normal_info(paramType, infoName, infoType); - case 66: + case 70: return ANARI_GEOMETRY_triangle_vertex_tangent_info(paramType, infoName, infoType); - case 62: + case 66: return ANARI_GEOMETRY_triangle_vertex_color_info(paramType, infoName, infoType); - case 57: + case 61: return ANARI_GEOMETRY_triangle_vertex_attribute0_info(paramType, infoName, infoType); - case 58: + case 62: return ANARI_GEOMETRY_triangle_vertex_attribute1_info(paramType, infoName, infoType); - case 59: + case 63: return ANARI_GEOMETRY_triangle_vertex_attribute2_info(paramType, infoName, infoType); - case 60: + case 64: return ANARI_GEOMETRY_triangle_vertex_attribute3_info(paramType, infoName, infoType); - case 43: + case 47: return ANARI_GEOMETRY_triangle_primitive_index_info(paramType, infoName, infoType); default: return nullptr; @@ -4980,7 +5172,7 @@ static const void * ANARI_MATERIAL_matte_name_info(ANARIDataType paramType, int static const char *extension = "KHR_MATERIAL_MATTE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -5025,7 +5217,7 @@ static const void * ANARI_MATERIAL_matte_color_info(ANARIDataType paramType, int static const char *extension = "KHR_MATERIAL_MATTE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -5064,7 +5256,7 @@ static const void * ANARI_MATERIAL_matte_opacity_info(ANARIDataType paramType, i static const char *extension = "KHR_MATERIAL_MATTE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -5103,7 +5295,7 @@ static const void * ANARI_MATERIAL_matte_alphaMode_info(ANARIDataType paramType, static const char *extension = "KHR_MATERIAL_MATTE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -5135,7 +5327,7 @@ static const void * ANARI_MATERIAL_matte_alphaCutoff_info(ANARIDataType paramTyp static const char *extension = "KHR_MATERIAL_MATTE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -5143,11 +5335,11 @@ static const void * ANARI_MATERIAL_matte_alphaCutoff_info(ANARIDataType paramTyp } static const void * ANARI_MATERIAL_matte_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_MATERIAL_matte_name_info(paramType, infoName, infoType); - case 11: + case 14: return ANARI_MATERIAL_matte_color_info(paramType, infoName, infoType); - case 32: + case 36: return ANARI_MATERIAL_matte_opacity_info(paramType, infoName, infoType); case 2: return ANARI_MATERIAL_matte_alphaMode_info(paramType, infoName, infoType); @@ -5176,7 +5368,7 @@ static const void * ANARI_SAMPLER_image1D_name_info(ANARIDataType paramType, int static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5208,7 +5400,7 @@ static const void * ANARI_SAMPLER_image1D_image_info(ANARIDataType paramType, in static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5247,7 +5439,7 @@ static const void * ANARI_SAMPLER_image1D_inAttribute_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5286,7 +5478,7 @@ static const void * ANARI_SAMPLER_image1D_filter_info(ANARIDataType paramType, i static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5325,7 +5517,7 @@ static const void * ANARI_SAMPLER_image1D_wrapMode1_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5357,7 +5549,7 @@ static const void * ANARI_SAMPLER_image1D_inTransform_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5389,7 +5581,7 @@ static const void * ANARI_SAMPLER_image1D_inOffset_info(ANARIDataType paramType, static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5421,7 +5613,7 @@ static const void * ANARI_SAMPLER_image1D_outTransform_info(ANARIDataType paramT static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5453,7 +5645,7 @@ static const void * ANARI_SAMPLER_image1D_outOffset_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5461,23 +5653,23 @@ static const void * ANARI_SAMPLER_image1D_outOffset_info(ANARIDataType paramType } static const void * ANARI_SAMPLER_image1D_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_SAMPLER_image1D_name_info(paramType, infoName, infoType); - case 20: + case 24: return ANARI_SAMPLER_image1D_image_info(paramType, infoName, infoType); - case 22: + case 26: return ANARI_SAMPLER_image1D_inAttribute_info(paramType, infoName, infoType); - case 15: + case 18: return ANARI_SAMPLER_image1D_filter_info(paramType, infoName, infoType); - case 69: + case 73: return ANARI_SAMPLER_image1D_wrapMode1_info(paramType, infoName, infoType); - case 24: + case 28: return ANARI_SAMPLER_image1D_inTransform_info(paramType, infoName, infoType); - case 23: + case 27: return ANARI_SAMPLER_image1D_inOffset_info(paramType, infoName, infoType); - case 35: + case 39: return ANARI_SAMPLER_image1D_outTransform_info(paramType, infoName, infoType); - case 34: + case 38: return ANARI_SAMPLER_image1D_outOffset_info(paramType, infoName, infoType); default: return nullptr; @@ -5502,7 +5694,7 @@ static const void * ANARI_SAMPLER_image2D_name_info(ANARIDataType paramType, int static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5534,7 +5726,7 @@ static const void * ANARI_SAMPLER_image2D_image_info(ANARIDataType paramType, in static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5573,7 +5765,7 @@ static const void * ANARI_SAMPLER_image2D_inAttribute_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5612,7 +5804,7 @@ static const void * ANARI_SAMPLER_image2D_filter_info(ANARIDataType paramType, i static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5651,7 +5843,7 @@ static const void * ANARI_SAMPLER_image2D_wrapMode1_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5690,7 +5882,7 @@ static const void * ANARI_SAMPLER_image2D_wrapMode2_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5722,7 +5914,7 @@ static const void * ANARI_SAMPLER_image2D_inTransform_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5754,7 +5946,7 @@ static const void * ANARI_SAMPLER_image2D_inOffset_info(ANARIDataType paramType, static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5786,7 +5978,7 @@ static const void * ANARI_SAMPLER_image2D_outTransform_info(ANARIDataType paramT static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5818,7 +6010,7 @@ static const void * ANARI_SAMPLER_image2D_outOffset_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5826,25 +6018,25 @@ static const void * ANARI_SAMPLER_image2D_outOffset_info(ANARIDataType paramType } static const void * ANARI_SAMPLER_image2D_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_SAMPLER_image2D_name_info(paramType, infoName, infoType); - case 20: + case 24: return ANARI_SAMPLER_image2D_image_info(paramType, infoName, infoType); - case 22: + case 26: return ANARI_SAMPLER_image2D_inAttribute_info(paramType, infoName, infoType); - case 15: + case 18: return ANARI_SAMPLER_image2D_filter_info(paramType, infoName, infoType); - case 69: + case 73: return ANARI_SAMPLER_image2D_wrapMode1_info(paramType, infoName, infoType); - case 70: + case 74: return ANARI_SAMPLER_image2D_wrapMode2_info(paramType, infoName, infoType); - case 24: + case 28: return ANARI_SAMPLER_image2D_inTransform_info(paramType, infoName, infoType); - case 23: + case 27: return ANARI_SAMPLER_image2D_inOffset_info(paramType, infoName, infoType); - case 35: + case 39: return ANARI_SAMPLER_image2D_outTransform_info(paramType, infoName, infoType); - case 34: + case 38: return ANARI_SAMPLER_image2D_outOffset_info(paramType, infoName, infoType); default: return nullptr; @@ -5869,7 +6061,7 @@ static const void * ANARI_SAMPLER_image3D_name_info(ANARIDataType paramType, int static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -5901,7 +6093,7 @@ static const void * ANARI_SAMPLER_image3D_image_info(ANARIDataType paramType, in static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -5940,7 +6132,7 @@ static const void * ANARI_SAMPLER_image3D_inAttribute_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -5979,7 +6171,7 @@ static const void * ANARI_SAMPLER_image3D_filter_info(ANARIDataType paramType, i static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -6018,7 +6210,7 @@ static const void * ANARI_SAMPLER_image3D_wrapMode1_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -6057,7 +6249,7 @@ static const void * ANARI_SAMPLER_image3D_wrapMode2_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -6096,7 +6288,7 @@ static const void * ANARI_SAMPLER_image3D_wrapMode3_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -6128,7 +6320,7 @@ static const void * ANARI_SAMPLER_image3D_inTransform_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -6160,7 +6352,7 @@ static const void * ANARI_SAMPLER_image3D_inOffset_info(ANARIDataType paramType, static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -6192,7 +6384,7 @@ static const void * ANARI_SAMPLER_image3D_outTransform_info(ANARIDataType paramT static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -6224,7 +6416,7 @@ static const void * ANARI_SAMPLER_image3D_outOffset_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -6232,27 +6424,27 @@ static const void * ANARI_SAMPLER_image3D_outOffset_info(ANARIDataType paramType } static const void * ANARI_SAMPLER_image3D_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_SAMPLER_image3D_name_info(paramType, infoName, infoType); - case 20: + case 24: return ANARI_SAMPLER_image3D_image_info(paramType, infoName, infoType); - case 22: + case 26: return ANARI_SAMPLER_image3D_inAttribute_info(paramType, infoName, infoType); - case 15: + case 18: return ANARI_SAMPLER_image3D_filter_info(paramType, infoName, infoType); - case 69: + case 73: return ANARI_SAMPLER_image3D_wrapMode1_info(paramType, infoName, infoType); - case 70: + case 74: return ANARI_SAMPLER_image3D_wrapMode2_info(paramType, infoName, infoType); - case 71: + case 75: return ANARI_SAMPLER_image3D_wrapMode3_info(paramType, infoName, infoType); - case 24: + case 28: return ANARI_SAMPLER_image3D_inTransform_info(paramType, infoName, infoType); - case 23: + case 27: return ANARI_SAMPLER_image3D_inOffset_info(paramType, infoName, infoType); - case 35: + case 39: return ANARI_SAMPLER_image3D_outTransform_info(paramType, infoName, infoType); - case 34: + case 38: return ANARI_SAMPLER_image3D_outOffset_info(paramType, infoName, infoType); default: return nullptr; @@ -6277,7 +6469,7 @@ static const void * ANARI_SAMPLER_primitive_name_info(ANARIDataType paramType, i static const char *extension = "KHR_SAMPLER_PRIMITIVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 13; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6309,7 +6501,7 @@ static const void * ANARI_SAMPLER_primitive_array_info(ANARIDataType paramType, static const char *extension = "KHR_SAMPLER_PRIMITIVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 13; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6341,7 +6533,7 @@ static const void * ANARI_SAMPLER_primitive_inOffset_info(ANARIDataType paramTyp static const char *extension = "KHR_SAMPLER_PRIMITIVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 13; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6349,11 +6541,11 @@ static const void * ANARI_SAMPLER_primitive_inOffset_info(ANARIDataType paramTyp } static const void * ANARI_SAMPLER_primitive_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_SAMPLER_primitive_name_info(paramType, infoName, infoType); case 4: return ANARI_SAMPLER_primitive_array_info(paramType, infoName, infoType); - case 23: + case 27: return ANARI_SAMPLER_primitive_inOffset_info(paramType, infoName, infoType); default: return nullptr; @@ -6378,7 +6570,7 @@ static const void * ANARI_SAMPLER_transform_name_info(ANARIDataType paramType, i static const char *extension = "KHR_SAMPLER_TRANSFORM"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 17; return &value; } default: return nullptr; @@ -6417,7 +6609,7 @@ static const void * ANARI_SAMPLER_transform_inAttribute_info(ANARIDataType param static const char *extension = "KHR_SAMPLER_TRANSFORM"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 17; return &value; } default: return nullptr; @@ -6449,7 +6641,7 @@ static const void * ANARI_SAMPLER_transform_outTransform_info(ANARIDataType para static const char *extension = "KHR_SAMPLER_TRANSFORM"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 17; return &value; } default: return nullptr; @@ -6481,7 +6673,7 @@ static const void * ANARI_SAMPLER_transform_outOffset_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_TRANSFORM"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 17; return &value; } default: return nullptr; @@ -6489,13 +6681,13 @@ static const void * ANARI_SAMPLER_transform_outOffset_info(ANARIDataType paramTy } static const void * ANARI_SAMPLER_transform_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_SAMPLER_transform_name_info(paramType, infoName, infoType); - case 22: + case 26: return ANARI_SAMPLER_transform_inAttribute_info(paramType, infoName, infoType); - case 35: + case 39: return ANARI_SAMPLER_transform_outTransform_info(paramType, infoName, infoType); - case 34: + case 38: return ANARI_SAMPLER_transform_outOffset_info(paramType, infoName, infoType); default: return nullptr; @@ -6520,7 +6712,7 @@ static const void * ANARI_SPATIAL_FIELD_structuredRegular_name_info(ANARIDataTyp static const char *extension = "KHR_SPATIAL_FIELD_STRUCTURED_REGULAR"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 18; return &value; } default: return nullptr; @@ -6552,7 +6744,7 @@ static const void * ANARI_SPATIAL_FIELD_structuredRegular_data_info(ANARIDataTyp static const char *extension = "KHR_SPATIAL_FIELD_STRUCTURED_REGULAR"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 18; return &value; } default: return nullptr; @@ -6584,7 +6776,7 @@ static const void * ANARI_SPATIAL_FIELD_structuredRegular_origin_info(ANARIDataT static const char *extension = "KHR_SPATIAL_FIELD_STRUCTURED_REGULAR"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 18; return &value; } default: return nullptr; @@ -6616,7 +6808,7 @@ static const void * ANARI_SPATIAL_FIELD_structuredRegular_spacing_info(ANARIData static const char *extension = "KHR_SPATIAL_FIELD_STRUCTURED_REGULAR"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 18; return &value; } default: return nullptr; @@ -6655,7 +6847,7 @@ static const void * ANARI_SPATIAL_FIELD_structuredRegular_filter_info(ANARIDataT static const char *extension = "KHR_SPATIAL_FIELD_STRUCTURED_REGULAR"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 18; return &value; } default: return nullptr; @@ -6663,15 +6855,15 @@ static const void * ANARI_SPATIAL_FIELD_structuredRegular_filter_info(ANARIDataT } static const void * ANARI_SPATIAL_FIELD_structuredRegular_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_SPATIAL_FIELD_structuredRegular_name_info(paramType, infoName, infoType); - case 12: + case 15: return ANARI_SPATIAL_FIELD_structuredRegular_data_info(paramType, infoName, infoType); - case 33: + case 37: return ANARI_SPATIAL_FIELD_structuredRegular_origin_info(paramType, infoName, infoType); - case 48: + case 52: return ANARI_SPATIAL_FIELD_structuredRegular_spacing_info(paramType, infoName, infoType); - case 15: + case 18: return ANARI_SPATIAL_FIELD_structuredRegular_filter_info(paramType, infoName, infoType); default: return nullptr; @@ -6696,7 +6888,7 @@ static const void * ANARI_VOLUME_transferFunction1D_name_info(ANARIDataType para static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 16; + static const int32_t value = 19; return &value; } default: return nullptr; @@ -6721,7 +6913,7 @@ static const void * ANARI_VOLUME_transferFunction1D_value_info(ANARIDataType par static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 16; + static const int32_t value = 19; return &value; } default: return nullptr; @@ -6753,7 +6945,7 @@ static const void * ANARI_VOLUME_transferFunction1D_valueRange_info(ANARIDataTyp static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 16; + static const int32_t value = 19; return &value; } default: return nullptr; @@ -6785,7 +6977,7 @@ static const void * ANARI_VOLUME_transferFunction1D_color_info(ANARIDataType par static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 16; + static const int32_t value = 19; return &value; } default: return nullptr; @@ -6817,7 +7009,7 @@ static const void * ANARI_VOLUME_transferFunction1D_opacity_info(ANARIDataType p static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 16; + static const int32_t value = 19; return &value; } default: return nullptr; @@ -6849,7 +7041,7 @@ static const void * ANARI_VOLUME_transferFunction1D_unitDistance_info(ANARIDataT static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 16; + static const int32_t value = 19; return &value; } default: return nullptr; @@ -6857,17 +7049,17 @@ static const void * ANARI_VOLUME_transferFunction1D_unitDistance_info(ANARIDataT } static const void * ANARI_VOLUME_transferFunction1D_param_info(const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(param_hash(paramName)) { - case 30: + case 34: return ANARI_VOLUME_transferFunction1D_name_info(paramType, infoName, infoType); - case 55: + case 59: return ANARI_VOLUME_transferFunction1D_value_info(paramType, infoName, infoType); - case 56: + case 60: return ANARI_VOLUME_transferFunction1D_valueRange_info(paramType, infoName, infoType); - case 11: + case 14: return ANARI_VOLUME_transferFunction1D_color_info(paramType, infoName, infoType); - case 32: + case 36: return ANARI_VOLUME_transferFunction1D_opacity_info(paramType, infoName, infoType); - case 53: + case 57: return ANARI_VOLUME_transferFunction1D_unitDistance_info(paramType, infoName, infoType); default: return nullptr; @@ -6875,9 +7067,9 @@ static const void * ANARI_VOLUME_transferFunction1D_param_info(const char *param } static const void * ANARI_CAMERA_param_info(const char *subtype, const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 8: - return ANARI_CAMERA_orthographic_param_info(paramName, paramType, infoName, infoType); case 9: + return ANARI_CAMERA_orthographic_param_info(paramName, paramType, infoName, infoType); + case 10: return ANARI_CAMERA_perspective_param_info(paramName, paramType, infoName, infoType); default: return nullptr; @@ -6885,17 +7077,17 @@ static const void * ANARI_CAMERA_param_info(const char *subtype, const char *par } static const void * ANARI_GEOMETRY_param_info(const char *subtype, const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 0: - return ANARI_GEOMETRY_cone_param_info(paramName, paramType, infoName, infoType); case 1: - return ANARI_GEOMETRY_curve_param_info(paramName, paramType, infoName, infoType); + return ANARI_GEOMETRY_cone_param_info(paramName, paramType, infoName, infoType); case 2: + return ANARI_GEOMETRY_curve_param_info(paramName, paramType, infoName, infoType); + case 3: return ANARI_GEOMETRY_cylinder_param_info(paramName, paramType, infoName, infoType); - case 11: - return ANARI_GEOMETRY_quad_param_info(paramName, paramType, infoName, infoType); case 12: + return ANARI_GEOMETRY_quad_param_info(paramName, paramType, infoName, infoType); + case 13: return ANARI_GEOMETRY_sphere_param_info(paramName, paramType, infoName, infoType); - case 16: + case 17: return ANARI_GEOMETRY_triangle_param_info(paramName, paramType, infoName, infoType); default: return nullptr; @@ -6903,7 +7095,7 @@ static const void * ANARI_GEOMETRY_param_info(const char *subtype, const char *p } static const void * ANARI_INSTANCE_param_info(const char *subtype, const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 15: + case 16: return ANARI_INSTANCE_transform_param_info(paramName, paramType, infoName, infoType); default: return nullptr; @@ -6911,7 +7103,7 @@ static const void * ANARI_INSTANCE_param_info(const char *subtype, const char *p } static const void * ANARI_MATERIAL_param_info(const char *subtype, const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 7: + case 8: return ANARI_MATERIAL_matte_param_info(paramName, paramType, infoName, infoType); default: return nullptr; @@ -6919,7 +7111,7 @@ static const void * ANARI_MATERIAL_param_info(const char *subtype, const char *p } static const void * ANARI_RENDERER_param_info(const char *subtype, const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 3: + case 4: return ANARI_RENDERER_default_param_info(paramName, paramType, infoName, infoType); default: return nullptr; @@ -6927,15 +7119,15 @@ static const void * ANARI_RENDERER_param_info(const char *subtype, const char *p } static const void * ANARI_SAMPLER_param_info(const char *subtype, const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 4: - return ANARI_SAMPLER_image1D_param_info(paramName, paramType, infoName, infoType); case 5: - return ANARI_SAMPLER_image2D_param_info(paramName, paramType, infoName, infoType); + return ANARI_SAMPLER_image1D_param_info(paramName, paramType, infoName, infoType); case 6: + return ANARI_SAMPLER_image2D_param_info(paramName, paramType, infoName, infoType); + case 7: return ANARI_SAMPLER_image3D_param_info(paramName, paramType, infoName, infoType); - case 10: + case 11: return ANARI_SAMPLER_primitive_param_info(paramName, paramType, infoName, infoType); - case 15: + case 16: return ANARI_SAMPLER_transform_param_info(paramName, paramType, infoName, infoType); default: return nullptr; @@ -6943,7 +7135,7 @@ static const void * ANARI_SAMPLER_param_info(const char *subtype, const char *pa } static const void * ANARI_SPATIAL_FIELD_param_info(const char *subtype, const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 13: + case 14: return ANARI_SPATIAL_FIELD_structuredRegular_param_info(paramName, paramType, infoName, infoType); default: return nullptr; @@ -6951,7 +7143,9 @@ static const void * ANARI_SPATIAL_FIELD_param_info(const char *subtype, const ch } static const void * ANARI_VOLUME_param_info(const char *subtype, const char *paramName, ANARIDataType paramType, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 14: + case 0: + return ANARI_VOLUME__param_info(paramName, paramType, infoName, infoType); + case 15: return ANARI_VOLUME_transferFunction1D_param_info(paramName, paramType, infoName, infoType); default: return nullptr; @@ -7026,6 +7220,9 @@ static const void * ANARI_DEVICE_info(int infoName, ANARIDataType infoType) { "ANARI_KHR_INSTANCE_TRANSFORM", "ANARI_KHR_CAMERA_ORTHOGRAPHIC", "ANARI_KHR_CAMERA_PERSPECTIVE", + "ANARI_KHR_FRAME_CHANNEL_PRIMITIVE_ID", + "ANARI_KHR_FRAME_CHANNEL_OBJECT_ID", + "ANARI_KHR_FRAME_CHANNEL_INSTANCE_ID", "ANARI_KHR_GEOMETRY_CONE", "ANARI_KHR_GEOMETRY_CURVE", "ANARI_KHR_GEOMETRY_CYLINDER", @@ -7075,6 +7272,9 @@ static const void * ANARI_RENDERER_default_info(int infoName, ANARIDataType info "ANARI_KHR_INSTANCE_TRANSFORM", "ANARI_KHR_CAMERA_ORTHOGRAPHIC", "ANARI_KHR_CAMERA_PERSPECTIVE", + "ANARI_KHR_FRAME_CHANNEL_PRIMITIVE_ID", + "ANARI_KHR_FRAME_CHANNEL_OBJECT_ID", + "ANARI_KHR_FRAME_CHANNEL_INSTANCE_ID", "ANARI_KHR_GEOMETRY_CONE", "ANARI_KHR_GEOMETRY_CURVE", "ANARI_KHR_GEOMETRY_CYLINDER", @@ -7175,6 +7375,9 @@ static const void * ANARI_FRAME_info(int infoName, ANARIDataType infoType) { {"size", ANARI_UINT32_VEC2}, {"channel.color", ANARI_DATA_TYPE}, {"channel.depth", ANARI_DATA_TYPE}, + {"channel.primitiveId", ANARI_DATA_TYPE}, + {"channel.objectId", ANARI_DATA_TYPE}, + {"channel.instanceId", ANARI_DATA_TYPE}, {0, ANARI_UNKNOWN} }; return parameters; @@ -7186,6 +7389,9 @@ static const void * ANARI_FRAME_info(int infoName, ANARIDataType infoType) { static const char *channel[] = { "channel.color", "channel.depth", + "channel.primitiveId", + "channel.objectId", + "channel.instanceId", 0 }; return channel; @@ -7255,6 +7461,7 @@ static const void * ANARI_SURFACE_info(int infoName, ANARIDataType infoType) { {"name", ANARI_STRING}, {"geometry", ANARI_GEOMETRY}, {"material", ANARI_MATERIAL}, + {"id", ANARI_UINT32}, {0, ANARI_UNKNOWN} }; return parameters; @@ -7277,6 +7484,7 @@ static const void * ANARI_INSTANCE_transform_info(int infoName, ANARIDataType in {"name", ANARI_STRING}, {"transform", ANARI_FLOAT32_MAT4}, {"group", ANARI_GROUP}, + {"id", ANARI_UINT32}, {0, ANARI_UNKNOWN} }; return parameters; @@ -7372,6 +7580,31 @@ static const void * ANARI_CAMERA_perspective_info(int infoName, ANARIDataType in default: return nullptr; } } +static const void * ANARI_VOLUME__info(int infoName, ANARIDataType infoType) { + switch(infoName) { + case 9: // parameter + if(infoType == ANARI_PARAMETER_LIST) { + static const ANARIParameter parameters[] = { + {"id", ANARI_UINT32}, + {0, ANARI_UNKNOWN} + }; + return parameters; + } else { + return nullptr; + } + case 7: // sourceExtension + if(infoType == ANARI_STRING) { + static const char *extension = "KHR_FRAME_CHANNEL_OBJECT_ID"; + return extension; + } else if(infoType == ANARI_INT32) { + static const int value = 4; + return &value; + } else { + return nullptr; + } + default: return nullptr; + } +} static const void * ANARI_GEOMETRY_cone_info(int infoName, ANARIDataType infoType) { switch(infoName) { case 4: // description @@ -7410,7 +7643,7 @@ static const void * ANARI_GEOMETRY_cone_info(int infoName, ANARIDataType infoTyp static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 3; + static const int value = 6; return &value; } else { return nullptr; @@ -7455,7 +7688,7 @@ static const void * ANARI_GEOMETRY_curve_info(int infoName, ANARIDataType infoTy static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 4; + static const int value = 7; return &value; } else { return nullptr; @@ -7502,7 +7735,7 @@ static const void * ANARI_GEOMETRY_cylinder_info(int infoName, ANARIDataType inf static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 5; + static const int value = 8; return &value; } else { return nullptr; @@ -7547,7 +7780,7 @@ static const void * ANARI_GEOMETRY_quad_info(int infoName, ANARIDataType infoTyp static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 6; + static const int value = 9; return &value; } else { return nullptr; @@ -7592,7 +7825,7 @@ static const void * ANARI_GEOMETRY_sphere_info(int infoName, ANARIDataType infoT static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 7; + static const int value = 10; return &value; } else { return nullptr; @@ -7637,7 +7870,7 @@ static const void * ANARI_GEOMETRY_triangle_info(int infoName, ANARIDataType inf static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 8; + static const int value = 11; return &value; } else { return nullptr; @@ -7675,7 +7908,7 @@ static const void * ANARI_MATERIAL_matte_info(int infoName, ANARIDataType infoTy static const char *extension = "KHR_MATERIAL_MATTE"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 9; + static const int value = 12; return &value; } else { return nullptr; @@ -7713,7 +7946,7 @@ static const void * ANARI_SAMPLER_image1D_info(int infoName, ANARIDataType infoT static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 10; + static const int value = 13; return &value; } else { return nullptr; @@ -7752,7 +7985,7 @@ static const void * ANARI_SAMPLER_image2D_info(int infoName, ANARIDataType infoT static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 11; + static const int value = 14; return &value; } else { return nullptr; @@ -7792,7 +8025,7 @@ static const void * ANARI_SAMPLER_image3D_info(int infoName, ANARIDataType infoT static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 12; + static const int value = 15; return &value; } else { return nullptr; @@ -7824,7 +8057,7 @@ static const void * ANARI_SAMPLER_primitive_info(int infoName, ANARIDataType inf static const char *extension = "KHR_SAMPLER_PRIMITIVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 13; + static const int value = 16; return &value; } else { return nullptr; @@ -7857,7 +8090,7 @@ static const void * ANARI_SAMPLER_transform_info(int infoName, ANARIDataType inf static const char *extension = "KHR_SAMPLER_TRANSFORM"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 14; + static const int value = 17; return &value; } else { return nullptr; @@ -7891,7 +8124,7 @@ static const void * ANARI_SPATIAL_FIELD_structuredRegular_info(int infoName, ANA static const char *extension = "KHR_SPATIAL_FIELD_STRUCTURED_REGULAR"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 15; + static const int value = 18; return &value; } else { return nullptr; @@ -7930,7 +8163,7 @@ static const void * ANARI_VOLUME_transferFunction1D_info(int infoName, ANARIData static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 16; + static const int value = 19; return &value; } else { return nullptr; @@ -7940,9 +8173,9 @@ static const void * ANARI_VOLUME_transferFunction1D_info(int infoName, ANARIData } static const void * ANARI_CAMERA_info(const char *subtype, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 8: - return ANARI_CAMERA_orthographic_info(infoName, infoType); case 9: + return ANARI_CAMERA_orthographic_info(infoName, infoType); + case 10: return ANARI_CAMERA_perspective_info(infoName, infoType); default: return nullptr; @@ -7950,17 +8183,17 @@ static const void * ANARI_CAMERA_info(const char *subtype, int infoName, ANARIDa } static const void * ANARI_GEOMETRY_info(const char *subtype, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 0: - return ANARI_GEOMETRY_cone_info(infoName, infoType); case 1: - return ANARI_GEOMETRY_curve_info(infoName, infoType); + return ANARI_GEOMETRY_cone_info(infoName, infoType); case 2: + return ANARI_GEOMETRY_curve_info(infoName, infoType); + case 3: return ANARI_GEOMETRY_cylinder_info(infoName, infoType); - case 11: - return ANARI_GEOMETRY_quad_info(infoName, infoType); case 12: + return ANARI_GEOMETRY_quad_info(infoName, infoType); + case 13: return ANARI_GEOMETRY_sphere_info(infoName, infoType); - case 16: + case 17: return ANARI_GEOMETRY_triangle_info(infoName, infoType); default: return nullptr; @@ -7968,7 +8201,7 @@ static const void * ANARI_GEOMETRY_info(const char *subtype, int infoName, ANARI } static const void * ANARI_INSTANCE_info(const char *subtype, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 15: + case 16: return ANARI_INSTANCE_transform_info(infoName, infoType); default: return nullptr; @@ -7976,7 +8209,7 @@ static const void * ANARI_INSTANCE_info(const char *subtype, int infoName, ANARI } static const void * ANARI_MATERIAL_info(const char *subtype, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 7: + case 8: return ANARI_MATERIAL_matte_info(infoName, infoType); default: return nullptr; @@ -7984,7 +8217,7 @@ static const void * ANARI_MATERIAL_info(const char *subtype, int infoName, ANARI } static const void * ANARI_RENDERER_info(const char *subtype, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 3: + case 4: return ANARI_RENDERER_default_info(infoName, infoType); default: return nullptr; @@ -7992,15 +8225,15 @@ static const void * ANARI_RENDERER_info(const char *subtype, int infoName, ANARI } static const void * ANARI_SAMPLER_info(const char *subtype, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 4: - return ANARI_SAMPLER_image1D_info(infoName, infoType); case 5: - return ANARI_SAMPLER_image2D_info(infoName, infoType); + return ANARI_SAMPLER_image1D_info(infoName, infoType); case 6: + return ANARI_SAMPLER_image2D_info(infoName, infoType); + case 7: return ANARI_SAMPLER_image3D_info(infoName, infoType); - case 10: + case 11: return ANARI_SAMPLER_primitive_info(infoName, infoType); - case 15: + case 16: return ANARI_SAMPLER_transform_info(infoName, infoType); default: return nullptr; @@ -8008,7 +8241,7 @@ static const void * ANARI_SAMPLER_info(const char *subtype, int infoName, ANARID } static const void * ANARI_SPATIAL_FIELD_info(const char *subtype, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 13: + case 14: return ANARI_SPATIAL_FIELD_structuredRegular_info(infoName, infoType); default: return nullptr; @@ -8016,7 +8249,9 @@ static const void * ANARI_SPATIAL_FIELD_info(const char *subtype, int infoName, } static const void * ANARI_VOLUME_info(const char *subtype, int infoName, ANARIDataType infoType) { switch(subtype_hash(subtype)) { - case 14: + case 0: + return ANARI_VOLUME__info(infoName, infoType); + case 15: return ANARI_VOLUME_transferFunction1D_info(infoName, infoType); default: return nullptr; diff --git a/libs/helide/HelideDeviceQueries.h b/libs/helide/HelideDeviceQueries.h index acc59a32..3b6c7f0d 100644 --- a/libs/helide/HelideDeviceQueries.h +++ b/libs/helide/HelideDeviceQueries.h @@ -18,7 +18,7 @@ namespace helide { #define ANARI_INFO_parameter 9 #define ANARI_INFO_channel 10 #define ANARI_INFO_use 11 -const int extension_count = 17; +const int extension_count = 20; const char ** query_extensions(); const char ** query_object_types(ANARIDataType type); const ANARIParameter * query_params(ANARIDataType type, const char *subtype); diff --git a/libs/helide/frame/Frame.cpp b/libs/helide/frame/Frame.cpp index 30138a8f..2ac0a91c 100644 --- a/libs/helide/frame/Frame.cpp +++ b/libs/helide/frame/Frame.cpp @@ -103,6 +103,10 @@ void Frame::commit() m_colorType = getParam("channel.color", ANARI_UNKNOWN); m_depthType = getParam("channel.depth", ANARI_UNKNOWN); + m_primIdType = + getParam("channel.primitiveId", ANARI_UNKNOWN); + m_objIdType = getParam("channel.objectId", ANARI_UNKNOWN); + m_instIdType = getParam("channel.instanceId", ANARI_UNKNOWN); m_frameData.size = getParam("size", uint2(10)); m_frameData.invSize = 1.f / float2(m_frameData.size); @@ -114,6 +118,17 @@ void Frame::commit() m_depthBuffer.resize(m_depthType == ANARI_FLOAT32 ? numPixels : 0); m_frameChanged = true; + + m_primIdBuffer.clear(); + m_objIdBuffer.clear(); + m_instIdBuffer.clear(); + + if (m_primIdType == ANARI_UINT32) + m_primIdBuffer.resize(numPixels); + if (m_objIdType == ANARI_UINT32) + m_objIdBuffer.resize(numPixels); + if (m_instIdType == ANARI_UINT32) + m_instIdBuffer.resize(numPixels); } bool Frame::getProperty( @@ -186,12 +201,21 @@ void *Frame::map(std::string_view channel, *width = m_frameData.size.x; *height = m_frameData.size.y; - if (channel == "color" || channel == "channel.color") { + if (channel == "channel.color") { *pixelType = m_colorType; - return mapColorBuffer(); - } else if (channel == "depth" || channel == "channel.depth") { + return m_pixelBuffer.data(); + } else if (channel == "channel.depth" && !m_depthBuffer.empty()) { *pixelType = ANARI_FLOAT32; - return mapDepthBuffer(); + return m_depthBuffer.data(); + } else if (channel == "channel.primitiveId" && !m_primIdBuffer.empty()) { + *pixelType = ANARI_UINT32; + return m_primIdBuffer.data(); + } else if (channel == "channel.objectId" && !m_objIdBuffer.empty()) { + *pixelType = ANARI_UINT32; + return m_objIdBuffer.data(); + } else if (channel == "channel.instanceId" && !m_instIdBuffer.empty()) { + *pixelType = ANARI_UINT32; + return m_instIdBuffer.data(); } else { *width = 0; *height = 0; @@ -220,16 +244,6 @@ void Frame::discard() // no-op } -void *Frame::mapColorBuffer() -{ - return m_pixelBuffer.data(); -} - -void *Frame::mapDepthBuffer() -{ - return m_depthBuffer.data(); -} - bool Frame::ready() const { return is_ready(m_future); @@ -274,6 +288,12 @@ void Frame::writeSample(int x, int y, const PixelSample &s) } if (!m_depthBuffer.empty()) m_depthBuffer[idx] = s.depth; + if (!m_primIdBuffer.empty()) + m_primIdBuffer[idx] = s.primId; + if (!m_objIdBuffer.empty()) + m_objIdBuffer[idx] = s.objId; + if (!m_instIdBuffer.empty()) + m_instIdBuffer[idx] = s.instId; } } // namespace helide diff --git a/libs/helide/frame/Frame.h b/libs/helide/frame/Frame.h index a694242a..fe7337e5 100644 --- a/libs/helide/frame/Frame.h +++ b/libs/helide/frame/Frame.h @@ -40,9 +40,6 @@ struct Frame : public helium::BaseFrame int frameReady(ANARIWaitMask m) override; void discard() override; - void *mapColorBuffer(); - void *mapDepthBuffer(); - bool ready() const; void wait() const; @@ -64,9 +61,15 @@ struct Frame : public helium::BaseFrame anari::DataType m_colorType{ANARI_UNKNOWN}; anari::DataType m_depthType{ANARI_UNKNOWN}; + anari::DataType m_primIdType{ANARI_UNKNOWN}; + anari::DataType m_objIdType{ANARI_UNKNOWN}; + anari::DataType m_instIdType{ANARI_UNKNOWN}; std::vector m_pixelBuffer; std::vector m_depthBuffer; + std::vector m_primIdBuffer; + std::vector m_objIdBuffer; + std::vector m_instIdBuffer; helium::IntrusivePtr m_renderer; helium::IntrusivePtr m_camera; diff --git a/libs/helide/helide_device.json b/libs/helide/helide_device.json index 6efb36af..4fb681fa 100644 --- a/libs/helide/helide_device.json +++ b/libs/helide/helide_device.json @@ -8,6 +8,9 @@ "khr_instance_transform", "khr_camera_orthographic", "khr_camera_perspective", + "khr_frame_channel_primitive_id", + "khr_frame_channel_object_id", + "khr_frame_channel_instance_id", "khr_geometry_cone", "khr_geometry_curve", "khr_geometry_cylinder", diff --git a/libs/helide/helide_math.h b/libs/helide/helide_math.h index 3d52a00d..b9f76d0e 100644 --- a/libs/helide/helide_math.h +++ b/libs/helide/helide_math.h @@ -99,6 +99,7 @@ struct VolumeRay float3 dir; box1 t{0.f, std::numeric_limits::max()}; Volume *volume{nullptr}; + uint32_t instID{RTC_INVALID_GEOMETRY_ID}; }; constexpr float4 DEFAULT_ATTRIBUTE_VALUE(0.f, 0.f, 0.f, 1.f); diff --git a/libs/helide/renderer/Renderer.cpp b/libs/helide/renderer/Renderer.cpp index 9abff30e..85da5126 100644 --- a/libs/helide/renderer/Renderer.cpp +++ b/libs/helide/renderer/Renderer.cpp @@ -119,6 +119,8 @@ void Renderer::commit() PixelSample Renderer::renderSample( const float2 &screen, Ray ray, const World &w) const { + PixelSample retval; + // Intersect Surfaces // RTCIntersectContext context; @@ -137,9 +139,16 @@ PixelSample Renderer::renderSample( // Shade // - const float4 color = shadeRay(screen, ray, vray, w); - const float depth = hitVolume ? std::min(ray.tfar, vray.t.lower) : ray.tfar; - return {color, depth}; + retval.color = shadeRay(screen, ray, vray, w); + retval.depth = hitVolume ? std::min(ray.tfar, vray.t.lower) : ray.tfar; + if (hitGeometry || hitVolume) { + retval.primId = hitVolume ? 0 : ray.primID; + retval.objId = hitVolume ? vray.volume->id() : w.surfaceFromRay(ray)->id(); + retval.instId = hitVolume ? w.instanceFromRay(vray)->id() + : w.instanceFromRay(ray)->id(); + } + + return retval; } Renderer *Renderer::createInstance( @@ -222,8 +231,8 @@ float4 Renderer::shadeRay(const float2 &screen, break; case RenderMode::OPACITY_HEATMAP: { if (hitGeometry) { - const Instance *inst = w.instances()[ray.instID]; - const Surface *surface = inst->group()->surfaces()[ray.geomID]; + const Instance *inst = w.instanceFromRay(ray); + const Surface *surface = w.surfaceFromRay(ray); const auto n = linalg::mul(inst->xfmInvRot(), ray.Ng); const auto falloff = @@ -240,8 +249,8 @@ float4 Renderer::shadeRay(const float2 &screen, case RenderMode::DEFAULT: default: { if (hitGeometry) { - const Instance *inst = w.instances()[ray.instID]; - const Surface *surface = inst->group()->surfaces()[ray.geomID]; + const Instance *inst = w.instanceFromRay(ray); + const Surface *surface = w.surfaceFromRay(ray); const auto n = linalg::mul(inst->xfmInvRot(), ray.Ng); const auto falloff = diff --git a/libs/helide/renderer/Renderer.h b/libs/helide/renderer/Renderer.h index b318873c..c4c3e409 100644 --- a/libs/helide/renderer/Renderer.h +++ b/libs/helide/renderer/Renderer.h @@ -14,6 +14,9 @@ struct PixelSample { float4 color; float depth; + uint32_t primId{~0u}; + uint32_t objId{~0u}; + uint32_t instId{~0u}; }; enum class RenderMode diff --git a/libs/helide/scene/Instance.cpp b/libs/helide/scene/Instance.cpp index 18f391de..612c1883 100644 --- a/libs/helide/scene/Instance.cpp +++ b/libs/helide/scene/Instance.cpp @@ -20,6 +20,7 @@ Instance::~Instance() void Instance::commit() { + m_id = getParam("id", ~0u); m_xfm = getParam("transform", mat4(linalg::identity)); m_xfmInvRot = linalg::inverse(extractRotation(m_xfm)); m_group = getParamObject("group"); @@ -27,6 +28,11 @@ void Instance::commit() reportMessage(ANARI_SEVERITY_WARNING, "missing 'group' on ANARIInstance"); } +uint32_t Instance::id() const +{ + return m_id; +} + const mat4 &Instance::xfm() const { return m_xfm; diff --git a/libs/helide/scene/Instance.h b/libs/helide/scene/Instance.h index 3fe234d1..1d6d5f19 100644 --- a/libs/helide/scene/Instance.h +++ b/libs/helide/scene/Instance.h @@ -14,6 +14,8 @@ struct Instance : public Object void commit() override; + uint32_t id() const; + const mat4 &xfm() const; const mat3 &xfmInvRot() const; bool xfmIsIdentity() const; @@ -29,6 +31,7 @@ struct Instance : public Object bool isValid() const override; private: + uint32_t m_id{~0u}; mat4 m_xfm; mat3 m_xfmInvRot; helium::IntrusivePtr m_group; diff --git a/libs/helide/scene/World.cpp b/libs/helide/scene/World.cpp index df450b17..2d1f55e2 100644 --- a/libs/helide/scene/World.cpp +++ b/libs/helide/scene/World.cpp @@ -74,6 +74,8 @@ void World::commit() } else m_zeroGroup->removeParam("volume"); + m_zeroInstance->setParam("id", getParam("id", ~0u)); + m_zeroGroup->commit(); m_zeroInstance->commit(); @@ -111,8 +113,13 @@ const std::vector &World::instances() const void World::intersectVolumes(VolumeRay &ray) const { - for (auto *i : instances()) - i->group()->intersectVolumes(ray); + const auto &insts = instances(); + for (uint32_t i = 0; i < insts.size(); i++) { + const auto *inst = insts[i]; + inst->group()->intersectVolumes(ray); + if (ray.volume) + ray.instID = i; + } } RTCScene World::embreeScene() const diff --git a/libs/helide/scene/World.h b/libs/helide/scene/World.h index 8bf57ca3..953b11c4 100644 --- a/libs/helide/scene/World.h +++ b/libs/helide/scene/World.h @@ -23,6 +23,10 @@ struct World : public Object void intersectVolumes(VolumeRay &ray) const; + const Instance *instanceFromRay(const Ray &ray) const; + const Instance *instanceFromRay(const VolumeRay &ray) const; + const Surface *surfaceFromRay(const Ray &ray) const; + RTCScene embreeScene() const; void embreeSceneUpdate(); @@ -56,6 +60,24 @@ struct World : public Object RTCScene m_embreeScene{nullptr}; }; +// Inlined definitions //////////////////////////////////////////////////////// + +inline const Instance *World::instanceFromRay(const Ray &ray) const +{ + return instances()[ray.instID]; +} + +inline const Instance *World::instanceFromRay(const VolumeRay &ray) const +{ + return instances()[ray.instID]; +} + +inline const Surface *World::surfaceFromRay(const Ray &ray) const +{ + auto *inst = instanceFromRay(ray); + return inst->group()->surfaces()[ray.geomID]; +} + } // namespace helide HELIDE_ANARI_TYPEFOR_SPECIALIZATION(helide::World *, ANARI_WORLD); diff --git a/libs/helide/scene/surface/Surface.cpp b/libs/helide/scene/surface/Surface.cpp index c74ba7ff..bd0ed305 100644 --- a/libs/helide/scene/surface/Surface.cpp +++ b/libs/helide/scene/surface/Surface.cpp @@ -17,6 +17,7 @@ Surface::~Surface() void Surface::commit() { + m_id = getParam("id", ~0u); m_geometry = getParamObject("geometry"); m_material = getParamObject("material"); diff --git a/libs/helide/scene/surface/Surface.h b/libs/helide/scene/surface/Surface.h index 7560980c..ebd597a4 100644 --- a/libs/helide/scene/surface/Surface.h +++ b/libs/helide/scene/surface/Surface.h @@ -15,6 +15,7 @@ struct Surface : public Object void commit() override; + uint32_t id() const; const Geometry *geometry() const; const Material *material() const; @@ -27,12 +28,18 @@ struct Surface : public Object bool isValid() const override; private: + uint32_t m_id{~0u}; helium::IntrusivePtr m_geometry; helium::IntrusivePtr m_material; }; // Inlined definitions //////////////////////////////////////////////////////// +inline uint32_t Surface::id() const +{ + return m_id; +} + inline float Surface::adjustedAlpha(float a) const { if (!material()) diff --git a/libs/helide/scene/volume/Volume.cpp b/libs/helide/scene/volume/Volume.cpp index 3a9b58f0..a70a9ec5 100644 --- a/libs/helide/scene/volume/Volume.cpp +++ b/libs/helide/scene/volume/Volume.cpp @@ -25,6 +25,11 @@ Volume *Volume::createInstance(std::string_view subtype, HelideGlobalState *s) return (Volume *)new UnknownObject(ANARI_VOLUME, s); } +void Volume::commit() +{ + m_id = getParam("id", ~0u); +} + } // namespace helide HELIDE_ANARI_TYPEFOR_DEFINITION(helide::Volume *); diff --git a/libs/helide/scene/volume/Volume.h b/libs/helide/scene/volume/Volume.h index d7093564..187c2e19 100644 --- a/libs/helide/scene/volume/Volume.h +++ b/libs/helide/scene/volume/Volume.h @@ -12,11 +12,26 @@ struct Volume : public Object Volume(HelideGlobalState *d); virtual ~Volume(); static Volume *createInstance(std::string_view subtype, HelideGlobalState *d); + + void commit() override; + + uint32_t id() const; + virtual box3 bounds() const = 0; virtual void render( const VolumeRay &vray, float3 &outputColor, float &outputOpacity) = 0; + + private: + uint32_t m_id{~0u}; }; +// Inlined definitions //////////////////////////////////////////////////////// + +inline uint32_t Volume::id() const +{ + return m_id; +} + } // namespace helide HELIDE_ANARI_TYPEFOR_SPECIALIZATION(helide::Volume *, ANARI_VOLUME); From d4765da32c643beb3cdf8cc38c44a997f21da9ce Mon Sep 17 00:00:00 2001 From: Stefan Zellmann Date: Wed, 27 Sep 2023 21:01:40 +0200 Subject: [PATCH 11/34] Simpler serialization based on C++ types --- libs/remote_device/Buffer.h | 49 ++++++ libs/remote_device/Device.cpp | 214 ++++++++++---------------- libs/remote_device/Server.cpp | 272 +++++++++++++--------------------- 3 files changed, 235 insertions(+), 300 deletions(-) diff --git a/libs/remote_device/Buffer.h b/libs/remote_device/Buffer.h index 178b0fc6..43cdd5e5 100644 --- a/libs/remote_device/Buffer.h +++ b/libs/remote_device/Buffer.h @@ -3,13 +3,59 @@ #pragma once +// std #include +#include #include +// anari +#include namespace remote { struct Buffer : std::vector { + // trivial or POD layout read function + template + bool read(T &val) + { + size_t res = read((char *)&val, sizeof(val)); + return res == sizeof(val); + } + + // trivial or POD layout write function + template + bool write(const T &val) + { + size_t res = write((const char *)&val, sizeof(val)); + return res == sizeof(val); + } + + // read std::string + bool read(std::string &val) + { + uint64_t strLen = 0; + read((char *)&strLen, sizeof(strLen)); + std::vector bytesToString(strLen); + size_t res = read(bytesToString.data(), bytesToString.size()); + if (res == strLen) { + val = std::string(bytesToString.data(), bytesToString.size()); + return true; + } else { + return false; + } + } + + // write std::string + bool write(const std::string &val) + { + uint64_t strLen = val.size(); + if (!write(strLen)) + return false; + size_t res = write(val.data(), val.size()); + return res == strLen; + } + + // low-level read function size_t read(char *ptr, size_t numBytes) { if (pos + numBytes > size()) @@ -22,6 +68,7 @@ struct Buffer : std::vector return numBytes; } + // low-level read function size_t write(const char *ptr, size_t numBytes) { if (pos + numBytes >= size()) { @@ -39,11 +86,13 @@ struct Buffer : std::vector return numBytes; } + // check if we moved past the end bool eof() const { return pos == size(); } + // jump to position void seek(size_t p) { pos = p; diff --git a/libs/remote_device/Device.cpp b/libs/remote_device/Device.cpp index cb34ec42..d307dfe1 100644 --- a/libs/remote_device/Device.cpp +++ b/libs/remote_device/Device.cpp @@ -151,8 +151,8 @@ ANARIArray3D Device::newArray3D(const void *appMemory, void *Device::mapArray(ANARIArray array) { auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&array, sizeof(array)); + buf->write(remoteDevice); + buf->write(array); write(MessageType::MapArray, buf); std::unique_lock l(syncMapArray.mtx); @@ -169,8 +169,8 @@ void *Device::mapArray(ANARIArray array) void Device::unmapArray(ANARIArray array) { auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&array, sizeof(array)); + buf->write(remoteDevice); + buf->write(array); uint64_t numBytes = arrays[array].value.size(); buf->write(arrays[array].value.data(), numBytes); write(MessageType::UnmapArray, buf); @@ -290,12 +290,10 @@ void Device::setParameter( } auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&object, sizeof(object)); - uint64_t nameLen = strlen(name); - buf->write((const char *)&nameLen, sizeof(nameLen)); - buf->write(name, nameLen); - buf->write((const char *)&type, sizeof(type)); + buf->write(remoteDevice); + buf->write(object); + buf->write(std::string(name)); + buf->write(type); buf->write(value.data(), value.size()); write(MessageType::SetParam, buf); @@ -311,11 +309,10 @@ void Device::unsetParameter(ANARIObject object, const char *name) } auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); + buf->write(remoteDevice); buf->write((const char *)&object, sizeof(object)); uint64_t nameLen = strlen(name); - buf->write((const char *)&nameLen, sizeof(nameLen)); - buf->write(name, nameLen); + buf->write(std::string(name)); write(MessageType::UnsetParam, buf); LOG(logging::Level::Info) @@ -330,8 +327,8 @@ void Device::unsetAllParameters(ANARIObject object) } auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&object, sizeof(object)); + buf->write(remoteDevice); + buf->write(object); write(MessageType::UnsetParam, buf); LOG(logging::Level::Info) @@ -349,13 +346,13 @@ void Device::commitParameters(ANARIObject object) == (ANARIObject)this) { // TODO: what happens if we actually assign our // pointer value via nextObjectID++ ??? :-D auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); + buf->write(remoteDevice); write( MessageType::CommitParams, buf); // one handle only: commit the device! } else { auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&object, sizeof(object)); + buf->write(remoteDevice); + buf->write(object); write(MessageType::CommitParams, buf); LOG(logging::Level::Info) << "Parameters committed on object " << object; @@ -374,8 +371,8 @@ void Device::release(ANARIObject object) frames.erase(object); auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&object, sizeof(object)); + buf->write(remoteDevice); + buf->write(object); write(MessageType::Release, buf); LOG(logging::Level::Info) << "Object released: " << object; @@ -389,8 +386,8 @@ void Device::retain(ANARIObject object) } auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&object, sizeof(object)); + buf->write(remoteDevice); + buf->write(object); write(MessageType::Retain, buf); LOG(logging::Level::Info) << "Object retained: " << object; @@ -411,14 +408,12 @@ int Device::getProperty(ANARIObject object, } auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&object, sizeof(object)); - uint64_t len = strlen(name); - buf->write((const char *)&len, sizeof(len)); - buf->write(name, len); - buf->write((const char *)&type, sizeof(type)); - buf->write((const char *)&size, sizeof(size)); - buf->write((const char *)&mask, sizeof(mask)); + buf->write(remoteDevice); + buf->write(object); + buf->write(std::string(name)); + buf->write(type); + buf->write(size); + buf->write(mask); write(MessageType::GetProperty, buf); std::unique_lock l(syncProperties.mtx); @@ -459,8 +454,8 @@ const char **Device::getObjectSubtypes(ANARIDataType objectType) } auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&objectType, sizeof(objectType)); + buf->write(remoteDevice); + buf->write(objectType); write(MessageType::GetObjectSubtypes, buf); std::unique_lock l(syncObjectSubtypes.mtx); @@ -493,15 +488,11 @@ const void *Device::getObjectInfo(ANARIDataType objectType, } auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&objectType, sizeof(objectType)); - uint64_t len = strlen(objectSubtype); - buf->write((const char *)&len, sizeof(len)); - buf->write(objectSubtype, len); - len = strlen(infoName); - buf->write((const char *)&len, sizeof(len)); - buf->write(infoName, len); - buf->write((const char *)&infoType, sizeof(infoType)); + buf->write(remoteDevice); + buf->write(objectType); + buf->write(std::string(objectSubtype)); + buf->write(std::string(infoName)); + buf->write(infoType); write(MessageType::GetObjectInfo, buf); std::unique_lock l(syncObjectInfo.mtx); @@ -549,19 +540,13 @@ const void *Device::getParameterInfo(ANARIDataType objectType, } auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&objectType, sizeof(objectType)); - uint64_t len = strlen(objectSubtype); - buf->write((const char *)&len, sizeof(len)); - buf->write(objectSubtype, len); - len = strlen(parameterName); - buf->write((const char *)&len, sizeof(len)); - buf->write(parameterName, len); - buf->write((const char *)¶meterType, sizeof(parameterType)); - len = strlen(infoName); - buf->write((const char *)&len, sizeof(len)); - buf->write(infoName, len); - buf->write((const char *)&infoType, sizeof(infoType)); + buf->write(remoteDevice); + buf->write(objectType); + buf->write(std::string(objectSubtype)); + buf->write(std::string(parameterName)); + buf->write(parameterType); + buf->write(std::string(infoName)); + buf->write(infoType); write(MessageType::GetParameterInfo, buf); std::unique_lock l(syncParameterInfo.mtx); @@ -674,8 +659,8 @@ void Device::renderFrame(ANARIFrame frame) l.unlock(); auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&frame, sizeof(frame)); + buf->write(remoteDevice); + buf->write(frame); write(MessageType::RenderFrame, buf); frm.state = Frame::Render; } @@ -696,9 +681,9 @@ int Device::frameReady(ANARIFrame frame, ANARIWaitMask m) if (frm.state == Frame::Render) { auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&frame, sizeof(frame)); - buf->write((const char *)&m, sizeof(m)); + buf->write(remoteDevice); + buf->write(frame); + buf->write(m); write(MessageType::FrameReady, buf); if (m == ANARI_WAIT) { // TODO: mask is probably a bitmask?! // block till device ID was returned by remote @@ -785,12 +770,11 @@ ANARIObject Device::registerNewObject(ANARIDataType type, std::string subtype) auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&type, sizeof(type)); + buf->write(remoteDevice); + buf->write(type); uint64_t len = subtype.length(); - buf->write((const char *)&len, sizeof(len)); - buf->write(subtype.c_str(), subtype.length()); - buf->write((const char *)&objectID, sizeof(objectID)); + buf->write(subtype); + buf->write(objectID); write(MessageType::NewObject, buf); @@ -815,13 +799,13 @@ ANARIArray Device::registerNewArray(ANARIDataType type, memcpy(&array, &objectID, sizeof(objectID)); auto buf = std::make_shared(); - buf->write((const char *)&remoteDevice, sizeof(remoteDevice)); - buf->write((const char *)&type, sizeof(type)); - buf->write((const char *)&objectID, sizeof(objectID)); - buf->write((const char *)&elementType, sizeof(elementType)); - buf->write((const char *)&numItems1, sizeof(numItems1)); - buf->write((const char *)&numItems2, sizeof(numItems2)); - buf->write((const char *)&numItems3, sizeof(numItems3)); + buf->write(remoteDevice); + buf->write(type); + buf->write(objectID); + buf->write(elementType); + buf->write(numItems1); + buf->write(numItems2); + buf->write(numItems3); ArrayInfo info(type, elementType, numItems1, numItems2, numItems3); @@ -847,13 +831,11 @@ void Device::initClient() syncConnectionEstablished.cv.wait(l1, [this]() { return conn; }); l1.unlock(); - int32_t remoteSubtypeLength = remoteSubtype.length(); CompressionFeatures cf = getCompressionFeatures(); // request remote device to be created, send other client info along auto buf = std::make_shared(); - buf->write((const char *)&remoteSubtypeLength, sizeof(remoteSubtypeLength)); - buf->write(remoteSubtype.c_str(), remoteSubtype.length()); + buf->write(remoteSubtype); buf->write((const char *)&cf, sizeof(cf)); // write(MessageType::NewDevice, buf); // post to queue directly: write() would call initClient() recursively! @@ -996,27 +978,16 @@ void Device::handleMessage(async::connection::reason reason, buf.write(message->data(), message->size()); buf.seek(0); - ANARIObject handle; - buf.read((char *)&handle, sizeof(handle)); - - property.object = handle; - - uint64_t len; - buf.read((char *)&len, sizeof(len)); - - std::vector name(len); - buf.read(name.data(), len); - name[len] = '\0'; // TODO: check... - property.name = std::string(name.data(), name.size()); - - buf.read((char *)&property.result, sizeof(property.result)); + buf.read(property.object); + buf.read(property.name); + buf.read(property.result); if (property.type == ANARI_STRING_LIST) { // Delete old list (if exists) auto it = std::find_if(stringListProperties.begin(), stringListProperties.end(), - [name](const StringListProperty &prop) { - return prop.name == std::string(name.data()); + [this](const StringListProperty &prop) { + return prop.name == property.name; }); if (it != stringListProperties.end()) { for (size_t i = 0; i < it->value.size(); ++i) { @@ -1026,18 +997,18 @@ void Device::handleMessage(async::connection::reason reason, StringListProperty prop; - prop.object = handle; - prop.name = std::string(name.data(), name.size()); + prop.object = property.object; + prop.name = property.name; uint64_t listSize; - buf.read((char *)&listSize, sizeof(listSize)); + buf.read(listSize); prop.value.resize(listSize + 1); prop.value[listSize] = nullptr; for (uint64_t i = 0; i < listSize; ++i) { uint64_t strLen; - buf.read((char *)&strLen, sizeof(strLen)); + buf.read(strLen); prop.value[i] = new char[strLen + 1]; buf.read(prop.value[i], strLen); @@ -1066,7 +1037,7 @@ void Device::handleMessage(async::connection::reason reason, ObjectSubtypes os; - buf.read((char *)&os.objectType, sizeof(os.objectType)); + buf.read(os.objectType); while (!buf.eof()) { uint64_t strLen; @@ -1092,23 +1063,12 @@ void Device::handleMessage(async::connection::reason reason, ObjectInfo oi; - buf.read((char *)&oi.objectType, sizeof(oi.objectType)); - uint64_t len; - buf.read((char *)&len, sizeof(len)); - std::vector bytesToString(len); - buf.read(bytesToString.data(), len); - oi.objectSubtype = std::string(bytesToString.data(), len); - buf.read((char *)&len, sizeof(len)); - bytesToString.resize(len); - buf.read(bytesToString.data(), len); - oi.info.name = std::string(bytesToString.data(), len); - buf.read((char *)&oi.info.type, sizeof(oi.info.type)); + buf.read(oi.objectType); + buf.read(oi.objectSubtype); + buf.read(oi.info.name); + buf.read(oi.info.type); if (oi.info.type == ANARI_STRING) { - uint64_t strLen; - buf.read((char *)&strLen, sizeof(strLen)); - oi.info.asString.resize(strLen + 1); - buf.read(oi.info.asString.data(), strLen); - oi.info.asString[strLen] = '\0'; + buf.read(oi.info.asString); } else if (oi.info.type == ANARI_STRING_LIST) { while (!buf.eof()) { uint64_t strLen; @@ -1129,7 +1089,7 @@ void Device::handleMessage(async::connection::reason reason, name[len] = '\0'; ANARIDataType type; - buf.read((char *)&type, sizeof(type)); + buf.read(type); oi.info.asParameterList.push_back({name, type}); } oi.info.asParameterList.push_back({nullptr, 0}); @@ -1153,28 +1113,14 @@ void Device::handleMessage(async::connection::reason reason, ParameterInfo pi; - buf.read((char *)&pi.objectType, sizeof(pi.objectType)); - uint64_t len; - buf.read((char *)&len, sizeof(len)); - std::vector bytesToString(len); - buf.read(bytesToString.data(), len); - pi.objectSubtype = std::string(bytesToString.data(), len); - buf.read((char *)&len, sizeof(len)); - bytesToString.resize(len); - buf.read(bytesToString.data(), len); - pi.parameterName = std::string(bytesToString.data(), len); - buf.read((char *)&pi.parameterType, sizeof(pi.parameterType)); - buf.read((char *)&len, sizeof(len)); - bytesToString.resize(len); - buf.read(bytesToString.data(), len); - pi.info.name = std::string(bytesToString.data(), len); - buf.read((char *)&pi.info.type, sizeof(pi.info.type)); + buf.read(pi.objectType); + buf.read(pi.objectSubtype); + buf.read(pi.parameterName); + buf.read(pi.parameterType); + buf.read(pi.info.name); + buf.read(pi.info.type); if (pi.info.type == ANARI_STRING) { - uint64_t strLen; - buf.read((char *)&strLen, sizeof(strLen)); - pi.info.asString.resize(strLen + 1); - buf.read(pi.info.asString.data(), strLen); - pi.info.asString[strLen] = '\0'; + buf.read(pi.info.asString); } else if (pi.info.type == ANARI_STRING_LIST) { while (!buf.eof()) { uint64_t strLen; @@ -1195,7 +1141,7 @@ void Device::handleMessage(async::connection::reason reason, name[len] = '\0'; ANARIDataType type; - buf.read((char *)&type, sizeof(type)); + buf.read(type); pi.info.asParameterList.push_back({name, type}); } pi.info.asParameterList.push_back({nullptr, 0}); diff --git a/libs/remote_device/Server.cpp b/libs/remote_device/Server.cpp index cf3b5712..58e9bdab 100644 --- a/libs/remote_device/Server.cpp +++ b/libs/remote_device/Server.cpp @@ -373,19 +373,16 @@ struct Server buf.seek(0); ANARIDevice deviceHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); + buf.read(deviceHandle); ANARIDataType type; - buf.read((char *)&type, sizeof(type)); + buf.read(type); - uint64_t len; - buf.read((char *)&len, sizeof(len)); - std::vector st(len); - buf.read(st.data(), st.size()); - std::string subtype(st.data(), st.size()); + std::string subtype; + buf.read(subtype); uint64_t objectID; - buf.read((char *)&objectID, sizeof(objectID)); + buf.read(objectID); ANARIDevice dev = resourceManager.getDevice((uint64_t)deviceHandle); if (!dev) { @@ -411,16 +408,16 @@ struct Server buf.seek(0); ANARIDevice deviceHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); + buf.read(deviceHandle); - buf.read((char *)&info.type, sizeof(info.type)); + buf.read(info.type); uint64_t objectID; - buf.read((char *)&objectID, sizeof(objectID)); - buf.read((char *)&info.elementType, sizeof(info.elementType)); - buf.read((char *)&info.numItems1, sizeof(info.numItems1)); - buf.read((char *)&info.numItems2, sizeof(info.numItems2)); - buf.read((char *)&info.numItems3, sizeof(info.numItems3)); + buf.read(objectID); + buf.read(info.elementType); + buf.read(info.numItems1); + buf.read(info.numItems2); + buf.read(info.numItems3); ANARIDevice dev = resourceManager.getDevice((uint64_t)deviceHandle); if (!dev) { @@ -451,8 +448,8 @@ struct Server buf.seek(0); Handle deviceHandle, objectHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); - buf.read((char *)&objectHandle, sizeof(objectHandle)); + buf.read(deviceHandle); + buf.read(objectHandle); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -466,14 +463,11 @@ struct Server return; } - uint64_t nameLen; - buf.read((char *)&nameLen, sizeof(nameLen)); - - std::vector nameBuf(nameLen); - buf.read(nameBuf.data(), nameBuf.size()); + std::string name; + buf.read(name); ANARIDataType parmType; - buf.read((char *)&parmType, sizeof(parmType)); + buf.read(parmType); std::vector parmValue; if (anari::isObject(parmType)) { @@ -484,8 +478,6 @@ struct Server buf.read((char *)parmValue.data(), anari::sizeOf(parmType)); } - std::string name(nameBuf.data(), nameBuf.size()); - if (anari::isObject(parmType)) { const auto &serverObjects = resourceManager.serverObjects[(uint64_t)deviceHandle]; @@ -516,8 +508,8 @@ struct Server buf.seek(0); Handle deviceHandle, objectHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); - buf.read((char *)&objectHandle, sizeof(objectHandle)); + buf.read(deviceHandle); + buf.read(objectHandle); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -531,13 +523,8 @@ struct Server return; } - uint64_t nameLen; - buf.read((char *)&nameLen, sizeof(nameLen)); - - std::vector nameBuf(nameLen); - buf.read(nameBuf.data(), nameBuf.size()); - - std::string name(nameBuf.data(), nameBuf.size()); + std::string name; + buf.read(name); anariUnsetParameter(dev, serverObj.handle, name.c_str()); } else if (message->type() == MessageType::UnsetAllParams) { @@ -548,8 +535,8 @@ struct Server buf.seek(0); Handle deviceHandle, objectHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); - buf.read((char *)&objectHandle, sizeof(objectHandle)); + buf.read(deviceHandle); + buf.read(objectHandle); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -590,8 +577,8 @@ struct Server anariCommitParameters(dev, dev); } else { Handle deviceHandle, objectHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); - buf.read((char *)&objectHandle, sizeof(objectHandle)); + buf.read(deviceHandle); + buf.read(objectHandle); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -619,8 +606,8 @@ struct Server buf.seek(0); Handle deviceHandle, objectHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); - buf.read((char *)&objectHandle, sizeof(objectHandle)); + buf.read(deviceHandle); + buf.read(objectHandle); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -647,8 +634,8 @@ struct Server buf.seek(0); Handle deviceHandle, objectHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); - buf.read((char *)&objectHandle, sizeof(objectHandle)); + buf.read(deviceHandle); + buf.read(objectHandle); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -675,8 +662,8 @@ struct Server buf.seek(0); Handle deviceHandle, objectHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); - buf.read((char *)&objectHandle, sizeof(objectHandle)); + buf.read(deviceHandle); + buf.read(objectHandle); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -698,8 +685,8 @@ struct Server uint64_t numBytes = info.getSizeInBytes(); auto outbuf = std::make_shared(); - outbuf->write((const char *)&objectHandle, sizeof(objectHandle)); - outbuf->write((const char *)&numBytes, sizeof(numBytes)); + outbuf->write(objectHandle); + outbuf->write(numBytes); outbuf->write((const char *)ptr, numBytes); write(MessageType::ArrayMapped, outbuf); @@ -713,8 +700,8 @@ struct Server buf.seek(0); Handle deviceHandle, objectHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); - buf.read((char *)&objectHandle, sizeof(objectHandle)); + buf.read(deviceHandle); + buf.read(objectHandle); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -747,7 +734,7 @@ struct Server anariUnmapArray(dev, (ANARIArray)serverObj.handle); auto outbuf = std::make_shared(); - outbuf->write((const char *)&objectHandle, sizeof(objectHandle)); + outbuf->write(objectHandle); write(MessageType::ArrayUnmapped, outbuf); LOG(logging::Level::Info) << "Unmapped array. Handle: " << objectHandle; @@ -760,8 +747,8 @@ struct Server buf.seek(0); Handle deviceHandle, objectHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); - buf.read((char *)&objectHandle, sizeof(objectHandle)); + buf.read(deviceHandle); + buf.read(objectHandle); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -790,10 +777,10 @@ struct Server type == ANARI_UNKNOWN ? 0 : width * height * anari::sizeOf(type); if (color != nullptr && colorSize != 0) { auto outbuf = std::make_shared(); - outbuf->write((const char *)&objectHandle, sizeof(objectHandle)); - outbuf->write((const char *)&width, sizeof(width)); - outbuf->write((const char *)&height, sizeof(height)); - outbuf->write((const char *)&type, sizeof(type)); + outbuf->write(objectHandle); + outbuf->write(width); + outbuf->write(height); + outbuf->write(type); bool compressionTurboJPEG = cf.hasTurboJPEG && client.compression.hasTurboJPEG; @@ -816,8 +803,7 @@ struct Server compressedSize, options)) { uint32_t compressedSize32(compressedSize); - outbuf->write( - (const char *)&compressedSize32, sizeof(compressedSize32)); + outbuf->write(compressedSize32); outbuf->write((const char *)compressed.data(), compressedSize); LOG(logging::Level::Info) << "turbojpeg compression size: " @@ -836,10 +822,10 @@ struct Server type == ANARI_UNKNOWN ? 0 : width * height * anari::sizeOf(type); if (depth != nullptr && depthSize != 0) { auto outbuf = std::make_shared(); - outbuf->write((const char *)&objectHandle, sizeof(objectHandle)); - outbuf->write((const char *)&width, sizeof(width)); - outbuf->write((const char *)&height, sizeof(height)); - outbuf->write((const char *)&type, sizeof(type)); + outbuf->write(objectHandle); + outbuf->write(width); + outbuf->write(height); + outbuf->write(type); bool compressionSNAPPY = cf.hasSNAPPY && client.compression.hasSNAPPY; @@ -858,8 +844,7 @@ struct Server options); uint32_t compressedSize32(compressedSize); - outbuf->write( - (const char *)&compressedSize32, sizeof(compressedSize32)); + outbuf->write(compressedSize32); outbuf->write((const char *)compressed.data(), compressedSize); } else { outbuf->write(depth, depthSize); @@ -878,8 +863,8 @@ struct Server buf.seek(0); Handle deviceHandle, objectHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); - buf.read((char *)&objectHandle, sizeof(objectHandle)); + buf.read(deviceHandle); + buf.read(objectHandle); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -891,7 +876,7 @@ struct Server } ANARIWaitMask waitMask; - buf.read((char *)&waitMask, sizeof(waitMask)); + buf.read(waitMask); ANARIFrame frame = (ANARIFrame)resourceManager .getServerObject(deviceHandle, objectHandle) @@ -899,7 +884,7 @@ struct Server anariFrameReady(dev, frame, waitMask); auto outbuf = std::make_shared(); - outbuf->write((const char *)&objectHandle, sizeof(objectHandle)); + outbuf->write(objectHandle); write(MessageType::FrameIsReady, outbuf); LOG(logging::Level::Info) << "Signal frame is ready to client"; @@ -912,8 +897,8 @@ struct Server buf.seek(0); Handle deviceHandle, objectHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); - buf.read((char *)&objectHandle, sizeof(objectHandle)); + buf.read(deviceHandle); + buf.read(objectHandle); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -934,20 +919,17 @@ struct Server serverObj.type = ANARI_DEVICE; } - uint64_t len; - buf.read((char *)&len, sizeof(len)); - std::vector name(len + 1); - buf.read(name.data(), len); - name[len] = '\0'; + std::string name; + buf.read(name); ANARIDataType type; - buf.read((char *)&type, sizeof(type)); + buf.read(type); uint64_t size; - buf.read((char *)&size, sizeof(size)); + buf.read(size); ANARIWaitMask mask; - buf.read((char *)&mask, sizeof(mask)); + buf.read(mask); auto outbuf = std::make_shared(); @@ -961,10 +943,9 @@ struct Server size, mask); - outbuf->write((const char *)&objectHandle, sizeof(objectHandle)); - outbuf->write((const char *)&len, sizeof(len)); - outbuf->write(name.data(), len); - outbuf->write((const char *)&result, sizeof(result)); + outbuf->write(objectHandle); + outbuf->write(name); + outbuf->write(result); uint64_t listSize = 0; auto sl = stringList; @@ -974,14 +955,12 @@ struct Server } } - outbuf->write((const char *)&listSize, sizeof(listSize)); + outbuf->write(listSize); sl = stringList; if (sl != nullptr) { while (const char *str = *sl++) { - uint64_t strLen = strlen(str); - outbuf->write((const char *)&strLen, sizeof(strLen)); - outbuf->write(str, strLen); + outbuf->write(std::string(str)); } } } else if (type == ANARI_DATA_TYPE_LIST) { @@ -993,10 +972,9 @@ struct Server int result = anariGetProperty( dev, serverObj.handle, name.data(), type, mem.data(), size, mask); - outbuf->write((const char *)&objectHandle, sizeof(objectHandle)); - outbuf->write((const char *)&len, sizeof(len)); - outbuf->write(name.data(), len); - outbuf->write((const char *)&result, sizeof(result)); + outbuf->write(objectHandle); + outbuf->write(name); + outbuf->write(result); outbuf->write((const char *)mem.data(), size); } write(MessageType::Property, outbuf); @@ -1010,10 +988,10 @@ struct Server buf.seek(0); Handle deviceHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); + buf.read(deviceHandle); ANARIDataType objectType; - buf.read((char *)&objectType, sizeof(objectType)); + buf.read(objectType); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -1025,15 +1003,13 @@ struct Server } auto outbuf = std::make_shared(); - outbuf->write((const char *)&objectType, sizeof(objectType)); + outbuf->write(objectType); const char **subtypes = anariGetObjectSubtypes(dev, objectType); if (subtypes != nullptr) { while (const char *str = *subtypes++) { - uint64_t strLen = strlen(str); - outbuf->write((const char *)&strLen, sizeof(strLen)); - outbuf->write(str, strLen); + outbuf->write(std::string(str)); } } write(MessageType::ObjectSubtypes, outbuf); @@ -1046,24 +1022,19 @@ struct Server buf.seek(0); Handle deviceHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); + buf.read(deviceHandle); ANARIDataType objectType; - buf.read((char *)&objectType, sizeof(objectType)); + buf.read(objectType); - uint64_t len; - buf.read((char *)&len, sizeof(len)); - std::vector objectSubtype(len + 1); - buf.read(objectSubtype.data(), len); - objectSubtype[len] = '\0'; + std::string objectSubtype; + buf.read(objectSubtype); - buf.read((char *)&len, sizeof(len)); - std::vector infoName(len + 1); - buf.read(infoName.data(), len); - infoName[len] = '\0'; + std::string infoName; + buf.read(infoName); ANARIDataType infoType; - buf.read((char *)&infoType, sizeof(infoType)); + buf.read(infoType); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -1075,14 +1046,10 @@ struct Server } auto outbuf = std::make_shared(); - outbuf->write((const char *)&objectType, sizeof(objectType)); - len = objectSubtype.size() - 1; - outbuf->write((const char *)&len, sizeof(len)); - outbuf->write(objectSubtype.data(), len); - len = infoName.size() - 1; - outbuf->write((const char *)&len, sizeof(len)); - outbuf->write(infoName.data(), len); - outbuf->write((const char *)&infoType, sizeof(infoType)); + outbuf->write(objectType); + outbuf->write(std::string(objectSubtype)); + outbuf->write(std::string(infoName)); + outbuf->write(infoType); const void *info = anariGetObjectInfo( dev, objectType, objectSubtype.data(), infoName.data(), infoType); @@ -1090,24 +1057,17 @@ struct Server if (info != nullptr) { if (infoType == ANARI_STRING) { auto *str = (const char *)info; - uint64_t strLen = strlen(str); - outbuf->write((const char *)&strLen, sizeof(strLen)); - outbuf->write(str, strLen); + outbuf->write(std::string(str)); } else if (infoType == ANARI_STRING_LIST) { const auto **strings = (const char **)info; while (const char *str = *strings++) { - uint64_t strLen = strlen(str); - outbuf->write((const char *)&strLen, sizeof(strLen)); - outbuf->write(str, strLen); + outbuf->write(std::string(str)); } } else if (infoType == ANARI_PARAMETER_LIST) { auto *parameter = (const ANARIParameter *)info; for (; parameter && parameter->name != nullptr; parameter++) { - uint64_t len = strlen(parameter->name); - outbuf->write((const char *)&len, sizeof(len)); - outbuf->write(parameter->name, len); - outbuf->write( - (const char *)¶meter->type, sizeof(parameter->type)); + outbuf->write(std::string(parameter->name)); + outbuf->write(parameter->type); } } else { outbuf->write((const char *)info, anari::sizeOf(infoType)); @@ -1123,32 +1083,25 @@ struct Server buf.seek(0); Handle deviceHandle; - buf.read((char *)&deviceHandle, sizeof(deviceHandle)); + buf.read(deviceHandle); ANARIDataType objectType; - buf.read((char *)&objectType, sizeof(objectType)); + buf.read(objectType); - uint64_t len; - buf.read((char *)&len, sizeof(len)); - std::vector objectSubtype(len + 1); - buf.read(objectSubtype.data(), len); - objectSubtype[len] = '\0'; + std::string objectSubtype; + buf.read(objectSubtype); - buf.read((char *)&len, sizeof(len)); - std::vector parameterName(len + 1); - buf.read(parameterName.data(), len); - parameterName[len] = '\0'; + std::string parameterName; + buf.read(parameterName); ANARIDataType parameterType; - buf.read((char *)¶meterType, sizeof(parameterType)); + buf.read(parameterType); - buf.read((char *)&len, sizeof(len)); - std::vector infoName(len + 1); - buf.read(infoName.data(), len); - infoName[len] = '\0'; + std::string infoName; + buf.read(infoName); ANARIDataType infoType; - buf.read((char *)&infoType, sizeof(infoType)); + buf.read(infoType); ANARIDevice dev = resourceManager.getDevice(deviceHandle); @@ -1160,18 +1113,12 @@ struct Server } auto outbuf = std::make_shared(); - outbuf->write((const char *)&objectType, sizeof(objectType)); - len = objectSubtype.size() - 1; - outbuf->write((const char *)&len, sizeof(len)); - outbuf->write(objectSubtype.data(), len); - len = parameterName.size() - 1; - outbuf->write((const char *)&len, sizeof(len)); - outbuf->write(parameterName.data(), len); - outbuf->write((const char *)¶meterType, sizeof(parameterType)); - len = infoName.size() - 1; - outbuf->write((const char *)&len, sizeof(len)); - outbuf->write(infoName.data(), len); - outbuf->write((const char *)&infoType, sizeof(infoType)); + outbuf->write(objectType); + outbuf->write(objectSubtype); + outbuf->write(parameterName); + outbuf->write(parameterType); + outbuf->write(infoName); + outbuf->write(infoType); const void *info = anariGetParameterInfo(dev, objectType, @@ -1184,24 +1131,17 @@ struct Server if (info != nullptr) { if (infoType == ANARI_STRING) { auto *str = (const char *)info; - uint64_t strLen = strlen(str); - outbuf->write((const char *)&strLen, sizeof(strLen)); - outbuf->write(str, strLen); + outbuf->write(std::string(str)); } else if (infoType == ANARI_STRING_LIST) { const auto **strings = (const char **)info; while (const char *str = *strings++) { - uint64_t strLen = strlen(str); - outbuf->write((const char *)&strLen, sizeof(strLen)); - outbuf->write(str, strLen); + outbuf->write(std::string(str)); } } else if (infoType == ANARI_PARAMETER_LIST) { auto *parameter = (const ANARIParameter *)info; for (; parameter && parameter->name != nullptr; parameter++) { - uint64_t len = strlen(parameter->name); - outbuf->write((const char *)&len, sizeof(len)); - outbuf->write(parameter->name, len); - outbuf->write( - (const char *)¶meter->type, sizeof(parameter->type)); + outbuf->write(std::string(parameter->name)); + outbuf->write(parameter->type); } } else { outbuf->write((const char *)info, anari::sizeOf(infoType)); From ce6fedd63b2c50e9e6d8131d6c7ae676712836a7 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Thu, 28 Sep 2023 11:58:09 -0500 Subject: [PATCH 12/34] disable tinyexr on Windows due to compile issues --- libs/anari_viewer/HDRImage.cpp | 6 ++++++ libs/anari_viewer/HDRImage.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/libs/anari_viewer/HDRImage.cpp b/libs/anari_viewer/HDRImage.cpp index 62663b31..dfa4d883 100644 --- a/libs/anari_viewer/HDRImage.cpp +++ b/libs/anari_viewer/HDRImage.cpp @@ -5,7 +5,9 @@ #define TINYEXR_IMPLEMENTATION 1 #include "external/stb_image/stb_image.h" #include "external/stb_image/stb_image_write.h" +#ifndef _WIN32 #include "external/tinyexr/tinyexr.h" +#endif #include "HDRImage.h" @@ -37,6 +39,9 @@ bool HDRImage::load(std::string fileName) stbi_image_free(imgData); return width > 0 && height > 0 && (numComponents == 3 || numComponents == 4); +#ifdef _WIN32 + } +#else } else { int w, h, n; float *imgData; @@ -56,6 +61,7 @@ bool HDRImage::load(std::string fileName) return width > 0 && height > 0 && (numComponents == 3 || numComponents == 4); } +#endif return false; } diff --git a/libs/anari_viewer/HDRImage.h b/libs/anari_viewer/HDRImage.h index a7708f85..ae37e201 100644 --- a/libs/anari_viewer/HDRImage.h +++ b/libs/anari_viewer/HDRImage.h @@ -3,6 +3,8 @@ #pragma once +// std +#include #include namespace importers { From 81deacafad729993b2127eea20b7183c10851cbe Mon Sep 17 00:00:00 2001 From: Stefan Zellmann Date: Mon, 9 Oct 2023 18:58:40 +0200 Subject: [PATCH 13/34] Cleanup and smaller fixes to the remote device (#161) * Move Buffer impl. into its own compilation unit * Move Buffer initialization into constructor * Simplify * Sanitize includes * Don't include list size in messages, for consistency * Add wrapper and serialization functions for ANARI_STRING_LIST * Consolidate synchronization points * Display "frame will wait" performance warning only once * Extend lifetime of info structs by making them shared_ptr's * Add wrapper and serialization functions for ANARI_PARAMETER_LIST * Issue a warning if compression is not supported * License headers * Info objects use AnariAny to store non-list values * Put info values in an anonymous struct * Append nullptr at the end of parameter lists * Add toString() function for message types * Use the correct message type for unsetAllParameters() --- libs/remote_device/ArrayInfo.h | 1 - libs/remote_device/Buffer.cpp | 152 ++++++++++++ libs/remote_device/Buffer.h | 83 +++---- libs/remote_device/CMakeLists.txt | 2 + libs/remote_device/Device.cpp | 366 ++++++++++++----------------- libs/remote_device/Device.h | 108 ++++----- libs/remote_device/Frame.h | 2 + libs/remote_device/ParameterList.h | 105 +++++++++ libs/remote_device/Server.cpp | 188 +++------------ libs/remote_device/StringList.h | 105 +++++++++ libs/remote_device/common.h | 64 +++++ 11 files changed, 690 insertions(+), 486 deletions(-) create mode 100644 libs/remote_device/Buffer.cpp create mode 100644 libs/remote_device/ParameterList.h create mode 100644 libs/remote_device/StringList.h diff --git a/libs/remote_device/ArrayInfo.h b/libs/remote_device/ArrayInfo.h index 2d0b48c0..a4bd971f 100644 --- a/libs/remote_device/ArrayInfo.h +++ b/libs/remote_device/ArrayInfo.h @@ -4,7 +4,6 @@ #pragma once #include -#include "Buffer.h" namespace remote { diff --git a/libs/remote_device/Buffer.cpp b/libs/remote_device/Buffer.cpp new file mode 100644 index 00000000..d489a3e2 --- /dev/null +++ b/libs/remote_device/Buffer.cpp @@ -0,0 +1,152 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#include "Buffer.h" + +namespace remote { + +Buffer::Buffer(const char *ptr, size_t numBytes) +{ + write(ptr, numBytes); + seek(0); +} + +// read overload for std::string +bool Buffer::read(std::string &val) +{ + uint64_t strLen = 0; + read((char *)&strLen, sizeof(strLen)); + std::vector bytesToString(strLen); + size_t res = read(bytesToString.data(), bytesToString.size()); + if (res == strLen) { + val = std::string(bytesToString.data(), bytesToString.size()); + return true; + } else { + return false; + } +} + +// write overload for std::string +bool Buffer::write(const std::string &val) +{ + uint64_t strLen = val.size(); + if (!write(strLen)) + return false; + size_t res = write(val.data(), val.size()); + return res == strLen; +} + +// low-level read function +size_t Buffer::read(char *ptr, size_t numBytes) +{ + if (pos + numBytes > size()) + return 0; + + memcpy(ptr, data() + pos, numBytes); + + pos += numBytes; + + return numBytes; +} + +// read overload for string lists +bool Buffer::read(StringList &val) +{ + uint64_t size = 0; + if (!read(size)) + return false; + + for (size_t i = 0; i < size; ++i) { + std::string str; + read(str); + val.push_back(str); + } + + return true; +} + +// write overload for string lists +bool Buffer::write(const StringList &val) +{ + if (!write(uint64_t(val.size()))) + return false; + + const char **strings = val.data(); + for (size_t i = 0; i < val.size(); ++i) { + std::string str; + if (strings[i] != nullptr) + str = std::string(strings[i]); + write(str); + } + + return true; +} + +// read overload for parameter lists +bool Buffer::read(ParameterList &val) +{ + uint64_t size = 0; + if (!read(size)) + return false; + + for (size_t i = 0; i < size; ++i) { + std::string name; + read(name); + + ANARIDataType type; + read(type); + + val.push_back(name, type); + } + + return true; +} + +// write overload for parameter lists +bool Buffer::write(const ParameterList &val) +{ + if (!write(uint64_t(val.size()))) + return false; + + const Parameter *params = val.data(); + for (size_t i = 0; i < val.size(); ++i) { + std::string name; + if (params[i].name != nullptr) + name = std::string(params[i].name); + write(name); + write(params[i].type); + } + + return true; +} +// low-level write function +size_t Buffer::write(const char *ptr, size_t numBytes) +{ + if (pos + numBytes >= size()) { + try { + resize(pos + numBytes); + } catch (...) { + return 0; + } + } + + memcpy(data() + pos, ptr, numBytes); + + pos += numBytes; + + return numBytes; +} + +// check if we moved past the end +bool Buffer::eof() const +{ + return pos == size(); +} + +// jump to position +void Buffer::seek(size_t p) +{ + pos = p; +} + +} // namespace remote diff --git a/libs/remote_device/Buffer.h b/libs/remote_device/Buffer.h index 43cdd5e5..56b82835 100644 --- a/libs/remote_device/Buffer.h +++ b/libs/remote_device/Buffer.h @@ -9,11 +9,22 @@ #include // anari #include +// ours +#include "ParameterList.h" +#include "StringList.h" namespace remote { struct Buffer : std::vector { + // Create empty buffer + Buffer() = default; + + // Fill buffer with data and set position to zero + // This is equivalent to creating an empty buffer + // and then calling: write(ptr, numBytes); seek(0); + Buffer(const char *ptr, size_t numBytes); + // trivial or POD layout read function template bool read(T &val) @@ -30,73 +41,35 @@ struct Buffer : std::vector return res == sizeof(val); } - // read std::string - bool read(std::string &val) - { - uint64_t strLen = 0; - read((char *)&strLen, sizeof(strLen)); - std::vector bytesToString(strLen); - size_t res = read(bytesToString.data(), bytesToString.size()); - if (res == strLen) { - val = std::string(bytesToString.data(), bytesToString.size()); - return true; - } else { - return false; - } - } + // read overload for std::string + bool read(std::string &val); - // write std::string - bool write(const std::string &val) - { - uint64_t strLen = val.size(); - if (!write(strLen)) - return false; - size_t res = write(val.data(), val.size()); - return res == strLen; - } + // write overload for std::string + bool write(const std::string &val); - // low-level read function - size_t read(char *ptr, size_t numBytes) - { - if (pos + numBytes > size()) - return 0; + // read overload for string lists + bool read(StringList &val); - memcpy(ptr, data() + pos, numBytes); + // write overload for string lists + bool write(const StringList &val); - pos += numBytes; + // read overload for parameter lists + bool read(ParameterList &val); - return numBytes; - } + // write overload for parameter lists + bool write(const ParameterList &val); // low-level read function - size_t write(const char *ptr, size_t numBytes) - { - if (pos + numBytes >= size()) { - try { - resize(pos + numBytes); - } catch (...) { - return 0; - } - } - - memcpy(data() + pos, ptr, numBytes); - - pos += numBytes; + size_t read(char *ptr, size_t numBytes); - return numBytes; - } + // low-level read function + size_t write(const char *ptr, size_t numBytes); // check if we moved past the end - bool eof() const - { - return pos == size(); - } + bool eof() const; // jump to position - void seek(size_t p) - { - pos = p; - } + void seek(size_t p); size_t pos = 0; }; diff --git a/libs/remote_device/CMakeLists.txt b/libs/remote_device/CMakeLists.txt index 01204692..2ccde8af 100644 --- a/libs/remote_device/CMakeLists.txt +++ b/libs/remote_device/CMakeLists.txt @@ -36,6 +36,7 @@ project_sources(PRIVATE async/connection_manager.cpp async/message.cpp ArrayInfo.cpp + Buffer.cpp Compression.cpp Device.cpp Frame.cpp @@ -76,6 +77,7 @@ PRIVATE async/connection_manager.cpp async/message.cpp ArrayInfo.cpp + Buffer.cpp Compression.cpp Logging.cpp Server.cpp diff --git a/libs/remote_device/Device.cpp b/libs/remote_device/Device.cpp index d307dfe1..fbaa8d1b 100644 --- a/libs/remote_device/Device.cpp +++ b/libs/remote_device/Device.cpp @@ -155,9 +155,9 @@ void *Device::mapArray(ANARIArray array) buf->write(array); write(MessageType::MapArray, buf); - std::unique_lock l(syncMapArray.mtx); + std::unique_lock l(sync[SyncPoints::MapArray].mtx); ArrayData &data = arrays[array]; - syncMapArray.cv.wait( + sync[SyncPoints::MapArray].cv.wait( l, [&]() { return (ssize_t)data.value.size() == data.bytesExpected; }); l.unlock(); @@ -175,9 +175,9 @@ void Device::unmapArray(ANARIArray array) buf->write(arrays[array].value.data(), numBytes); write(MessageType::UnmapArray, buf); - std::unique_lock l(syncMapArray.mtx); + std::unique_lock l(sync[SyncPoints::MapArray].mtx); ArrayData &data = arrays[array]; - syncMapArray.cv.wait(l, [&]() { return data.value.empty(); }); + sync[SyncPoints::MapArray].cv.wait(l, [&]() { return data.value.empty(); }); l.unlock(); arrays.erase(array); @@ -329,7 +329,7 @@ void Device::unsetAllParameters(ANARIObject object) auto buf = std::make_shared(); buf->write(remoteDevice); buf->write(object); - write(MessageType::UnsetParam, buf); + write(MessageType::UnsetAllParams, buf); LOG(logging::Level::Info) << "All parameters unset on object unset on object " << object; @@ -416,11 +416,12 @@ int Device::getProperty(ANARIObject object, buf->write(mask); write(MessageType::GetProperty, buf); - std::unique_lock l(syncProperties.mtx); + std::unique_lock l(sync[SyncPoints::Properties].mtx); property.object = nullptr; property.type = type; property.size = size; - syncProperties.cv.wait(l, [&, this]() { return property.object; }); + sync[SyncPoints::Properties].cv.wait( + l, [&, this]() { return property.object; }); if (type == ANARI_STRING_LIST) { auto it = std::find_if(stringListProperties.begin(), @@ -458,8 +459,8 @@ const char **Device::getObjectSubtypes(ANARIDataType objectType) buf->write(objectType); write(MessageType::GetObjectSubtypes, buf); - std::unique_lock l(syncObjectSubtypes.mtx); - syncObjectSubtypes.cv.wait(l, [this, &it, objectType]() { + std::unique_lock l(sync[SyncPoints::ObjectSubtypes].mtx); + sync[SyncPoints::ObjectSubtypes].cv.wait(l, [this, &it, objectType]() { it = std::find_if(objectSubtypes.begin(), objectSubtypes.end(), [&it, objectType]( @@ -477,14 +478,15 @@ const void *Device::getObjectInfo(ANARIDataType objectType, { auto it = std::find_if(objectInfos.begin(), objectInfos.end(), - [objectType, objectSubtype, infoName, infoType](const ObjectInfo &oi) { - return oi.objectType == objectType - && oi.objectSubtype == std::string(objectSubtype) - && oi.info.name == std::string(infoName) - && oi.info.type == infoType; + [objectType, objectSubtype, infoName, infoType]( + const ObjectInfo::Ptr &oi) { + return oi->objectType == objectType + && oi->objectSubtype == std::string(objectSubtype) + && oi->info.name == std::string(infoName) + && oi->info.type == infoType; }); if (it != objectInfos.end()) { - return it->info.data(); + return (*it)->info.data(); } auto buf = std::make_shared(); @@ -495,22 +497,22 @@ const void *Device::getObjectInfo(ANARIDataType objectType, buf->write(infoType); write(MessageType::GetObjectInfo, buf); - std::unique_lock l(syncObjectInfo.mtx); - syncObjectInfo.cv.wait( + std::unique_lock l(sync[SyncPoints::ObjectInfo].mtx); + sync[SyncPoints::ObjectInfo].cv.wait( l, [this, &it, objectType, objectSubtype, infoName, infoType]() { it = std::find_if(objectInfos.begin(), objectInfos.end(), [&it, objectType, objectSubtype, infoName, infoType]( - const ObjectInfo &oi) { - return oi.objectType == objectType - && oi.objectSubtype == std::string(objectSubtype) - && oi.info.name == std::string(infoName) - && oi.info.type == infoType; + const ObjectInfo::Ptr &oi) { + return oi->objectType == objectType + && oi->objectSubtype == std::string(objectSubtype) + && oi->info.name == std::string(infoName) + && oi->info.type == infoType; }); return it != objectInfos.end(); }); - return it->info.data(); + return (*it)->info.data(); } const void *Device::getParameterInfo(ANARIDataType objectType, @@ -527,16 +529,16 @@ const void *Device::getParameterInfo(ANARIDataType objectType, parameterName, parameterType, infoName, - infoType](const ParameterInfo &pi) { - return pi.objectType == objectType - && pi.objectSubtype == std::string(objectSubtype) - && pi.parameterName == std::string(parameterName) - && pi.parameterType == parameterType - && pi.info.name == std::string(infoName) - && pi.info.type == infoType; + infoType](const ParameterInfo::Ptr &pi) { + return pi->objectType == objectType + && pi->objectSubtype == std::string(objectSubtype) + && pi->parameterName == std::string(parameterName) + && pi->parameterType == parameterType + && pi->info.name == std::string(infoName) + && pi->info.type == infoType; }); if (it != parameterInfos.end()) { - return it->info.data(); + return (*it)->info.data(); } auto buf = std::make_shared(); @@ -549,8 +551,8 @@ const void *Device::getParameterInfo(ANARIDataType objectType, buf->write(infoType); write(MessageType::GetParameterInfo, buf); - std::unique_lock l(syncParameterInfo.mtx); - syncParameterInfo.cv.wait(l, + std::unique_lock l(sync[SyncPoints::ParameterInfo].mtx); + sync[SyncPoints::ParameterInfo].cv.wait(l, [this, &it, objectType, @@ -567,18 +569,18 @@ const void *Device::getParameterInfo(ANARIDataType objectType, parameterName, parameterType, infoName, - infoType](const ParameterInfo &pi) { - return pi.objectType == objectType - && pi.objectSubtype == std::string(objectSubtype) - && pi.parameterName == std::string(parameterName) - && pi.parameterType == parameterType - && pi.info.name == std::string(infoName) - && pi.info.type == infoType; + infoType](const ParameterInfo::Ptr &pi) { + return pi->objectType == objectType + && pi->objectSubtype == std::string(objectSubtype) + && pi->parameterName == std::string(parameterName) + && pi->parameterType == parameterType + && pi->info.name == std::string(infoName) + && pi->info.type == infoType; }); return it != parameterInfos.end(); }); - return it->info.data(); + return (*it)->info.data(); } //--- FrameBuffer Manipulation ------------------------ @@ -654,8 +656,9 @@ void Device::renderFrame(ANARIFrame frame) Frame &frm = frames[frame]; // block till frame was unmapped - std::unique_lock l(syncFrameIsReady.mtx); - syncFrameIsReady.cv.wait(l, [&]() { return frm.state != Frame::Mapped; }); + std::unique_lock l(sync[SyncPoints::FrameIsReady].mtx); + sync[SyncPoints::FrameIsReady].cv.wait( + l, [&]() { return frm.state != Frame::Mapped; }); l.unlock(); auto buf = std::make_shared(); @@ -667,11 +670,6 @@ void Device::renderFrame(ANARIFrame frame) int Device::frameReady(ANARIFrame frame, ANARIWaitMask m) { - if (m != ANARI_WAIT) { - LOG(logging::Level::Warning) << "Performance: anariFrameReady() will wait"; - m = ANARI_WAIT; - } - if (!frame) { LOG(logging::Level::Warning) << "Invalid object: " << __PRETTY_FUNCTION__; return 0; @@ -679,6 +677,13 @@ int Device::frameReady(ANARIFrame frame, ANARIWaitMask m) Frame &frm = frames[frame]; + if (m != ANARI_WAIT) { + if (frm.frameID == 0) + LOG(logging::Level::Warning) + << "Performance: anariFrameReady() will wait"; + m = ANARI_WAIT; + } + if (frm.state == Frame::Render) { auto buf = std::make_shared(); buf->write(remoteDevice); @@ -687,8 +692,9 @@ int Device::frameReady(ANARIFrame frame, ANARIWaitMask m) write(MessageType::FrameReady, buf); if (m == ANARI_WAIT) { // TODO: mask is probably a bitmask?! // block till device ID was returned by remote - std::unique_lock l(syncFrameIsReady.mtx); - syncFrameIsReady.cv.wait(l, [&]() { return frm.state == Frame::Ready; }); + std::unique_lock l(sync[SyncPoints::FrameIsReady].mtx); + sync[SyncPoints::FrameIsReady].cv.wait( + l, [&]() { return frm.state == Frame::Ready; }); l.unlock(); timing.afterFrameReady = getCurrentTime(); @@ -735,32 +741,7 @@ Device::Device(std::string subtype) : manager(async::make_connection_manager()) remoteSubtype = subtype; } -Device::~Device() -{ - for (size_t i = 0; i < stringListProperties.size(); ++i) { - for (size_t j = 0; j < stringListProperties[i].value.size(); ++j) { - delete[] stringListProperties[i].value[j]; - } - } - - for (size_t i = 0; i < objectSubtypes.size(); ++i) { - for (size_t j = 0; j < objectSubtypes[i].value.size(); ++j) { - delete[] objectSubtypes[i].value[j]; - } - } - - for (size_t i = 0; i < objectInfos.size(); ++i) { - for (size_t j = 0; j < objectInfos[i].info.asStringList.size(); ++j) { - delete[] objectInfos[i].info.asStringList[j]; - } - } - - for (size_t i = 0; i < parameterInfos.size(); ++i) { - for (size_t j = 0; j < parameterInfos[i].info.asStringList.size(); ++j) { - delete[] parameterInfos[i].info.asStringList[j]; - } - } -} +Device::~Device() {} ANARIObject Device::registerNewObject(ANARIDataType type, std::string subtype) { @@ -827,8 +808,9 @@ void Device::initClient() run(); // wait till server accepted connection - std::unique_lock l1(syncConnectionEstablished.mtx); - syncConnectionEstablished.cv.wait(l1, [this]() { return conn; }); + std::unique_lock l1(sync[SyncPoints::ConnectionEstablished].mtx); + sync[SyncPoints::ConnectionEstablished].cv.wait( + l1, [this]() { return conn; }); l1.unlock(); CompressionFeatures cf = getCompressionFeatures(); @@ -836,14 +818,15 @@ void Device::initClient() // request remote device to be created, send other client info along auto buf = std::make_shared(); buf->write(remoteSubtype); - buf->write((const char *)&cf, sizeof(cf)); + buf->write(cf); // write(MessageType::NewDevice, buf); // post to queue directly: write() would call initClient() recursively! queue.post(std::bind(&Device::writeImpl, this, MessageType::NewDevice, buf)); // block till device ID was returned by remote - std::unique_lock l2(syncDeviceHandleRemote.mtx); - syncDeviceHandleRemote.cv.wait(l2, [this]() { return remoteDevice; }); + std::unique_lock l2(sync[SyncPoints::DeviceHandleRemote].mtx); + sync[SyncPoints::DeviceHandleRemote].cv.wait( + l2, [this]() { return remoteDevice; }); l2.unlock(); } @@ -906,7 +889,7 @@ bool Device::handleNewConnection( std::placeholders::_3)); // Notify main thread about the connection established - syncConnectionEstablished.cv.notify_all(); + sync[SyncPoints::ConnectionEstablished].cv.notify_all(); return true; } @@ -923,7 +906,7 @@ void Device::handleMessage(async::connection::reason reason, if (reason == async::connection::Read) { if (message->type() == MessageType::DeviceHandle) { - std::unique_lock l(syncDeviceHandleRemote.mtx); + std::unique_lock l(sync[SyncPoints::DeviceHandleRemote].mtx); char *msg = message->data(); @@ -934,14 +917,14 @@ void Device::handleMessage(async::connection::reason reason, msg += sizeof(CompressionFeatures); l.unlock(); - syncDeviceHandleRemote.cv.notify_all(); + sync[SyncPoints::DeviceHandleRemote].cv.notify_all(); LOG(logging::Level::Info) << "Got remote device handle: " << remoteDevice; LOG(logging::Level::Info) << "Server has TurboJPEG: " << server.compression.hasTurboJPEG; LOG(logging::Level::Info) << "Server has SNAPPY: " << server.compression.hasSNAPPY; } else if (message->type() == MessageType::ArrayMapped) { - std::unique_lock l(syncMapArray.mtx); + std::unique_lock l(sync[SyncPoints::MapArray].mtx); char *msg = message->data(); @@ -955,65 +938,48 @@ void Device::handleMessage(async::connection::reason reason, arrays[arr].value.resize(numBytes); memcpy(arrays[arr].value.data(), msg, numBytes); l.unlock(); - syncMapArray.cv.notify_all(); + sync[SyncPoints::MapArray].cv.notify_all(); } else if (message->type() == MessageType::ArrayUnmapped) { - std::unique_lock l(syncUnmapArray.mtx); + std::unique_lock l(sync[SyncPoints::UnmapArray].mtx); char *msg = message->data(); ANARIArray arr = *(ANARIArray *)message->data(); arrays[arr].bytesExpected = -1; arrays[arr].value.resize(0); l.unlock(); - syncMapArray.cv.notify_all(); + sync[SyncPoints::MapArray].cv.notify_all(); } else if (message->type() == MessageType::FrameIsReady) { assert(message->size() == sizeof(Handle)); ANARIObject hnd = *(ANARIObject *)message->data(); Frame &frm = frames[hnd]; frm.state = Frame::Ready; - syncFrameIsReady.cv.notify_all(); + frm.frameID++; + sync[SyncPoints::FrameIsReady].cv.notify_all(); // LOG(logging::Level::Info) << "Frame state: " << frameState; } else if (message->type() == MessageType::Property) { - std::unique_lock l(syncProperties.mtx); + std::unique_lock l(sync[SyncPoints::Properties].mtx); - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); buf.read(property.object); buf.read(property.name); buf.read(property.result); if (property.type == ANARI_STRING_LIST) { - // Delete old list (if exists) + // Remove old list (if exists) auto it = std::find_if(stringListProperties.begin(), stringListProperties.end(), [this](const StringListProperty &prop) { return prop.name == property.name; }); if (it != stringListProperties.end()) { - for (size_t i = 0; i < it->value.size(); ++i) { - delete[] it->value[i]; - } + stringListProperties.erase(it); } StringListProperty prop; prop.object = property.object; prop.name = property.name; - - uint64_t listSize; - buf.read(listSize); - - prop.value.resize(listSize + 1); - prop.value[listSize] = nullptr; - - for (uint64_t i = 0; i < listSize; ++i) { - uint64_t strLen; - buf.read(strLen); - - prop.value[i] = new char[strLen + 1]; - buf.read(prop.value[i], strLen); - prop.value[i][strLen] = '\0'; - } + buf.read(prop.value); stringListProperties.push_back(prop); } else if (property.type == ANARI_DATA_TYPE_LIST) { @@ -1025,137 +991,87 @@ void Device::handleMessage(async::connection::reason reason, } l.unlock(); - syncProperties.cv.notify_all(); + sync[SyncPoints::Properties].cv.notify_all(); // LOG(logging::Level::Info) << "Property: " << property.name; } else if (message->type() == MessageType::ObjectSubtypes) { - std::unique_lock l(syncObjectSubtypes.mtx); + std::unique_lock l(sync[SyncPoints::ObjectSubtypes].mtx); - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); ObjectSubtypes os; buf.read(os.objectType); - - while (!buf.eof()) { - uint64_t strLen; - buf.read((char *)&strLen, sizeof(strLen)); - - char *subtype = new char[strLen + 1]; - buf.read(subtype, strLen); - subtype[strLen] = '\0'; - os.value.push_back(subtype); - } - os.value.push_back(nullptr); + buf.read(os.value); objectSubtypes.push_back(os); l.unlock(); - syncObjectSubtypes.cv.notify_all(); + sync[SyncPoints::ObjectSubtypes].cv.notify_all(); } else if (message->type() == MessageType::ObjectInfo) { - std::unique_lock l(syncObjectInfo.mtx); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); - - ObjectInfo oi; - - buf.read(oi.objectType); - buf.read(oi.objectSubtype); - buf.read(oi.info.name); - buf.read(oi.info.type); - if (oi.info.type == ANARI_STRING) { - buf.read(oi.info.asString); - } else if (oi.info.type == ANARI_STRING_LIST) { - while (!buf.eof()) { - uint64_t strLen; - buf.read((char *)&strLen, sizeof(strLen)); - - char *str = new char[strLen + 1]; - buf.read(str, strLen); - str[strLen] = '\0'; - oi.info.asStringList.push_back(str); - } - oi.info.asStringList.push_back(nullptr); - } else if (oi.info.type == ANARI_PARAMETER_LIST) { - while (!buf.eof()) { - uint64_t len; - buf.read((char *)&len, sizeof(len)); - char *name = new char[len + 1]; - buf.read(name, len); - name[len] = '\0'; - - ANARIDataType type; - buf.read(type); - oi.info.asParameterList.push_back({name, type}); - } - oi.info.asParameterList.push_back({nullptr, 0}); + std::unique_lock l(sync[SyncPoints::ObjectInfo].mtx); + + Buffer buf(message->data(), message->size()); + + auto oi = std::make_shared(); + + buf.read(oi->objectType); + buf.read(oi->objectSubtype); + buf.read(oi->info.name); + buf.read(oi->info.type); + if (oi->info.type == ANARI_STRING) { + std::string str; + buf.read(str); + oi->info.value.asAny = helium::AnariAny(oi->info.type, str.c_str()); + } else if (oi->info.type == ANARI_STRING_LIST) { + buf.read(oi->info.value.asStringList); + } else if (oi->info.type == ANARI_PARAMETER_LIST) { + buf.read(oi->info.value.asParameterList); } else { if (!buf.eof()) { - oi.info.asOther.resize(anari::sizeOf(oi.info.type)); - buf.read(oi.info.asOther.data(), anari::sizeOf(oi.info.type)); + std::vector bytes(anari::sizeOf(oi->info.type)); + buf.read(bytes.data(), bytes.size()); + oi->info.value.asAny = helium::AnariAny(oi->info.type, bytes.data()); } } objectInfos.push_back(oi); l.unlock(); - syncObjectInfo.cv.notify_all(); + sync[SyncPoints::ObjectInfo].cv.notify_all(); } else if (message->type() == MessageType::ParameterInfo) { - std::unique_lock l(syncParameterInfo.mtx); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); - - ParameterInfo pi; - - buf.read(pi.objectType); - buf.read(pi.objectSubtype); - buf.read(pi.parameterName); - buf.read(pi.parameterType); - buf.read(pi.info.name); - buf.read(pi.info.type); - if (pi.info.type == ANARI_STRING) { - buf.read(pi.info.asString); - } else if (pi.info.type == ANARI_STRING_LIST) { - while (!buf.eof()) { - uint64_t strLen; - buf.read((char *)&strLen, sizeof(strLen)); - - char *str = new char[strLen + 1]; - buf.read(str, strLen); - str[strLen] = '\0'; - pi.info.asStringList.push_back(str); - } - pi.info.asStringList.push_back(nullptr); - } else if (pi.info.type == ANARI_PARAMETER_LIST) { - while (!buf.eof()) { - uint64_t len; - buf.read((char *)&len, sizeof(len)); - char *name = new char[len + 1]; - buf.read(name, len); - name[len] = '\0'; - - ANARIDataType type; - buf.read(type); - pi.info.asParameterList.push_back({name, type}); - } - pi.info.asParameterList.push_back({nullptr, 0}); + std::unique_lock l(sync[SyncPoints::ParameterInfo].mtx); + + Buffer buf(message->data(), message->size()); + + auto pi = std::make_shared(); + + buf.read(pi->objectType); + buf.read(pi->objectSubtype); + buf.read(pi->parameterName); + buf.read(pi->parameterType); + buf.read(pi->info.name); + buf.read(pi->info.type); + if (pi->info.type == ANARI_STRING) { + std::string str; + buf.read(str); + pi->info.value.asAny = helium::AnariAny(pi->info.type, str.c_str()); + } else if (pi->info.type == ANARI_STRING_LIST) { + buf.read(pi->info.value.asStringList); + } else if (pi->info.type == ANARI_PARAMETER_LIST) { + buf.read(pi->info.value.asParameterList); } else { if (!buf.eof()) { - pi.info.asOther.resize(anari::sizeOf(pi.info.type)); - buf.read(pi.info.asOther.data(), anari::sizeOf(pi.info.type)); + std::vector bytes(anari::sizeOf(pi->info.type)); + buf.read(bytes.data(), bytes.size()); + pi->info.value.asAny = helium::AnariAny(pi->info.type, bytes.data()); } } parameterInfos.push_back(pi); l.unlock(); - syncParameterInfo.cv.notify_all(); + sync[SyncPoints::ParameterInfo].cv.notify_all(); } else if (message->type() == MessageType::ChannelColor || message->type() == MessageType::ChannelDepth) { size_t off = 0; @@ -1192,6 +1108,18 @@ void Device::handleMessage(async::connection::reason reason, bool compressionTurboJPEG = cf.hasTurboJPEG && server.compression.hasTurboJPEG; + if (!compressionTurboJPEG && frm.frameID == 0) { + if (cf.hasTurboJPEG) + LOG(logging::Level::Warning) + << "Performance: client supports TurboJPEG compression for colors, but server does not"; + else if (server.compression.hasTurboJPEG) + LOG(logging::Level::Warning) + << "Performance: server supports TurboJPEG compression for colors, but client does not"; + else + LOG(logging::Level::Warning) + << "Performance: neither client nor server support TurboJPEG compression for colors"; + } + if (compressionTurboJPEG && type == ANARI_UFIXED8_RGBA_SRGB) { // TODO: more formats.. uint32_t jpegSize = *(uint32_t *)(message->data() + off); @@ -1220,6 +1148,18 @@ void Device::handleMessage(async::connection::reason reason, bool compressionSNAPPY = cf.hasSNAPPY && server.compression.hasSNAPPY; + if (!compressionSNAPPY && frm.frameID == 0) { + if (cf.hasTurboJPEG) + LOG(logging::Level::Warning) + << "Performance: client supports SNAPPY compression for depths, but server does not"; + else if (server.compression.hasSNAPPY) + LOG(logging::Level::Warning) + << "Performance: server supports SNAPPY compression for depths, but client does not"; + else + LOG(logging::Level::Warning) + << "Performance: neither client nor server support SNAPPY compression for depths"; + } + if (compressionSNAPPY && type == ANARI_FLOAT32) { uint32_t snappySize = *(uint32_t *)(message->data() + off); off += sizeof(snappySize); diff --git a/libs/remote_device/Device.h b/libs/remote_device/Device.h index c643f64a..be10de9d 100644 --- a/libs/remote_device/Device.h +++ b/libs/remote_device/Device.h @@ -11,9 +11,12 @@ #include "Buffer.h" #include "Compression.h" #include "Frame.h" +#include "ParameterList.h" +#include "StringList.h" #include "async/connection.h" #include "async/connection_manager.h" #include "async/work_queue.h" +#include "utility/AnariAny.h" #include "utility/IntrusivePtr.h" #include "utility/ParameterizedObject.h" @@ -177,60 +180,31 @@ struct Device : anari::DeviceImpl, helium::ParameterizedObject async::connection_pointer conn; async::work_queue queue; - struct - { - std::mutex mtx; - std::condition_variable cv; - } syncConnectionEstablished; - - struct - { - std::mutex mtx; - std::condition_variable cv; - } syncDeviceHandleRemote; - - struct - { - std::mutex mtx; - std::condition_variable cv; - } syncMapArray; - - struct - { - std::mutex mtx; - std::condition_variable cv; - } syncUnmapArray; - - struct - { - std::mutex mtx; - std::condition_variable cv; - } syncFrameIsReady; - - struct - { - std::mutex mtx; - std::condition_variable cv; - size_t which; - } syncProperties; - - struct + struct SyncPrimitives { std::mutex mtx; std::condition_variable cv; - } syncObjectSubtypes; + }; - struct + struct SyncPoints { - std::mutex mtx; - std::condition_variable cv; - } syncObjectInfo; + enum + { + ConnectionEstablished, + DeviceHandleRemote, + MapArray, + UnmapArray, + FrameIsReady, + Properties, + ObjectSubtypes, + ObjectInfo, + ParameterInfo, + // Keep last: + Count, + }; + }; - struct - { - std::mutex mtx; - std::condition_variable cv; - } syncParameterInfo; + SyncPrimitives sync[SyncPoints::Count]; ANARIDevice remoteDevice{nullptr}; std::string remoteSubtype = "default"; @@ -253,7 +227,7 @@ struct Device : anari::DeviceImpl, helium::ParameterizedObject { ANARIObject object{nullptr}; std::string name; - std::vector value; + StringList value; }; std::vector stringListProperties; @@ -262,58 +236,56 @@ struct Device : anari::DeviceImpl, helium::ParameterizedObject struct ObjectSubtypes { ANARIDataType objectType; - std::vector value; + StringList value; }; std::vector objectSubtypes; - struct Parameter - { - char *name; - ANARIDataType type; - }; - struct Info { std::string name; ANARIDataType type; - std::string asString; - std::vector asStringList; - std::vector asParameterList; - std::vector asOther; + struct + { + helium::AnariAny asAny; + StringList asStringList; + remote::ParameterList asParameterList; + } value; const void *data() const { - if (type == ANARI_STRING) - return asString.data(); - else if (type == ANARI_STRING_LIST) - return asStringList.data(); + if (type == ANARI_STRING_LIST) + return value.asStringList.data(); else if (type == ANARI_PARAMETER_LIST) - return asParameterList.data(); + return value.asParameterList.data(); + else if (value.asAny.type() != ANARI_UNKNOWN) + return value.asAny.data(); else - return asOther.data(); + return nullptr; } }; // Cache for "object infos" struct ObjectInfo { + typedef std::shared_ptr Ptr; ANARIDataType objectType; std::string objectSubtype; std::string infoName; Info info; }; - std::vector objectInfos; + std::vector objectInfos; // Cache for "parameter infos" struct ParameterInfo { + typedef std::shared_ptr Ptr; ANARIDataType objectType; std::string objectSubtype; std::string parameterName; ANARIDataType parameterType; Info info; }; - std::vector parameterInfos; + std::vector parameterInfos; std::map frames; struct ArrayData diff --git a/libs/remote_device/Frame.h b/libs/remote_device/Frame.h index 89c0b882..92ed6f3f 100644 --- a/libs/remote_device/Frame.h +++ b/libs/remote_device/Frame.h @@ -18,6 +18,8 @@ struct Frame Mapped, }; + uint64_t frameID{0}; + void resizeColor(uint32_t width, uint32_t height, ANARIDataType type); void resizeDepth(uint32_t width, uint32_t height, ANARIDataType type); diff --git a/libs/remote_device/ParameterList.h b/libs/remote_device/ParameterList.h new file mode 100644 index 00000000..08c55927 --- /dev/null +++ b/libs/remote_device/ParameterList.h @@ -0,0 +1,105 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +namespace remote { + +struct Parameter +{ + char *name; + ANARIDataType type; +}; + +// RAII List type storing parameters that can be +// converted to {const char *, type} pairs +class ParameterList +{ + public: + ParameterList() = default; + + // initialize from list of params + // last pointer must be NULL! + ParameterList(const Parameter *parameter) + { + for (; parameter && parameter->name != nullptr; parameter++) { + this->push_back(std::string(parameter->name), parameter->type); + } + + if (parameter != nullptr) + value.push_back({nullptr, parameter->type}); + else + value.push_back({nullptr, ANARI_UNKNOWN}); + } + + ParameterList(const ParameterList &other) + { + for (size_t i = 0; i < other.value.size(); ++i) { + if (other.value[i].name == nullptr) + value.push_back({nullptr, other.value[i].type}); + else + this->push_back(std::string(other.value[i].name), other.value[i].type); + } + } + + ParameterList(ParameterList &&other) + { + value = std::move(other.value); + other.value.clear(); + } + + ~ParameterList() + { + for (size_t i = 0; i < value.size(); ++i) { + delete[] value[i].name; + } + } + + ParameterList &operator=(const ParameterList &other) + { + if (&other != this) { + for (size_t i = 0; i < other.value.size(); ++i) { + if (other.value[i].name == nullptr) + value.push_back({nullptr, other.value[i].type}); + else + this->push_back(std::string(other.value[i].name), other.value[i].type); + } + } + return *this; + } + + ParameterList &operator=(ParameterList &&other) + { + if (&other != this) { + value = std::move(other.value); + } + return *this; + } + + void push_back(std::string name, ANARIDataType type) + { + if (name.length() > 0) { + char *val = new char[name.length() + 1]; + memcpy(val, name.data(), name.length()); + val[name.length()] = '\0'; + value.push_back({val, type}); + } else { + value.push_back({nullptr, type}); + } + } + + const Parameter *data() const + { + return (const Parameter *)value.data(); + } + + size_t size() const + { + return value.size(); + } + + private: + std::vector value; +}; + +} // namespace remote diff --git a/libs/remote_device/Server.cpp b/libs/remote_device/Server.cpp index 58e9bdab..5a322a6b 100644 --- a/libs/remote_device/Server.cpp +++ b/libs/remote_device/Server.cpp @@ -6,6 +6,7 @@ #include #include #include "ArrayInfo.h" +#include "Buffer.h" #include "Compression.h" #include "Logging.h" #include "async/connection.h" @@ -331,11 +332,11 @@ struct Server return; } + LOG(logging::Level::Info) << "Message: " << toString(message->type()) + << ", message size: " << prettyBytes(message->size()); + if (reason == async::connection::Read) { if (message->type() == MessageType::NewDevice) { - LOG(logging::Level::Info) << "Message: NewDevice, message size: " - << prettyBytes(message->size()); - const char *msg = message->data(); int32_t len = *(int32_t *)msg; @@ -353,8 +354,8 @@ struct Server // return device handle and other info to client auto buf = std::make_shared(); - buf->write((char *)&deviceHandle, sizeof(deviceHandle)); - buf->write((char *)&cf, sizeof(cf)); + buf->write(deviceHandle); + buf->write(cf); write(MessageType::DeviceHandle, buf); LOG(logging::Level::Info) @@ -365,12 +366,7 @@ struct Server LOG(logging::Level::Info) << "Client has SNAPPY: " << client.compression.hasSNAPPY; } else if (message->type() == MessageType::NewObject) { - LOG(logging::Level::Info) << "Message: NewObject, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); ANARIDevice deviceHandle; buf.read(deviceHandle); @@ -399,17 +395,12 @@ struct Server << "Creating new object, objectID: " << objectID << ", ANARI handle: " << anariObj; } else if (message->type() == MessageType::NewArray) { - LOG(logging::Level::Info) << "Message: NewArray, message size: " - << prettyBytes(message->size()); - - ArrayInfo info; - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); ANARIDevice deviceHandle; buf.read(deviceHandle); + ArrayInfo info; buf.read(info.type); uint64_t objectID; @@ -440,12 +431,7 @@ struct Server << "Creating new array, objectID: " << objectID << ", ANARI handle: " << anariArr; } else if (message->type() == MessageType::SetParam) { - LOG(logging::Level::Info) << "Message: SetParam, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); Handle deviceHandle, objectHandle; buf.read(deviceHandle); @@ -500,12 +486,7 @@ struct Server << "Set param \"" << name << "\" on object: " << objectHandle; } } else if (message->type() == MessageType::UnsetParam) { - LOG(logging::Level::Info) << "Message: UnsetParam, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); Handle deviceHandle, objectHandle; buf.read(deviceHandle); @@ -528,11 +509,7 @@ struct Server anariUnsetParameter(dev, serverObj.handle, name.c_str()); } else if (message->type() == MessageType::UnsetAllParams) { - LOG(logging::Level::Info) << "Message: UnsetAllParams"; - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); Handle deviceHandle, objectHandle; buf.read(deviceHandle); @@ -553,12 +530,7 @@ struct Server anariUnsetAllParameters(dev, serverObj.handle); } else if (message->type() == MessageType::CommitParams) { - LOG(logging::Level::Info) << "Message: CommitParams, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); if (message->size() == sizeof(Handle)) { // handle only => commit params of the device itself! @@ -598,12 +570,7 @@ struct Server << "Committed object. Handle: " << objectHandle; } } else if (message->type() == MessageType::Release) { - LOG(logging::Level::Info) << "Message: Release, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); Handle deviceHandle, objectHandle; buf.read(deviceHandle); @@ -626,12 +593,7 @@ struct Server LOG(logging::Level::Info) << "Released object. Handle: " << objectHandle; } else if (message->type() == MessageType::Retain) { - LOG(logging::Level::Info) << "Message: Retain, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); Handle deviceHandle, objectHandle; buf.read(deviceHandle); @@ -654,12 +616,7 @@ struct Server LOG(logging::Level::Info) << "Retained object. Handle: " << objectHandle; } else if (message->type() == MessageType::MapArray) { - LOG(logging::Level::Info) << "Message: MapArray, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); Handle deviceHandle, objectHandle; buf.read(deviceHandle); @@ -692,12 +649,7 @@ struct Server LOG(logging::Level::Info) << "Mapped array. Handle: " << objectHandle; } else if (message->type() == MessageType::UnmapArray) { - LOG(logging::Level::Info) << "Message: UnmapArray, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); Handle deviceHandle, objectHandle; buf.read(deviceHandle); @@ -739,12 +691,7 @@ struct Server LOG(logging::Level::Info) << "Unmapped array. Handle: " << objectHandle; } else if (message->type() == MessageType::RenderFrame) { - LOG(logging::Level::Info) << "Message: RenderFrame, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); Handle deviceHandle, objectHandle; buf.read(deviceHandle); @@ -855,12 +802,7 @@ struct Server LOG(logging::Level::Info) << "Frame rendered. Object handle: " << objectHandle; } else if (message->type() == MessageType::FrameReady) { - LOG(logging::Level::Info) << "Message: FrameReady, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); Handle deviceHandle, objectHandle; buf.read(deviceHandle); @@ -889,12 +831,7 @@ struct Server LOG(logging::Level::Info) << "Signal frame is ready to client"; } else if (message->type() == MessageType::GetProperty) { - LOG(logging::Level::Info) << "Message: GetProperty, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); Handle deviceHandle, objectHandle; buf.read(deviceHandle); @@ -934,35 +871,16 @@ struct Server auto outbuf = std::make_shared(); if (type == ANARI_STRING_LIST) { - const char *const *stringList = nullptr; - int result = anariGetProperty(dev, - serverObj.handle, - name.data(), - type, - &stringList, - size, - mask); + const char *const *value = nullptr; + int result = anariGetProperty( + dev, serverObj.handle, name.data(), type, &value, size, mask); outbuf->write(objectHandle); outbuf->write(name); outbuf->write(result); - uint64_t listSize = 0; - auto sl = stringList; - if (sl != nullptr) { - while (const char *str = *sl++) { - listSize++; - } - } - - outbuf->write(listSize); - - sl = stringList; - if (sl != nullptr) { - while (const char *str = *sl++) { - outbuf->write(std::string(str)); - } - } + StringList stringList((const char **)value); + outbuf->write(stringList); } else if (type == ANARI_DATA_TYPE_LIST) { throw std::runtime_error( "getProperty with ANARI_DATA_TYPE_LIST not implemented yet!"); @@ -979,13 +897,7 @@ struct Server } write(MessageType::Property, outbuf); } else if (message->type() == MessageType::GetObjectSubtypes) { - LOG(logging::Level::Info) - << "Message: GetObjectSubtypes, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); Handle deviceHandle; buf.read(deviceHandle); @@ -1007,19 +919,12 @@ struct Server const char **subtypes = anariGetObjectSubtypes(dev, objectType); - if (subtypes != nullptr) { - while (const char *str = *subtypes++) { - outbuf->write(std::string(str)); - } - } + StringList stringList(subtypes); + outbuf->write(stringList); + write(MessageType::ObjectSubtypes, outbuf); } else if (message->type() == MessageType::GetObjectInfo) { - LOG(logging::Level::Info) << "Message: GetObjectInfo, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); Handle deviceHandle; buf.read(deviceHandle); @@ -1059,28 +964,18 @@ struct Server auto *str = (const char *)info; outbuf->write(std::string(str)); } else if (infoType == ANARI_STRING_LIST) { - const auto **strings = (const char **)info; - while (const char *str = *strings++) { - outbuf->write(std::string(str)); - } + StringList stringList((const char **)info); + outbuf->write(stringList); } else if (infoType == ANARI_PARAMETER_LIST) { - auto *parameter = (const ANARIParameter *)info; - for (; parameter && parameter->name != nullptr; parameter++) { - outbuf->write(std::string(parameter->name)); - outbuf->write(parameter->type); - } + ParameterList parameterList((const Parameter *)info); + outbuf->write(parameterList); } else { outbuf->write((const char *)info, anari::sizeOf(infoType)); } } write(MessageType::ObjectInfo, outbuf); } else if (message->type() == MessageType::GetParameterInfo) { - LOG(logging::Level::Info) << "Message: GetParameterInfo, message size: " - << prettyBytes(message->size()); - - Buffer buf; - buf.write(message->data(), message->size()); - buf.seek(0); + Buffer buf(message->data(), message->size()); Handle deviceHandle; buf.read(deviceHandle); @@ -1133,16 +1028,11 @@ struct Server auto *str = (const char *)info; outbuf->write(std::string(str)); } else if (infoType == ANARI_STRING_LIST) { - const auto **strings = (const char **)info; - while (const char *str = *strings++) { - outbuf->write(std::string(str)); - } + StringList stringList((const char **)info); + outbuf->write(stringList); } else if (infoType == ANARI_PARAMETER_LIST) { - auto *parameter = (const ANARIParameter *)info; - for (; parameter && parameter->name != nullptr; parameter++) { - outbuf->write(std::string(parameter->name)); - outbuf->write(parameter->type); - } + ParameterList parameterList((const Parameter *)info); + outbuf->write(parameterList); } else { outbuf->write((const char *)info, anari::sizeOf(infoType)); } diff --git a/libs/remote_device/StringList.h b/libs/remote_device/StringList.h new file mode 100644 index 00000000..a642e3cc --- /dev/null +++ b/libs/remote_device/StringList.h @@ -0,0 +1,105 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include + +namespace remote { + +// RAII List type compatible with the const char ** +// semantics of ANARI string lists +class StringList +{ + public: + StringList() = default; + + // initialize from list of const char * + // last pointer must be NULL! + StringList(const char **strings) + { + if (strings) { + while (auto c_str = *strings++) { + std::string str(c_str); + this->push_back(str); + } + value.push_back(nullptr); + } + } + + StringList(const StringList &other) + { + for (size_t i = 0; i < other.value.size(); ++i) { + if (other.value[i] == nullptr) + value.push_back(nullptr); + else { + std::string str(other.value[i]); + this->push_back(str); + } + } + } + + StringList(StringList &&other) + { + value = std::move(other.value); + other.value.clear(); + } + + ~StringList() + { + for (size_t i = 0; i < value.size(); ++i) { + delete[] value[i]; + } + } + + StringList &operator=(const StringList &other) + { + if (&other != this) { + for (size_t i = 0; i < other.value.size(); ++i) { + if (other.value[i] == nullptr) + value.push_back(nullptr); + else { + std::string str(other.value[i]); + this->push_back(str); + } + } + } + return *this; + } + + StringList &operator=(StringList &&other) + { + if (&other != this) { + value = std::move(other.value); + } + return *this; + } + + void push_back(std::string str) + { + if (str.length() > 0) { + char *val = new char[str.length() + 1]; + memcpy(val, str.data(), str.length()); + val[str.length()] = '\0'; + value.push_back(val); + } else { + value.push_back(nullptr); + } + } + + const char **data() const + { + return (const char **)value.data(); + } + + size_t size() const + { + return value.size(); + } + + private: + std::vector value; +}; + +} // namespace remote diff --git a/libs/remote_device/common.h b/libs/remote_device/common.h index 80154763..078c01b7 100644 --- a/libs/remote_device/common.h +++ b/libs/remote_device/common.h @@ -52,6 +52,70 @@ struct MessageType }; }; +inline const char *toString(unsigned mt) +{ + switch (mt) { + case MessageType::NewDevice: + return "NewDevice"; + case MessageType::NewObject: + return "NewObject"; + case MessageType::NewArray: + return "NewArray"; + case MessageType::DeviceHandle: + return "DeviceHandle"; + case MessageType::SetParam: + return "SetParam"; + case MessageType::UnsetParam: + return "UnsetParam"; + case MessageType::UnsetAllParams: + return "UnsetAllParams"; + case MessageType::CommitParams: + return "CommitParams"; + case MessageType::Release: + return "Release"; + case MessageType::Retain: + return "Retain"; + case MessageType::ArrayData: + return "ArrayData"; + case MessageType::MapArray: + return "MapArray"; + case MessageType::ArrayMapped: + return "ArrayMapped"; + case MessageType::UnmapArray: + return "UnmapArray"; + case MessageType::ArrayUnmapped: + return "ArrayUnmapped"; + case MessageType::RenderFrame: + return "RenderFrame"; + case MessageType::FrameReady: + return "FrameReady"; + case MessageType::FrameIsReady: + return "FrameIsReady"; + case MessageType::GetProperty: + return "GetProperty"; + case MessageType::Property: + return "Property"; + case MessageType::GetObjectSubtypes: + return "GetObjectSubtypes"; + case MessageType::ObjectSubtypes: + return "ObjectSubtypes"; + case MessageType::GetObjectInfo: + return "GetObjectInfo"; + case MessageType::ObjectInfo: + return "ObjectInfo"; + case MessageType::GetParameterInfo: + return "GetParameterInfo"; + case MessageType::ParameterInfo: + return "ParameterInfo"; + case MessageType::ChannelColor: + return "CannelColor"; + case MessageType::ChannelDepth: + return "ChannelDepth"; + default: + return "Unknown"; + } +} + typedef int64_t Handle; inline std::string prettyNumber(const size_t s) From 878fe5150140266e68a14f270d3befad4c27032f Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Tue, 10 Oct 2023 17:02:41 -0500 Subject: [PATCH 14/34] fix incorrect volume blending in helide (#162) --- libs/helide/renderer/Renderer.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/libs/helide/renderer/Renderer.cpp b/libs/helide/renderer/Renderer.cpp index 85da5126..137569df 100644 --- a/libs/helide/renderer/Renderer.cpp +++ b/libs/helide/renderer/Renderer.cpp @@ -176,6 +176,9 @@ float4 Renderer::shadeRay(const float2 &screen, float3 color(0.f, 0.f, 0.f); float opacity = 0.f; + float3 volumeColor = bgColor; + float volumeOpacity = 0.f; + float3 geometryColor(0.f, 0.f, 0.f); float geometryOpacity = hitGeometry ? 1.f : 0.f; @@ -257,23 +260,26 @@ float4 Renderer::shadeRay(const float2 &screen, std::abs(linalg::dot(-ray.dir, linalg::normalize(n))); const float4 c = surface->getSurfaceColor(ray); const float3 sc = float3(c.x, c.y, c.z) * falloff; - geometryColor = linalg::min( + volumeColor = geometryColor = linalg::min( (0.8f * sc + 0.2f * float3(c.x, c.y, c.z)) * m_ambientRadiance, float3(1.f)); } if (hitVolume) - vray.volume->render(vray, color, opacity); + vray.volume->render(vray, volumeColor, volumeOpacity); } break; } - color = linalg::min(color, float3(1.f)); + geometryColor = linalg::min(geometryColor, float3(1.f)); + volumeColor = linalg::min(volumeColor, float3(1.f)); - accumulateValue(color, geometryColor, opacity); + accumulateValue(color, volumeColor * volumeOpacity, opacity); + accumulateValue(opacity, volumeOpacity, opacity); + accumulateValue(color, geometryColor * geometryOpacity, opacity); accumulateValue(opacity, geometryOpacity, opacity); - color *= opacity; - accumulateValue(color, bgColor, opacity); + accumulateValue(color, bgColor * bgColorOpacity.w, opacity); + accumulateValue(opacity, bgColorOpacity.w, opacity); return {color, opacity}; } From 4ebc3c5c581e1a94474dfed9ab54925ccb1d94d7 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Tue, 31 Oct 2023 11:00:44 -0500 Subject: [PATCH 15/34] export targets for other libraries built by the SDK (#165) --- libs/debug_device/CMakeLists.txt | 2 ++ libs/helide/CMakeLists.txt | 2 ++ libs/remote_device/CMakeLists.txt | 2 ++ libs/sink_device/CMakeLists.txt | 2 ++ 4 files changed, 8 insertions(+) diff --git a/libs/debug_device/CMakeLists.txt b/libs/debug_device/CMakeLists.txt index 107a04f2..5cf575c8 100644 --- a/libs/debug_device/CMakeLists.txt +++ b/libs/debug_device/CMakeLists.txt @@ -32,7 +32,9 @@ project_link_libraries(PUBLIC anari helium) project_compile_definitions(PRIVATE "anari_library_debug_EXPORTS") install(TARGETS ${PROJECT_NAME} + EXPORT anari_Exports LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + NAMELINK_SKIP ) diff --git a/libs/helide/CMakeLists.txt b/libs/helide/CMakeLists.txt index 683e6be1..4c70303c 100644 --- a/libs/helide/CMakeLists.txt +++ b/libs/helide/CMakeLists.txt @@ -122,9 +122,11 @@ endif() ## Installation ## install(TARGETS ${PROJECT_NAME} + EXPORT anari_Exports LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + NAMELINK_SKIP ) install( diff --git a/libs/remote_device/CMakeLists.txt b/libs/remote_device/CMakeLists.txt index 2ccde8af..ec42f959 100644 --- a/libs/remote_device/CMakeLists.txt +++ b/libs/remote_device/CMakeLists.txt @@ -95,7 +95,9 @@ PUBLIC ## Installation ## install(TARGETS ${PROJECT_NAME} + EXPORT anari_Exports LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + NAMELINK_SKIP ) diff --git a/libs/sink_device/CMakeLists.txt b/libs/sink_device/CMakeLists.txt index eb96851c..108ca6a9 100644 --- a/libs/sink_device/CMakeLists.txt +++ b/libs/sink_device/CMakeLists.txt @@ -19,7 +19,9 @@ project_link_libraries(PRIVATE anari::helium) project_compile_definitions(PRIVATE "anari_library_sink_EXPORTS") install(TARGETS ${PROJECT_NAME} + EXPORT anari_Exports LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + NAMELINK_SKIP ) From 152f2e882a55077b9d1fb56b1af5e630b01c8b55 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Wed, 1 Nov 2023 20:16:05 -0500 Subject: [PATCH 16/34] move common helide array impl to helium (#163) * move helide Array implementation into helium * put math types/functions into its own sub-namespace to avoid ambiguities * move Array::isValid() into BaseArray * add upload hooks to helium arrays * further tweaks for downstream consumers * better const-correctness * bump version --- CMakeLists.txt | 2 +- .../include/anari/anari_cpp/ext/linalg.h | 64 ++-- libs/anari_test_scenes/anari_test_scenes.h | 12 +- .../scenes/demo/cornell_box.cpp | 16 +- .../scenes/demo/gravity_spheres_volume.cpp | 20 +- libs/anari_test_scenes/scenes/file/obj.cpp | 6 +- libs/anari_test_scenes/scenes/scene.cpp | 16 +- libs/anari_test_scenes/scenes/scene.h | 2 +- .../scenes/test/attributes.cpp | 10 +- .../scenes/test/instanced_cubes.cpp | 26 +- .../scenes/test/pbr_spheres.cpp | 8 +- .../scenes/test/random_cylinders.cpp | 4 +- .../scenes/test/random_spheres.cpp | 4 +- .../scenes/test/textured_cube.cpp | 40 +- libs/anari_viewer/Orbit.cpp | 48 +-- libs/anari_viewer/Orbit.h | 32 +- libs/anari_viewer/windows/LightsEditor.cpp | 2 +- libs/anari_viewer/windows/LightsEditor.h | 6 +- libs/anari_viewer/windows/Viewport.cpp | 32 +- libs/anari_viewer/windows/Viewport.h | 8 +- libs/helide/CMakeLists.txt | 1 - libs/helide/HelideGlobalState.h | 17 + libs/helide/Object.h | 12 +- libs/helide/array/Array1D.cpp | 73 +--- libs/helide/array/Array1D.h | 81 +---- libs/helide/array/Array2D.cpp | 36 +- libs/helide/array/Array2D.h | 29 +- libs/helide/array/Array3D.cpp | 38 +- libs/helide/array/Array3D.h | 31 +- libs/helide/array/ObjectArray.cpp | 135 +------ libs/helide/array/ObjectArray.h | 35 +- libs/helide/camera/Perspective.cpp | 2 +- libs/helide/helide_math.h | 333 +---------------- libs/helide/renderer/Renderer.cpp | 3 +- libs/helide/scene/Group.cpp | 4 +- libs/helide/scene/World.cpp | 2 +- libs/helide/scene/surface/geometry/Geometry.h | 5 +- .../spatial_field/StructuredRegularField.h | 2 +- libs/helium/BaseArray.cpp | 16 - libs/helium/BaseArray.h | 23 +- libs/helium/BaseDevice.cpp | 2 +- libs/helium/BaseGlobalDeviceState.h | 6 +- libs/helium/BaseObject.cpp | 5 + libs/helium/BaseObject.h | 4 +- libs/helium/CMakeLists.txt | 7 +- libs/{helide => helium}/array/Array.cpp | 104 ++++-- libs/{helide => helium}/array/Array.h | 82 +++-- libs/helium/array/Array1D.cpp | 88 +++++ libs/helium/array/Array1D.h | 91 +++++ libs/helium/array/Array2D.cpp | 48 +++ libs/helium/array/Array2D.h | 39 ++ libs/helium/array/Array3D.cpp | 51 +++ libs/helium/array/Array3D.h | 41 +++ libs/helium/array/ObjectArray.cpp | 147 ++++++++ libs/helium/array/ObjectArray.h | 44 +++ libs/helium/helium_math.h | 341 ++++++++++++++++++ tests/render/main.cpp | 4 +- 57 files changed, 1296 insertions(+), 1044 deletions(-) delete mode 100644 libs/helium/BaseArray.cpp rename libs/{helide => helium}/array/Array.cpp (72%) rename libs/{helide => helium}/array/Array.h (51%) create mode 100644 libs/helium/array/Array1D.cpp create mode 100644 libs/helium/array/Array1D.h create mode 100644 libs/helium/array/Array2D.cpp create mode 100644 libs/helium/array/Array2D.h create mode 100644 libs/helium/array/Array3D.cpp create mode 100644 libs/helium/array/Array3D.h create mode 100644 libs/helium/array/ObjectArray.cpp create mode 100644 libs/helium/array/ObjectArray.h create mode 100644 libs/helium/helium_math.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3aaf493e..9af815ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,7 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake) ## Establish project -project(anari VERSION 0.7.3 LANGUAGES C CXX) +project(anari VERSION 0.8.0 LANGUAGES C CXX) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) diff --git a/libs/anari/include/anari/anari_cpp/ext/linalg.h b/libs/anari/include/anari/anari_cpp/ext/linalg.h index 20a5365f..f502f25a 100644 --- a/libs/anari/include/anari/anari_cpp/ext/linalg.h +++ b/libs/anari/include/anari/anari_cpp/ext/linalg.h @@ -14,9 +14,8 @@ // Stan Melax // Dimitri Diakopoulos // -// Some features are deprecated. Define LINALG_FORWARD_COMPATIBLE to remove them. - - +// Some features are deprecated. Define LINALG_FORWARD_COMPATIBLE to remove +// them. // This is free and unencumbered software released into the public domain. // @@ -43,7 +42,7 @@ // // For more information, please refer to - +// clang-format off #pragma once #ifndef LINALG_H @@ -721,37 +720,46 @@ template linalg::mat linalg::frustum_matrix(T x0, T x1, T y0, T return {{2*n/(x1-x0),0,0,0}, {0,2*n/(y1-y0),0,0}, {-s*(x0+x1)/(x1-x0),-s*(y0+y1)/(y1-y0),s*(f+o)/(f-n),s}, {0,0,-(n+o)*f/(f-n),0}}; } -namespace anari { +// clang-format on + +namespace anari::math { using namespace linalg::aliases; using namespace linalg; +using mat3 = float3x3; using mat4 = float4x4; -ANARI_TYPEFOR_SPECIALIZATION(float2, ANARI_FLOAT32_VEC2); -ANARI_TYPEFOR_SPECIALIZATION(float3, ANARI_FLOAT32_VEC3); -ANARI_TYPEFOR_SPECIALIZATION(float4, ANARI_FLOAT32_VEC4); -ANARI_TYPEFOR_SPECIALIZATION(byte2, ANARI_UINT8_VEC2); -ANARI_TYPEFOR_SPECIALIZATION(byte3, ANARI_UINT8_VEC3); -ANARI_TYPEFOR_SPECIALIZATION(byte4, ANARI_UINT8_VEC4); -ANARI_TYPEFOR_SPECIALIZATION(int2, ANARI_INT32_VEC2); -ANARI_TYPEFOR_SPECIALIZATION(int3, ANARI_INT32_VEC3); -ANARI_TYPEFOR_SPECIALIZATION(int4, ANARI_INT32_VEC4); -ANARI_TYPEFOR_SPECIALIZATION(uint2, ANARI_UINT32_VEC2); -ANARI_TYPEFOR_SPECIALIZATION(uint3, ANARI_UINT32_VEC3); -ANARI_TYPEFOR_SPECIALIZATION(uint4, ANARI_UINT32_VEC4); -ANARI_TYPEFOR_SPECIALIZATION(mat4, ANARI_FLOAT32_MAT4); +} // namespace anari::math + +namespace anari { + +ANARI_TYPEFOR_SPECIALIZATION(math::float2, ANARI_FLOAT32_VEC2); +ANARI_TYPEFOR_SPECIALIZATION(math::float3, ANARI_FLOAT32_VEC3); +ANARI_TYPEFOR_SPECIALIZATION(math::float4, ANARI_FLOAT32_VEC4); +ANARI_TYPEFOR_SPECIALIZATION(math::byte2, ANARI_UINT8_VEC2); +ANARI_TYPEFOR_SPECIALIZATION(math::byte3, ANARI_UINT8_VEC3); +ANARI_TYPEFOR_SPECIALIZATION(math::byte4, ANARI_UINT8_VEC4); +ANARI_TYPEFOR_SPECIALIZATION(math::int2, ANARI_INT32_VEC2); +ANARI_TYPEFOR_SPECIALIZATION(math::int3, ANARI_INT32_VEC3); +ANARI_TYPEFOR_SPECIALIZATION(math::int4, ANARI_INT32_VEC4); +ANARI_TYPEFOR_SPECIALIZATION(math::uint2, ANARI_UINT32_VEC2); +ANARI_TYPEFOR_SPECIALIZATION(math::uint3, ANARI_UINT32_VEC3); +ANARI_TYPEFOR_SPECIALIZATION(math::uint4, ANARI_UINT32_VEC4); +ANARI_TYPEFOR_SPECIALIZATION(math::mat3, ANARI_FLOAT32_MAT3); +ANARI_TYPEFOR_SPECIALIZATION(math::mat4, ANARI_FLOAT32_MAT4); #ifdef ANARI_LINALG_DEFINITIONS -ANARI_TYPEFOR_DEFINITION(float2); -ANARI_TYPEFOR_DEFINITION(float3); -ANARI_TYPEFOR_DEFINITION(float4); -ANARI_TYPEFOR_DEFINITION(int2); -ANARI_TYPEFOR_DEFINITION(int3); -ANARI_TYPEFOR_DEFINITION(int4); -ANARI_TYPEFOR_DEFINITION(uint2); -ANARI_TYPEFOR_DEFINITION(uint3); -ANARI_TYPEFOR_DEFINITION(uint4); -ANARI_TYPEFOR_DEFINITION(mat4); +ANARI_TYPEFOR_DEFINITION(math::float2); +ANARI_TYPEFOR_DEFINITION(math::float3); +ANARI_TYPEFOR_DEFINITION(math::float4); +ANARI_TYPEFOR_DEFINITION(math::int2); +ANARI_TYPEFOR_DEFINITION(math::int3); +ANARI_TYPEFOR_DEFINITION(math::int4); +ANARI_TYPEFOR_DEFINITION(math::uint2); +ANARI_TYPEFOR_DEFINITION(math::uint3); +ANARI_TYPEFOR_DEFINITION(math::uint4); +ANARI_TYPEFOR_DEFINITION(math::mat3); +ANARI_TYPEFOR_DEFINITION(math::mat4); #endif inline float radians(float degrees) diff --git a/libs/anari_test_scenes/anari_test_scenes.h b/libs/anari_test_scenes/anari_test_scenes.h index f8048c05..a564c909 100644 --- a/libs/anari_test_scenes/anari_test_scenes.h +++ b/libs/anari_test_scenes/anari_test_scenes.h @@ -20,14 +20,14 @@ namespace anari { namespace scenes { using Any = helium::AnariAny; -using mat4 = anari::mat4; +using mat4 = math::mat4; struct Camera { - anari::float3 position; - anari::float3 direction; - anari::float3 at; - anari::float3 up; + math::float3 position; + math::float3 direction; + math::float3 at; + math::float3 up; }; struct ParameterInfo @@ -58,7 +58,7 @@ ParameterInfo makeParameterInfo(const char *name, const char *value, std::vector stringValues); -using Bounds = std::array; +using Bounds = std::array; struct TestScene; using SceneHandle = TestScene *; diff --git a/libs/anari_test_scenes/scenes/demo/cornell_box.cpp b/libs/anari_test_scenes/scenes/demo/cornell_box.cpp index 998e08ea..42c60b89 100644 --- a/libs/anari_test_scenes/scenes/demo/cornell_box.cpp +++ b/libs/anari_test_scenes/scenes/demo/cornell_box.cpp @@ -7,7 +7,7 @@ namespace anari { namespace scenes { // quad mesh data -static std::vector vertices = { +static std::vector vertices = { // Floor {1.00f, -1.00f, -1.00f}, {-1.00f, -1.00f, -1.00f}, @@ -94,7 +94,7 @@ static std::vector vertices = { {0.14f, -1.00f, 0.67f}, {0.71f, -1.00f, 0.49f}}; -static std::vector indices = { +static std::vector indices = { {0, 1, 2}, // Floor {0, 2, 3}, // Floor {4, 5, 6}, // Ceiling @@ -131,7 +131,7 @@ static std::vector indices = { {64, 66, 67}, // TallBox Bottom Face }; -static std::vector colors = { +static std::vector colors = { // Floor {0.725f, 0.710f, 0.68f, 1.0f}, {0.725f, 0.710f, 0.68f, 1.0f}, @@ -275,14 +275,14 @@ void CornellBox::commit() // fix this up with new check if (false/*anari::deviceImplements(d, "ANARI_KHR_AREA_LIGHTS")*/) { light = anari::newObject(d, "quad"); - anari::setParameter(d, light, "color", anari::float3(0.78f, 0.551f, 0.183f)); + anari::setParameter(d, light, "color", math::float3(0.78f, 0.551f, 0.183f)); anari::setParameter(d, light, "intensity", 47.f); - anari::setParameter(d, light, "position", anari::float3(-0.23f, 0.98f, -0.16f)); - anari::setParameter(d, light, "edge1", anari::float3(0.47f, 0.0f, 0.0f)); - anari::setParameter(d, light, "edge2", anari::float3(0.0f, 0.0f, 0.38f)); + anari::setParameter(d, light, "position", math::float3(-0.23f, 0.98f, -0.16f)); + anari::setParameter(d, light, "edge1", math::float3(0.47f, 0.0f, 0.0f)); + anari::setParameter(d, light, "edge2", math::float3(0.0f, 0.0f, 0.38f)); } else { light = anari::newObject(d, "directional"); - anari::setParameter(d, light, "direction", anari::float3(0.f, -0.5f, 1.f)); + anari::setParameter(d, light, "direction", math::float3(0.f, -0.5f, 1.f)); } anari::commitParameters(d, light); diff --git a/libs/anari_test_scenes/scenes/demo/gravity_spheres_volume.cpp b/libs/anari_test_scenes/scenes/demo/gravity_spheres_volume.cpp index 4ebadb3d..42e1d090 100644 --- a/libs/anari_test_scenes/scenes/demo/gravity_spheres_volume.cpp +++ b/libs/anari_test_scenes/scenes/demo/gravity_spheres_volume.cpp @@ -10,7 +10,7 @@ namespace scenes { struct Point { - anari::float3 center; + math::float3 center; float weight; }; @@ -37,12 +37,12 @@ static std::vector generatePoints(size_t numPoints) } static std::vector generateVoxels( - const std::vector &points, anari::int3 dims) + const std::vector &points, math::int3 dims) { // get world coordinate in [-1.f, 1.f] from logical coordinates in [0, // volumeDimension) auto logicalToWorldCoordinates = [&](int i, int j, int k) { - return anari::float3(-1.f + float(i) / float(dims.x - 1) * 2.f, + return math::float3(-1.f + float(i) / float(dims.x - 1) * 2.f, -1.f + float(j) / float(dims.y - 1) * 2.f, -1.f + float(k) / float(dims.z - 1) * 2.f); }; @@ -61,8 +61,8 @@ static std::vector generateVoxels( float value = 0.f; for (auto &p : points) { - anari::float3 pointCoordinate = logicalToWorldCoordinates(i, j, k); - const float distance = anari::length(pointCoordinate - p.center); + math::float3 pointCoordinate = logicalToWorldCoordinates(i, j, k); + const float distance = math::length(pointCoordinate - p.center); // contribution proportional to weighted inverse-square distance // (i.e. gravity) @@ -111,11 +111,11 @@ void GravityVolume::commit() const float voxelRange[2] = {0.f, 10.f}; auto points = generatePoints(numPoints); - auto voxels = generateVoxels(points, anari::int3(volumeDims)); + auto voxels = generateVoxels(points, math::int3(volumeDims)); auto field = anari::newObject(d, "structuredRegular"); - anari::setParameter(d, field, "origin", anari::float3(-1.f)); - anari::setParameter(d, field, "spacing", anari::float3(2.f / volumeDims)); + anari::setParameter(d, field, "origin", math::float3(-1.f)); + anari::setParameter(d, field, "spacing", math::float3(2.f / volumeDims)); anari::setParameterArray3D( d, field, "data", voxels.data(), volumeDims, volumeDims, volumeDims); anari::commitParameters(d, field); @@ -124,7 +124,7 @@ void GravityVolume::commit() anari::setAndReleaseParameter(d, volume, "field", field); { - std::vector colors; + std::vector colors; std::vector opacities; colors.emplace_back(0.f, 0.f, 1.f); @@ -146,7 +146,7 @@ void GravityVolume::commit() anari::commitParameters(d, volume); if (withGeometry) { - std::vector positions(numPoints); + std::vector positions(numPoints); std::transform( points.begin(), points.end(), positions.begin(), [](const Point &p) { return p.center; diff --git a/libs/anari_test_scenes/scenes/file/obj.cpp b/libs/anari_test_scenes/scenes/file/obj.cpp index eed418b3..7a28c1a2 100644 --- a/libs/anari_test_scenes/scenes/file/obj.cpp +++ b/libs/anari_test_scenes/scenes/file/obj.cpp @@ -120,7 +120,7 @@ static void loadObj( auto defaultMaterial = anari::newObject(d, "matte"); anari::setParameter( - d, defaultMaterial, "color", anari::float3(0.f, 1.f, 0.f)); + d, defaultMaterial, "color", math::float3(0.f, 1.f, 0.f)); anari::commitParameters(d, defaultMaterial); TextureCache cache; @@ -154,8 +154,8 @@ static void loadObj( auto *vertices = objdata.attrib.vertices.data(); auto *texcoords = objdata.attrib.texcoords.data(); - std::vector v; - std::vector vt; + std::vector v; + std::vector vt; for (auto &shape : objdata.shapes) { v.clear(); diff --git a/libs/anari_test_scenes/scenes/scene.cpp b/libs/anari_test_scenes/scenes/scene.cpp index ef3945cf..442d70eb 100644 --- a/libs/anari_test_scenes/scenes/scene.cpp +++ b/libs/anari_test_scenes/scenes/scene.cpp @@ -24,25 +24,25 @@ Camera TestScene::createDefaultCameraFromWorld(anari::World w) anari::getProperty(m_device, w, "bounds", bounds); - const anari::float3 bounds_size = bounds[1] - bounds[0]; - const anari::float3 bounds_center = 0.5f * (bounds[0] + bounds[1]); - const float distance = anari::length(bounds_size) * 0.8f; + const math::float3 bounds_size = bounds[1] - bounds[0]; + const math::float3 bounds_center = 0.5f * (bounds[0] + bounds[1]); + const float distance = math::length(bounds_size) * 0.8f; - const anari::float3 eye_pos = bounds_center + anari::float3(0, 0, -distance); + const math::float3 eye_pos = bounds_center + math::float3(0, 0, -distance); Camera cam; cam.position = eye_pos; - cam.direction = anari::normalize(bounds_center - eye_pos); + cam.direction = math::normalize(bounds_center - eye_pos); cam.at = bounds_center; - cam.up = anari::float3(0, 1, 0); + cam.up = math::float3(0, 1, 0); return cam; } box3 TestScene::bounds() { - box3 retval = {anari::float3(-5), anari::float3(5)}; + box3 retval = {math::float3(-5), math::float3(5)}; anari::getProperty(m_device, world(), "bounds", retval); return retval; } @@ -70,7 +70,7 @@ void TestScene::computeNextFrame() void TestScene::setDefaultLight(anari::World w) { auto light = anari::newObject(m_device, "directional"); - anari::setParameter(m_device, light, "direction", anari::float3(0, -1, 0)); + anari::setParameter(m_device, light, "direction", math::float3(0, -1, 0)); anari::setParameter(m_device, light, "irradiance", 4.f); anari::commitParameters(m_device, light); anari::setAndReleaseParameter( diff --git a/libs/anari_test_scenes/scenes/scene.h b/libs/anari_test_scenes/scenes/scene.h index f4c84558..7cb81df0 100644 --- a/libs/anari_test_scenes/scenes/scene.h +++ b/libs/anari_test_scenes/scenes/scene.h @@ -12,7 +12,7 @@ namespace anari { namespace scenes { -using box3 = std::array; // bounds_lower, bounds_upper; +using box3 = std::array; // bounds_lower, bounds_upper; struct ANARI_TEST_SCENES_INTERFACE TestScene : public helium::ParameterizedObject diff --git a/libs/anari_test_scenes/scenes/test/attributes.cpp b/libs/anari_test_scenes/scenes/test/attributes.cpp index 2fb3bb85..ab3ef815 100644 --- a/libs/anari_test_scenes/scenes/test/attributes.cpp +++ b/libs/anari_test_scenes/scenes/test/attributes.cpp @@ -577,10 +577,10 @@ void Attributes::commit() int y = i/4; auto inst = anari::newObject(d, "transform"); - auto tl = anari::translation_matrix(2.0f*anari::float3(x-3.5f, y-3.5f, 0.f)); + auto tl = math::translation_matrix(2.0f*math::float3(x-3.5f, y-3.5f, 0.f)); { // NOTE: exercise anari::setParameter with C-array type - anari::mat4 _xfm = tl; + math::mat4 _xfm = tl; float xfm[16]; std::memcpy(xfm, &_xfm, sizeof(_xfm)); anari::setParameter(d, inst, "transform", xfm); @@ -613,10 +613,10 @@ void Attributes::commit() int y = i/4; auto inst = anari::newObject(d, "transform"); - auto tl = anari::translation_matrix(2.0f*anari::float3(x+0.5f, y-3.5f, 0.f)); + auto tl = math::translation_matrix(2.0f*math::float3(x+0.5f, y-3.5f, 0.f)); { // NOTE: exercise anari::setParameter with C-array type - anari::mat4 _xfm = tl; + math::mat4 _xfm = tl; float xfm[16]; std::memcpy(xfm, &_xfm, sizeof(_xfm)); anari::setParameter(d, inst, "transform", xfm); @@ -663,7 +663,7 @@ void Attributes::commit() anari::release(d, i); auto light = anari::newObject(d, "directional"); - anari::setParameter(d, light, "direction", anari::float3(0, 0, 1)); + anari::setParameter(d, light, "direction", math::float3(0, 0, 1)); anari::setParameter(d, light, "irradiance", 1.f); anari::commitParameters(d, light); anari::setAndReleaseParameter( diff --git a/libs/anari_test_scenes/scenes/test/instanced_cubes.cpp b/libs/anari_test_scenes/scenes/test/instanced_cubes.cpp index ddee79bc..7735cb13 100644 --- a/libs/anari_test_scenes/scenes/test/instanced_cubes.cpp +++ b/libs/anari_test_scenes/scenes/test/instanced_cubes.cpp @@ -6,7 +6,7 @@ namespace anari { namespace scenes { -static std::vector vertices = { +static std::vector vertices = { // {1.f, 1.f, 1.f}, {1.f, 1.f, -1.f}, @@ -19,7 +19,7 @@ static std::vector vertices = { // }; -static std::vector indices = { +static std::vector indices = { // top {0, 1, 2}, {3, 2, 1}, @@ -41,7 +41,7 @@ static std::vector indices = { // }; -static std::vector colors = { +static std::vector colors = { // {0.f, 1.f, 0.f, 1.f}, {0.f, 1.f, 1.f, 1.f}, @@ -112,18 +112,18 @@ void InstancedCubes::commit() for (int y = 1; y < 4; y++) { for (int z = 1; z < 4; z++) { auto inst = anari::newObject(d, "transform"); - auto tl = anari::translation_matrix(4.f * anari::float3(x, y, z)); - auto rot_x = anari::rotation_matrix( - anari::rotation_quat(anari::float3(1, 0, 0), float(x))); - auto rot_y = anari::rotation_matrix( - anari::rotation_quat(anari::float3(0, 1, 0), float(y))); - auto rot_z = anari::rotation_matrix( - anari::rotation_quat(anari::float3(0, 0, 1), float(z))); + auto tl = math::translation_matrix(4.f * math::float3(x, y, z)); + auto rot_x = math::rotation_matrix( + math::rotation_quat(math::float3(1, 0, 0), float(x))); + auto rot_y = math::rotation_matrix( + math::rotation_quat(math::float3(0, 1, 0), float(y))); + auto rot_z = math::rotation_matrix( + math::rotation_quat(math::float3(0, 0, 1), float(z))); { // NOTE: exercise anari::setParameter with C-array type - // anari::mat4 _xfm = tl * rot_x * rot_y * rot_z; - anari::mat4 _xfm = anari::mul( - tl, anari::mul(rot_x, anari::mul(rot_y, rot_z))); + // math::mat4 _xfm = tl * rot_x * rot_y * rot_z; + math::mat4 _xfm = math::mul( + tl, math::mul(rot_x, math::mul(rot_y, rot_z))); float xfm[16]; std::memcpy(xfm, &_xfm, sizeof(_xfm)); anari::setParameter(d, inst, "transform", xfm); diff --git a/libs/anari_test_scenes/scenes/test/pbr_spheres.cpp b/libs/anari_test_scenes/scenes/test/pbr_spheres.cpp index 9740bb8c..27d55ab8 100644 --- a/libs/anari_test_scenes/scenes/test/pbr_spheres.cpp +++ b/libs/anari_test_scenes/scenes/test/pbr_spheres.cpp @@ -30,7 +30,7 @@ void PbrSpheres::commit() auto surface = anari::newObject(d); auto geom = anari::newObject(d, "sphere"); auto mat = anari::newObject(d, "physicallyBased"); - anari::setParameter(d, mat, "baseColor", anari::float3(1,0,0)); + anari::setParameter(d, mat, "baseColor", math::float3(1,0,0)); anari::setParameter(d, mat, "metallic", "attribute0"); anari::setParameter(d, mat, "roughness", "attribute1"); anari::commitParameters(d, mat); @@ -39,7 +39,7 @@ void PbrSpheres::commit() d, m_world, "surface", anari::newArray1D(d, &surface)); auto light = anari::newObject(d, "directional"); - anari::setParameter(d, light, "direction", anari::float3(0, 0, 1)); + anari::setParameter(d, light, "direction", math::float3(0, 0, 1)); anari::setParameter(d, light, "irradiance", 1.f); anari::commitParameters(d, light); anari::setAndReleaseParameter( @@ -51,12 +51,12 @@ void PbrSpheres::commit() anari::setParameter(d, surface, "geometry", geom); anari::setParameter(d, surface, "material", mat); - std::vector spherePositions; + std::vector spherePositions; std::vector sphereMetallic; std::vector sphereRoughness; for(int i = 0;i<10;++i) { for(int j = 0;j<10;++j) { - spherePositions.push_back(anari::float3(i, j, 0)); + spherePositions.push_back(math::float3(i, j, 0)); sphereMetallic.push_back(i/10.0f + 0.1f); sphereRoughness.push_back(j/10.0f + 0.1f); } diff --git a/libs/anari_test_scenes/scenes/test/random_cylinders.cpp b/libs/anari_test_scenes/scenes/test/random_cylinders.cpp index 441e5ece..787f7be6 100644 --- a/libs/anari_test_scenes/scenes/test/random_cylinders.cpp +++ b/libs/anari_test_scenes/scenes/test/random_cylinders.cpp @@ -69,8 +69,8 @@ void RandomCylinders::commit() rng.seed(0); std::normal_distribution vert_dist(0.5f, 0.5f); - std::vector cylinderPositions(2 * (size_t(numCylinders))); - std::vector cylinderColors(2 * (size_t(numCylinders))); + std::vector cylinderPositions(2 * (size_t(numCylinders))); + std::vector cylinderColors(2 * (size_t(numCylinders))); for (int i = 0; i < numCylinders; ++i) { auto &a = cylinderPositions[2 * i]; diff --git a/libs/anari_test_scenes/scenes/test/random_spheres.cpp b/libs/anari_test_scenes/scenes/test/random_spheres.cpp index a6ce0937..8cc8562f 100644 --- a/libs/anari_test_scenes/scenes/test/random_spheres.cpp +++ b/libs/anari_test_scenes/scenes/test/random_spheres.cpp @@ -68,8 +68,8 @@ void RandomSpheres::commit() rng.seed(0); std::normal_distribution vert_dist(0.5f, 0.5f); - std::vector spherePositions((size_t(numSpheres))); - std::vector sphereColors((size_t(numSpheres))); + std::vector spherePositions((size_t(numSpheres))); + std::vector sphereColors((size_t(numSpheres))); for (auto &s : spherePositions) { s.x = vert_dist(rng); diff --git a/libs/anari_test_scenes/scenes/test/textured_cube.cpp b/libs/anari_test_scenes/scenes/test/textured_cube.cpp index 0b49a14a..bb765537 100644 --- a/libs/anari_test_scenes/scenes/test/textured_cube.cpp +++ b/libs/anari_test_scenes/scenes/test/textured_cube.cpp @@ -11,7 +11,7 @@ static void anari_free(const void *ptr, const void *) namespace anari { namespace scenes { -static std::vector vertices = { +static std::vector vertices = { // {-.5f, .5f, 0.f}, {.5f, .5f, 0.f}, @@ -20,14 +20,14 @@ static std::vector vertices = { // }; -static std::vector indices = { +static std::vector indices = { // {0, 2, 3}, {3, 1, 0}, // }; -static std::vector texcoords = { +static std::vector texcoords = { // {0.f, 1.f}, {1.f, 1.f}, @@ -38,15 +38,15 @@ static std::vector texcoords = { static anari::Array2D makeTextureData(anari::Device d, int dim) { - auto *data = new anari::float3[dim * dim]; + auto *data = new math::float3[dim * dim]; for (int h = 0; h < dim; h++) { for (int w = 0; w < dim; w++) { bool even = h & 1; if (even) - data[h * dim + w] = w & 1 ? anari::float3(.8f) : anari::float3(.2f); + data[h * dim + w] = w & 1 ? math::float3(.8f) : math::float3(.2f); else - data[h * dim + w] = w & 1 ? anari::float3(.2f) : anari::float3(.8f); + data[h * dim + w] = w & 1 ? math::float3(.2f) : math::float3(.8f); } } @@ -119,29 +119,29 @@ void TexturedCube::commit() std::vector instances; - auto createInstance = [&](float rotation, anari::float3 axis) { + auto createInstance = [&](float rotation, math::float3 axis) { auto inst = anari::newObject(d, "transform"); - auto tl = anari::translation_matrix(anari::float3(0, 0, .5f)); - auto rot = anari::rotation_matrix(anari::rotation_quat(axis, rotation)); - anari::setParameter(d, inst, "transform", anari::mul(rot, tl)); + auto tl = math::translation_matrix(math::float3(0, 0, .5f)); + auto rot = math::rotation_matrix(math::rotation_quat(axis, rotation)); + anari::setParameter(d, inst, "transform", math::mul(rot, tl)); anari::setParameter(d, inst, "group", group); anari::commitParameters(d, inst); return inst; }; instances.push_back( - createInstance(anari::radians(0.f), anari::float3(0, 1, 0))); + createInstance(anari::radians(0.f), math::float3(0, 1, 0))); instances.push_back( - createInstance(anari::radians(180.f), anari::float3(0, 1, 0))); + createInstance(anari::radians(180.f), math::float3(0, 1, 0))); instances.push_back( - createInstance(anari::radians(90.f), anari::float3(0, 1, 0))); + createInstance(anari::radians(90.f), math::float3(0, 1, 0))); instances.push_back( - createInstance(anari::radians(270.f), anari::float3(0, 1, 0))); + createInstance(anari::radians(270.f), math::float3(0, 1, 0))); instances.push_back( - createInstance(anari::radians(90.f), anari::float3(1, 0, 0))); + createInstance(anari::radians(90.f), math::float3(1, 0, 0))); instances.push_back( - createInstance(anari::radians(270.f), anari::float3(1, 0, 0))); + createInstance(anari::radians(270.f), math::float3(1, 0, 0))); anari::setAndReleaseParameter(d, m_world, @@ -160,10 +160,10 @@ void TexturedCube::commit() std::vector TexturedCube::cameras() { Camera cam; - cam.position = anari::float3(1.25f); - cam.at = anari::float3(0.f); - cam.direction = anari::normalize(cam.at - cam.position); - cam.up = anari::float3(0, 1, 0); + cam.position = math::float3(1.25f); + cam.at = math::float3(0.f); + cam.direction = math::normalize(cam.at - cam.position); + cam.up = math::float3(0, 1, 0); return {cam}; } diff --git a/libs/anari_viewer/Orbit.cpp b/libs/anari_viewer/Orbit.cpp index dcb3a4ad..34203f14 100644 --- a/libs/anari_viewer/Orbit.cpp +++ b/libs/anari_viewer/Orbit.cpp @@ -14,24 +14,24 @@ static float degreesToRadians(float degrees) return degrees * M_PI / 180.f; } -static anari::float3 azelToDirection(float az, float el, OrbitAxis axis) +static anari::math::float3 azelToDirection(float az, float el, OrbitAxis axis) { const float x = std::sin(az) * std::cos(el); const float y = std::cos(az) * std::cos(el); const float z = std::sin(el); switch (axis) { case OrbitAxis::POS_X: - return -normalize(anari::float3(z, y, x)); + return -normalize(anari::math::float3(z, y, x)); case OrbitAxis::POS_Y: - return -normalize(anari::float3(x, z, y)); + return -normalize(anari::math::float3(x, z, y)); case OrbitAxis::POS_Z: - return -normalize(anari::float3(x, y, z)); + return -normalize(anari::math::float3(x, y, z)); case OrbitAxis::NEG_X: - return normalize(anari::float3(z, y, x)); + return normalize(anari::math::float3(z, y, x)); case OrbitAxis::NEG_Y: - return normalize(anari::float3(x, z, y)); + return normalize(anari::math::float3(x, z, y)); case OrbitAxis::NEG_Z: - return normalize(anari::float3(x, y, z)); + return normalize(anari::math::float3(x, y, z)); } return {}; } @@ -66,12 +66,12 @@ static float maintainUnitCircle(float inDegrees) // Orbit definitions ////////////////////////////////////////////////////////// -Orbit::Orbit(anari::float3 at, float dist, anari::float2 azel) +Orbit::Orbit(anari::math::float3 at, float dist, anari::math::float2 azel) { setConfig(at, dist, azel); } -void Orbit::setConfig(anari::float3 at, float dist, anari::float2 azel) +void Orbit::setConfig(anari::math::float3 at, float dist, anari::math::float2 azel) { m_at = at; m_distance = dist; @@ -95,7 +95,7 @@ bool Orbit::hasChanged(UpdateToken &t) const return false; } -void Orbit::rotate(anari::float2 delta) +void Orbit::rotate(anari::math::float2 delta) { delta *= 100; delta.x = m_invertRotation ? -delta.x : delta.x; @@ -112,11 +112,11 @@ void Orbit::zoom(float delta) update(); } -void Orbit::pan(anari::float2 delta) +void Orbit::pan(anari::math::float2 delta) { delta *= m_speed; - const anari::float3 amount = delta.x * m_right + -delta.y * m_up; + const anari::math::float3 amount = delta.x * m_right + -delta.y * m_up; m_eye += amount; m_at += amount; @@ -130,27 +130,27 @@ void Orbit::setAxis(OrbitAxis axis) update(); } -anari::float2 Orbit::azel() const +anari::math::float2 Orbit::azel() const { return m_azel; } -anari::float3 Orbit::eye() const +anari::math::float3 Orbit::eye() const { return m_eye; } -anari::float3 Orbit::at() const +anari::math::float3 Orbit::at() const { return m_at; } -anari::float3 Orbit::dir() const +anari::math::float3 Orbit::dir() const { return linalg::normalize(at() - eye()); } -anari::float3 Orbit::up() const +anari::math::float3 Orbit::up() const { return m_up; } @@ -160,7 +160,7 @@ float Orbit::distance() const return m_distance; } -anari::float3 Orbit::eye_FixedDistance() const +anari::math::float3 Orbit::eye_FixedDistance() const { return m_eyeFixedDistance; } @@ -174,17 +174,17 @@ void Orbit::update() const float azimuth = degreesToRadians(m_azel.x); const float elevation = degreesToRadians(m_azel.y); - const anari::float3 toLocalOrbit = azelToDirection(azimuth, elevation, axis); + const anari::math::float3 toLocalOrbit = azelToDirection(azimuth, elevation, axis); - const anari::float3 localOrbitPos = toLocalOrbit * distance; - const anari::float3 fromLocalOrbit = -localOrbitPos; + const anari::math::float3 localOrbitPos = toLocalOrbit * distance; + const anari::math::float3 fromLocalOrbit = -localOrbitPos; - const anari::float3 alteredElevation = + const anari::math::float3 alteredElevation = azelToDirection(azimuth, elevation + 3, m_axis); - const anari::float3 cameraRight = + const anari::math::float3 cameraRight = linalg::cross(toLocalOrbit, alteredElevation); - const anari::float3 cameraUp = linalg::cross(cameraRight, fromLocalOrbit); + const anari::math::float3 cameraUp = linalg::cross(cameraRight, fromLocalOrbit); m_eye = localOrbitPos + m_at; m_up = linalg::normalize(cameraUp); diff --git a/libs/anari_viewer/Orbit.h b/libs/anari_viewer/Orbit.h index 4f54f5dc..06f25bda 100644 --- a/libs/anari_viewer/Orbit.h +++ b/libs/anari_viewer/Orbit.h @@ -23,31 +23,31 @@ class Orbit { public: Orbit() = default; - Orbit(anari::float3 at, float dist, anari::float2 azel = anari::float2(0.f)); + Orbit(anari::math::float3 at, float dist, anari::math::float2 azel = anari::math::float2(0.f)); void setConfig( - anari::float3 at, float dist, anari::float2 azel = anari::float2(0.f)); + anari::math::float3 at, float dist, anari::math::float2 azel = anari::math::float2(0.f)); void startNewRotation(); bool hasChanged(UpdateToken &t) const; - void rotate(anari::float2 delta); + void rotate(anari::math::float2 delta); void zoom(float delta); - void pan(anari::float2 delta); + void pan(anari::math::float2 delta); void setAxis(OrbitAxis axis); - anari::float2 azel() const; + anari::math::float2 azel() const; - anari::float3 eye() const; - anari::float3 at() const; - anari::float3 dir() const; - anari::float3 up() const; + anari::math::float3 eye() const; + anari::math::float3 at() const; + anari::math::float3 dir() const; + anari::math::float3 up() const; float distance() const; - anari::float3 eye_FixedDistance() const; // using original distance + anari::math::float3 eye_FixedDistance() const; // using original distance protected: void update(); @@ -57,7 +57,7 @@ class Orbit UpdateToken m_token{1}; // NOTE: degrees - anari::float2 m_azel{0.f}; + anari::math::float2 m_azel{0.f}; float m_distance{1.f}; float m_originalDistance{1.f}; @@ -65,11 +65,11 @@ class Orbit bool m_invertRotation{false}; - anari::float3 m_eye; - anari::float3 m_eyeFixedDistance; - anari::float3 m_at; - anari::float3 m_up; - anari::float3 m_right; + anari::math::float3 m_eye; + anari::math::float3 m_eyeFixedDistance; + anari::math::float3 m_at; + anari::math::float3 m_up; + anari::math::float3 m_right; OrbitAxis m_axis{OrbitAxis::POS_Y}; }; diff --git a/libs/anari_viewer/windows/LightsEditor.cpp b/libs/anari_viewer/windows/LightsEditor.cpp index 2bdbaf24..415ce391 100644 --- a/libs/anari_viewer/windows/LightsEditor.cpp +++ b/libs/anari_viewer/windows/LightsEditor.cpp @@ -231,7 +231,7 @@ void LightsEditor::updateLight(const Light &l) if (l.type == Light::DIRECTIONAL || l.type == Light::SPOT) { const float az = radians(l.directionalAZEL.x); const float el = radians(l.directionalAZEL.y); - anari::float3 dir(std::sin(az) * std::cos(el), + anari::math::float3 dir(std::sin(az) * std::cos(el), std::sin(el), std::cos(az) * std::cos(el)); anari::setParameter(device, light, "direction", dir); diff --git a/libs/anari_viewer/windows/LightsEditor.h b/libs/anari_viewer/windows/LightsEditor.h index 6aeb820e..152dd288 100644 --- a/libs/anari_viewer/windows/LightsEditor.h +++ b/libs/anari_viewer/windows/LightsEditor.h @@ -26,9 +26,9 @@ struct Light LightType type{DIRECTIONAL}; float intensity{1.f}; float openingAngle{3.14159f}; - anari::float3 color{1.f}; - anari::float2 directionalAZEL{0.f, 345.f}; - anari::float3 pointPosition{0.f}; + anari::math::float3 color{1.f}; + anari::math::float2 directionalAZEL{0.f, 345.f}; + anari::math::float3 pointPosition{0.f}; std::string hdriRadiance; float scale{1.f}; std::vector handles; diff --git a/libs/anari_viewer/windows/Viewport.cpp b/libs/anari_viewer/windows/Viewport.cpp index b2fbfd5e..15300bcc 100644 --- a/libs/anari_viewer/windows/Viewport.cpp +++ b/libs/anari_viewer/windows/Viewport.cpp @@ -92,7 +92,7 @@ Viewport::~Viewport() void Viewport::buildUI() { ImVec2 _viewportSize = ImGui::GetContentRegionAvail(); - anari::int2 viewportSize(_viewportSize.x, _viewportSize.y); + anari::math::int2 viewportSize(_viewportSize.x, _viewportSize.y); if (m_viewportSize != viewportSize) reshape(viewportSize); @@ -141,7 +141,7 @@ void Viewport::setWorld(anari::World world, bool resetCameraView) void Viewport::resetView(bool resetAzEl) { - anari::float3 bounds[2]; + anari::math::float3 bounds[2]; anariGetProperty(m_device, m_world, @@ -154,7 +154,7 @@ void Viewport::resetView(bool resetAzEl) auto center = 0.5f * (bounds[0] + bounds[1]); auto diag = bounds[1] - bounds[0]; - auto azel = resetAzEl ? anari::float2(180.f, 200.f) : m_arcball->azel(); + auto azel = resetAzEl ? anari::math::float2(180.f, 200.f) : m_arcball->azel(); m_arcball->setConfig(center, 1.25f * linalg::length(diag), azel); m_cameraToken = 0; } @@ -164,7 +164,7 @@ anari::Device Viewport::device() const return m_device; } -void Viewport::reshape(anari::int2 newSize) +void Viewport::reshape(anari::math::int2 newSize) { if (newSize.x <= 0 || newSize.y <= 0) return; @@ -200,7 +200,7 @@ void Viewport::startNewFrame() void Viewport::updateFrame() { - anari::setParameter(m_device, m_frame, "size", anari::uint2(m_viewportSize)); + anari::setParameter(m_device, m_frame, "size", anari::math::uint2(m_viewportSize)); anari::setParameter( m_device, m_frame, "channel.color", ANARI_UFIXED8_RGBA_SRGB); anari::setParameter(m_device, m_frame, "accumulation", true); @@ -313,7 +313,7 @@ void Viewport::ui_handleInput() if (!anyDown) { m_manipulating = false; - m_previousMouse = anari::float2(-1); + m_previousMouse = anari::math::float2(-1); } else if (ImGui::IsItemHovered() && !m_manipulating) m_manipulating = true; @@ -321,21 +321,21 @@ void Viewport::ui_handleInput() m_mouseRotating = false; if (m_manipulating) { - anari::float2 position; + anari::math::float2 position; std::memcpy(&position, &io.MousePos, sizeof(position)); - const anari::float2 mouse(position.x, position.y); + const anari::math::float2 mouse(position.x, position.y); - if (anyDown && m_previousMouse != anari::float2(-1)) { - const anari::float2 prev = m_previousMouse; + if (anyDown && m_previousMouse != anari::math::float2(-1)) { + const anari::math::float2 prev = m_previousMouse; - const anari::float2 mouseFrom = - prev * 2.f / anari::float2(m_viewportSize); - const anari::float2 mouseTo = mouse * 2.f / anari::float2(m_viewportSize); + const anari::math::float2 mouseFrom = + prev * 2.f / anari::math::float2(m_viewportSize); + const anari::math::float2 mouseTo = mouse * 2.f / anari::math::float2(m_viewportSize); - const anari::float2 mouseDelta = mouseTo - mouseFrom; + const anari::math::float2 mouseDelta = mouseTo - mouseFrom; - if (mouseDelta != anari::float2(0.f)) { + if (mouseDelta != anari::math::float2(0.f)) { if (leftDown) { if (!m_mouseRotating) { m_arcball->startNewRotation(); @@ -433,7 +433,7 @@ void Viewport::ui_contextMenu() ImGui::Indent(INDENT_AMOUNT); if (ImGui::MenuItem("print bounds")) { - anari::float3 bounds[2]; + anari::math::float3 bounds[2]; anariGetProperty(m_device, m_world, diff --git a/libs/anari_viewer/windows/Viewport.h b/libs/anari_viewer/windows/Viewport.h index 7887b22c..da3c9f72 100644 --- a/libs/anari_viewer/windows/Viewport.h +++ b/libs/anari_viewer/windows/Viewport.h @@ -36,7 +36,7 @@ struct Viewport : public anari_viewer::Window anari::Device device() const; private: - void reshape(anari::int2 newWindowSize); + void reshape(anari::math::int2 newWindowSize); void startNewFrame(); void updateFrame(); @@ -50,7 +50,7 @@ struct Viewport : public anari_viewer::Window // Data ///////////////////////////////////////////////////////////////////// - anari::float2 m_previousMouse{-1.f, -1.f}; + anari::math::float2 m_previousMouse{-1.f, -1.f}; bool m_mouseRotating{false}; bool m_manipulating{false}; bool m_currentlyRendering{true}; @@ -91,8 +91,8 @@ struct Viewport : public anari_viewer::Window // OpenGL + display GLuint m_framebufferTexture{0}; - anari::int2 m_viewportSize{1920, 1080}; - anari::int2 m_renderSize{1920, 1080}; + anari::math::int2 m_viewportSize{1920, 1080}; + anari::math::int2 m_renderSize{1920, 1080}; float m_latestFL{1.f}; float m_minFL{std::numeric_limits::max()}; diff --git a/libs/helide/CMakeLists.txt b/libs/helide/CMakeLists.txt index 4c70303c..0166e651 100644 --- a/libs/helide/CMakeLists.txt +++ b/libs/helide/CMakeLists.txt @@ -64,7 +64,6 @@ project_sources(PRIVATE HelideGlobalState.cpp HelideLibrary.cpp Object.cpp - array/Array.cpp array/Array1D.cpp array/Array2D.cpp array/Array3D.cpp diff --git a/libs/helide/HelideGlobalState.h b/libs/helide/HelideGlobalState.h index 60f7c240..25cb3b8d 100644 --- a/libs/helide/HelideGlobalState.h +++ b/libs/helide/HelideGlobalState.h @@ -55,4 +55,21 @@ struct HelideGlobalState : public helium::BaseGlobalDeviceState void waitOnCurrentFrame() const; }; +// Helper functions/macros //////////////////////////////////////////////////// + +inline HelideGlobalState *asHelideState(helium::BaseGlobalDeviceState *s) +{ + return (HelideGlobalState *)s; +} + +#define HELIDE_ANARI_TYPEFOR_SPECIALIZATION(type, anari_type) \ + namespace anari { \ + ANARI_TYPEFOR_SPECIALIZATION(type, anari_type); \ + } + +#define HELIDE_ANARI_TYPEFOR_DEFINITION(type) \ + namespace anari { \ + ANARI_TYPEFOR_DEFINITION(type); \ + } + } // namespace helide diff --git a/libs/helide/Object.h b/libs/helide/Object.h index 2a7b5137..a4425719 100644 --- a/libs/helide/Object.h +++ b/libs/helide/Object.h @@ -24,7 +24,7 @@ struct Object : public helium::BaseObject virtual void commit(); - virtual bool isValid() const; + bool isValid() const override; HelideGlobalState *deviceState() const; }; @@ -38,14 +38,4 @@ struct UnknownObject : public Object } // namespace helide -#define HELIDE_ANARI_TYPEFOR_SPECIALIZATION(type, anari_type) \ - namespace anari { \ - ANARI_TYPEFOR_SPECIALIZATION(type, anari_type); \ - } - -#define HELIDE_ANARI_TYPEFOR_DEFINITION(type) \ - namespace anari { \ - ANARI_TYPEFOR_DEFINITION(type); \ - } - HELIDE_ANARI_TYPEFOR_SPECIALIZATION(helide::Object *, ANARI_OBJECT); diff --git a/libs/helide/array/Array1D.cpp b/libs/helide/array/Array1D.cpp index 3219c481..df49b216 100644 --- a/libs/helide/array/Array1D.cpp +++ b/libs/helide/array/Array1D.cpp @@ -6,79 +6,14 @@ namespace helide { Array1D::Array1D(HelideGlobalState *state, const Array1DMemoryDescriptor &d) - : Array(ANARI_ARRAY1D, state, d), m_capacity(d.numItems), m_end(d.numItems) + : helium::Array1D(state, d) { - initManagedMemory(); + state->objectCounts.arrays++; } -void Array1D::commit() +Array1D::~Array1D() { - auto oldBegin = m_begin; - auto oldEnd = m_end; - - m_begin = getParam("begin", 0); - m_begin = std::clamp(m_begin, size_t(0), m_capacity - 1); - m_end = getParam("end", m_capacity); - m_end = std::clamp(m_end, size_t(1), m_capacity); - - if (size() == 0) { - reportMessage(ANARI_SEVERITY_ERROR, "array size must be greater than zero"); - return; - } - - if (m_begin > m_end) { - reportMessage(ANARI_SEVERITY_WARNING, - "array 'begin' is not less than 'end', swapping values"); - std::swap(m_begin, m_end); - } - - if (m_begin != oldBegin || m_end != oldEnd) - notifyCommitObservers(); -} - -size_t Array1D::totalSize() const -{ - return size(); -} - -size_t Array1D::totalCapacity() const -{ - return m_capacity; -} - -void *Array1D::begin() const -{ - auto *p = (unsigned char *)data(); - auto s = anari::sizeOf(elementType()); - return p + (s * m_begin); -} - -void *Array1D::end() const -{ - auto *p = (unsigned char *)data(); - auto s = anari::sizeOf(elementType()); - return p + (s * m_end); -} - -size_t Array1D::size() const -{ - return m_end - m_begin; -} - -float4 Array1D::readAsAttributeValue(int32_t i, WrapMode wrap) const -{ - const auto idx = calculateWrapIndex(i, size(), wrap); - return readAsAttributeValueFlat(begin(), elementType(), idx); -} - -void Array1D::privatize() -{ - makePrivatizedCopy(size()); -} - -float4 readAttributeValue(const Array1D *arr, uint32_t i) -{ - return arr ? arr->readAsAttributeValue(i) : DEFAULT_ATTRIBUTE_VALUE; + asHelideState(deviceState())->objectCounts.arrays--; } } // namespace helide diff --git a/libs/helide/array/Array1D.h b/libs/helide/array/Array1D.h index 05b365cc..874c0365 100644 --- a/libs/helide/array/Array1D.h +++ b/libs/helide/array/Array1D.h @@ -3,89 +3,20 @@ #pragma once -#include "array/Array.h" +#include "../HelideGlobalState.h" +// helium +#include "helium/array/Array1D.h" namespace helide { -struct Array1DMemoryDescriptor : public ArrayMemoryDescriptor -{ - uint64_t numItems{0}; -}; - -bool isCompact(const Array1DMemoryDescriptor &d); +using Array1DMemoryDescriptor = helium::Array1DMemoryDescriptor; -struct Array1D : public Array +struct Array1D : public helium::Array1D { Array1D(HelideGlobalState *state, const Array1DMemoryDescriptor &d); - - void commit() override; - - size_t totalSize() const override; - size_t totalCapacity() const override; - - void *begin() const; - void *end() const; - - template - T *beginAs() const; - template - T *endAs() const; - - size_t size() const; - - float4 readAsAttributeValue( - int32_t i, WrapMode wrap = WrapMode::DEFAULT) const; - template - T valueAtLinear(float in) const; // 'in' must be clamped to [0, 1] - template - T valueAtClosest(float in) const; // 'in' must be clamped to [0, 1] - - void privatize() override; - - private: - size_t m_capacity{0}; - size_t m_begin{0}; - size_t m_end{0}; + ~Array1D() override; }; -float4 readAttributeValue(const Array1D *arr, uint32_t i); - -// Inlined definitions //////////////////////////////////////////////////////// - -template -inline T *Array1D::beginAs() const -{ - if (anari::ANARITypeFor::value != elementType()) - throw std::runtime_error("incorrect element type queried for array"); - - return (T *)data() + m_begin; -} - -template -inline T *Array1D::endAs() const -{ - if (anari::ANARITypeFor::value != elementType()) - throw std::runtime_error("incorrect element type queried for array"); - - return (T *)data() + m_end; -} - -template -inline T Array1D::valueAtLinear(float in) const -{ - const T *data = dataAs(); - const auto i = getInterpolant(in, size(), false); - return linalg::lerp(data[i.lower], data[i.upper], i.frac); -} - -template -inline T Array1D::valueAtClosest(float in) const -{ - const T *data = dataAs(); - const auto i = getInterpolant(in, size(), false); - return i.frac <= 0.5f ? data[i.lower] : data[i.upper]; -} - } // namespace helide HELIDE_ANARI_TYPEFOR_SPECIALIZATION(helide::Array1D *, ANARI_ARRAY1D); diff --git a/libs/helide/array/Array2D.cpp b/libs/helide/array/Array2D.cpp index f37c6a96..b921d5d1 100644 --- a/libs/helide/array/Array2D.cpp +++ b/libs/helide/array/Array2D.cpp @@ -2,45 +2,19 @@ // SPDX-License-Identifier: Apache-2.0 #include "array/Array2D.h" +#include "../HelideGlobalState.h" namespace helide { Array2D::Array2D(HelideGlobalState *state, const Array2DMemoryDescriptor &d) - : Array(ANARI_ARRAY2D, state, d) + : helium::Array2D(state, d) { - m_size[0] = d.numItems1; - m_size[1] = d.numItems2; - - initManagedMemory(); -} - -size_t Array2D::totalSize() const -{ - return size(0) * size(1); -} - -size_t Array2D::size(int dim) const -{ - return m_size[dim]; -} - -uint2 Array2D::size() const -{ - return uint2(uint32_t(size(0)), uint32_t(size(1))); -} - -float4 Array2D::readAsAttributeValue( - int2 i, WrapMode wrap1, WrapMode wrap2) const -{ - const auto i_x = calculateWrapIndex(i.x, size().x, wrap1); - const auto i_y = calculateWrapIndex(i.y, size().y, wrap2); - const size_t idx = i_y * size().x + i_x; - return readAsAttributeValueFlat(data(), elementType(), idx); + state->objectCounts.arrays++; } -void Array2D::privatize() +Array2D::~Array2D() { - makePrivatizedCopy(size(0) * size(1)); + asHelideState(deviceState())->objectCounts.arrays--; } } // namespace helide diff --git a/libs/helide/array/Array2D.h b/libs/helide/array/Array2D.h index 50d0d483..dd016a3a 100644 --- a/libs/helide/array/Array2D.h +++ b/libs/helide/array/Array2D.h @@ -3,35 +3,18 @@ #pragma once -#include "array/Array.h" +#include "../HelideGlobalState.h" +// helium +#include "helium/array/Array2D.h" namespace helide { -struct Array2DMemoryDescriptor : public ArrayMemoryDescriptor -{ - uint64_t numItems1{0}; - uint64_t numItems2{0}; -}; +using Array2DMemoryDescriptor = helium::Array2DMemoryDescriptor; -bool isCompact(const Array2DMemoryDescriptor &d); - -struct Array2D : public Array +struct Array2D : public helium::Array2D { Array2D(HelideGlobalState *state, const Array2DMemoryDescriptor &d); - - size_t totalSize() const override; - - size_t size(int dim) const; - uint2 size() const; - - float4 readAsAttributeValue(int2 i, - WrapMode wrap1 = WrapMode::DEFAULT, - WrapMode wrap2 = WrapMode::DEFAULT) const; - - void privatize() override; - - private: - size_t m_size[2] = {0, 0}; + ~Array2D() override; }; } // namespace helide diff --git a/libs/helide/array/Array3D.cpp b/libs/helide/array/Array3D.cpp index 650d5c9e..c8c3ff36 100644 --- a/libs/helide/array/Array3D.cpp +++ b/libs/helide/array/Array3D.cpp @@ -6,44 +6,14 @@ namespace helide { Array3D::Array3D(HelideGlobalState *state, const Array3DMemoryDescriptor &d) - : Array(ANARI_ARRAY3D, state, d) + : helium::Array3D(state, d) { - m_size[0] = d.numItems1; - m_size[1] = d.numItems2; - m_size[2] = d.numItems3; - - initManagedMemory(); -} - -size_t Array3D::totalSize() const -{ - return size(0) * size(1) * size(2); -} - -size_t Array3D::size(int dim) const -{ - return m_size[dim]; -} - -uint3 Array3D::size() const -{ - return uint3(uint32_t(size(0)), uint32_t(size(1)), uint32_t(size(2))); -} - -float4 Array3D::readAsAttributeValue( - int3 i, WrapMode wrap1, WrapMode wrap2, WrapMode wrap3) const -{ - const auto i_x = calculateWrapIndex(i.x, size().x, wrap1); - const auto i_y = calculateWrapIndex(i.y, size().y, wrap2); - const auto i_z = calculateWrapIndex(i.z, size().z, wrap3); - const size_t idx = - size_t(i_x) + size().x * (size_t(i_y) + size().y * size_t(i_z)); - return readAsAttributeValueFlat(data(), elementType(), idx); + state->objectCounts.arrays++; } -void Array3D::privatize() +Array3D::~Array3D() { - makePrivatizedCopy(size(0) * size(1) * size(2)); + asHelideState(deviceState())->objectCounts.arrays--; } } // namespace helide diff --git a/libs/helide/array/Array3D.h b/libs/helide/array/Array3D.h index ac6ae904..46a48ed7 100644 --- a/libs/helide/array/Array3D.h +++ b/libs/helide/array/Array3D.h @@ -3,37 +3,18 @@ #pragma once -#include "array/Array.h" +#include "../HelideGlobalState.h" +// helium +#include "helium/array/Array3D.h" namespace helide { -struct Array3DMemoryDescriptor : public ArrayMemoryDescriptor -{ - uint64_t numItems1{0}; - uint64_t numItems2{0}; - uint64_t numItems3{0}; -}; +using Array3DMemoryDescriptor = helium::Array3DMemoryDescriptor; -bool isCompact(const Array3DMemoryDescriptor &d); - -struct Array3D : public Array +struct Array3D : public helium::Array3D { Array3D(HelideGlobalState *state, const Array3DMemoryDescriptor &d); - - size_t totalSize() const override; - - size_t size(int dim) const; - uint3 size() const; - - float4 readAsAttributeValue(int3 i, - WrapMode wrap1 = WrapMode::DEFAULT, - WrapMode wrap2 = WrapMode::DEFAULT, - WrapMode wrap3 = WrapMode::DEFAULT) const; - - void privatize() override; - - private: - size_t m_size[3] = {0, 0, 0}; + ~Array3D() override; }; } // namespace helide diff --git a/libs/helide/array/ObjectArray.cpp b/libs/helide/array/ObjectArray.cpp index 6c9bb111..29a27f77 100644 --- a/libs/helide/array/ObjectArray.cpp +++ b/libs/helide/array/ObjectArray.cpp @@ -2,147 +2,20 @@ // SPDX-License-Identifier: Apache-2.0 #include "array/ObjectArray.h" +#include "../HelideGlobalState.h" namespace helide { -// Helper functions /////////////////////////////////////////////////////////// - -static void refIncObject(Object *obj) -{ - if (obj) - obj->refInc(helium::RefType::INTERNAL); -} - -static void refDecObject(Object *obj) -{ - if (obj) - obj->refDec(helium::RefType::INTERNAL); -} - -// ObjectArray definitions //////////////////////////////////////////////////// - ObjectArray::ObjectArray( HelideGlobalState *state, const Array1DMemoryDescriptor &d) - : Array(ANARI_ARRAY1D, state, d), m_capacity(d.numItems), m_end(d.numItems) + : helium::ObjectArray(state, d) { - m_appHandles.resize(d.numItems, nullptr); - initManagedMemory(); - updateInternalHandleArrays(); + state->objectCounts.arrays++; } ObjectArray::~ObjectArray() { - std::for_each(m_appHandles.begin(), m_appHandles.end(), refDecObject); - std::for_each( - m_appendedHandles.begin(), m_appendedHandles.end(), refDecObject); -} - -void ObjectArray::commit() -{ - auto oldBegin = m_begin; - auto oldEnd = m_end; - - m_begin = getParam("begin", 0); - m_begin = std::clamp(m_begin, size_t(0), m_capacity - 1); - m_end = getParam("end", m_capacity); - m_end = std::clamp(m_end, size_t(1), m_capacity); - - if (size() == 0) { - reportMessage(ANARI_SEVERITY_ERROR, "array size must be greater than zero"); - return; - } - - if (m_begin > m_end) { - reportMessage(ANARI_SEVERITY_WARNING, - "array 'begin' is not less than 'end', swapping values"); - std::swap(m_begin, m_end); - } - - if (m_begin != oldBegin || m_end != oldEnd) - notifyCommitObservers(); -} - -size_t ObjectArray::totalSize() const -{ - return size() + m_appendedHandles.size(); -} - -size_t ObjectArray::totalCapacity() const -{ - return m_capacity; -} - -size_t ObjectArray::size() const -{ - return m_end - m_begin; -} - -void ObjectArray::privatize() -{ - makePrivatizedCopy(size()); - freeAppMemory(); - if (data()) { - reportMessage(ANARI_SEVERITY_WARNING, - "ObjectArray privatized but host array still present"); - } -} - -void ObjectArray::unmap() -{ - if (!m_mapped) { - reportMessage(ANARI_SEVERITY_WARNING, - "array unmapped again without being previously mapped"); - return; - } - m_mapped = false; - updateInternalHandleArrays(); - notifyCommitObservers(); -} - -Object **ObjectArray::handlesBegin() const -{ - return m_liveHandles.data() + m_begin; -} - -Object **ObjectArray::handlesEnd() const -{ - return handlesBegin() + totalSize(); -} - -void ObjectArray::appendHandle(Object *o) -{ - o->refInc(helium::RefType::INTERNAL); - m_appendedHandles.push_back(o); - updateInternalHandleArrays(); -} - -void ObjectArray::removeAppendedHandles() -{ - m_liveHandles.resize(size()); - for (auto o : m_appendedHandles) - o->refDec(helium::RefType::INTERNAL); - m_appendedHandles.clear(); -} - -void ObjectArray::updateInternalHandleArrays() const -{ - m_liveHandles.resize(totalSize()); - - if (data()) { - auto **srcAllBegin = (Object **)data(); - auto **srcAllEnd = srcAllBegin + totalCapacity(); - std::for_each(srcAllBegin, srcAllEnd, refIncObject); - std::for_each(m_appHandles.begin(), m_appHandles.end(), refDecObject); - std::copy(srcAllBegin, srcAllEnd, m_appHandles.data()); - - auto **srcRegionBegin = srcAllBegin + m_begin; - auto **srcRegionEnd = srcRegionBegin + size(); - std::copy(srcRegionBegin, srcRegionEnd, m_liveHandles.data()); - } - - std::copy(m_appendedHandles.begin(), - m_appendedHandles.end(), - m_liveHandles.begin() + size()); + asHelideState(deviceState())->objectCounts.arrays--; } } // namespace helide diff --git a/libs/helide/array/ObjectArray.h b/libs/helide/array/ObjectArray.h index 23939e2b..9d83c6ae 100644 --- a/libs/helide/array/ObjectArray.h +++ b/libs/helide/array/ObjectArray.h @@ -3,40 +3,17 @@ #pragma once -#include "array/Array1D.h" +#include "../HelideGlobalState.h" +#include "Array1D.h" +// helium +#include "helium/array/ObjectArray.h" namespace helide { -struct ObjectArray : public Array +struct ObjectArray : public helium::ObjectArray { ObjectArray(HelideGlobalState *state, const Array1DMemoryDescriptor &d); - ~ObjectArray(); - - void commit() override; - - size_t totalSize() const override; - size_t totalCapacity() const override; - - size_t size() const; - - void privatize() override; - void unmap() override; - - Object **handlesBegin() const; - Object **handlesEnd() const; - - void appendHandle(Object *); - void removeAppendedHandles(); - - private: - void updateInternalHandleArrays() const; - - mutable std::vector m_appendedHandles; - mutable std::vector m_appHandles; - mutable std::vector m_liveHandles; - size_t m_capacity{0}; - size_t m_begin{0}; - size_t m_end{0}; + ~ObjectArray() override; }; } // namespace helide diff --git a/libs/helide/camera/Perspective.cpp b/libs/helide/camera/Perspective.cpp index 7f286c73..d94f3a9a 100644 --- a/libs/helide/camera/Perspective.cpp +++ b/libs/helide/camera/Perspective.cpp @@ -14,7 +14,7 @@ void Perspective::commit() // NOTE: demonstrate alternative 'raw' method for getting parameter values float fovy = 0.f; if (!getParam("fovy", ANARI_FLOAT32, &fovy)) - fovy = radians(60.f); + fovy = anari::radians(60.f); float aspect = getParam("aspect", 1.f); float2 imgPlaneSize; diff --git a/libs/helide/helide_math.h b/libs/helide/helide_math.h index b9f76d0e..3e4fd0d3 100644 --- a/libs/helide/helide_math.h +++ b/libs/helide/helide_math.h @@ -3,71 +3,15 @@ #pragma once -// anari -#include -#include -// std -#include -#include +// helium +#include "helium/helium_math.h" // embree #include namespace helide { -// Types ////////////////////////////////////////////////////////////////////// - -using namespace linalg::aliases; -using mat3 = float3x3; -using mat4 = float4x4; - -template -struct range_t -{ - using element_t = T; - - range_t() = default; - range_t(const T &t) : lower(t), upper(t) {} - range_t(const T &_lower, const T &_upper) : lower(_lower), upper(_upper) {} - - range_t &extend(const T &t) - { - lower = min(lower, t); - upper = max(upper, t); - return *this; - } - - range_t &extend(const range_t &t) - { - lower = min(lower, t.lower); - upper = max(upper, t.upper); - return *this; - } - - T lower{T(std::numeric_limits::max())}; - T upper{T(-std::numeric_limits::max())}; -}; - -using box1 = range_t; -using box2 = range_t; -using box3 = range_t; - -template -inline typename range_t::element_t size(const range_t &r) -{ - return r.upper - r.lower; -} - -template -inline typename range_t::element_t clamp( - const typename range_t::element_t &t, const range_t &r) -{ - return linalg::max(r.lower, linalg::min(t, r.upper)); -} - -inline float position(float v, const box1 &r) -{ - return (v - r.lower) * (1.f / size(r)); -} +using namespace anari::math; +using namespace helium::math; struct Ray { @@ -102,273 +46,4 @@ struct VolumeRay uint32_t instID{RTC_INVALID_GEOMETRY_ID}; }; -constexpr float4 DEFAULT_ATTRIBUTE_VALUE(0.f, 0.f, 0.f, 1.f); - -enum class Attribute -{ - ATTRIBUTE_0 = 0, - ATTRIBUTE_1, - ATTRIBUTE_2, - ATTRIBUTE_3, - COLOR, - NONE -}; - -enum WrapMode -{ - CLAMP_TO_EDGE = 0, - REPEAT, - MIRROR_REPEAT, - DEFAULT -}; - -enum class AlphaMode -{ - OPAQUE, - MASK, - BLEND -}; - -// Functions ////////////////////////////////////////////////////////////////// - -inline float radians(float degrees) -{ - return degrees * float(M_PI) / 180.f; -} - -inline mat3 extractRotation(const mat4 &m) -{ - return mat3(float3(m[0].x, m[0].y, m[0].z), - float3(m[1].x, m[1].y, m[1].z), - float3(m[2].x, m[2].y, m[2].z)); -} - -template -inline float toneMap(float v) -{ - if constexpr (SRGB) - return std::pow(v, 1.f / 2.2f); - else - return v; -} - -struct Interpolant -{ - int32_t lower; - int32_t upper; - float frac; -}; - -inline Interpolant getInterpolant(float in, size_t size, bool texOffset = false) -{ - const float scale = float(size); - const float lowf = - texOffset ? (in - (0.5f / scale)) * scale : (in * (scale - 1.f)); - const int32_t low = std::floor(lowf); - const int32_t high = low + 1; - const float frac = lowf - low; - return {low, high, frac}; -} - -template -inline T lerp(const T &x, const T &y, const U &a) -{ - return static_cast(x * (U(1) - a) + y * a); -} - -template -inline void accumulateValue(T &a, const T &b, float interp) -{ - a += b * (1.f - interp); -} - -inline int32_t computeMirroredRepeatIndex(int32_t x, int32_t size) -{ - x = std::abs(x + (x < 0)) % (2 * size); - return x >= size ? 2 * size - x - 1 : x; -}; - -inline int32_t calculateWrapIndex(int32_t i, size_t size, WrapMode wrap) -{ - switch (wrap) { - case WrapMode::CLAMP_TO_EDGE: - case WrapMode::DEFAULT: - default: - return linalg::clamp(i, 0, int32_t(size - 1)); - break; - case WrapMode::REPEAT: - return i % size; - break; - case WrapMode::MIRROR_REPEAT: - return computeMirroredRepeatIndex(i, int32_t(size)); - break; - } -} - -inline Attribute attributeFromString(const std::string &str) -{ - if (str == "color") - return Attribute::COLOR; - else if (str == "attribute0") - return Attribute::ATTRIBUTE_0; - else if (str == "attribute1") - return Attribute::ATTRIBUTE_1; - else if (str == "attribute2") - return Attribute::ATTRIBUTE_2; - else if (str == "attribute3") - return Attribute::ATTRIBUTE_3; - else - return Attribute::NONE; -} - -inline WrapMode wrapModeFromString(const std::string &str) -{ - if (str == "clampToEdge") - return WrapMode::CLAMP_TO_EDGE; - else if (str == "repeat") - return WrapMode::REPEAT; - else if (str == "mirrorRepeat") - return WrapMode::MIRROR_REPEAT; - else - return WrapMode::DEFAULT; -} - -inline AlphaMode alphaModeFromString(const std::string &str) -{ - if (str == "blend") - return AlphaMode::BLEND; - else if (str == "mask") - return AlphaMode::MASK; - else - return AlphaMode::OPAQUE; -} - -inline float adjustOpacityFromMode( - float opacity, float maskThreshold, AlphaMode mode) -{ - switch (mode) { - case AlphaMode::BLEND: - return opacity; - case AlphaMode::MASK: - return opacity >= maskThreshold ? 1.f : 0.f; - case AlphaMode::OPAQUE: - default: - return 1.f; - } -} - -template -static const T *typedOffset(const void *mem, uint64_t offset) -{ - return ((const T *)mem) + offset; -} - -template -static float4 getAttributeArrayAt_ufixed(void *data, uint64_t offset) -{ - constexpr float m = std::numeric_limits::max(); - float4 retval(0.f, 0.f, 0.f, 1.f); - switch (NUM_COMPONENTS) { - case 4: - retval.w = toneMap( - *typedOffset(data, NUM_COMPONENTS * offset + 3) / m); - case 3: - retval.z = toneMap( - *typedOffset(data, NUM_COMPONENTS * offset + 2) / m); - case 2: - retval.y = toneMap( - *typedOffset(data, NUM_COMPONENTS * offset + 1) / m); - case 1: - retval.x = toneMap( - *typedOffset(data, NUM_COMPONENTS * offset + 0) / m); - default: - break; - } - - return retval; -} - -inline float4 readAsAttributeValueFlat( - void *data, ANARIDataType type, uint64_t i) -{ - auto retval = DEFAULT_ATTRIBUTE_VALUE; - - switch (type) { - case ANARI_FLOAT32: - std::memcpy(&retval, typedOffset(data, i), sizeof(float)); - break; - case ANARI_FLOAT32_VEC2: - std::memcpy(&retval, typedOffset(data, i), sizeof(float2)); - break; - case ANARI_FLOAT32_VEC3: - std::memcpy(&retval, typedOffset(data, i), sizeof(float3)); - break; - case ANARI_FLOAT32_VEC4: - std::memcpy(&retval, typedOffset(data, i), sizeof(float4)); - break; - case ANARI_UFIXED8_R_SRGB: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED8_RA_SRGB: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED8_RGB_SRGB: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED8_RGBA_SRGB: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED8: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED8_VEC2: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED8_VEC3: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED8_VEC4: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED16: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED16_VEC2: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED16_VEC3: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED16_VEC4: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED32: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED32_VEC2: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED32_VEC3: - retval = getAttributeArrayAt_ufixed(data, i); - break; - case ANARI_UFIXED32_VEC4: - retval = getAttributeArrayAt_ufixed(data, i); - break; - default: - break; - } - - return retval; -} - } // namespace helide - -namespace anari { - -ANARI_TYPEFOR_SPECIALIZATION(helide::box1, ANARI_FLOAT32_BOX1); - -#ifdef HELIDE_ANARI_DEFINITIONS -ANARI_TYPEFOR_DEFINITION(helide::box1); -#endif - -} // namespace anari diff --git a/libs/helide/renderer/Renderer.cpp b/libs/helide/renderer/Renderer.cpp index 137569df..64b6ceac 100644 --- a/libs/helide/renderer/Renderer.cpp +++ b/libs/helide/renderer/Renderer.cpp @@ -96,11 +96,12 @@ Renderer::Renderer(HelideGlobalState *s) : Object(ANARI_RENDERER, s) m_heatmap = new Array1D(s, md); m_heatmap->refDec(helium::RefType::PUBLIC); - auto *colors = m_heatmap->beginAs(); + auto *colors = (float3 *)m_heatmap->map(); colors[0] = float3(0.f, 0.f, 1.f); colors[1] = float3(1.f, 0.f, 0.f); colors[2] = float3(1.f, 1.f, 0.f); colors[3] = float3(1.f, 1.f, 1.f); + m_heatmap->unmap(); } Renderer::~Renderer() diff --git a/libs/helide/scene/Group.cpp b/libs/helide/scene/Group.cpp index 6f8c8497..e0a3ce42 100644 --- a/libs/helide/scene/Group.cpp +++ b/libs/helide/scene/Group.cpp @@ -54,7 +54,7 @@ void Group::commit() std::transform(m_volumeData->handlesBegin(), m_volumeData->handlesEnd(), std::back_inserter(m_volumes), - [](Object *o) { return (Volume *)o; }); + [](auto *o) { return (Volume *)o; }); } } @@ -123,7 +123,7 @@ void Group::embreeSceneConstruct() uint32_t id = 0; std::for_each(m_surfaceData->handlesBegin(), m_surfaceData->handlesEnd(), - [&](Object *o) { + [&](auto *o) { auto *s = (Surface *)o; if (s && s->isValid()) { m_surfaces.push_back(s); diff --git a/libs/helide/scene/World.cpp b/libs/helide/scene/World.cpp index 2d1f55e2..ce4beffb 100644 --- a/libs/helide/scene/World.cpp +++ b/libs/helide/scene/World.cpp @@ -89,7 +89,7 @@ void World::commit() m_instanceData->appendHandle(m_zeroInstance.ptr); std::for_each(m_instanceData->handlesBegin(), m_instanceData->handlesEnd(), - [&](Object *o) { + [&](auto *o) { if (o && o->isValid()) m_instances.push_back((Instance *)o); }); diff --git a/libs/helide/scene/surface/geometry/Geometry.h b/libs/helide/scene/surface/geometry/Geometry.h index cb7e2aab..5d261a28 100644 --- a/libs/helide/scene/surface/geometry/Geometry.h +++ b/libs/helide/scene/surface/geometry/Geometry.h @@ -3,6 +3,7 @@ #pragma once +#include "Object.h" #include "array/Array1D.h" // std #include @@ -22,11 +23,9 @@ struct Geometry : public Object void commit() override; void markCommitted() override; - virtual float4 getAttributeValue( - const Attribute &attr, const Ray &ray) const; + virtual float4 getAttributeValue(const Attribute &attr, const Ray &ray) const; protected: - RTCGeometry m_embreeGeometry{nullptr}; std::array, 5> m_attributes; diff --git a/libs/helide/scene/volume/spatial_field/StructuredRegularField.h b/libs/helide/scene/volume/spatial_field/StructuredRegularField.h index ce89cbb7..6dc7d3f0 100644 --- a/libs/helide/scene/volume/spatial_field/StructuredRegularField.h +++ b/libs/helide/scene/volume/spatial_field/StructuredRegularField.h @@ -34,7 +34,7 @@ struct StructuredRegularField : public SpatialField helium::IntrusivePtr m_dataArray; - void *m_data{nullptr}; + const void *m_data{nullptr}; anari::DataType m_type{ANARI_UNKNOWN}; }; diff --git a/libs/helium/BaseArray.cpp b/libs/helium/BaseArray.cpp deleted file mode 100644 index 8364c8c6..00000000 --- a/libs/helium/BaseArray.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2022 The Khronos Group -// SPDX-License-Identifier: Apache-2.0 - -#include "BaseArray.h" -// std -#include - -namespace helium { - -BaseArray::BaseArray(ANARIDataType type, BaseGlobalDeviceState *s) - : BaseObject(type, s) -{} - -} // namespace helium - -HELIUM_ANARI_TYPEFOR_DEFINITION(helium::BaseArray *); diff --git a/libs/helium/BaseArray.h b/libs/helium/BaseArray.h index c23e541f..e73353de 100644 --- a/libs/helium/BaseArray.h +++ b/libs/helium/BaseArray.h @@ -3,25 +3,4 @@ #pragma once -#include "BaseObject.h" - -namespace helium { - -struct BaseArray : public BaseObject -{ - BaseArray(ANARIDataType type, BaseGlobalDeviceState *s); - - // Implement anariMapArray() - virtual void *map() = 0; - - // Implement anariUnmapArray() - virtual void unmap() = 0; - - // This is invoked when this object's public ref count is 0, but still has a - // non-zero internal ref count. See README for additional explanation. - virtual void privatize() = 0; -}; - -} // namespace helium - -HELIUM_ANARI_TYPEFOR_SPECIALIZATION(helium::BaseArray *, ANARI_ARRAY); +#include "array/Array.h" diff --git a/libs/helium/BaseDevice.cpp b/libs/helium/BaseDevice.cpp index 6f7cb85c..0f2d57c8 100644 --- a/libs/helium/BaseDevice.cpp +++ b/libs/helium/BaseDevice.cpp @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 #include "BaseDevice.h" -#include "BaseArray.h" #include "BaseFrame.h" +#include "array/Array.h" // anari #include "anari/backend/LibraryImpl.h" diff --git a/libs/helium/BaseGlobalDeviceState.h b/libs/helium/BaseGlobalDeviceState.h index de0394ce..eb0e3a5b 100644 --- a/libs/helium/BaseGlobalDeviceState.h +++ b/libs/helium/BaseGlobalDeviceState.h @@ -5,13 +5,17 @@ #include "utility/DeferredCommitBuffer.h" // anari -#include +#include +#include // std #include #include namespace helium { +using namespace linalg::aliases; +using mat4 = float4x4; + struct BaseGlobalDeviceState { ANARIStatusCallback statusCB{nullptr}; diff --git a/libs/helium/BaseObject.cpp b/libs/helium/BaseObject.cpp index 2b7e07d0..ef31bdbc 100644 --- a/libs/helium/BaseObject.cpp +++ b/libs/helium/BaseObject.cpp @@ -100,6 +100,11 @@ void BaseObject::notifyCommitObservers() const notifyObserver(o); } +BaseGlobalDeviceState *BaseObject::deviceState() const +{ + return m_state; +} + void BaseObject::notifyObserver(BaseObject *obj) const { // no-op diff --git a/libs/helium/BaseObject.h b/libs/helium/BaseObject.h index 3c93c7b3..9471915c 100644 --- a/libs/helium/BaseObject.h +++ b/libs/helium/BaseObject.h @@ -38,7 +38,7 @@ struct BaseObject : public RefCounted, ParameterizedObject // means. Devices must be able to handle object subtypes that it does not // implement, or handle cases when objects are ill-formed. This gives a // generic place to ask the object if it's 'OK' to use. - virtual bool isValid() const; + virtual bool isValid() const = 0; // Object ANARIDataType type() const; @@ -60,6 +60,8 @@ struct BaseObject : public RefCounted, ParameterizedObject void removeCommitObserver(BaseObject *obj); void notifyCommitObservers() const; + BaseGlobalDeviceState *deviceState() const; + protected: // Handle what happens when the observing object 'obj' is being notified of // that this object has changed. diff --git a/libs/helium/CMakeLists.txt b/libs/helium/CMakeLists.txt index bd6e7aa7..d2a5cf08 100644 --- a/libs/helium/CMakeLists.txt +++ b/libs/helium/CMakeLists.txt @@ -10,12 +10,17 @@ project(helium LANGUAGES CXX) project_add_library(STATIC) project_sources(PRIVATE - BaseArray.cpp BaseDevice.cpp BaseFrame.cpp BaseGlobalDeviceState.cpp BaseObject.cpp + array/Array.cpp + array/Array1D.cpp + array/Array2D.cpp + array/Array3D.cpp + array/ObjectArray.cpp + utility/DeferredCommitBuffer.cpp utility/ParameterizedObject.cpp utility/TimeStamp.cpp diff --git a/libs/helide/array/Array.cpp b/libs/helium/array/Array.cpp similarity index 72% rename from libs/helide/array/Array.cpp rename to libs/helium/array/Array.cpp index a9234bbc..f979f5a3 100644 --- a/libs/helide/array/Array.cpp +++ b/libs/helium/array/Array.cpp @@ -1,9 +1,9 @@ -// Copyright 2022 The Khronos Group +// Copyright 2023 The Khronos Group // SPDX-License-Identifier: Apache-2.0 #include "array/Array.h" -namespace helide { +namespace helium { // Helper functions // @@ -13,18 +13,28 @@ static void zeroOutStruct(T &v) std::memset(&v, 0, sizeof(T)); } +// BaseArray // + +BaseArray::BaseArray(ANARIDataType type, BaseGlobalDeviceState *s) + : BaseObject(type, s) +{} + +bool BaseArray::isValid() const +{ + return true; +} + // Array // Array::Array(ANARIDataType type, - HelideGlobalState *state, + BaseGlobalDeviceState *state, const ArrayMemoryDescriptor &d) - : helium::BaseArray(type, state), m_elementType(d.elementType) + : BaseArray(type, state), m_elementType(d.elementType) { - state->objectCounts.arrays++; - if (d.appMemory) { m_ownership = d.deleter ? ArrayDataOwnership::CAPTURED : ArrayDataOwnership::SHARED; + markDataModified(); } else m_ownership = ArrayDataOwnership::MANAGED; @@ -45,7 +55,6 @@ Array::Array(ANARIDataType type, Array::~Array() { freeAppMemory(); - deviceState()->objectCounts.arrays--; } ANARIDataType Array::elementType() const @@ -58,18 +67,17 @@ ArrayDataOwnership Array::ownership() const return m_ownership; } -void *Array::data() const +const void *Array::data() const { switch (ownership()) { case ArrayDataOwnership::SHARED: - return const_cast( - wasPrivatized() ? m_hostData.privatized.mem : m_hostData.shared.mem); + return wasPrivatized() ? m_hostData.privatized.mem : m_hostData.shared.mem; break; case ArrayDataOwnership::CAPTURED: - return const_cast(m_hostData.captured.mem); + return m_hostData.captured.mem; break; case ArrayDataOwnership::MANAGED: - return const_cast(m_hostData.managed.mem); + return m_hostData.managed.mem; break; default: break; @@ -83,47 +91,79 @@ size_t Array::totalCapacity() const return totalSize(); } -bool Array::getProperty( - const std::string_view &name, ANARIDataType type, void *ptr, uint32_t flags) -{ - return 0; -} - -void Array::commit() -{ - // no-op -} - void *Array::map() { - if (m_mapped) { + if (isMapped()) { reportMessage(ANARI_SEVERITY_WARNING, "array mapped again without being previously unmapped"); } m_mapped = true; - deviceState()->waitOnCurrentFrame(); - return data(); + return const_cast(data()); } void Array::unmap() { - if (!m_mapped) { + if (!isMapped()) { reportMessage(ANARI_SEVERITY_WARNING, "array unmapped again without being previously mapped"); return; } m_mapped = false; + markDataModified(); notifyCommitObservers(); } +bool Array::isMapped() const +{ + return m_mapped; +} + bool Array::wasPrivatized() const { return m_privatized; } -HelideGlobalState *Array::deviceState() const +void Array::markDataModified() +{ + m_lastDataModified = helium::newTimeStamp(); +} + +bool Array::isOffloaded() const { - return (HelideGlobalState *)helium::BaseObject::m_state; + return m_isOffloaded; +} + +void Array::markDataIsOffloaded(bool isOffloaded) +{ + m_isOffloaded = isOffloaded; +} + +void Array::uploadArrayData() const +{ + if (!isOffloaded() || !needToUploadData()) + return; + markDataUploaded(); +} + +void Array::markDataUploaded() const +{ + m_lastDataUploaded = helium::newTimeStamp(); +} + +bool Array::needToUploadData() const +{ + return m_lastDataModified > m_lastDataUploaded; +} + +bool Array::getProperty( + const std::string_view &name, ANARIDataType type, void *ptr, uint32_t flags) +{ + return 0; +} + +void Array::commit() +{ + // no-op } void Array::makePrivatizedCopy(size_t numElements) @@ -173,7 +213,7 @@ void Array::initManagedMemory() if (ownership() == ArrayDataOwnership::MANAGED) { auto totalBytes = totalSize() * anari::sizeOf(elementType()); m_hostData.managed.mem = malloc(totalBytes); - std::memset(data(), 0, totalBytes); + std::memset(m_hostData.managed.mem, 0, totalBytes); } } @@ -183,6 +223,6 @@ void Array::notifyObserver(BaseObject *o) const deviceState()->commitBuffer.addObject(o); } -} // namespace helide +} // namespace helium -HELIDE_ANARI_TYPEFOR_DEFINITION(helide::Array *); +HELIUM_ANARI_TYPEFOR_DEFINITION(helium::Array *); diff --git a/libs/helide/array/Array.h b/libs/helium/array/Array.h similarity index 51% rename from libs/helide/array/Array.h rename to libs/helium/array/Array.h index 46931436..94b19cf9 100644 --- a/libs/helide/array/Array.h +++ b/libs/helium/array/Array.h @@ -1,15 +1,34 @@ -// Copyright 2022 The Khronos Group +// Copyright 2023 The Khronos Group // SPDX-License-Identifier: Apache-2.0 #pragma once -#include "Object.h" -// helium -#include "helium/BaseArray.h" -// anari -#include "anari/anari_cpp.hpp" +#include "../BaseObject.h" +#include "../helium_math.h" -namespace helide { +namespace helium { + +// BaseArray interface //////////////////////////////////////////////////////// + +struct BaseArray : public BaseObject +{ + BaseArray(ANARIDataType type, BaseGlobalDeviceState *s); + + // Implement anariMapArray() + virtual void *map() = 0; + + // Implement anariUnmapArray() + virtual void unmap() = 0; + + // This is invoked when this object's public ref count is 0, but still has a + // non-zero internal ref count. See README for additional explanation. + virtual void privatize() = 0; + + // Arrays are always considered to be valid, though subclasses can override + bool isValid() const override; +}; + +// Basic, host-based Array implementation ///////////////////////////////////// enum class ArrayDataOwnership { @@ -27,38 +46,46 @@ struct ArrayMemoryDescriptor ANARIDataType elementType{ANARI_UNKNOWN}; }; -struct Array : public helium::BaseArray +struct Array : public BaseArray { Array(ANARIDataType type, - HelideGlobalState *state, + BaseGlobalDeviceState *state, const ArrayMemoryDescriptor &d); - virtual ~Array(); + virtual ~Array() override; ANARIDataType elementType() const; ArrayDataOwnership ownership() const; - void *data() const; + const void *data() const; template - T *dataAs() const; + const T *dataAs() const; virtual size_t totalSize() const = 0; virtual size_t totalCapacity() const; - bool getProperty(const std::string_view &name, - ANARIDataType type, - void *ptr, - uint32_t flags) override; - void commit() override; - void *map() override; + virtual void *map() override; virtual void unmap() override; virtual void privatize() override = 0; + bool isMapped() const; + bool wasPrivatized() const; - // CONSOLIDATE INTO helide::Object ////////////////////////////////////////// - HelideGlobalState *deviceState() const; - ///////////////////////////////////////////////////////////////////////////// + void markDataModified(); + + bool isOffloaded() const; + void markDataIsOffloaded(bool isOffloaded = true); + + virtual void uploadArrayData() const; + void markDataUploaded() const; + bool needToUploadData() const; + + virtual bool getProperty(const std::string_view &name, + ANARIDataType type, + void *ptr, + uint32_t flags); + virtual void commit(); protected: void makePrivatizedCopy(size_t numElements); @@ -92,26 +119,29 @@ struct Array : public helium::BaseArray } privatized; } m_hostData; + helium::TimeStamp m_lastDataModified{0}; + mutable helium::TimeStamp m_lastDataUploaded{0}; bool m_mapped{false}; private: ArrayDataOwnership m_ownership{ArrayDataOwnership::INVALID}; ANARIDataType m_elementType{ANARI_UNKNOWN}; bool m_privatized{false}; - mutable bool m_usedOnDevice{false}; + mutable bool m_isOffloaded{false}; }; // Inlined definitions //////////////////////////////////////////////////////// template -inline T *Array::dataAs() const +inline const T *Array::dataAs() const { if (anari::ANARITypeFor::value != m_elementType) throw std::runtime_error("incorrect element type queried for array"); - return (T *)data(); + return (const T *)data(); } -} // namespace helide +} // namespace helium -HELIDE_ANARI_TYPEFOR_SPECIALIZATION(helide::Array *, ANARI_ARRAY); +HELIUM_ANARI_TYPEFOR_SPECIALIZATION(helium::BaseArray *, ANARI_ARRAY); +HELIUM_ANARI_TYPEFOR_SPECIALIZATION(helium::Array *, ANARI_ARRAY); diff --git a/libs/helium/array/Array1D.cpp b/libs/helium/array/Array1D.cpp new file mode 100644 index 00000000..6d826f33 --- /dev/null +++ b/libs/helium/array/Array1D.cpp @@ -0,0 +1,88 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#include "array/Array1D.h" + +namespace helium { + +Array1D::Array1D(BaseGlobalDeviceState *state, const Array1DMemoryDescriptor &d) + : Array(ANARI_ARRAY1D, state, d), m_capacity(d.numItems), m_end(d.numItems) +{ + initManagedMemory(); +} + +void Array1D::commit() +{ + auto oldBegin = m_begin; + auto oldEnd = m_end; + + m_begin = getParam("begin", 0); + m_begin = std::clamp(m_begin, size_t(0), m_capacity - 1); + m_end = getParam("end", m_capacity); + m_end = std::clamp(m_end, size_t(1), m_capacity); + + if (size() == 0) { + reportMessage(ANARI_SEVERITY_ERROR, "array size must be greater than zero"); + return; + } + + if (m_begin > m_end) { + reportMessage(ANARI_SEVERITY_WARNING, + "array 'begin' is not less than 'end', swapping values"); + std::swap(m_begin, m_end); + } + + if (m_begin != oldBegin || m_end != oldEnd) { + markDataModified(); + notifyCommitObservers(); + } +} + +size_t Array1D::totalSize() const +{ + return size(); +} + +size_t Array1D::totalCapacity() const +{ + return m_capacity; +} + +const void *Array1D::begin() const +{ + auto *p = (unsigned char *)data(); + auto s = anari::sizeOf(elementType()); + return p + (s * m_begin); +} + +const void *Array1D::end() const +{ + auto *p = (unsigned char *)data(); + auto s = anari::sizeOf(elementType()); + return p + (s * m_end); +} + +size_t Array1D::size() const +{ + return m_end - m_begin; +} + +float4 Array1D::readAsAttributeValue(int32_t i, WrapMode wrap) const +{ + const auto idx = calculateWrapIndex(i, size(), wrap); + return readAsAttributeValueFlat(begin(), elementType(), idx); +} + +void Array1D::privatize() +{ + makePrivatizedCopy(size()); +} + +float4 readAttributeValue(const Array1D *arr, uint32_t i) +{ + return arr ? arr->readAsAttributeValue(i) : DEFAULT_ATTRIBUTE_VALUE; +} + +} // namespace helium + +HELIUM_ANARI_TYPEFOR_DEFINITION(helium::Array1D *); diff --git a/libs/helium/array/Array1D.h b/libs/helium/array/Array1D.h new file mode 100644 index 00000000..8c4e71b1 --- /dev/null +++ b/libs/helium/array/Array1D.h @@ -0,0 +1,91 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "Array.h" + +namespace helium { + +struct Array1DMemoryDescriptor : public ArrayMemoryDescriptor +{ + uint64_t numItems{0}; +}; + +bool isCompact(const Array1DMemoryDescriptor &d); + +struct Array1D : public Array +{ + Array1D(BaseGlobalDeviceState *state, const Array1DMemoryDescriptor &d); + + void commit() override; + + size_t totalSize() const override; + size_t totalCapacity() const override; + + const void *begin() const; + const void *end() const; + + template + const T *beginAs() const; + template + const T *endAs() const; + + size_t size() const; + + anari::math::float4 readAsAttributeValue( + int32_t i, WrapMode wrap = WrapMode::DEFAULT) const; + template + T valueAtLinear(float in) const; // 'in' must be clamped to [0, 1] + template + T valueAtClosest(float in) const; // 'in' must be clamped to [0, 1] + + void privatize() override; + + protected: + size_t m_capacity{0}; + size_t m_begin{0}; + size_t m_end{0}; +}; + +anari::math::float4 readAttributeValue(const Array1D *arr, uint32_t i); + +// Inlined definitions //////////////////////////////////////////////////////// + +template +inline const T *Array1D::beginAs() const +{ + if (anari::ANARITypeFor::value != elementType()) + throw std::runtime_error("incorrect element type queried for array"); + + return (T *)data() + m_begin; +} + +template +inline const T *Array1D::endAs() const +{ + if (anari::ANARITypeFor::value != elementType()) + throw std::runtime_error("incorrect element type queried for array"); + + return (T *)data() + m_end; +} + +template +inline T Array1D::valueAtLinear(float in) const +{ + const T *data = dataAs(); + const auto i = getInterpolant(in, size(), false); + return linalg::lerp(data[i.lower], data[i.upper], i.frac); +} + +template +inline T Array1D::valueAtClosest(float in) const +{ + const T *data = dataAs(); + const auto i = getInterpolant(in, size(), false); + return i.frac <= 0.5f ? data[i.lower] : data[i.upper]; +} + +} // namespace helium + +HELIUM_ANARI_TYPEFOR_SPECIALIZATION(helium::Array1D *, ANARI_ARRAY1D); diff --git a/libs/helium/array/Array2D.cpp b/libs/helium/array/Array2D.cpp new file mode 100644 index 00000000..ae3f05e5 --- /dev/null +++ b/libs/helium/array/Array2D.cpp @@ -0,0 +1,48 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#include "array/Array2D.h" + +namespace helium { + +Array2D::Array2D(BaseGlobalDeviceState *state, const Array2DMemoryDescriptor &d) + : Array(ANARI_ARRAY2D, state, d) +{ + m_size[0] = d.numItems1; + m_size[1] = d.numItems2; + + initManagedMemory(); +} + +size_t Array2D::totalSize() const +{ + return size(0) * size(1); +} + +size_t Array2D::size(int dim) const +{ + return m_size[dim]; +} + +uint2 Array2D::size() const +{ + return uint2(uint32_t(size(0)), uint32_t(size(1))); +} + +float4 Array2D::readAsAttributeValue( + int2 i, WrapMode wrap1, WrapMode wrap2) const +{ + const auto i_x = calculateWrapIndex(i.x, size().x, wrap1); + const auto i_y = calculateWrapIndex(i.y, size().y, wrap2); + const size_t idx = i_y * size().x + i_x; + return readAsAttributeValueFlat(data(), elementType(), idx); +} + +void Array2D::privatize() +{ + makePrivatizedCopy(size(0) * size(1)); +} + +} // namespace helium + +HELIUM_ANARI_TYPEFOR_DEFINITION(helium::Array2D *); diff --git a/libs/helium/array/Array2D.h b/libs/helium/array/Array2D.h new file mode 100644 index 00000000..5f44a854 --- /dev/null +++ b/libs/helium/array/Array2D.h @@ -0,0 +1,39 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "Array.h" + +namespace helium { + +struct Array2DMemoryDescriptor : public ArrayMemoryDescriptor +{ + uint64_t numItems1{0}; + uint64_t numItems2{0}; +}; + +bool isCompact(const Array2DMemoryDescriptor &d); + +struct Array2D : public Array +{ + Array2D(BaseGlobalDeviceState *state, const Array2DMemoryDescriptor &d); + + size_t totalSize() const override; + + size_t size(int dim) const; + anari::math::uint2 size() const; + + anari::math::float4 readAsAttributeValue(anari::math::int2 i, + WrapMode wrap1 = WrapMode::DEFAULT, + WrapMode wrap2 = WrapMode::DEFAULT) const; + + void privatize() override; + + private: + size_t m_size[2] = {0, 0}; +}; + +} // namespace helium + +HELIUM_ANARI_TYPEFOR_SPECIALIZATION(helium::Array2D *, ANARI_ARRAY2D); diff --git a/libs/helium/array/Array3D.cpp b/libs/helium/array/Array3D.cpp new file mode 100644 index 00000000..2f6530b1 --- /dev/null +++ b/libs/helium/array/Array3D.cpp @@ -0,0 +1,51 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#include "array/Array3D.h" + +namespace helium { + +Array3D::Array3D(BaseGlobalDeviceState *state, const Array3DMemoryDescriptor &d) + : Array(ANARI_ARRAY3D, state, d) +{ + m_size[0] = d.numItems1; + m_size[1] = d.numItems2; + m_size[2] = d.numItems3; + + initManagedMemory(); +} + +size_t Array3D::totalSize() const +{ + return size(0) * size(1) * size(2); +} + +size_t Array3D::size(int dim) const +{ + return m_size[dim]; +} + +uint3 Array3D::size() const +{ + return uint3(uint32_t(size(0)), uint32_t(size(1)), uint32_t(size(2))); +} + +float4 Array3D::readAsAttributeValue( + int3 i, WrapMode wrap1, WrapMode wrap2, WrapMode wrap3) const +{ + const auto i_x = calculateWrapIndex(i.x, size().x, wrap1); + const auto i_y = calculateWrapIndex(i.y, size().y, wrap2); + const auto i_z = calculateWrapIndex(i.z, size().z, wrap3); + const size_t idx = + size_t(i_x) + size().x * (size_t(i_y) + size().y * size_t(i_z)); + return readAsAttributeValueFlat(data(), elementType(), idx); +} + +void Array3D::privatize() +{ + makePrivatizedCopy(size(0) * size(1) * size(2)); +} + +} // namespace helium + +HELIUM_ANARI_TYPEFOR_DEFINITION(helium::Array3D *); diff --git a/libs/helium/array/Array3D.h b/libs/helium/array/Array3D.h new file mode 100644 index 00000000..c181cd38 --- /dev/null +++ b/libs/helium/array/Array3D.h @@ -0,0 +1,41 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "Array.h" + +namespace helium { + +struct Array3DMemoryDescriptor : public ArrayMemoryDescriptor +{ + uint64_t numItems1{0}; + uint64_t numItems2{0}; + uint64_t numItems3{0}; +}; + +bool isCompact(const Array3DMemoryDescriptor &d); + +struct Array3D : public Array +{ + Array3D(BaseGlobalDeviceState *state, const Array3DMemoryDescriptor &d); + + size_t totalSize() const override; + + size_t size(int dim) const; + anari::math::uint3 size() const; + + anari::math::float4 readAsAttributeValue(anari::math::int3 i, + WrapMode wrap1 = WrapMode::DEFAULT, + WrapMode wrap2 = WrapMode::DEFAULT, + WrapMode wrap3 = WrapMode::DEFAULT) const; + + void privatize() override; + + private: + size_t m_size[3] = {0, 0, 0}; +}; + +} // namespace helium + +HELIUM_ANARI_TYPEFOR_SPECIALIZATION(helium::Array3D *, ANARI_ARRAY3D); diff --git a/libs/helium/array/ObjectArray.cpp b/libs/helium/array/ObjectArray.cpp new file mode 100644 index 00000000..b7648e4f --- /dev/null +++ b/libs/helium/array/ObjectArray.cpp @@ -0,0 +1,147 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#include "array/ObjectArray.h" + +namespace helium { + +// Helper functions /////////////////////////////////////////////////////////// + +static void refIncObject(BaseObject *obj) +{ + if (obj) + obj->refInc(helium::RefType::INTERNAL); +} + +static void refDecObject(BaseObject *obj) +{ + if (obj) + obj->refDec(helium::RefType::INTERNAL); +} + +// ObjectArray definitions //////////////////////////////////////////////////// + +ObjectArray::ObjectArray( + BaseGlobalDeviceState *state, const Array1DMemoryDescriptor &d) + : Array(ANARI_ARRAY1D, state, d), m_capacity(d.numItems), m_end(d.numItems) +{ + m_appHandles.resize(d.numItems, nullptr); + initManagedMemory(); + updateInternalHandleArrays(); +} + +ObjectArray::~ObjectArray() +{ + std::for_each(m_appHandles.begin(), m_appHandles.end(), refDecObject); + std::for_each( + m_appendedHandles.begin(), m_appendedHandles.end(), refDecObject); +} + +void ObjectArray::commit() +{ + auto oldBegin = m_begin; + auto oldEnd = m_end; + + m_begin = getParam("begin", 0); + m_begin = std::clamp(m_begin, size_t(0), m_capacity - 1); + m_end = getParam("end", m_capacity); + m_end = std::clamp(m_end, size_t(1), m_capacity); + + if (size() == 0) { + reportMessage(ANARI_SEVERITY_ERROR, "array size must be greater than zero"); + return; + } + + if (m_begin > m_end) { + reportMessage(ANARI_SEVERITY_WARNING, + "array 'begin' is not less than 'end', swapping values"); + std::swap(m_begin, m_end); + } + + if (m_begin != oldBegin || m_end != oldEnd) { + markDataModified(); + notifyCommitObservers(); + } +} + +size_t ObjectArray::totalSize() const +{ + return size() + m_appendedHandles.size(); +} + +size_t ObjectArray::totalCapacity() const +{ + return m_capacity; +} + +size_t ObjectArray::size() const +{ + return m_end - m_begin; +} + +void ObjectArray::privatize() +{ + makePrivatizedCopy(size()); + freeAppMemory(); + if (data()) { + reportMessage(ANARI_SEVERITY_WARNING, + "ObjectArray privatized but host array still present"); + } +} + +void ObjectArray::unmap() +{ + if (isMapped()) + updateInternalHandleArrays(); + Array::unmap(); +} + +BaseObject **ObjectArray::handlesBegin() const +{ + return m_liveHandles.data() + m_begin; +} + +BaseObject **ObjectArray::handlesEnd() const +{ + return handlesBegin() + totalSize(); +} + +void ObjectArray::appendHandle(BaseObject *o) +{ + o->refInc(helium::RefType::INTERNAL); + m_appendedHandles.push_back(o); + updateInternalHandleArrays(); +} + +void ObjectArray::removeAppendedHandles() +{ + m_liveHandles.resize(size()); + for (auto o : m_appendedHandles) + o->refDec(helium::RefType::INTERNAL); + m_appendedHandles.clear(); +} + +void ObjectArray::updateInternalHandleArrays() const +{ + m_liveHandles.resize(totalSize()); + + if (data()) { + auto **srcAllBegin = (BaseObject **)data(); + auto **srcAllEnd = srcAllBegin + totalCapacity(); + std::for_each(srcAllBegin, srcAllEnd, refIncObject); + std::for_each(m_appHandles.begin(), m_appHandles.end(), refDecObject); + std::copy(srcAllBegin, srcAllEnd, m_appHandles.data()); + + auto **srcRegionBegin = srcAllBegin + m_begin; + auto **srcRegionEnd = srcRegionBegin + size(); + std::copy(srcRegionBegin, srcRegionEnd, m_liveHandles.data()); + } + + std::copy(m_appendedHandles.begin(), + m_appendedHandles.end(), + m_liveHandles.begin() + size()); +} + +} // namespace helium + +HELIUM_ANARI_TYPEFOR_DEFINITION(helium::ObjectArray *); diff --git a/libs/helium/array/ObjectArray.h b/libs/helium/array/ObjectArray.h new file mode 100644 index 00000000..776e0d7d --- /dev/null +++ b/libs/helium/array/ObjectArray.h @@ -0,0 +1,44 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "Array1D.h" + +namespace helium { + +struct ObjectArray : public Array +{ + ObjectArray(BaseGlobalDeviceState *state, const Array1DMemoryDescriptor &d); + ~ObjectArray(); + + void commit() override; + + size_t totalSize() const override; + size_t totalCapacity() const override; + + size_t size() const; + + void privatize() override; + void unmap() override; + + BaseObject **handlesBegin() const; + BaseObject **handlesEnd() const; + + void appendHandle(BaseObject *); + void removeAppendedHandles(); + + private: + void updateInternalHandleArrays() const; + + mutable std::vector m_appendedHandles; + mutable std::vector m_appHandles; + mutable std::vector m_liveHandles; + size_t m_capacity{0}; + size_t m_begin{0}; + size_t m_end{0}; +}; + +} // namespace helium + +HELIUM_ANARI_TYPEFOR_SPECIALIZATION(helium::ObjectArray *, ANARI_ARRAY1D); diff --git a/libs/helium/helium_math.h b/libs/helium/helium_math.h new file mode 100644 index 00000000..5691f3de --- /dev/null +++ b/libs/helium/helium_math.h @@ -0,0 +1,341 @@ +// Copyright 2022 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +// anari +#include +#include +// std +#include +#include + +namespace helium::math { + +// Types ////////////////////////////////////////////////////////////////////// + +template +struct range_t +{ + using element_t = T; + + range_t() = default; + range_t(const T &t) : lower(t), upper(t) {} + range_t(const T &_lower, const T &_upper) : lower(_lower), upper(_upper) {} + + range_t &extend(const T &t) + { + lower = min(lower, t); + upper = max(upper, t); + return *this; + } + + range_t &extend(const range_t &t) + { + lower = min(lower, t.lower); + upper = max(upper, t.upper); + return *this; + } + + T lower{T(std::numeric_limits::max())}; + T upper{T(-std::numeric_limits::max())}; +}; + +using box1 = range_t; +using box2 = range_t; +using box3 = range_t; + +template +inline typename range_t::element_t size(const range_t &r) +{ + return r.upper - r.lower; +} + +template +inline typename range_t::element_t clamp( + const typename range_t::element_t &t, const range_t &r) +{ + return linalg::max(r.lower, linalg::min(t, r.upper)); +} + +inline float position(float v, const box1 &r) +{ + return (v - r.lower) * (1.f / size(r)); +} + +constexpr anari::math::float4 DEFAULT_ATTRIBUTE_VALUE(0.f, 0.f, 0.f, 1.f); + +enum class Attribute +{ + ATTRIBUTE_0 = 0, + ATTRIBUTE_1, + ATTRIBUTE_2, + ATTRIBUTE_3, + COLOR, + NONE +}; + +enum WrapMode +{ + CLAMP_TO_EDGE = 0, + REPEAT, + MIRROR_REPEAT, + DEFAULT +}; + +enum class AlphaMode +{ + OPAQUE, + MASK, + BLEND +}; + +// Functions ////////////////////////////////////////////////////////////////// + +inline anari::math::mat3 extractRotation(const anari::math::mat4 &m) +{ + return anari::math::mat3(anari::math::float3(m[0].x, m[0].y, m[0].z), + anari::math::float3(m[1].x, m[1].y, m[1].z), + anari::math::float3(m[2].x, m[2].y, m[2].z)); +} + +template +inline float toneMap(float v) +{ + if constexpr (SRGB) + return std::pow(v, 1.f / 2.2f); + else + return v; +} + +struct Interpolant +{ + int32_t lower; + int32_t upper; + float frac; +}; + +inline Interpolant getInterpolant(float in, size_t size, bool texOffset = false) +{ + const float scale = float(size); + const float lowf = + texOffset ? (in - (0.5f / scale)) * scale : (in * (scale - 1.f)); + const int32_t low = std::floor(lowf); + const int32_t high = low + 1; + const float frac = lowf - low; + return {low, high, frac}; +} + +template +inline T lerp(const T &x, const T &y, const U &a) +{ + return static_cast(x * (U(1) - a) + y * a); +} + +template +inline void accumulateValue(T &a, const T &b, float interp) +{ + a += b * (1.f - interp); +} + +inline int32_t computeMirroredRepeatIndex(int32_t x, int32_t size) +{ + x = std::abs(x + (x < 0)) % (2 * size); + return x >= size ? 2 * size - x - 1 : x; +}; + +inline int32_t calculateWrapIndex(int32_t i, size_t size, WrapMode wrap) +{ + switch (wrap) { + case WrapMode::CLAMP_TO_EDGE: + case WrapMode::DEFAULT: + default: + return linalg::clamp(i, 0, int32_t(size - 1)); + break; + case WrapMode::REPEAT: + return i % size; + break; + case WrapMode::MIRROR_REPEAT: + return computeMirroredRepeatIndex(i, int32_t(size)); + break; + } +} + +inline Attribute attributeFromString(const std::string &str) +{ + if (str == "color") + return Attribute::COLOR; + else if (str == "attribute0") + return Attribute::ATTRIBUTE_0; + else if (str == "attribute1") + return Attribute::ATTRIBUTE_1; + else if (str == "attribute2") + return Attribute::ATTRIBUTE_2; + else if (str == "attribute3") + return Attribute::ATTRIBUTE_3; + else + return Attribute::NONE; +} + +inline WrapMode wrapModeFromString(const std::string &str) +{ + if (str == "clampToEdge") + return WrapMode::CLAMP_TO_EDGE; + else if (str == "repeat") + return WrapMode::REPEAT; + else if (str == "mirrorRepeat") + return WrapMode::MIRROR_REPEAT; + else + return WrapMode::DEFAULT; +} + +inline AlphaMode alphaModeFromString(const std::string &str) +{ + if (str == "blend") + return AlphaMode::BLEND; + else if (str == "mask") + return AlphaMode::MASK; + else + return AlphaMode::OPAQUE; +} + +inline float adjustOpacityFromMode( + float opacity, float maskThreshold, AlphaMode mode) +{ + switch (mode) { + case AlphaMode::BLEND: + return opacity; + case AlphaMode::MASK: + return opacity >= maskThreshold ? 1.f : 0.f; + case AlphaMode::OPAQUE: + default: + return 1.f; + } +} + +template +static const T *typedOffset(const void *mem, uint64_t offset) +{ + return ((const T *)mem) + offset; +} + +template +static anari::math::float4 getAttributeArrayAt_ufixed( + const void *data, uint64_t offset) +{ + constexpr float m = std::numeric_limits::max(); + anari::math::float4 retval(0.f, 0.f, 0.f, 1.f); + switch (NUM_COMPONENTS) { + case 4: + retval.w = toneMap( + *typedOffset(data, NUM_COMPONENTS * offset + 3) / m); + case 3: + retval.z = toneMap( + *typedOffset(data, NUM_COMPONENTS * offset + 2) / m); + case 2: + retval.y = toneMap( + *typedOffset(data, NUM_COMPONENTS * offset + 1) / m); + case 1: + retval.x = toneMap( + *typedOffset(data, NUM_COMPONENTS * offset + 0) / m); + default: + break; + } + + return retval; +} + +inline anari::math::float4 readAsAttributeValueFlat( + const void *data, ANARIDataType type, uint64_t i) +{ + auto retval = DEFAULT_ATTRIBUTE_VALUE; + + switch (type) { + case ANARI_FLOAT32: + std::memcpy(&retval, typedOffset(data, i), sizeof(float)); + break; + case ANARI_FLOAT32_VEC2: + std::memcpy(&retval, + typedOffset(data, i), + sizeof(anari::math::float2)); + break; + case ANARI_FLOAT32_VEC3: + std::memcpy(&retval, + typedOffset(data, i), + sizeof(anari::math::float3)); + break; + case ANARI_FLOAT32_VEC4: + std::memcpy(&retval, + typedOffset(data, i), + sizeof(anari::math::float4)); + break; + case ANARI_UFIXED8_R_SRGB: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED8_RA_SRGB: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED8_RGB_SRGB: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED8_RGBA_SRGB: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED8: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED8_VEC2: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED8_VEC3: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED8_VEC4: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED16: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED16_VEC2: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED16_VEC3: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED16_VEC4: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED32: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED32_VEC2: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED32_VEC3: + retval = getAttributeArrayAt_ufixed(data, i); + break; + case ANARI_UFIXED32_VEC4: + retval = getAttributeArrayAt_ufixed(data, i); + break; + default: + break; + } + + return retval; +} + +} // namespace helium::math + +namespace helium { +using namespace ::helium::math; +} // namespace helium + +namespace anari { + +ANARI_TYPEFOR_SPECIALIZATION(helium::box1, ANARI_FLOAT32_BOX1); + +#ifdef helium_ANARI_DEFINITIONS +ANARI_TYPEFOR_DEFINITION(helium::box1); +#endif + +} // namespace anari diff --git a/tests/render/main.cpp b/tests/render/main.cpp index 85a939f2..d839178b 100644 --- a/tests/render/main.cpp +++ b/tests/render/main.cpp @@ -32,7 +32,7 @@ static const std::vector> g_scenes = []() { std::string g_category; std::string g_scene; -anari::uint2 g_frameSize(1024, 768); +anari::math::uint2 g_frameSize(1024, 768); int g_numPixelSamples = 1; std::string g_libraryType = "environment"; std::string g_deviceType = "default"; @@ -117,7 +117,7 @@ static void renderScene( auto renderer = anari::newObject(d, g_rendererType.c_str()); anari::setParameter(d, renderer, "pixelSamples", g_numPixelSamples); anari::setParameter( - d, renderer, "background", anari::float4(anari::float3(0.1f), 1)); + d, renderer, "background", anari::math::float4(anari::math::float3(0.1f), 1)); anari::commitParameters(d, renderer); auto frame = anari::newObject(d); From bf50ded5c94632c6f45c145d12b38631c6340ac5 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Thu, 2 Nov 2023 16:29:27 -0500 Subject: [PATCH 17/34] CMake updates (#166) * remove unused link to glm in CTS backend * remove glm linkage in main library, move to cts * remove unused Threads link in frontend lib * remove version information for dependent anari_viewer external libs * Use CMake components to optionally include viewer + code_gen downstream * remove unused generator expressions --- CMakeLists.txt | 4 --- README.md | 14 ++++++++++ cmake/anariConfig.cmake.in | 19 ++++++++------ code_gen/CMakeLists.txt | 1 + cts/CMakeLists.txt | 4 +++ .../external}/glm/include/glm/common.hpp | 0 .../glm/include/glm/detail/_features.hpp | 0 .../glm/include/glm/detail/_fixes.hpp | 0 .../glm/include/glm/detail/_noise.hpp | 0 .../glm/include/glm/detail/_swizzle.hpp | 0 .../glm/include/glm/detail/_swizzle_func.hpp | 0 .../glm/include/glm/detail/_vectorize.hpp | 0 .../glm/include/glm/detail/compute_common.hpp | 0 .../glm/detail/compute_vector_relational.hpp | 0 .../glm/include/glm/detail/func_common.inl | 0 .../include/glm/detail/func_common_simd.inl | 0 .../include/glm/detail/func_exponential.inl | 0 .../glm/detail/func_exponential_simd.inl | 0 .../glm/include/glm/detail/func_geometric.inl | 0 .../glm/detail/func_geometric_simd.inl | 0 .../glm/include/glm/detail/func_integer.inl | 0 .../include/glm/detail/func_integer_simd.inl | 0 .../glm/include/glm/detail/func_matrix.inl | 0 .../include/glm/detail/func_matrix_simd.inl | 0 .../glm/include/glm/detail/func_packing.inl | 0 .../include/glm/detail/func_packing_simd.inl | 0 .../include/glm/detail/func_trigonometric.inl | 0 .../glm/detail/func_trigonometric_simd.inl | 0 .../glm/detail/func_vector_relational.inl | 0 .../detail/func_vector_relational_simd.inl | 0 .../external}/glm/include/glm/detail/glm.cpp | 0 .../glm/include/glm/detail/qualifier.hpp | 0 .../glm/include/glm/detail/setup.hpp | 0 .../glm/include/glm/detail/type_float.hpp | 0 .../glm/include/glm/detail/type_half.hpp | 0 .../glm/include/glm/detail/type_half.inl | 0 .../glm/include/glm/detail/type_mat2x2.hpp | 0 .../glm/include/glm/detail/type_mat2x2.inl | 0 .../glm/include/glm/detail/type_mat2x3.hpp | 0 .../glm/include/glm/detail/type_mat2x3.inl | 0 .../glm/include/glm/detail/type_mat2x4.hpp | 0 .../glm/include/glm/detail/type_mat2x4.inl | 0 .../glm/include/glm/detail/type_mat3x2.hpp | 0 .../glm/include/glm/detail/type_mat3x2.inl | 0 .../glm/include/glm/detail/type_mat3x3.hpp | 0 .../glm/include/glm/detail/type_mat3x3.inl | 0 .../glm/include/glm/detail/type_mat3x4.hpp | 0 .../glm/include/glm/detail/type_mat3x4.inl | 0 .../glm/include/glm/detail/type_mat4x2.hpp | 0 .../glm/include/glm/detail/type_mat4x2.inl | 0 .../glm/include/glm/detail/type_mat4x3.hpp | 0 .../glm/include/glm/detail/type_mat4x3.inl | 0 .../glm/include/glm/detail/type_mat4x4.hpp | 0 .../glm/include/glm/detail/type_mat4x4.inl | 0 .../include/glm/detail/type_mat4x4_simd.inl | 0 .../glm/include/glm/detail/type_quat.hpp | 0 .../glm/include/glm/detail/type_quat.inl | 0 .../glm/include/glm/detail/type_quat_simd.inl | 0 .../glm/include/glm/detail/type_vec1.hpp | 0 .../glm/include/glm/detail/type_vec1.inl | 0 .../glm/include/glm/detail/type_vec2.hpp | 0 .../glm/include/glm/detail/type_vec2.inl | 0 .../glm/include/glm/detail/type_vec3.hpp | 0 .../glm/include/glm/detail/type_vec3.inl | 0 .../glm/include/glm/detail/type_vec4.hpp | 0 .../glm/include/glm/detail/type_vec4.inl | 0 .../glm/include/glm/detail/type_vec4_simd.inl | 0 .../external}/glm/include/glm/exponential.hpp | 0 .../external}/glm/include/glm/ext.hpp | 0 .../glm/include/glm/ext/matrix_clip_space.hpp | 0 .../glm/include/glm/ext/matrix_clip_space.inl | 0 .../glm/include/glm/ext/matrix_common.hpp | 0 .../glm/include/glm/ext/matrix_common.inl | 0 .../glm/include/glm/ext/matrix_double2x2.hpp | 0 .../glm/ext/matrix_double2x2_precision.hpp | 0 .../glm/include/glm/ext/matrix_double2x3.hpp | 0 .../glm/ext/matrix_double2x3_precision.hpp | 0 .../glm/include/glm/ext/matrix_double2x4.hpp | 0 .../glm/ext/matrix_double2x4_precision.hpp | 0 .../glm/include/glm/ext/matrix_double3x2.hpp | 0 .../glm/ext/matrix_double3x2_precision.hpp | 0 .../glm/include/glm/ext/matrix_double3x3.hpp | 0 .../glm/ext/matrix_double3x3_precision.hpp | 0 .../glm/include/glm/ext/matrix_double3x4.hpp | 0 .../glm/ext/matrix_double3x4_precision.hpp | 0 .../glm/include/glm/ext/matrix_double4x2.hpp | 0 .../glm/ext/matrix_double4x2_precision.hpp | 0 .../glm/include/glm/ext/matrix_double4x3.hpp | 0 .../glm/ext/matrix_double4x3_precision.hpp | 0 .../glm/include/glm/ext/matrix_double4x4.hpp | 0 .../glm/ext/matrix_double4x4_precision.hpp | 0 .../glm/include/glm/ext/matrix_float2x2.hpp | 0 .../glm/ext/matrix_float2x2_precision.hpp | 0 .../glm/include/glm/ext/matrix_float2x3.hpp | 0 .../glm/ext/matrix_float2x3_precision.hpp | 0 .../glm/include/glm/ext/matrix_float2x4.hpp | 0 .../glm/ext/matrix_float2x4_precision.hpp | 0 .../glm/include/glm/ext/matrix_float3x2.hpp | 0 .../glm/ext/matrix_float3x2_precision.hpp | 0 .../glm/include/glm/ext/matrix_float3x3.hpp | 0 .../glm/ext/matrix_float3x3_precision.hpp | 0 .../glm/include/glm/ext/matrix_float3x4.hpp | 0 .../glm/ext/matrix_float3x4_precision.hpp | 0 .../glm/include/glm/ext/matrix_float4x2.hpp | 0 .../glm/ext/matrix_float4x2_precision.hpp | 0 .../glm/include/glm/ext/matrix_float4x3.hpp | 0 .../glm/ext/matrix_float4x3_precision.hpp | 0 .../glm/include/glm/ext/matrix_float4x4.hpp | 0 .../glm/ext/matrix_float4x4_precision.hpp | 0 .../glm/include/glm/ext/matrix_int2x2.hpp | 0 .../include/glm/ext/matrix_int2x2_sized.hpp | 0 .../glm/include/glm/ext/matrix_int2x3.hpp | 0 .../include/glm/ext/matrix_int2x3_sized.hpp | 0 .../glm/include/glm/ext/matrix_int2x4.hpp | 0 .../include/glm/ext/matrix_int2x4_sized.hpp | 0 .../glm/include/glm/ext/matrix_int3x2.hpp | 0 .../include/glm/ext/matrix_int3x2_sized.hpp | 0 .../glm/include/glm/ext/matrix_int3x3.hpp | 0 .../include/glm/ext/matrix_int3x3_sized.hpp | 0 .../glm/include/glm/ext/matrix_int3x4.hpp | 0 .../include/glm/ext/matrix_int3x4_sized.hpp | 0 .../glm/include/glm/ext/matrix_int4x2.hpp | 0 .../include/glm/ext/matrix_int4x2_sized.hpp | 0 .../glm/include/glm/ext/matrix_int4x3.hpp | 0 .../include/glm/ext/matrix_int4x3_sized.hpp | 0 .../glm/include/glm/ext/matrix_int4x4.hpp | 0 .../include/glm/ext/matrix_int4x4_sized.hpp | 0 .../glm/include/glm/ext/matrix_integer.hpp | 0 .../glm/include/glm/ext/matrix_integer.inl | 0 .../glm/include/glm/ext/matrix_projection.hpp | 0 .../glm/include/glm/ext/matrix_projection.inl | 0 .../glm/include/glm/ext/matrix_relational.hpp | 0 .../glm/include/glm/ext/matrix_relational.inl | 0 .../glm/include/glm/ext/matrix_transform.hpp | 0 .../glm/include/glm/ext/matrix_transform.inl | 0 .../glm/include/glm/ext/matrix_uint2x2.hpp | 0 .../include/glm/ext/matrix_uint2x2_sized.hpp | 0 .../glm/include/glm/ext/matrix_uint2x3.hpp | 0 .../include/glm/ext/matrix_uint2x3_sized.hpp | 0 .../glm/include/glm/ext/matrix_uint2x4.hpp | 0 .../include/glm/ext/matrix_uint2x4_sized.hpp | 0 .../glm/include/glm/ext/matrix_uint3x2.hpp | 0 .../include/glm/ext/matrix_uint3x2_sized.hpp | 0 .../glm/include/glm/ext/matrix_uint3x3.hpp | 0 .../include/glm/ext/matrix_uint3x3_sized.hpp | 0 .../glm/include/glm/ext/matrix_uint3x4.hpp | 0 .../include/glm/ext/matrix_uint3x4_sized.hpp | 0 .../glm/include/glm/ext/matrix_uint4x2.hpp | 0 .../include/glm/ext/matrix_uint4x2_sized.hpp | 0 .../glm/include/glm/ext/matrix_uint4x3.hpp | 0 .../include/glm/ext/matrix_uint4x3_sized.hpp | 0 .../glm/include/glm/ext/matrix_uint4x4.hpp | 0 .../include/glm/ext/matrix_uint4x4_sized.hpp | 0 .../glm/include/glm/ext/quaternion_common.hpp | 0 .../glm/include/glm/ext/quaternion_common.inl | 0 .../glm/ext/quaternion_common_simd.inl | 0 .../glm/include/glm/ext/quaternion_double.hpp | 0 .../glm/ext/quaternion_double_precision.hpp | 0 .../glm/ext/quaternion_exponential.hpp | 0 .../glm/ext/quaternion_exponential.inl | 0 .../glm/include/glm/ext/quaternion_float.hpp | 0 .../glm/ext/quaternion_float_precision.hpp | 0 .../include/glm/ext/quaternion_geometric.hpp | 0 .../include/glm/ext/quaternion_geometric.inl | 0 .../include/glm/ext/quaternion_relational.hpp | 0 .../include/glm/ext/quaternion_relational.inl | 0 .../include/glm/ext/quaternion_transform.hpp | 0 .../include/glm/ext/quaternion_transform.inl | 0 .../glm/ext/quaternion_trigonometric.hpp | 0 .../glm/ext/quaternion_trigonometric.inl | 0 .../glm/include/glm/ext/scalar_common.hpp | 0 .../glm/include/glm/ext/scalar_common.inl | 0 .../glm/include/glm/ext/scalar_constants.hpp | 0 .../glm/include/glm/ext/scalar_constants.inl | 0 .../glm/include/glm/ext/scalar_int_sized.hpp | 0 .../glm/include/glm/ext/scalar_integer.hpp | 0 .../glm/include/glm/ext/scalar_integer.inl | 0 .../glm/include/glm/ext/scalar_packing.hpp | 0 .../glm/include/glm/ext/scalar_packing.inl | 0 .../glm/include/glm/ext/scalar_reciprocal.hpp | 0 .../glm/include/glm/ext/scalar_reciprocal.inl | 0 .../glm/include/glm/ext/scalar_relational.hpp | 0 .../glm/include/glm/ext/scalar_relational.inl | 0 .../glm/include/glm/ext/scalar_uint_sized.hpp | 0 .../glm/include/glm/ext/scalar_ulp.hpp | 0 .../glm/include/glm/ext/scalar_ulp.inl | 0 .../glm/include/glm/ext/vector_bool1.hpp | 0 .../glm/ext/vector_bool1_precision.hpp | 0 .../glm/include/glm/ext/vector_bool2.hpp | 0 .../glm/ext/vector_bool2_precision.hpp | 0 .../glm/include/glm/ext/vector_bool3.hpp | 0 .../glm/ext/vector_bool3_precision.hpp | 0 .../glm/include/glm/ext/vector_bool4.hpp | 0 .../glm/ext/vector_bool4_precision.hpp | 0 .../glm/include/glm/ext/vector_common.hpp | 0 .../glm/include/glm/ext/vector_common.inl | 0 .../glm/include/glm/ext/vector_double1.hpp | 0 .../glm/ext/vector_double1_precision.hpp | 0 .../glm/include/glm/ext/vector_double2.hpp | 0 .../glm/ext/vector_double2_precision.hpp | 0 .../glm/include/glm/ext/vector_double3.hpp | 0 .../glm/ext/vector_double3_precision.hpp | 0 .../glm/include/glm/ext/vector_double4.hpp | 0 .../glm/ext/vector_double4_precision.hpp | 0 .../glm/include/glm/ext/vector_float1.hpp | 0 .../glm/ext/vector_float1_precision.hpp | 0 .../glm/include/glm/ext/vector_float2.hpp | 0 .../glm/ext/vector_float2_precision.hpp | 0 .../glm/include/glm/ext/vector_float3.hpp | 0 .../glm/ext/vector_float3_precision.hpp | 0 .../glm/include/glm/ext/vector_float4.hpp | 0 .../glm/ext/vector_float4_precision.hpp | 0 .../glm/include/glm/ext/vector_int1.hpp | 0 .../glm/include/glm/ext/vector_int1_sized.hpp | 0 .../glm/include/glm/ext/vector_int2.hpp | 0 .../glm/include/glm/ext/vector_int2_sized.hpp | 0 .../glm/include/glm/ext/vector_int3.hpp | 0 .../glm/include/glm/ext/vector_int3_sized.hpp | 0 .../glm/include/glm/ext/vector_int4.hpp | 0 .../glm/include/glm/ext/vector_int4_sized.hpp | 0 .../glm/include/glm/ext/vector_integer.hpp | 0 .../glm/include/glm/ext/vector_integer.inl | 0 .../glm/include/glm/ext/vector_packing.hpp | 0 .../glm/include/glm/ext/vector_packing.inl | 0 .../glm/include/glm/ext/vector_reciprocal.hpp | 0 .../glm/include/glm/ext/vector_reciprocal.inl | 0 .../glm/include/glm/ext/vector_relational.hpp | 0 .../glm/include/glm/ext/vector_relational.inl | 0 .../glm/include/glm/ext/vector_uint1.hpp | 0 .../include/glm/ext/vector_uint1_sized.hpp | 0 .../glm/include/glm/ext/vector_uint2.hpp | 0 .../include/glm/ext/vector_uint2_sized.hpp | 0 .../glm/include/glm/ext/vector_uint3.hpp | 0 .../include/glm/ext/vector_uint3_sized.hpp | 0 .../glm/include/glm/ext/vector_uint4.hpp | 0 .../include/glm/ext/vector_uint4_sized.hpp | 0 .../glm/include/glm/ext/vector_ulp.hpp | 0 .../glm/include/glm/ext/vector_ulp.inl | 0 .../external}/glm/include/glm/fwd.hpp | 0 .../external}/glm/include/glm/geometric.hpp | 0 .../external}/glm/include/glm/glm.hpp | 0 .../glm/include/glm/gtc/bitfield.hpp | 0 .../glm/include/glm/gtc/bitfield.inl | 0 .../glm/include/glm/gtc/color_space.hpp | 0 .../glm/include/glm/gtc/color_space.inl | 0 .../glm/include/glm/gtc/constants.hpp | 0 .../glm/include/glm/gtc/constants.inl | 0 .../external}/glm/include/glm/gtc/epsilon.hpp | 0 .../external}/glm/include/glm/gtc/epsilon.inl | 0 .../external}/glm/include/glm/gtc/integer.hpp | 0 .../external}/glm/include/glm/gtc/integer.inl | 0 .../glm/include/glm/gtc/matrix_access.hpp | 0 .../glm/include/glm/gtc/matrix_access.inl | 0 .../glm/include/glm/gtc/matrix_integer.hpp | 0 .../glm/include/glm/gtc/matrix_inverse.hpp | 0 .../glm/include/glm/gtc/matrix_inverse.inl | 0 .../glm/include/glm/gtc/matrix_transform.hpp | 0 .../glm/include/glm/gtc/matrix_transform.inl | 0 .../external}/glm/include/glm/gtc/noise.hpp | 0 .../external}/glm/include/glm/gtc/noise.inl | 0 .../external}/glm/include/glm/gtc/packing.hpp | 0 .../external}/glm/include/glm/gtc/packing.inl | 0 .../glm/include/glm/gtc/quaternion.hpp | 0 .../glm/include/glm/gtc/quaternion.inl | 0 .../glm/include/glm/gtc/quaternion_simd.inl | 0 .../external}/glm/include/glm/gtc/random.hpp | 0 .../external}/glm/include/glm/gtc/random.inl | 0 .../glm/include/glm/gtc/reciprocal.hpp | 0 .../external}/glm/include/glm/gtc/round.hpp | 0 .../external}/glm/include/glm/gtc/round.inl | 0 .../glm/include/glm/gtc/type_aligned.hpp | 0 .../glm/include/glm/gtc/type_precision.hpp | 0 .../glm/include/glm/gtc/type_precision.inl | 0 .../glm/include/glm/gtc/type_ptr.hpp | 0 .../glm/include/glm/gtc/type_ptr.inl | 0 .../external}/glm/include/glm/gtc/ulp.hpp | 0 .../external}/glm/include/glm/gtc/ulp.inl | 0 .../external}/glm/include/glm/gtc/vec1.hpp | 0 .../include/glm/gtx/associated_min_max.hpp | 0 .../include/glm/gtx/associated_min_max.inl | 0 .../external}/glm/include/glm/gtx/bit.hpp | 0 .../external}/glm/include/glm/gtx/bit.inl | 0 .../glm/include/glm/gtx/closest_point.hpp | 0 .../glm/include/glm/gtx/closest_point.inl | 0 .../glm/include/glm/gtx/color_encoding.hpp | 0 .../glm/include/glm/gtx/color_encoding.inl | 0 .../glm/include/glm/gtx/color_space.hpp | 0 .../glm/include/glm/gtx/color_space.inl | 0 .../glm/include/glm/gtx/color_space_YCoCg.hpp | 0 .../glm/include/glm/gtx/color_space_YCoCg.inl | 0 .../external}/glm/include/glm/gtx/common.hpp | 0 .../external}/glm/include/glm/gtx/common.inl | 0 .../glm/include/glm/gtx/compatibility.hpp | 0 .../glm/include/glm/gtx/compatibility.inl | 0 .../glm/include/glm/gtx/component_wise.hpp | 0 .../glm/include/glm/gtx/component_wise.inl | 0 .../glm/include/glm/gtx/dual_quaternion.hpp | 0 .../glm/include/glm/gtx/dual_quaternion.inl | 0 .../external}/glm/include/glm/gtx/easing.hpp | 0 .../external}/glm/include/glm/gtx/easing.inl | 0 .../glm/include/glm/gtx/euler_angles.hpp | 0 .../glm/include/glm/gtx/euler_angles.inl | 0 .../external}/glm/include/glm/gtx/extend.hpp | 0 .../external}/glm/include/glm/gtx/extend.inl | 0 .../glm/include/glm/gtx/extended_min_max.hpp | 0 .../glm/include/glm/gtx/extended_min_max.inl | 0 .../glm/include/glm/gtx/exterior_product.hpp | 0 .../glm/include/glm/gtx/exterior_product.inl | 0 .../glm/include/glm/gtx/fast_exponential.hpp | 0 .../glm/include/glm/gtx/fast_exponential.inl | 0 .../glm/include/glm/gtx/fast_square_root.hpp | 0 .../glm/include/glm/gtx/fast_square_root.inl | 0 .../glm/include/glm/gtx/fast_trigonometry.hpp | 0 .../glm/include/glm/gtx/fast_trigonometry.inl | 0 .../glm/include/glm/gtx/float_notmalize.inl | 0 .../glm/include/glm/gtx/functions.hpp | 0 .../glm/include/glm/gtx/functions.inl | 0 .../glm/include/glm/gtx/gradient_paint.hpp | 0 .../glm/include/glm/gtx/gradient_paint.inl | 0 .../glm/gtx/handed_coordinate_space.hpp | 0 .../glm/gtx/handed_coordinate_space.inl | 0 .../external}/glm/include/glm/gtx/hash.hpp | 0 .../external}/glm/include/glm/gtx/hash.inl | 0 .../external}/glm/include/glm/gtx/integer.hpp | 0 .../external}/glm/include/glm/gtx/integer.inl | 0 .../glm/include/glm/gtx/intersect.hpp | 0 .../glm/include/glm/gtx/intersect.inl | 0 .../external}/glm/include/glm/gtx/io.hpp | 0 .../external}/glm/include/glm/gtx/io.inl | 0 .../glm/include/glm/gtx/log_base.hpp | 0 .../glm/include/glm/gtx/log_base.inl | 0 .../include/glm/gtx/matrix_cross_product.hpp | 0 .../include/glm/gtx/matrix_cross_product.inl | 0 .../glm/include/glm/gtx/matrix_decompose.hpp | 0 .../glm/include/glm/gtx/matrix_decompose.inl | 0 .../include/glm/gtx/matrix_factorisation.hpp | 0 .../include/glm/gtx/matrix_factorisation.inl | 0 .../include/glm/gtx/matrix_interpolation.hpp | 0 .../include/glm/gtx/matrix_interpolation.inl | 0 .../include/glm/gtx/matrix_major_storage.hpp | 0 .../include/glm/gtx/matrix_major_storage.inl | 0 .../glm/include/glm/gtx/matrix_operation.hpp | 0 .../glm/include/glm/gtx/matrix_operation.inl | 0 .../glm/include/glm/gtx/matrix_query.hpp | 0 .../glm/include/glm/gtx/matrix_query.inl | 0 .../include/glm/gtx/matrix_transform_2d.hpp | 0 .../include/glm/gtx/matrix_transform_2d.inl | 0 .../glm/include/glm/gtx/mixed_product.hpp | 0 .../glm/include/glm/gtx/mixed_product.inl | 0 .../external}/glm/include/glm/gtx/norm.hpp | 0 .../external}/glm/include/glm/gtx/norm.inl | 0 .../external}/glm/include/glm/gtx/normal.hpp | 0 .../external}/glm/include/glm/gtx/normal.inl | 0 .../glm/include/glm/gtx/normalize_dot.hpp | 0 .../glm/include/glm/gtx/normalize_dot.inl | 0 .../glm/include/glm/gtx/number_precision.hpp | 0 .../glm/include/glm/gtx/number_precision.inl | 0 .../glm/include/glm/gtx/optimum_pow.hpp | 0 .../glm/include/glm/gtx/optimum_pow.inl | 0 .../glm/include/glm/gtx/orthonormalize.hpp | 0 .../glm/include/glm/gtx/orthonormalize.inl | 0 .../external}/glm/include/glm/gtx/pca.hpp | 0 .../external}/glm/include/glm/gtx/pca.inl | 0 .../glm/include/glm/gtx/perpendicular.hpp | 0 .../glm/include/glm/gtx/perpendicular.inl | 0 .../glm/include/glm/gtx/polar_coordinates.hpp | 0 .../glm/include/glm/gtx/polar_coordinates.inl | 0 .../glm/include/glm/gtx/projection.hpp | 0 .../glm/include/glm/gtx/projection.inl | 0 .../glm/include/glm/gtx/quaternion.hpp | 0 .../glm/include/glm/gtx/quaternion.inl | 0 .../external}/glm/include/glm/gtx/range.hpp | 0 .../glm/include/glm/gtx/raw_data.hpp | 0 .../glm/include/glm/gtx/raw_data.inl | 0 .../glm/gtx/rotate_normalized_axis.hpp | 0 .../glm/gtx/rotate_normalized_axis.inl | 0 .../glm/include/glm/gtx/rotate_vector.hpp | 0 .../glm/include/glm/gtx/rotate_vector.inl | 0 .../include/glm/gtx/scalar_multiplication.hpp | 0 .../glm/include/glm/gtx/scalar_relational.hpp | 0 .../glm/include/glm/gtx/scalar_relational.inl | 0 .../external}/glm/include/glm/gtx/spline.hpp | 0 .../external}/glm/include/glm/gtx/spline.inl | 0 .../glm/include/glm/gtx/std_based_type.hpp | 0 .../glm/include/glm/gtx/std_based_type.inl | 0 .../glm/include/glm/gtx/string_cast.hpp | 0 .../glm/include/glm/gtx/string_cast.inl | 0 .../external}/glm/include/glm/gtx/texture.hpp | 0 .../external}/glm/include/glm/gtx/texture.inl | 0 .../glm/include/glm/gtx/transform.hpp | 0 .../glm/include/glm/gtx/transform.inl | 0 .../glm/include/glm/gtx/transform2.hpp | 0 .../glm/include/glm/gtx/transform2.inl | 0 .../glm/include/glm/gtx/type_aligned.hpp | 0 .../glm/include/glm/gtx/type_aligned.inl | 0 .../glm/include/glm/gtx/type_trait.hpp | 0 .../glm/include/glm/gtx/type_trait.inl | 0 .../glm/include/glm/gtx/vec_swizzle.hpp | 0 .../glm/include/glm/gtx/vector_angle.hpp | 0 .../glm/include/glm/gtx/vector_angle.inl | 0 .../glm/include/glm/gtx/vector_query.hpp | 0 .../glm/include/glm/gtx/vector_query.inl | 0 .../external}/glm/include/glm/gtx/wrap.hpp | 0 .../external}/glm/include/glm/gtx/wrap.inl | 0 .../external}/glm/include/glm/integer.hpp | 0 .../external}/glm/include/glm/mat2x2.hpp | 0 .../external}/glm/include/glm/mat2x3.hpp | 0 .../external}/glm/include/glm/mat2x4.hpp | 0 .../external}/glm/include/glm/mat3x2.hpp | 0 .../external}/glm/include/glm/mat3x3.hpp | 0 .../external}/glm/include/glm/mat3x4.hpp | 0 .../external}/glm/include/glm/mat4x2.hpp | 0 .../external}/glm/include/glm/mat4x3.hpp | 0 .../external}/glm/include/glm/mat4x4.hpp | 0 .../external}/glm/include/glm/matrix.hpp | 0 .../external}/glm/include/glm/packing.hpp | 0 .../external}/glm/include/glm/simd/common.h | 0 .../glm/include/glm/simd/exponential.h | 0 .../glm/include/glm/simd/geometric.h | 0 .../external}/glm/include/glm/simd/integer.h | 0 .../external}/glm/include/glm/simd/matrix.h | 0 .../external}/glm/include/glm/simd/neon.h | 0 .../external}/glm/include/glm/simd/packing.h | 0 .../external}/glm/include/glm/simd/platform.h | 0 .../glm/include/glm/simd/trigonometric.h | 0 .../glm/include/glm/simd/vector_relational.h | 0 .../glm/include/glm/trigonometric.hpp | 0 .../external}/glm/include/glm/vec2.hpp | 0 .../external}/glm/include/glm/vec3.hpp | 0 .../external}/glm/include/glm/vec4.hpp | 0 .../glm/include/glm/vector_relational.hpp | 0 .../glm/lib/cmake/glm/glmConfig.cmake | 0 .../glm/lib/cmake/glm/glmConfigVersion.cmake | 0 examples/viewer/CMakeLists.txt | 2 +- libs/anari/CMakeLists.txt | 23 ++++++---------- libs/anari/anari_cpp_glm_defs.cpp | 5 ---- libs/anari_viewer/CMakeLists.txt | 1 + .../anari_viewer/external/glad/CMakeLists.txt | 10 +++---- .../external/imgui/CMakeLists.txt | 26 +++++++++---------- .../external/nativefiledialog/CMakeLists.txt | 2 +- 440 files changed, 56 insertions(+), 55 deletions(-) rename {external => cts/external}/glm/include/glm/common.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/_features.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/_fixes.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/_noise.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/_swizzle.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/_swizzle_func.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/_vectorize.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/compute_common.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/compute_vector_relational.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/func_common.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_common_simd.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_exponential.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_exponential_simd.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_geometric.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_geometric_simd.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_integer.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_integer_simd.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_matrix.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_matrix_simd.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_packing.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_packing_simd.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_trigonometric.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_trigonometric_simd.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_vector_relational.inl (100%) rename {external => cts/external}/glm/include/glm/detail/func_vector_relational_simd.inl (100%) rename {external => cts/external}/glm/include/glm/detail/glm.cpp (100%) rename {external => cts/external}/glm/include/glm/detail/qualifier.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/setup.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_float.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_half.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_half.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat2x2.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat2x2.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat2x3.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat2x3.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat2x4.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat2x4.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat3x2.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat3x2.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat3x3.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat3x3.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat3x4.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat3x4.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat4x2.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat4x2.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat4x3.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat4x3.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat4x4.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat4x4.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_mat4x4_simd.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_quat.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_quat.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_quat_simd.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_vec1.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_vec1.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_vec2.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_vec2.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_vec3.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_vec3.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_vec4.hpp (100%) rename {external => cts/external}/glm/include/glm/detail/type_vec4.inl (100%) rename {external => cts/external}/glm/include/glm/detail/type_vec4_simd.inl (100%) rename {external => cts/external}/glm/include/glm/exponential.hpp (100%) rename {external => cts/external}/glm/include/glm/ext.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_clip_space.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_clip_space.inl (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_common.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_common.inl (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double2x2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double2x2_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double2x3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double2x3_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double2x4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double2x4_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double3x2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double3x2_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double3x3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double3x3_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double3x4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double3x4_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double4x2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double4x2_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double4x3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double4x3_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double4x4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_double4x4_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float2x2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float2x2_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float2x3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float2x3_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float2x4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float2x4_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float3x2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float3x2_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float3x3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float3x3_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float3x4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float3x4_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float4x2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float4x2_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float4x3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float4x3_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float4x4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_float4x4_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int2x2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int2x2_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int2x3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int2x3_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int2x4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int2x4_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int3x2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int3x2_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int3x3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int3x3_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int3x4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int3x4_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int4x2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int4x2_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int4x3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int4x3_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int4x4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_int4x4_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_integer.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_integer.inl (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_projection.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_projection.inl (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_relational.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_relational.inl (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_transform.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_transform.inl (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint2x2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint2x2_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint2x3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint2x3_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint2x4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint2x4_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint3x2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint3x2_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint3x3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint3x3_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint3x4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint3x4_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint4x2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint4x2_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint4x3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint4x3_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint4x4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/matrix_uint4x4_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_common.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_common.inl (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_common_simd.inl (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_double.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_double_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_exponential.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_exponential.inl (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_float.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_float_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_geometric.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_geometric.inl (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_relational.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_relational.inl (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_transform.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_transform.inl (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_trigonometric.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/quaternion_trigonometric.inl (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_common.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_common.inl (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_constants.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_constants.inl (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_int_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_integer.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_integer.inl (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_packing.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_packing.inl (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_reciprocal.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_reciprocal.inl (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_relational.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_relational.inl (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_uint_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_ulp.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/scalar_ulp.inl (100%) rename {external => cts/external}/glm/include/glm/ext/vector_bool1.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_bool1_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_bool2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_bool2_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_bool3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_bool3_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_bool4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_bool4_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_common.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_common.inl (100%) rename {external => cts/external}/glm/include/glm/ext/vector_double1.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_double1_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_double2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_double2_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_double3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_double3_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_double4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_double4_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_float1.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_float1_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_float2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_float2_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_float3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_float3_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_float4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_float4_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_int1.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_int1_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_int2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_int2_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_int3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_int3_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_int4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_int4_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_integer.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_integer.inl (100%) rename {external => cts/external}/glm/include/glm/ext/vector_packing.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_packing.inl (100%) rename {external => cts/external}/glm/include/glm/ext/vector_reciprocal.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_reciprocal.inl (100%) rename {external => cts/external}/glm/include/glm/ext/vector_relational.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_relational.inl (100%) rename {external => cts/external}/glm/include/glm/ext/vector_uint1.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_uint1_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_uint2.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_uint2_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_uint3.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_uint3_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_uint4.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_uint4_sized.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_ulp.hpp (100%) rename {external => cts/external}/glm/include/glm/ext/vector_ulp.inl (100%) rename {external => cts/external}/glm/include/glm/fwd.hpp (100%) rename {external => cts/external}/glm/include/glm/geometric.hpp (100%) rename {external => cts/external}/glm/include/glm/glm.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/bitfield.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/bitfield.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/color_space.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/color_space.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/constants.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/constants.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/epsilon.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/epsilon.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/integer.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/integer.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/matrix_access.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/matrix_access.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/matrix_integer.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/matrix_inverse.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/matrix_inverse.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/matrix_transform.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/matrix_transform.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/noise.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/noise.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/packing.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/packing.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/quaternion.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/quaternion.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/quaternion_simd.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/random.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/random.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/reciprocal.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/round.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/round.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/type_aligned.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/type_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/type_precision.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/type_ptr.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/type_ptr.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/ulp.hpp (100%) rename {external => cts/external}/glm/include/glm/gtc/ulp.inl (100%) rename {external => cts/external}/glm/include/glm/gtc/vec1.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/associated_min_max.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/associated_min_max.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/bit.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/bit.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/closest_point.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/closest_point.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/color_encoding.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/color_encoding.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/color_space.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/color_space.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/color_space_YCoCg.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/color_space_YCoCg.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/common.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/common.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/compatibility.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/compatibility.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/component_wise.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/component_wise.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/dual_quaternion.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/dual_quaternion.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/easing.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/easing.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/euler_angles.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/euler_angles.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/extend.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/extend.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/extended_min_max.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/extended_min_max.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/exterior_product.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/exterior_product.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/fast_exponential.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/fast_exponential.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/fast_square_root.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/fast_square_root.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/fast_trigonometry.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/fast_trigonometry.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/float_notmalize.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/functions.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/functions.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/gradient_paint.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/gradient_paint.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/handed_coordinate_space.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/handed_coordinate_space.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/hash.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/hash.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/integer.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/integer.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/intersect.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/intersect.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/io.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/io.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/log_base.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/log_base.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_cross_product.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_cross_product.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_decompose.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_decompose.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_factorisation.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_factorisation.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_interpolation.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_interpolation.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_major_storage.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_major_storage.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_operation.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_operation.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_query.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_query.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_transform_2d.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/matrix_transform_2d.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/mixed_product.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/mixed_product.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/norm.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/norm.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/normal.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/normal.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/normalize_dot.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/normalize_dot.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/number_precision.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/number_precision.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/optimum_pow.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/optimum_pow.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/orthonormalize.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/orthonormalize.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/pca.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/pca.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/perpendicular.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/perpendicular.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/polar_coordinates.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/polar_coordinates.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/projection.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/projection.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/quaternion.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/quaternion.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/range.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/raw_data.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/raw_data.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/rotate_normalized_axis.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/rotate_normalized_axis.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/rotate_vector.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/rotate_vector.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/scalar_multiplication.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/scalar_relational.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/scalar_relational.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/spline.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/spline.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/std_based_type.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/std_based_type.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/string_cast.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/string_cast.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/texture.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/texture.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/transform.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/transform.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/transform2.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/transform2.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/type_aligned.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/type_aligned.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/type_trait.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/type_trait.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/vec_swizzle.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/vector_angle.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/vector_angle.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/vector_query.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/vector_query.inl (100%) rename {external => cts/external}/glm/include/glm/gtx/wrap.hpp (100%) rename {external => cts/external}/glm/include/glm/gtx/wrap.inl (100%) rename {external => cts/external}/glm/include/glm/integer.hpp (100%) rename {external => cts/external}/glm/include/glm/mat2x2.hpp (100%) rename {external => cts/external}/glm/include/glm/mat2x3.hpp (100%) rename {external => cts/external}/glm/include/glm/mat2x4.hpp (100%) rename {external => cts/external}/glm/include/glm/mat3x2.hpp (100%) rename {external => cts/external}/glm/include/glm/mat3x3.hpp (100%) rename {external => cts/external}/glm/include/glm/mat3x4.hpp (100%) rename {external => cts/external}/glm/include/glm/mat4x2.hpp (100%) rename {external => cts/external}/glm/include/glm/mat4x3.hpp (100%) rename {external => cts/external}/glm/include/glm/mat4x4.hpp (100%) rename {external => cts/external}/glm/include/glm/matrix.hpp (100%) rename {external => cts/external}/glm/include/glm/packing.hpp (100%) rename {external => cts/external}/glm/include/glm/simd/common.h (100%) rename {external => cts/external}/glm/include/glm/simd/exponential.h (100%) rename {external => cts/external}/glm/include/glm/simd/geometric.h (100%) rename {external => cts/external}/glm/include/glm/simd/integer.h (100%) rename {external => cts/external}/glm/include/glm/simd/matrix.h (100%) rename {external => cts/external}/glm/include/glm/simd/neon.h (100%) rename {external => cts/external}/glm/include/glm/simd/packing.h (100%) rename {external => cts/external}/glm/include/glm/simd/platform.h (100%) rename {external => cts/external}/glm/include/glm/simd/trigonometric.h (100%) rename {external => cts/external}/glm/include/glm/simd/vector_relational.h (100%) rename {external => cts/external}/glm/include/glm/trigonometric.hpp (100%) rename {external => cts/external}/glm/include/glm/vec2.hpp (100%) rename {external => cts/external}/glm/include/glm/vec3.hpp (100%) rename {external => cts/external}/glm/include/glm/vec4.hpp (100%) rename {external => cts/external}/glm/include/glm/vector_relational.hpp (100%) rename {external => cts/external}/glm/lib/cmake/glm/glmConfig.cmake (100%) rename {external => cts/external}/glm/lib/cmake/glm/glmConfigVersion.cmake (100%) delete mode 100644 libs/anari/anari_cpp_glm_defs.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9af815ba..7e36fff8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,10 +71,6 @@ include(cmake/anari_sdk_fetch_project.cmake) ## Add library and executable targets -set(glm_DIR ${CMAKE_CURRENT_LIST_DIR}/external/glm/lib/cmake/glm) -find_package(glm REQUIRED) -mark_as_advanced(glm_DIR) - add_subdirectory(libs) add_subdirectory(external) add_subdirectory(code_gen) diff --git a/README.md b/README.md index 64d5da5d..160513f2 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,20 @@ These targets can be found with CMake via `find_package(anari)`. The examples are written such that they can be built stand alone from the SDK source tree. The simplest usage can be found [here](examples/simple). +The follwoing additional helper library components can be requested by listing +them under `find_pacakge(anari)`: + +- `viewer` : Source library target `anari::anari_viewer` for building small viewer apps +- `code_gen` : Enable the use of code generation CMake functions downstream + +Both of these libraries are both optionally installed and are not available +to downstream projects unless they are explicitly requested. To request one of +these components, simply add them to the `COMPONENTS` portion of `find_package`: + +```cmake +find_package(anari COMPONENTS viewer code_gen) +``` + ## Running the examples The basic tutorial app (built by default) uses the `helide` device as an diff --git a/cmake/anariConfig.cmake.in b/cmake/anariConfig.cmake.in index aa4d8f02..cfcab4dc 100644 --- a/cmake/anariConfig.cmake.in +++ b/cmake/anariConfig.cmake.in @@ -5,14 +5,8 @@ include(CMakeFindDependencyMacro) -set(CMAKE_THREAD_PREFER_PTHREAD TRUE) -set(THREADS_PREFER_PTHREAD_FLAG TRUE) -find_dependency(Threads) - include(${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@_Exports.cmake) -check_required_components(@PROJECT_NAME@) - if (NOT TARGET anari::anari) message(FATAL_ERROR "CMAKE_PREFIX_PATH or anari_DIR are pointing to an \ ANARI-SDK build directory. Please do a full install of the SDK \ @@ -29,16 +23,25 @@ if (@INSTALL_CODE_GEN_SCRIPTS@) set(ANARI_CODE_GEN_ROOT ${ANARI_DATAROOTDIR}/code_gen) include(${CMAKE_CURRENT_LIST_DIR}/cmake/anari_generate_frontend.cmake) include(${CMAKE_CURRENT_LIST_DIR}/cmake/anari_generate_codegen.cmake) + set(anari_code_gen_FOUND 1) +elseif(anari_FIND_REQUIRED_code_gen) + message(ERROR "The 'code_gen' component was requested but not found. To + enable this component, the SDK must be built with \ + INSTALL_CODE_GEN_SCRIPTS=ON") endif() include(${CMAKE_CURRENT_LIST_DIR}/cmake/anari_sdk_fetch_project.cmake) include(${CMAKE_CURRENT_LIST_DIR}/cmake/cmake_project_commands.cmake) -if (@INSTALL_VIEWER_LIBRARY@ AND NOT TARGET anari_viewer) +if (anari_FIND_REQUIRED_viewer AND @INSTALL_VIEWER_LIBRARY@) add_subdirectory( ${ANARI_DATAROOTDIR}/anari_viewer ${CMAKE_CURRENT_BINARY_DIR}/anari_viewer ) + set(anari_viewer_FOUND 1) +elseif(anari_FIND_REQUIRED_viewer) + message(ERROR "The 'viewer' component was requested but not found. To + enable this component, the SDK must be built with INSTALL_VIEWER_LIBRARY=ON") endif() -set(ANARI_FOUND TRUE) +check_required_components(@PROJECT_NAME@) diff --git a/code_gen/CMakeLists.txt b/code_gen/CMakeLists.txt index 28d63453..02f46f1e 100644 --- a/code_gen/CMakeLists.txt +++ b/code_gen/CMakeLists.txt @@ -58,6 +58,7 @@ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.12") if (INSTALL_CODE_GEN_SCRIPTS) install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/anari + COMPONENT code_gen FILES_MATCHING PATTERN *.py PATTERN *.h diff --git a/cts/CMakeLists.txt b/cts/CMakeLists.txt index 386b1589..ad07f7f9 100644 --- a/cts/CMakeLists.txt +++ b/cts/CMakeLists.txt @@ -15,6 +15,10 @@ set(REFERENCE_LIB helide) project(anariCTSBackend LANGUAGES CXX) +set(glm_DIR ${CMAKE_CURRENT_LIST_DIR}/external/glm/lib/cmake/glm) +find_package(glm REQUIRED) +mark_as_advanced(glm_DIR) + find_package(anari REQUIRED) include(pybind11.cmake) diff --git a/external/glm/include/glm/common.hpp b/cts/external/glm/include/glm/common.hpp similarity index 100% rename from external/glm/include/glm/common.hpp rename to cts/external/glm/include/glm/common.hpp diff --git a/external/glm/include/glm/detail/_features.hpp b/cts/external/glm/include/glm/detail/_features.hpp similarity index 100% rename from external/glm/include/glm/detail/_features.hpp rename to cts/external/glm/include/glm/detail/_features.hpp diff --git a/external/glm/include/glm/detail/_fixes.hpp b/cts/external/glm/include/glm/detail/_fixes.hpp similarity index 100% rename from external/glm/include/glm/detail/_fixes.hpp rename to cts/external/glm/include/glm/detail/_fixes.hpp diff --git a/external/glm/include/glm/detail/_noise.hpp b/cts/external/glm/include/glm/detail/_noise.hpp similarity index 100% rename from external/glm/include/glm/detail/_noise.hpp rename to cts/external/glm/include/glm/detail/_noise.hpp diff --git a/external/glm/include/glm/detail/_swizzle.hpp b/cts/external/glm/include/glm/detail/_swizzle.hpp similarity index 100% rename from external/glm/include/glm/detail/_swizzle.hpp rename to cts/external/glm/include/glm/detail/_swizzle.hpp diff --git a/external/glm/include/glm/detail/_swizzle_func.hpp b/cts/external/glm/include/glm/detail/_swizzle_func.hpp similarity index 100% rename from external/glm/include/glm/detail/_swizzle_func.hpp rename to cts/external/glm/include/glm/detail/_swizzle_func.hpp diff --git a/external/glm/include/glm/detail/_vectorize.hpp b/cts/external/glm/include/glm/detail/_vectorize.hpp similarity index 100% rename from external/glm/include/glm/detail/_vectorize.hpp rename to cts/external/glm/include/glm/detail/_vectorize.hpp diff --git a/external/glm/include/glm/detail/compute_common.hpp b/cts/external/glm/include/glm/detail/compute_common.hpp similarity index 100% rename from external/glm/include/glm/detail/compute_common.hpp rename to cts/external/glm/include/glm/detail/compute_common.hpp diff --git a/external/glm/include/glm/detail/compute_vector_relational.hpp b/cts/external/glm/include/glm/detail/compute_vector_relational.hpp similarity index 100% rename from external/glm/include/glm/detail/compute_vector_relational.hpp rename to cts/external/glm/include/glm/detail/compute_vector_relational.hpp diff --git a/external/glm/include/glm/detail/func_common.inl b/cts/external/glm/include/glm/detail/func_common.inl similarity index 100% rename from external/glm/include/glm/detail/func_common.inl rename to cts/external/glm/include/glm/detail/func_common.inl diff --git a/external/glm/include/glm/detail/func_common_simd.inl b/cts/external/glm/include/glm/detail/func_common_simd.inl similarity index 100% rename from external/glm/include/glm/detail/func_common_simd.inl rename to cts/external/glm/include/glm/detail/func_common_simd.inl diff --git a/external/glm/include/glm/detail/func_exponential.inl b/cts/external/glm/include/glm/detail/func_exponential.inl similarity index 100% rename from external/glm/include/glm/detail/func_exponential.inl rename to cts/external/glm/include/glm/detail/func_exponential.inl diff --git a/external/glm/include/glm/detail/func_exponential_simd.inl b/cts/external/glm/include/glm/detail/func_exponential_simd.inl similarity index 100% rename from external/glm/include/glm/detail/func_exponential_simd.inl rename to cts/external/glm/include/glm/detail/func_exponential_simd.inl diff --git a/external/glm/include/glm/detail/func_geometric.inl b/cts/external/glm/include/glm/detail/func_geometric.inl similarity index 100% rename from external/glm/include/glm/detail/func_geometric.inl rename to cts/external/glm/include/glm/detail/func_geometric.inl diff --git a/external/glm/include/glm/detail/func_geometric_simd.inl b/cts/external/glm/include/glm/detail/func_geometric_simd.inl similarity index 100% rename from external/glm/include/glm/detail/func_geometric_simd.inl rename to cts/external/glm/include/glm/detail/func_geometric_simd.inl diff --git a/external/glm/include/glm/detail/func_integer.inl b/cts/external/glm/include/glm/detail/func_integer.inl similarity index 100% rename from external/glm/include/glm/detail/func_integer.inl rename to cts/external/glm/include/glm/detail/func_integer.inl diff --git a/external/glm/include/glm/detail/func_integer_simd.inl b/cts/external/glm/include/glm/detail/func_integer_simd.inl similarity index 100% rename from external/glm/include/glm/detail/func_integer_simd.inl rename to cts/external/glm/include/glm/detail/func_integer_simd.inl diff --git a/external/glm/include/glm/detail/func_matrix.inl b/cts/external/glm/include/glm/detail/func_matrix.inl similarity index 100% rename from external/glm/include/glm/detail/func_matrix.inl rename to cts/external/glm/include/glm/detail/func_matrix.inl diff --git a/external/glm/include/glm/detail/func_matrix_simd.inl b/cts/external/glm/include/glm/detail/func_matrix_simd.inl similarity index 100% rename from external/glm/include/glm/detail/func_matrix_simd.inl rename to cts/external/glm/include/glm/detail/func_matrix_simd.inl diff --git a/external/glm/include/glm/detail/func_packing.inl b/cts/external/glm/include/glm/detail/func_packing.inl similarity index 100% rename from external/glm/include/glm/detail/func_packing.inl rename to cts/external/glm/include/glm/detail/func_packing.inl diff --git a/external/glm/include/glm/detail/func_packing_simd.inl b/cts/external/glm/include/glm/detail/func_packing_simd.inl similarity index 100% rename from external/glm/include/glm/detail/func_packing_simd.inl rename to cts/external/glm/include/glm/detail/func_packing_simd.inl diff --git a/external/glm/include/glm/detail/func_trigonometric.inl b/cts/external/glm/include/glm/detail/func_trigonometric.inl similarity index 100% rename from external/glm/include/glm/detail/func_trigonometric.inl rename to cts/external/glm/include/glm/detail/func_trigonometric.inl diff --git a/external/glm/include/glm/detail/func_trigonometric_simd.inl b/cts/external/glm/include/glm/detail/func_trigonometric_simd.inl similarity index 100% rename from external/glm/include/glm/detail/func_trigonometric_simd.inl rename to cts/external/glm/include/glm/detail/func_trigonometric_simd.inl diff --git a/external/glm/include/glm/detail/func_vector_relational.inl b/cts/external/glm/include/glm/detail/func_vector_relational.inl similarity index 100% rename from external/glm/include/glm/detail/func_vector_relational.inl rename to cts/external/glm/include/glm/detail/func_vector_relational.inl diff --git a/external/glm/include/glm/detail/func_vector_relational_simd.inl b/cts/external/glm/include/glm/detail/func_vector_relational_simd.inl similarity index 100% rename from external/glm/include/glm/detail/func_vector_relational_simd.inl rename to cts/external/glm/include/glm/detail/func_vector_relational_simd.inl diff --git a/external/glm/include/glm/detail/glm.cpp b/cts/external/glm/include/glm/detail/glm.cpp similarity index 100% rename from external/glm/include/glm/detail/glm.cpp rename to cts/external/glm/include/glm/detail/glm.cpp diff --git a/external/glm/include/glm/detail/qualifier.hpp b/cts/external/glm/include/glm/detail/qualifier.hpp similarity index 100% rename from external/glm/include/glm/detail/qualifier.hpp rename to cts/external/glm/include/glm/detail/qualifier.hpp diff --git a/external/glm/include/glm/detail/setup.hpp b/cts/external/glm/include/glm/detail/setup.hpp similarity index 100% rename from external/glm/include/glm/detail/setup.hpp rename to cts/external/glm/include/glm/detail/setup.hpp diff --git a/external/glm/include/glm/detail/type_float.hpp b/cts/external/glm/include/glm/detail/type_float.hpp similarity index 100% rename from external/glm/include/glm/detail/type_float.hpp rename to cts/external/glm/include/glm/detail/type_float.hpp diff --git a/external/glm/include/glm/detail/type_half.hpp b/cts/external/glm/include/glm/detail/type_half.hpp similarity index 100% rename from external/glm/include/glm/detail/type_half.hpp rename to cts/external/glm/include/glm/detail/type_half.hpp diff --git a/external/glm/include/glm/detail/type_half.inl b/cts/external/glm/include/glm/detail/type_half.inl similarity index 100% rename from external/glm/include/glm/detail/type_half.inl rename to cts/external/glm/include/glm/detail/type_half.inl diff --git a/external/glm/include/glm/detail/type_mat2x2.hpp b/cts/external/glm/include/glm/detail/type_mat2x2.hpp similarity index 100% rename from external/glm/include/glm/detail/type_mat2x2.hpp rename to cts/external/glm/include/glm/detail/type_mat2x2.hpp diff --git a/external/glm/include/glm/detail/type_mat2x2.inl b/cts/external/glm/include/glm/detail/type_mat2x2.inl similarity index 100% rename from external/glm/include/glm/detail/type_mat2x2.inl rename to cts/external/glm/include/glm/detail/type_mat2x2.inl diff --git a/external/glm/include/glm/detail/type_mat2x3.hpp b/cts/external/glm/include/glm/detail/type_mat2x3.hpp similarity index 100% rename from external/glm/include/glm/detail/type_mat2x3.hpp rename to cts/external/glm/include/glm/detail/type_mat2x3.hpp diff --git a/external/glm/include/glm/detail/type_mat2x3.inl b/cts/external/glm/include/glm/detail/type_mat2x3.inl similarity index 100% rename from external/glm/include/glm/detail/type_mat2x3.inl rename to cts/external/glm/include/glm/detail/type_mat2x3.inl diff --git a/external/glm/include/glm/detail/type_mat2x4.hpp b/cts/external/glm/include/glm/detail/type_mat2x4.hpp similarity index 100% rename from external/glm/include/glm/detail/type_mat2x4.hpp rename to cts/external/glm/include/glm/detail/type_mat2x4.hpp diff --git a/external/glm/include/glm/detail/type_mat2x4.inl b/cts/external/glm/include/glm/detail/type_mat2x4.inl similarity index 100% rename from external/glm/include/glm/detail/type_mat2x4.inl rename to cts/external/glm/include/glm/detail/type_mat2x4.inl diff --git a/external/glm/include/glm/detail/type_mat3x2.hpp b/cts/external/glm/include/glm/detail/type_mat3x2.hpp similarity index 100% rename from external/glm/include/glm/detail/type_mat3x2.hpp rename to cts/external/glm/include/glm/detail/type_mat3x2.hpp diff --git a/external/glm/include/glm/detail/type_mat3x2.inl b/cts/external/glm/include/glm/detail/type_mat3x2.inl similarity index 100% rename from external/glm/include/glm/detail/type_mat3x2.inl rename to cts/external/glm/include/glm/detail/type_mat3x2.inl diff --git a/external/glm/include/glm/detail/type_mat3x3.hpp b/cts/external/glm/include/glm/detail/type_mat3x3.hpp similarity index 100% rename from external/glm/include/glm/detail/type_mat3x3.hpp rename to cts/external/glm/include/glm/detail/type_mat3x3.hpp diff --git a/external/glm/include/glm/detail/type_mat3x3.inl b/cts/external/glm/include/glm/detail/type_mat3x3.inl similarity index 100% rename from external/glm/include/glm/detail/type_mat3x3.inl rename to cts/external/glm/include/glm/detail/type_mat3x3.inl diff --git a/external/glm/include/glm/detail/type_mat3x4.hpp b/cts/external/glm/include/glm/detail/type_mat3x4.hpp similarity index 100% rename from external/glm/include/glm/detail/type_mat3x4.hpp rename to cts/external/glm/include/glm/detail/type_mat3x4.hpp diff --git a/external/glm/include/glm/detail/type_mat3x4.inl b/cts/external/glm/include/glm/detail/type_mat3x4.inl similarity index 100% rename from external/glm/include/glm/detail/type_mat3x4.inl rename to cts/external/glm/include/glm/detail/type_mat3x4.inl diff --git a/external/glm/include/glm/detail/type_mat4x2.hpp b/cts/external/glm/include/glm/detail/type_mat4x2.hpp similarity index 100% rename from external/glm/include/glm/detail/type_mat4x2.hpp rename to cts/external/glm/include/glm/detail/type_mat4x2.hpp diff --git a/external/glm/include/glm/detail/type_mat4x2.inl b/cts/external/glm/include/glm/detail/type_mat4x2.inl similarity index 100% rename from external/glm/include/glm/detail/type_mat4x2.inl rename to cts/external/glm/include/glm/detail/type_mat4x2.inl diff --git a/external/glm/include/glm/detail/type_mat4x3.hpp b/cts/external/glm/include/glm/detail/type_mat4x3.hpp similarity index 100% rename from external/glm/include/glm/detail/type_mat4x3.hpp rename to cts/external/glm/include/glm/detail/type_mat4x3.hpp diff --git a/external/glm/include/glm/detail/type_mat4x3.inl b/cts/external/glm/include/glm/detail/type_mat4x3.inl similarity index 100% rename from external/glm/include/glm/detail/type_mat4x3.inl rename to cts/external/glm/include/glm/detail/type_mat4x3.inl diff --git a/external/glm/include/glm/detail/type_mat4x4.hpp b/cts/external/glm/include/glm/detail/type_mat4x4.hpp similarity index 100% rename from external/glm/include/glm/detail/type_mat4x4.hpp rename to cts/external/glm/include/glm/detail/type_mat4x4.hpp diff --git a/external/glm/include/glm/detail/type_mat4x4.inl b/cts/external/glm/include/glm/detail/type_mat4x4.inl similarity index 100% rename from external/glm/include/glm/detail/type_mat4x4.inl rename to cts/external/glm/include/glm/detail/type_mat4x4.inl diff --git a/external/glm/include/glm/detail/type_mat4x4_simd.inl b/cts/external/glm/include/glm/detail/type_mat4x4_simd.inl similarity index 100% rename from external/glm/include/glm/detail/type_mat4x4_simd.inl rename to cts/external/glm/include/glm/detail/type_mat4x4_simd.inl diff --git a/external/glm/include/glm/detail/type_quat.hpp b/cts/external/glm/include/glm/detail/type_quat.hpp similarity index 100% rename from external/glm/include/glm/detail/type_quat.hpp rename to cts/external/glm/include/glm/detail/type_quat.hpp diff --git a/external/glm/include/glm/detail/type_quat.inl b/cts/external/glm/include/glm/detail/type_quat.inl similarity index 100% rename from external/glm/include/glm/detail/type_quat.inl rename to cts/external/glm/include/glm/detail/type_quat.inl diff --git a/external/glm/include/glm/detail/type_quat_simd.inl b/cts/external/glm/include/glm/detail/type_quat_simd.inl similarity index 100% rename from external/glm/include/glm/detail/type_quat_simd.inl rename to cts/external/glm/include/glm/detail/type_quat_simd.inl diff --git a/external/glm/include/glm/detail/type_vec1.hpp b/cts/external/glm/include/glm/detail/type_vec1.hpp similarity index 100% rename from external/glm/include/glm/detail/type_vec1.hpp rename to cts/external/glm/include/glm/detail/type_vec1.hpp diff --git a/external/glm/include/glm/detail/type_vec1.inl b/cts/external/glm/include/glm/detail/type_vec1.inl similarity index 100% rename from external/glm/include/glm/detail/type_vec1.inl rename to cts/external/glm/include/glm/detail/type_vec1.inl diff --git a/external/glm/include/glm/detail/type_vec2.hpp b/cts/external/glm/include/glm/detail/type_vec2.hpp similarity index 100% rename from external/glm/include/glm/detail/type_vec2.hpp rename to cts/external/glm/include/glm/detail/type_vec2.hpp diff --git a/external/glm/include/glm/detail/type_vec2.inl b/cts/external/glm/include/glm/detail/type_vec2.inl similarity index 100% rename from external/glm/include/glm/detail/type_vec2.inl rename to cts/external/glm/include/glm/detail/type_vec2.inl diff --git a/external/glm/include/glm/detail/type_vec3.hpp b/cts/external/glm/include/glm/detail/type_vec3.hpp similarity index 100% rename from external/glm/include/glm/detail/type_vec3.hpp rename to cts/external/glm/include/glm/detail/type_vec3.hpp diff --git a/external/glm/include/glm/detail/type_vec3.inl b/cts/external/glm/include/glm/detail/type_vec3.inl similarity index 100% rename from external/glm/include/glm/detail/type_vec3.inl rename to cts/external/glm/include/glm/detail/type_vec3.inl diff --git a/external/glm/include/glm/detail/type_vec4.hpp b/cts/external/glm/include/glm/detail/type_vec4.hpp similarity index 100% rename from external/glm/include/glm/detail/type_vec4.hpp rename to cts/external/glm/include/glm/detail/type_vec4.hpp diff --git a/external/glm/include/glm/detail/type_vec4.inl b/cts/external/glm/include/glm/detail/type_vec4.inl similarity index 100% rename from external/glm/include/glm/detail/type_vec4.inl rename to cts/external/glm/include/glm/detail/type_vec4.inl diff --git a/external/glm/include/glm/detail/type_vec4_simd.inl b/cts/external/glm/include/glm/detail/type_vec4_simd.inl similarity index 100% rename from external/glm/include/glm/detail/type_vec4_simd.inl rename to cts/external/glm/include/glm/detail/type_vec4_simd.inl diff --git a/external/glm/include/glm/exponential.hpp b/cts/external/glm/include/glm/exponential.hpp similarity index 100% rename from external/glm/include/glm/exponential.hpp rename to cts/external/glm/include/glm/exponential.hpp diff --git a/external/glm/include/glm/ext.hpp b/cts/external/glm/include/glm/ext.hpp similarity index 100% rename from external/glm/include/glm/ext.hpp rename to cts/external/glm/include/glm/ext.hpp diff --git a/external/glm/include/glm/ext/matrix_clip_space.hpp b/cts/external/glm/include/glm/ext/matrix_clip_space.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_clip_space.hpp rename to cts/external/glm/include/glm/ext/matrix_clip_space.hpp diff --git a/external/glm/include/glm/ext/matrix_clip_space.inl b/cts/external/glm/include/glm/ext/matrix_clip_space.inl similarity index 100% rename from external/glm/include/glm/ext/matrix_clip_space.inl rename to cts/external/glm/include/glm/ext/matrix_clip_space.inl diff --git a/external/glm/include/glm/ext/matrix_common.hpp b/cts/external/glm/include/glm/ext/matrix_common.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_common.hpp rename to cts/external/glm/include/glm/ext/matrix_common.hpp diff --git a/external/glm/include/glm/ext/matrix_common.inl b/cts/external/glm/include/glm/ext/matrix_common.inl similarity index 100% rename from external/glm/include/glm/ext/matrix_common.inl rename to cts/external/glm/include/glm/ext/matrix_common.inl diff --git a/external/glm/include/glm/ext/matrix_double2x2.hpp b/cts/external/glm/include/glm/ext/matrix_double2x2.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double2x2.hpp rename to cts/external/glm/include/glm/ext/matrix_double2x2.hpp diff --git a/external/glm/include/glm/ext/matrix_double2x2_precision.hpp b/cts/external/glm/include/glm/ext/matrix_double2x2_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double2x2_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_double2x2_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_double2x3.hpp b/cts/external/glm/include/glm/ext/matrix_double2x3.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double2x3.hpp rename to cts/external/glm/include/glm/ext/matrix_double2x3.hpp diff --git a/external/glm/include/glm/ext/matrix_double2x3_precision.hpp b/cts/external/glm/include/glm/ext/matrix_double2x3_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double2x3_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_double2x3_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_double2x4.hpp b/cts/external/glm/include/glm/ext/matrix_double2x4.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double2x4.hpp rename to cts/external/glm/include/glm/ext/matrix_double2x4.hpp diff --git a/external/glm/include/glm/ext/matrix_double2x4_precision.hpp b/cts/external/glm/include/glm/ext/matrix_double2x4_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double2x4_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_double2x4_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_double3x2.hpp b/cts/external/glm/include/glm/ext/matrix_double3x2.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double3x2.hpp rename to cts/external/glm/include/glm/ext/matrix_double3x2.hpp diff --git a/external/glm/include/glm/ext/matrix_double3x2_precision.hpp b/cts/external/glm/include/glm/ext/matrix_double3x2_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double3x2_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_double3x2_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_double3x3.hpp b/cts/external/glm/include/glm/ext/matrix_double3x3.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double3x3.hpp rename to cts/external/glm/include/glm/ext/matrix_double3x3.hpp diff --git a/external/glm/include/glm/ext/matrix_double3x3_precision.hpp b/cts/external/glm/include/glm/ext/matrix_double3x3_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double3x3_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_double3x3_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_double3x4.hpp b/cts/external/glm/include/glm/ext/matrix_double3x4.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double3x4.hpp rename to cts/external/glm/include/glm/ext/matrix_double3x4.hpp diff --git a/external/glm/include/glm/ext/matrix_double3x4_precision.hpp b/cts/external/glm/include/glm/ext/matrix_double3x4_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double3x4_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_double3x4_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_double4x2.hpp b/cts/external/glm/include/glm/ext/matrix_double4x2.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double4x2.hpp rename to cts/external/glm/include/glm/ext/matrix_double4x2.hpp diff --git a/external/glm/include/glm/ext/matrix_double4x2_precision.hpp b/cts/external/glm/include/glm/ext/matrix_double4x2_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double4x2_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_double4x2_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_double4x3.hpp b/cts/external/glm/include/glm/ext/matrix_double4x3.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double4x3.hpp rename to cts/external/glm/include/glm/ext/matrix_double4x3.hpp diff --git a/external/glm/include/glm/ext/matrix_double4x3_precision.hpp b/cts/external/glm/include/glm/ext/matrix_double4x3_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double4x3_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_double4x3_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_double4x4.hpp b/cts/external/glm/include/glm/ext/matrix_double4x4.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double4x4.hpp rename to cts/external/glm/include/glm/ext/matrix_double4x4.hpp diff --git a/external/glm/include/glm/ext/matrix_double4x4_precision.hpp b/cts/external/glm/include/glm/ext/matrix_double4x4_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_double4x4_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_double4x4_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_float2x2.hpp b/cts/external/glm/include/glm/ext/matrix_float2x2.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float2x2.hpp rename to cts/external/glm/include/glm/ext/matrix_float2x2.hpp diff --git a/external/glm/include/glm/ext/matrix_float2x2_precision.hpp b/cts/external/glm/include/glm/ext/matrix_float2x2_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float2x2_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_float2x2_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_float2x3.hpp b/cts/external/glm/include/glm/ext/matrix_float2x3.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float2x3.hpp rename to cts/external/glm/include/glm/ext/matrix_float2x3.hpp diff --git a/external/glm/include/glm/ext/matrix_float2x3_precision.hpp b/cts/external/glm/include/glm/ext/matrix_float2x3_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float2x3_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_float2x3_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_float2x4.hpp b/cts/external/glm/include/glm/ext/matrix_float2x4.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float2x4.hpp rename to cts/external/glm/include/glm/ext/matrix_float2x4.hpp diff --git a/external/glm/include/glm/ext/matrix_float2x4_precision.hpp b/cts/external/glm/include/glm/ext/matrix_float2x4_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float2x4_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_float2x4_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_float3x2.hpp b/cts/external/glm/include/glm/ext/matrix_float3x2.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float3x2.hpp rename to cts/external/glm/include/glm/ext/matrix_float3x2.hpp diff --git a/external/glm/include/glm/ext/matrix_float3x2_precision.hpp b/cts/external/glm/include/glm/ext/matrix_float3x2_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float3x2_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_float3x2_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_float3x3.hpp b/cts/external/glm/include/glm/ext/matrix_float3x3.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float3x3.hpp rename to cts/external/glm/include/glm/ext/matrix_float3x3.hpp diff --git a/external/glm/include/glm/ext/matrix_float3x3_precision.hpp b/cts/external/glm/include/glm/ext/matrix_float3x3_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float3x3_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_float3x3_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_float3x4.hpp b/cts/external/glm/include/glm/ext/matrix_float3x4.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float3x4.hpp rename to cts/external/glm/include/glm/ext/matrix_float3x4.hpp diff --git a/external/glm/include/glm/ext/matrix_float3x4_precision.hpp b/cts/external/glm/include/glm/ext/matrix_float3x4_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float3x4_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_float3x4_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_float4x2.hpp b/cts/external/glm/include/glm/ext/matrix_float4x2.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float4x2.hpp rename to cts/external/glm/include/glm/ext/matrix_float4x2.hpp diff --git a/external/glm/include/glm/ext/matrix_float4x2_precision.hpp b/cts/external/glm/include/glm/ext/matrix_float4x2_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float4x2_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_float4x2_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_float4x3.hpp b/cts/external/glm/include/glm/ext/matrix_float4x3.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float4x3.hpp rename to cts/external/glm/include/glm/ext/matrix_float4x3.hpp diff --git a/external/glm/include/glm/ext/matrix_float4x3_precision.hpp b/cts/external/glm/include/glm/ext/matrix_float4x3_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float4x3_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_float4x3_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_float4x4.hpp b/cts/external/glm/include/glm/ext/matrix_float4x4.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float4x4.hpp rename to cts/external/glm/include/glm/ext/matrix_float4x4.hpp diff --git a/external/glm/include/glm/ext/matrix_float4x4_precision.hpp b/cts/external/glm/include/glm/ext/matrix_float4x4_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_float4x4_precision.hpp rename to cts/external/glm/include/glm/ext/matrix_float4x4_precision.hpp diff --git a/external/glm/include/glm/ext/matrix_int2x2.hpp b/cts/external/glm/include/glm/ext/matrix_int2x2.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int2x2.hpp rename to cts/external/glm/include/glm/ext/matrix_int2x2.hpp diff --git a/external/glm/include/glm/ext/matrix_int2x2_sized.hpp b/cts/external/glm/include/glm/ext/matrix_int2x2_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int2x2_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_int2x2_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_int2x3.hpp b/cts/external/glm/include/glm/ext/matrix_int2x3.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int2x3.hpp rename to cts/external/glm/include/glm/ext/matrix_int2x3.hpp diff --git a/external/glm/include/glm/ext/matrix_int2x3_sized.hpp b/cts/external/glm/include/glm/ext/matrix_int2x3_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int2x3_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_int2x3_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_int2x4.hpp b/cts/external/glm/include/glm/ext/matrix_int2x4.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int2x4.hpp rename to cts/external/glm/include/glm/ext/matrix_int2x4.hpp diff --git a/external/glm/include/glm/ext/matrix_int2x4_sized.hpp b/cts/external/glm/include/glm/ext/matrix_int2x4_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int2x4_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_int2x4_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_int3x2.hpp b/cts/external/glm/include/glm/ext/matrix_int3x2.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int3x2.hpp rename to cts/external/glm/include/glm/ext/matrix_int3x2.hpp diff --git a/external/glm/include/glm/ext/matrix_int3x2_sized.hpp b/cts/external/glm/include/glm/ext/matrix_int3x2_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int3x2_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_int3x2_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_int3x3.hpp b/cts/external/glm/include/glm/ext/matrix_int3x3.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int3x3.hpp rename to cts/external/glm/include/glm/ext/matrix_int3x3.hpp diff --git a/external/glm/include/glm/ext/matrix_int3x3_sized.hpp b/cts/external/glm/include/glm/ext/matrix_int3x3_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int3x3_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_int3x3_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_int3x4.hpp b/cts/external/glm/include/glm/ext/matrix_int3x4.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int3x4.hpp rename to cts/external/glm/include/glm/ext/matrix_int3x4.hpp diff --git a/external/glm/include/glm/ext/matrix_int3x4_sized.hpp b/cts/external/glm/include/glm/ext/matrix_int3x4_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int3x4_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_int3x4_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_int4x2.hpp b/cts/external/glm/include/glm/ext/matrix_int4x2.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int4x2.hpp rename to cts/external/glm/include/glm/ext/matrix_int4x2.hpp diff --git a/external/glm/include/glm/ext/matrix_int4x2_sized.hpp b/cts/external/glm/include/glm/ext/matrix_int4x2_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int4x2_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_int4x2_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_int4x3.hpp b/cts/external/glm/include/glm/ext/matrix_int4x3.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int4x3.hpp rename to cts/external/glm/include/glm/ext/matrix_int4x3.hpp diff --git a/external/glm/include/glm/ext/matrix_int4x3_sized.hpp b/cts/external/glm/include/glm/ext/matrix_int4x3_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int4x3_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_int4x3_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_int4x4.hpp b/cts/external/glm/include/glm/ext/matrix_int4x4.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int4x4.hpp rename to cts/external/glm/include/glm/ext/matrix_int4x4.hpp diff --git a/external/glm/include/glm/ext/matrix_int4x4_sized.hpp b/cts/external/glm/include/glm/ext/matrix_int4x4_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_int4x4_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_int4x4_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_integer.hpp b/cts/external/glm/include/glm/ext/matrix_integer.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_integer.hpp rename to cts/external/glm/include/glm/ext/matrix_integer.hpp diff --git a/external/glm/include/glm/ext/matrix_integer.inl b/cts/external/glm/include/glm/ext/matrix_integer.inl similarity index 100% rename from external/glm/include/glm/ext/matrix_integer.inl rename to cts/external/glm/include/glm/ext/matrix_integer.inl diff --git a/external/glm/include/glm/ext/matrix_projection.hpp b/cts/external/glm/include/glm/ext/matrix_projection.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_projection.hpp rename to cts/external/glm/include/glm/ext/matrix_projection.hpp diff --git a/external/glm/include/glm/ext/matrix_projection.inl b/cts/external/glm/include/glm/ext/matrix_projection.inl similarity index 100% rename from external/glm/include/glm/ext/matrix_projection.inl rename to cts/external/glm/include/glm/ext/matrix_projection.inl diff --git a/external/glm/include/glm/ext/matrix_relational.hpp b/cts/external/glm/include/glm/ext/matrix_relational.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_relational.hpp rename to cts/external/glm/include/glm/ext/matrix_relational.hpp diff --git a/external/glm/include/glm/ext/matrix_relational.inl b/cts/external/glm/include/glm/ext/matrix_relational.inl similarity index 100% rename from external/glm/include/glm/ext/matrix_relational.inl rename to cts/external/glm/include/glm/ext/matrix_relational.inl diff --git a/external/glm/include/glm/ext/matrix_transform.hpp b/cts/external/glm/include/glm/ext/matrix_transform.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_transform.hpp rename to cts/external/glm/include/glm/ext/matrix_transform.hpp diff --git a/external/glm/include/glm/ext/matrix_transform.inl b/cts/external/glm/include/glm/ext/matrix_transform.inl similarity index 100% rename from external/glm/include/glm/ext/matrix_transform.inl rename to cts/external/glm/include/glm/ext/matrix_transform.inl diff --git a/external/glm/include/glm/ext/matrix_uint2x2.hpp b/cts/external/glm/include/glm/ext/matrix_uint2x2.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint2x2.hpp rename to cts/external/glm/include/glm/ext/matrix_uint2x2.hpp diff --git a/external/glm/include/glm/ext/matrix_uint2x2_sized.hpp b/cts/external/glm/include/glm/ext/matrix_uint2x2_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint2x2_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_uint2x2_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_uint2x3.hpp b/cts/external/glm/include/glm/ext/matrix_uint2x3.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint2x3.hpp rename to cts/external/glm/include/glm/ext/matrix_uint2x3.hpp diff --git a/external/glm/include/glm/ext/matrix_uint2x3_sized.hpp b/cts/external/glm/include/glm/ext/matrix_uint2x3_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint2x3_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_uint2x3_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_uint2x4.hpp b/cts/external/glm/include/glm/ext/matrix_uint2x4.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint2x4.hpp rename to cts/external/glm/include/glm/ext/matrix_uint2x4.hpp diff --git a/external/glm/include/glm/ext/matrix_uint2x4_sized.hpp b/cts/external/glm/include/glm/ext/matrix_uint2x4_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint2x4_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_uint2x4_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_uint3x2.hpp b/cts/external/glm/include/glm/ext/matrix_uint3x2.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint3x2.hpp rename to cts/external/glm/include/glm/ext/matrix_uint3x2.hpp diff --git a/external/glm/include/glm/ext/matrix_uint3x2_sized.hpp b/cts/external/glm/include/glm/ext/matrix_uint3x2_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint3x2_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_uint3x2_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_uint3x3.hpp b/cts/external/glm/include/glm/ext/matrix_uint3x3.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint3x3.hpp rename to cts/external/glm/include/glm/ext/matrix_uint3x3.hpp diff --git a/external/glm/include/glm/ext/matrix_uint3x3_sized.hpp b/cts/external/glm/include/glm/ext/matrix_uint3x3_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint3x3_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_uint3x3_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_uint3x4.hpp b/cts/external/glm/include/glm/ext/matrix_uint3x4.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint3x4.hpp rename to cts/external/glm/include/glm/ext/matrix_uint3x4.hpp diff --git a/external/glm/include/glm/ext/matrix_uint3x4_sized.hpp b/cts/external/glm/include/glm/ext/matrix_uint3x4_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint3x4_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_uint3x4_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_uint4x2.hpp b/cts/external/glm/include/glm/ext/matrix_uint4x2.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint4x2.hpp rename to cts/external/glm/include/glm/ext/matrix_uint4x2.hpp diff --git a/external/glm/include/glm/ext/matrix_uint4x2_sized.hpp b/cts/external/glm/include/glm/ext/matrix_uint4x2_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint4x2_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_uint4x2_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_uint4x3.hpp b/cts/external/glm/include/glm/ext/matrix_uint4x3.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint4x3.hpp rename to cts/external/glm/include/glm/ext/matrix_uint4x3.hpp diff --git a/external/glm/include/glm/ext/matrix_uint4x3_sized.hpp b/cts/external/glm/include/glm/ext/matrix_uint4x3_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint4x3_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_uint4x3_sized.hpp diff --git a/external/glm/include/glm/ext/matrix_uint4x4.hpp b/cts/external/glm/include/glm/ext/matrix_uint4x4.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint4x4.hpp rename to cts/external/glm/include/glm/ext/matrix_uint4x4.hpp diff --git a/external/glm/include/glm/ext/matrix_uint4x4_sized.hpp b/cts/external/glm/include/glm/ext/matrix_uint4x4_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/matrix_uint4x4_sized.hpp rename to cts/external/glm/include/glm/ext/matrix_uint4x4_sized.hpp diff --git a/external/glm/include/glm/ext/quaternion_common.hpp b/cts/external/glm/include/glm/ext/quaternion_common.hpp similarity index 100% rename from external/glm/include/glm/ext/quaternion_common.hpp rename to cts/external/glm/include/glm/ext/quaternion_common.hpp diff --git a/external/glm/include/glm/ext/quaternion_common.inl b/cts/external/glm/include/glm/ext/quaternion_common.inl similarity index 100% rename from external/glm/include/glm/ext/quaternion_common.inl rename to cts/external/glm/include/glm/ext/quaternion_common.inl diff --git a/external/glm/include/glm/ext/quaternion_common_simd.inl b/cts/external/glm/include/glm/ext/quaternion_common_simd.inl similarity index 100% rename from external/glm/include/glm/ext/quaternion_common_simd.inl rename to cts/external/glm/include/glm/ext/quaternion_common_simd.inl diff --git a/external/glm/include/glm/ext/quaternion_double.hpp b/cts/external/glm/include/glm/ext/quaternion_double.hpp similarity index 100% rename from external/glm/include/glm/ext/quaternion_double.hpp rename to cts/external/glm/include/glm/ext/quaternion_double.hpp diff --git a/external/glm/include/glm/ext/quaternion_double_precision.hpp b/cts/external/glm/include/glm/ext/quaternion_double_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/quaternion_double_precision.hpp rename to cts/external/glm/include/glm/ext/quaternion_double_precision.hpp diff --git a/external/glm/include/glm/ext/quaternion_exponential.hpp b/cts/external/glm/include/glm/ext/quaternion_exponential.hpp similarity index 100% rename from external/glm/include/glm/ext/quaternion_exponential.hpp rename to cts/external/glm/include/glm/ext/quaternion_exponential.hpp diff --git a/external/glm/include/glm/ext/quaternion_exponential.inl b/cts/external/glm/include/glm/ext/quaternion_exponential.inl similarity index 100% rename from external/glm/include/glm/ext/quaternion_exponential.inl rename to cts/external/glm/include/glm/ext/quaternion_exponential.inl diff --git a/external/glm/include/glm/ext/quaternion_float.hpp b/cts/external/glm/include/glm/ext/quaternion_float.hpp similarity index 100% rename from external/glm/include/glm/ext/quaternion_float.hpp rename to cts/external/glm/include/glm/ext/quaternion_float.hpp diff --git a/external/glm/include/glm/ext/quaternion_float_precision.hpp b/cts/external/glm/include/glm/ext/quaternion_float_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/quaternion_float_precision.hpp rename to cts/external/glm/include/glm/ext/quaternion_float_precision.hpp diff --git a/external/glm/include/glm/ext/quaternion_geometric.hpp b/cts/external/glm/include/glm/ext/quaternion_geometric.hpp similarity index 100% rename from external/glm/include/glm/ext/quaternion_geometric.hpp rename to cts/external/glm/include/glm/ext/quaternion_geometric.hpp diff --git a/external/glm/include/glm/ext/quaternion_geometric.inl b/cts/external/glm/include/glm/ext/quaternion_geometric.inl similarity index 100% rename from external/glm/include/glm/ext/quaternion_geometric.inl rename to cts/external/glm/include/glm/ext/quaternion_geometric.inl diff --git a/external/glm/include/glm/ext/quaternion_relational.hpp b/cts/external/glm/include/glm/ext/quaternion_relational.hpp similarity index 100% rename from external/glm/include/glm/ext/quaternion_relational.hpp rename to cts/external/glm/include/glm/ext/quaternion_relational.hpp diff --git a/external/glm/include/glm/ext/quaternion_relational.inl b/cts/external/glm/include/glm/ext/quaternion_relational.inl similarity index 100% rename from external/glm/include/glm/ext/quaternion_relational.inl rename to cts/external/glm/include/glm/ext/quaternion_relational.inl diff --git a/external/glm/include/glm/ext/quaternion_transform.hpp b/cts/external/glm/include/glm/ext/quaternion_transform.hpp similarity index 100% rename from external/glm/include/glm/ext/quaternion_transform.hpp rename to cts/external/glm/include/glm/ext/quaternion_transform.hpp diff --git a/external/glm/include/glm/ext/quaternion_transform.inl b/cts/external/glm/include/glm/ext/quaternion_transform.inl similarity index 100% rename from external/glm/include/glm/ext/quaternion_transform.inl rename to cts/external/glm/include/glm/ext/quaternion_transform.inl diff --git a/external/glm/include/glm/ext/quaternion_trigonometric.hpp b/cts/external/glm/include/glm/ext/quaternion_trigonometric.hpp similarity index 100% rename from external/glm/include/glm/ext/quaternion_trigonometric.hpp rename to cts/external/glm/include/glm/ext/quaternion_trigonometric.hpp diff --git a/external/glm/include/glm/ext/quaternion_trigonometric.inl b/cts/external/glm/include/glm/ext/quaternion_trigonometric.inl similarity index 100% rename from external/glm/include/glm/ext/quaternion_trigonometric.inl rename to cts/external/glm/include/glm/ext/quaternion_trigonometric.inl diff --git a/external/glm/include/glm/ext/scalar_common.hpp b/cts/external/glm/include/glm/ext/scalar_common.hpp similarity index 100% rename from external/glm/include/glm/ext/scalar_common.hpp rename to cts/external/glm/include/glm/ext/scalar_common.hpp diff --git a/external/glm/include/glm/ext/scalar_common.inl b/cts/external/glm/include/glm/ext/scalar_common.inl similarity index 100% rename from external/glm/include/glm/ext/scalar_common.inl rename to cts/external/glm/include/glm/ext/scalar_common.inl diff --git a/external/glm/include/glm/ext/scalar_constants.hpp b/cts/external/glm/include/glm/ext/scalar_constants.hpp similarity index 100% rename from external/glm/include/glm/ext/scalar_constants.hpp rename to cts/external/glm/include/glm/ext/scalar_constants.hpp diff --git a/external/glm/include/glm/ext/scalar_constants.inl b/cts/external/glm/include/glm/ext/scalar_constants.inl similarity index 100% rename from external/glm/include/glm/ext/scalar_constants.inl rename to cts/external/glm/include/glm/ext/scalar_constants.inl diff --git a/external/glm/include/glm/ext/scalar_int_sized.hpp b/cts/external/glm/include/glm/ext/scalar_int_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/scalar_int_sized.hpp rename to cts/external/glm/include/glm/ext/scalar_int_sized.hpp diff --git a/external/glm/include/glm/ext/scalar_integer.hpp b/cts/external/glm/include/glm/ext/scalar_integer.hpp similarity index 100% rename from external/glm/include/glm/ext/scalar_integer.hpp rename to cts/external/glm/include/glm/ext/scalar_integer.hpp diff --git a/external/glm/include/glm/ext/scalar_integer.inl b/cts/external/glm/include/glm/ext/scalar_integer.inl similarity index 100% rename from external/glm/include/glm/ext/scalar_integer.inl rename to cts/external/glm/include/glm/ext/scalar_integer.inl diff --git a/external/glm/include/glm/ext/scalar_packing.hpp b/cts/external/glm/include/glm/ext/scalar_packing.hpp similarity index 100% rename from external/glm/include/glm/ext/scalar_packing.hpp rename to cts/external/glm/include/glm/ext/scalar_packing.hpp diff --git a/external/glm/include/glm/ext/scalar_packing.inl b/cts/external/glm/include/glm/ext/scalar_packing.inl similarity index 100% rename from external/glm/include/glm/ext/scalar_packing.inl rename to cts/external/glm/include/glm/ext/scalar_packing.inl diff --git a/external/glm/include/glm/ext/scalar_reciprocal.hpp b/cts/external/glm/include/glm/ext/scalar_reciprocal.hpp similarity index 100% rename from external/glm/include/glm/ext/scalar_reciprocal.hpp rename to cts/external/glm/include/glm/ext/scalar_reciprocal.hpp diff --git a/external/glm/include/glm/ext/scalar_reciprocal.inl b/cts/external/glm/include/glm/ext/scalar_reciprocal.inl similarity index 100% rename from external/glm/include/glm/ext/scalar_reciprocal.inl rename to cts/external/glm/include/glm/ext/scalar_reciprocal.inl diff --git a/external/glm/include/glm/ext/scalar_relational.hpp b/cts/external/glm/include/glm/ext/scalar_relational.hpp similarity index 100% rename from external/glm/include/glm/ext/scalar_relational.hpp rename to cts/external/glm/include/glm/ext/scalar_relational.hpp diff --git a/external/glm/include/glm/ext/scalar_relational.inl b/cts/external/glm/include/glm/ext/scalar_relational.inl similarity index 100% rename from external/glm/include/glm/ext/scalar_relational.inl rename to cts/external/glm/include/glm/ext/scalar_relational.inl diff --git a/external/glm/include/glm/ext/scalar_uint_sized.hpp b/cts/external/glm/include/glm/ext/scalar_uint_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/scalar_uint_sized.hpp rename to cts/external/glm/include/glm/ext/scalar_uint_sized.hpp diff --git a/external/glm/include/glm/ext/scalar_ulp.hpp b/cts/external/glm/include/glm/ext/scalar_ulp.hpp similarity index 100% rename from external/glm/include/glm/ext/scalar_ulp.hpp rename to cts/external/glm/include/glm/ext/scalar_ulp.hpp diff --git a/external/glm/include/glm/ext/scalar_ulp.inl b/cts/external/glm/include/glm/ext/scalar_ulp.inl similarity index 100% rename from external/glm/include/glm/ext/scalar_ulp.inl rename to cts/external/glm/include/glm/ext/scalar_ulp.inl diff --git a/external/glm/include/glm/ext/vector_bool1.hpp b/cts/external/glm/include/glm/ext/vector_bool1.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_bool1.hpp rename to cts/external/glm/include/glm/ext/vector_bool1.hpp diff --git a/external/glm/include/glm/ext/vector_bool1_precision.hpp b/cts/external/glm/include/glm/ext/vector_bool1_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_bool1_precision.hpp rename to cts/external/glm/include/glm/ext/vector_bool1_precision.hpp diff --git a/external/glm/include/glm/ext/vector_bool2.hpp b/cts/external/glm/include/glm/ext/vector_bool2.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_bool2.hpp rename to cts/external/glm/include/glm/ext/vector_bool2.hpp diff --git a/external/glm/include/glm/ext/vector_bool2_precision.hpp b/cts/external/glm/include/glm/ext/vector_bool2_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_bool2_precision.hpp rename to cts/external/glm/include/glm/ext/vector_bool2_precision.hpp diff --git a/external/glm/include/glm/ext/vector_bool3.hpp b/cts/external/glm/include/glm/ext/vector_bool3.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_bool3.hpp rename to cts/external/glm/include/glm/ext/vector_bool3.hpp diff --git a/external/glm/include/glm/ext/vector_bool3_precision.hpp b/cts/external/glm/include/glm/ext/vector_bool3_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_bool3_precision.hpp rename to cts/external/glm/include/glm/ext/vector_bool3_precision.hpp diff --git a/external/glm/include/glm/ext/vector_bool4.hpp b/cts/external/glm/include/glm/ext/vector_bool4.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_bool4.hpp rename to cts/external/glm/include/glm/ext/vector_bool4.hpp diff --git a/external/glm/include/glm/ext/vector_bool4_precision.hpp b/cts/external/glm/include/glm/ext/vector_bool4_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_bool4_precision.hpp rename to cts/external/glm/include/glm/ext/vector_bool4_precision.hpp diff --git a/external/glm/include/glm/ext/vector_common.hpp b/cts/external/glm/include/glm/ext/vector_common.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_common.hpp rename to cts/external/glm/include/glm/ext/vector_common.hpp diff --git a/external/glm/include/glm/ext/vector_common.inl b/cts/external/glm/include/glm/ext/vector_common.inl similarity index 100% rename from external/glm/include/glm/ext/vector_common.inl rename to cts/external/glm/include/glm/ext/vector_common.inl diff --git a/external/glm/include/glm/ext/vector_double1.hpp b/cts/external/glm/include/glm/ext/vector_double1.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_double1.hpp rename to cts/external/glm/include/glm/ext/vector_double1.hpp diff --git a/external/glm/include/glm/ext/vector_double1_precision.hpp b/cts/external/glm/include/glm/ext/vector_double1_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_double1_precision.hpp rename to cts/external/glm/include/glm/ext/vector_double1_precision.hpp diff --git a/external/glm/include/glm/ext/vector_double2.hpp b/cts/external/glm/include/glm/ext/vector_double2.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_double2.hpp rename to cts/external/glm/include/glm/ext/vector_double2.hpp diff --git a/external/glm/include/glm/ext/vector_double2_precision.hpp b/cts/external/glm/include/glm/ext/vector_double2_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_double2_precision.hpp rename to cts/external/glm/include/glm/ext/vector_double2_precision.hpp diff --git a/external/glm/include/glm/ext/vector_double3.hpp b/cts/external/glm/include/glm/ext/vector_double3.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_double3.hpp rename to cts/external/glm/include/glm/ext/vector_double3.hpp diff --git a/external/glm/include/glm/ext/vector_double3_precision.hpp b/cts/external/glm/include/glm/ext/vector_double3_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_double3_precision.hpp rename to cts/external/glm/include/glm/ext/vector_double3_precision.hpp diff --git a/external/glm/include/glm/ext/vector_double4.hpp b/cts/external/glm/include/glm/ext/vector_double4.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_double4.hpp rename to cts/external/glm/include/glm/ext/vector_double4.hpp diff --git a/external/glm/include/glm/ext/vector_double4_precision.hpp b/cts/external/glm/include/glm/ext/vector_double4_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_double4_precision.hpp rename to cts/external/glm/include/glm/ext/vector_double4_precision.hpp diff --git a/external/glm/include/glm/ext/vector_float1.hpp b/cts/external/glm/include/glm/ext/vector_float1.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_float1.hpp rename to cts/external/glm/include/glm/ext/vector_float1.hpp diff --git a/external/glm/include/glm/ext/vector_float1_precision.hpp b/cts/external/glm/include/glm/ext/vector_float1_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_float1_precision.hpp rename to cts/external/glm/include/glm/ext/vector_float1_precision.hpp diff --git a/external/glm/include/glm/ext/vector_float2.hpp b/cts/external/glm/include/glm/ext/vector_float2.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_float2.hpp rename to cts/external/glm/include/glm/ext/vector_float2.hpp diff --git a/external/glm/include/glm/ext/vector_float2_precision.hpp b/cts/external/glm/include/glm/ext/vector_float2_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_float2_precision.hpp rename to cts/external/glm/include/glm/ext/vector_float2_precision.hpp diff --git a/external/glm/include/glm/ext/vector_float3.hpp b/cts/external/glm/include/glm/ext/vector_float3.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_float3.hpp rename to cts/external/glm/include/glm/ext/vector_float3.hpp diff --git a/external/glm/include/glm/ext/vector_float3_precision.hpp b/cts/external/glm/include/glm/ext/vector_float3_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_float3_precision.hpp rename to cts/external/glm/include/glm/ext/vector_float3_precision.hpp diff --git a/external/glm/include/glm/ext/vector_float4.hpp b/cts/external/glm/include/glm/ext/vector_float4.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_float4.hpp rename to cts/external/glm/include/glm/ext/vector_float4.hpp diff --git a/external/glm/include/glm/ext/vector_float4_precision.hpp b/cts/external/glm/include/glm/ext/vector_float4_precision.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_float4_precision.hpp rename to cts/external/glm/include/glm/ext/vector_float4_precision.hpp diff --git a/external/glm/include/glm/ext/vector_int1.hpp b/cts/external/glm/include/glm/ext/vector_int1.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_int1.hpp rename to cts/external/glm/include/glm/ext/vector_int1.hpp diff --git a/external/glm/include/glm/ext/vector_int1_sized.hpp b/cts/external/glm/include/glm/ext/vector_int1_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_int1_sized.hpp rename to cts/external/glm/include/glm/ext/vector_int1_sized.hpp diff --git a/external/glm/include/glm/ext/vector_int2.hpp b/cts/external/glm/include/glm/ext/vector_int2.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_int2.hpp rename to cts/external/glm/include/glm/ext/vector_int2.hpp diff --git a/external/glm/include/glm/ext/vector_int2_sized.hpp b/cts/external/glm/include/glm/ext/vector_int2_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_int2_sized.hpp rename to cts/external/glm/include/glm/ext/vector_int2_sized.hpp diff --git a/external/glm/include/glm/ext/vector_int3.hpp b/cts/external/glm/include/glm/ext/vector_int3.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_int3.hpp rename to cts/external/glm/include/glm/ext/vector_int3.hpp diff --git a/external/glm/include/glm/ext/vector_int3_sized.hpp b/cts/external/glm/include/glm/ext/vector_int3_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_int3_sized.hpp rename to cts/external/glm/include/glm/ext/vector_int3_sized.hpp diff --git a/external/glm/include/glm/ext/vector_int4.hpp b/cts/external/glm/include/glm/ext/vector_int4.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_int4.hpp rename to cts/external/glm/include/glm/ext/vector_int4.hpp diff --git a/external/glm/include/glm/ext/vector_int4_sized.hpp b/cts/external/glm/include/glm/ext/vector_int4_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_int4_sized.hpp rename to cts/external/glm/include/glm/ext/vector_int4_sized.hpp diff --git a/external/glm/include/glm/ext/vector_integer.hpp b/cts/external/glm/include/glm/ext/vector_integer.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_integer.hpp rename to cts/external/glm/include/glm/ext/vector_integer.hpp diff --git a/external/glm/include/glm/ext/vector_integer.inl b/cts/external/glm/include/glm/ext/vector_integer.inl similarity index 100% rename from external/glm/include/glm/ext/vector_integer.inl rename to cts/external/glm/include/glm/ext/vector_integer.inl diff --git a/external/glm/include/glm/ext/vector_packing.hpp b/cts/external/glm/include/glm/ext/vector_packing.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_packing.hpp rename to cts/external/glm/include/glm/ext/vector_packing.hpp diff --git a/external/glm/include/glm/ext/vector_packing.inl b/cts/external/glm/include/glm/ext/vector_packing.inl similarity index 100% rename from external/glm/include/glm/ext/vector_packing.inl rename to cts/external/glm/include/glm/ext/vector_packing.inl diff --git a/external/glm/include/glm/ext/vector_reciprocal.hpp b/cts/external/glm/include/glm/ext/vector_reciprocal.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_reciprocal.hpp rename to cts/external/glm/include/glm/ext/vector_reciprocal.hpp diff --git a/external/glm/include/glm/ext/vector_reciprocal.inl b/cts/external/glm/include/glm/ext/vector_reciprocal.inl similarity index 100% rename from external/glm/include/glm/ext/vector_reciprocal.inl rename to cts/external/glm/include/glm/ext/vector_reciprocal.inl diff --git a/external/glm/include/glm/ext/vector_relational.hpp b/cts/external/glm/include/glm/ext/vector_relational.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_relational.hpp rename to cts/external/glm/include/glm/ext/vector_relational.hpp diff --git a/external/glm/include/glm/ext/vector_relational.inl b/cts/external/glm/include/glm/ext/vector_relational.inl similarity index 100% rename from external/glm/include/glm/ext/vector_relational.inl rename to cts/external/glm/include/glm/ext/vector_relational.inl diff --git a/external/glm/include/glm/ext/vector_uint1.hpp b/cts/external/glm/include/glm/ext/vector_uint1.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_uint1.hpp rename to cts/external/glm/include/glm/ext/vector_uint1.hpp diff --git a/external/glm/include/glm/ext/vector_uint1_sized.hpp b/cts/external/glm/include/glm/ext/vector_uint1_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_uint1_sized.hpp rename to cts/external/glm/include/glm/ext/vector_uint1_sized.hpp diff --git a/external/glm/include/glm/ext/vector_uint2.hpp b/cts/external/glm/include/glm/ext/vector_uint2.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_uint2.hpp rename to cts/external/glm/include/glm/ext/vector_uint2.hpp diff --git a/external/glm/include/glm/ext/vector_uint2_sized.hpp b/cts/external/glm/include/glm/ext/vector_uint2_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_uint2_sized.hpp rename to cts/external/glm/include/glm/ext/vector_uint2_sized.hpp diff --git a/external/glm/include/glm/ext/vector_uint3.hpp b/cts/external/glm/include/glm/ext/vector_uint3.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_uint3.hpp rename to cts/external/glm/include/glm/ext/vector_uint3.hpp diff --git a/external/glm/include/glm/ext/vector_uint3_sized.hpp b/cts/external/glm/include/glm/ext/vector_uint3_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_uint3_sized.hpp rename to cts/external/glm/include/glm/ext/vector_uint3_sized.hpp diff --git a/external/glm/include/glm/ext/vector_uint4.hpp b/cts/external/glm/include/glm/ext/vector_uint4.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_uint4.hpp rename to cts/external/glm/include/glm/ext/vector_uint4.hpp diff --git a/external/glm/include/glm/ext/vector_uint4_sized.hpp b/cts/external/glm/include/glm/ext/vector_uint4_sized.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_uint4_sized.hpp rename to cts/external/glm/include/glm/ext/vector_uint4_sized.hpp diff --git a/external/glm/include/glm/ext/vector_ulp.hpp b/cts/external/glm/include/glm/ext/vector_ulp.hpp similarity index 100% rename from external/glm/include/glm/ext/vector_ulp.hpp rename to cts/external/glm/include/glm/ext/vector_ulp.hpp diff --git a/external/glm/include/glm/ext/vector_ulp.inl b/cts/external/glm/include/glm/ext/vector_ulp.inl similarity index 100% rename from external/glm/include/glm/ext/vector_ulp.inl rename to cts/external/glm/include/glm/ext/vector_ulp.inl diff --git a/external/glm/include/glm/fwd.hpp b/cts/external/glm/include/glm/fwd.hpp similarity index 100% rename from external/glm/include/glm/fwd.hpp rename to cts/external/glm/include/glm/fwd.hpp diff --git a/external/glm/include/glm/geometric.hpp b/cts/external/glm/include/glm/geometric.hpp similarity index 100% rename from external/glm/include/glm/geometric.hpp rename to cts/external/glm/include/glm/geometric.hpp diff --git a/external/glm/include/glm/glm.hpp b/cts/external/glm/include/glm/glm.hpp similarity index 100% rename from external/glm/include/glm/glm.hpp rename to cts/external/glm/include/glm/glm.hpp diff --git a/external/glm/include/glm/gtc/bitfield.hpp b/cts/external/glm/include/glm/gtc/bitfield.hpp similarity index 100% rename from external/glm/include/glm/gtc/bitfield.hpp rename to cts/external/glm/include/glm/gtc/bitfield.hpp diff --git a/external/glm/include/glm/gtc/bitfield.inl b/cts/external/glm/include/glm/gtc/bitfield.inl similarity index 100% rename from external/glm/include/glm/gtc/bitfield.inl rename to cts/external/glm/include/glm/gtc/bitfield.inl diff --git a/external/glm/include/glm/gtc/color_space.hpp b/cts/external/glm/include/glm/gtc/color_space.hpp similarity index 100% rename from external/glm/include/glm/gtc/color_space.hpp rename to cts/external/glm/include/glm/gtc/color_space.hpp diff --git a/external/glm/include/glm/gtc/color_space.inl b/cts/external/glm/include/glm/gtc/color_space.inl similarity index 100% rename from external/glm/include/glm/gtc/color_space.inl rename to cts/external/glm/include/glm/gtc/color_space.inl diff --git a/external/glm/include/glm/gtc/constants.hpp b/cts/external/glm/include/glm/gtc/constants.hpp similarity index 100% rename from external/glm/include/glm/gtc/constants.hpp rename to cts/external/glm/include/glm/gtc/constants.hpp diff --git a/external/glm/include/glm/gtc/constants.inl b/cts/external/glm/include/glm/gtc/constants.inl similarity index 100% rename from external/glm/include/glm/gtc/constants.inl rename to cts/external/glm/include/glm/gtc/constants.inl diff --git a/external/glm/include/glm/gtc/epsilon.hpp b/cts/external/glm/include/glm/gtc/epsilon.hpp similarity index 100% rename from external/glm/include/glm/gtc/epsilon.hpp rename to cts/external/glm/include/glm/gtc/epsilon.hpp diff --git a/external/glm/include/glm/gtc/epsilon.inl b/cts/external/glm/include/glm/gtc/epsilon.inl similarity index 100% rename from external/glm/include/glm/gtc/epsilon.inl rename to cts/external/glm/include/glm/gtc/epsilon.inl diff --git a/external/glm/include/glm/gtc/integer.hpp b/cts/external/glm/include/glm/gtc/integer.hpp similarity index 100% rename from external/glm/include/glm/gtc/integer.hpp rename to cts/external/glm/include/glm/gtc/integer.hpp diff --git a/external/glm/include/glm/gtc/integer.inl b/cts/external/glm/include/glm/gtc/integer.inl similarity index 100% rename from external/glm/include/glm/gtc/integer.inl rename to cts/external/glm/include/glm/gtc/integer.inl diff --git a/external/glm/include/glm/gtc/matrix_access.hpp b/cts/external/glm/include/glm/gtc/matrix_access.hpp similarity index 100% rename from external/glm/include/glm/gtc/matrix_access.hpp rename to cts/external/glm/include/glm/gtc/matrix_access.hpp diff --git a/external/glm/include/glm/gtc/matrix_access.inl b/cts/external/glm/include/glm/gtc/matrix_access.inl similarity index 100% rename from external/glm/include/glm/gtc/matrix_access.inl rename to cts/external/glm/include/glm/gtc/matrix_access.inl diff --git a/external/glm/include/glm/gtc/matrix_integer.hpp b/cts/external/glm/include/glm/gtc/matrix_integer.hpp similarity index 100% rename from external/glm/include/glm/gtc/matrix_integer.hpp rename to cts/external/glm/include/glm/gtc/matrix_integer.hpp diff --git a/external/glm/include/glm/gtc/matrix_inverse.hpp b/cts/external/glm/include/glm/gtc/matrix_inverse.hpp similarity index 100% rename from external/glm/include/glm/gtc/matrix_inverse.hpp rename to cts/external/glm/include/glm/gtc/matrix_inverse.hpp diff --git a/external/glm/include/glm/gtc/matrix_inverse.inl b/cts/external/glm/include/glm/gtc/matrix_inverse.inl similarity index 100% rename from external/glm/include/glm/gtc/matrix_inverse.inl rename to cts/external/glm/include/glm/gtc/matrix_inverse.inl diff --git a/external/glm/include/glm/gtc/matrix_transform.hpp b/cts/external/glm/include/glm/gtc/matrix_transform.hpp similarity index 100% rename from external/glm/include/glm/gtc/matrix_transform.hpp rename to cts/external/glm/include/glm/gtc/matrix_transform.hpp diff --git a/external/glm/include/glm/gtc/matrix_transform.inl b/cts/external/glm/include/glm/gtc/matrix_transform.inl similarity index 100% rename from external/glm/include/glm/gtc/matrix_transform.inl rename to cts/external/glm/include/glm/gtc/matrix_transform.inl diff --git a/external/glm/include/glm/gtc/noise.hpp b/cts/external/glm/include/glm/gtc/noise.hpp similarity index 100% rename from external/glm/include/glm/gtc/noise.hpp rename to cts/external/glm/include/glm/gtc/noise.hpp diff --git a/external/glm/include/glm/gtc/noise.inl b/cts/external/glm/include/glm/gtc/noise.inl similarity index 100% rename from external/glm/include/glm/gtc/noise.inl rename to cts/external/glm/include/glm/gtc/noise.inl diff --git a/external/glm/include/glm/gtc/packing.hpp b/cts/external/glm/include/glm/gtc/packing.hpp similarity index 100% rename from external/glm/include/glm/gtc/packing.hpp rename to cts/external/glm/include/glm/gtc/packing.hpp diff --git a/external/glm/include/glm/gtc/packing.inl b/cts/external/glm/include/glm/gtc/packing.inl similarity index 100% rename from external/glm/include/glm/gtc/packing.inl rename to cts/external/glm/include/glm/gtc/packing.inl diff --git a/external/glm/include/glm/gtc/quaternion.hpp b/cts/external/glm/include/glm/gtc/quaternion.hpp similarity index 100% rename from external/glm/include/glm/gtc/quaternion.hpp rename to cts/external/glm/include/glm/gtc/quaternion.hpp diff --git a/external/glm/include/glm/gtc/quaternion.inl b/cts/external/glm/include/glm/gtc/quaternion.inl similarity index 100% rename from external/glm/include/glm/gtc/quaternion.inl rename to cts/external/glm/include/glm/gtc/quaternion.inl diff --git a/external/glm/include/glm/gtc/quaternion_simd.inl b/cts/external/glm/include/glm/gtc/quaternion_simd.inl similarity index 100% rename from external/glm/include/glm/gtc/quaternion_simd.inl rename to cts/external/glm/include/glm/gtc/quaternion_simd.inl diff --git a/external/glm/include/glm/gtc/random.hpp b/cts/external/glm/include/glm/gtc/random.hpp similarity index 100% rename from external/glm/include/glm/gtc/random.hpp rename to cts/external/glm/include/glm/gtc/random.hpp diff --git a/external/glm/include/glm/gtc/random.inl b/cts/external/glm/include/glm/gtc/random.inl similarity index 100% rename from external/glm/include/glm/gtc/random.inl rename to cts/external/glm/include/glm/gtc/random.inl diff --git a/external/glm/include/glm/gtc/reciprocal.hpp b/cts/external/glm/include/glm/gtc/reciprocal.hpp similarity index 100% rename from external/glm/include/glm/gtc/reciprocal.hpp rename to cts/external/glm/include/glm/gtc/reciprocal.hpp diff --git a/external/glm/include/glm/gtc/round.hpp b/cts/external/glm/include/glm/gtc/round.hpp similarity index 100% rename from external/glm/include/glm/gtc/round.hpp rename to cts/external/glm/include/glm/gtc/round.hpp diff --git a/external/glm/include/glm/gtc/round.inl b/cts/external/glm/include/glm/gtc/round.inl similarity index 100% rename from external/glm/include/glm/gtc/round.inl rename to cts/external/glm/include/glm/gtc/round.inl diff --git a/external/glm/include/glm/gtc/type_aligned.hpp b/cts/external/glm/include/glm/gtc/type_aligned.hpp similarity index 100% rename from external/glm/include/glm/gtc/type_aligned.hpp rename to cts/external/glm/include/glm/gtc/type_aligned.hpp diff --git a/external/glm/include/glm/gtc/type_precision.hpp b/cts/external/glm/include/glm/gtc/type_precision.hpp similarity index 100% rename from external/glm/include/glm/gtc/type_precision.hpp rename to cts/external/glm/include/glm/gtc/type_precision.hpp diff --git a/external/glm/include/glm/gtc/type_precision.inl b/cts/external/glm/include/glm/gtc/type_precision.inl similarity index 100% rename from external/glm/include/glm/gtc/type_precision.inl rename to cts/external/glm/include/glm/gtc/type_precision.inl diff --git a/external/glm/include/glm/gtc/type_ptr.hpp b/cts/external/glm/include/glm/gtc/type_ptr.hpp similarity index 100% rename from external/glm/include/glm/gtc/type_ptr.hpp rename to cts/external/glm/include/glm/gtc/type_ptr.hpp diff --git a/external/glm/include/glm/gtc/type_ptr.inl b/cts/external/glm/include/glm/gtc/type_ptr.inl similarity index 100% rename from external/glm/include/glm/gtc/type_ptr.inl rename to cts/external/glm/include/glm/gtc/type_ptr.inl diff --git a/external/glm/include/glm/gtc/ulp.hpp b/cts/external/glm/include/glm/gtc/ulp.hpp similarity index 100% rename from external/glm/include/glm/gtc/ulp.hpp rename to cts/external/glm/include/glm/gtc/ulp.hpp diff --git a/external/glm/include/glm/gtc/ulp.inl b/cts/external/glm/include/glm/gtc/ulp.inl similarity index 100% rename from external/glm/include/glm/gtc/ulp.inl rename to cts/external/glm/include/glm/gtc/ulp.inl diff --git a/external/glm/include/glm/gtc/vec1.hpp b/cts/external/glm/include/glm/gtc/vec1.hpp similarity index 100% rename from external/glm/include/glm/gtc/vec1.hpp rename to cts/external/glm/include/glm/gtc/vec1.hpp diff --git a/external/glm/include/glm/gtx/associated_min_max.hpp b/cts/external/glm/include/glm/gtx/associated_min_max.hpp similarity index 100% rename from external/glm/include/glm/gtx/associated_min_max.hpp rename to cts/external/glm/include/glm/gtx/associated_min_max.hpp diff --git a/external/glm/include/glm/gtx/associated_min_max.inl b/cts/external/glm/include/glm/gtx/associated_min_max.inl similarity index 100% rename from external/glm/include/glm/gtx/associated_min_max.inl rename to cts/external/glm/include/glm/gtx/associated_min_max.inl diff --git a/external/glm/include/glm/gtx/bit.hpp b/cts/external/glm/include/glm/gtx/bit.hpp similarity index 100% rename from external/glm/include/glm/gtx/bit.hpp rename to cts/external/glm/include/glm/gtx/bit.hpp diff --git a/external/glm/include/glm/gtx/bit.inl b/cts/external/glm/include/glm/gtx/bit.inl similarity index 100% rename from external/glm/include/glm/gtx/bit.inl rename to cts/external/glm/include/glm/gtx/bit.inl diff --git a/external/glm/include/glm/gtx/closest_point.hpp b/cts/external/glm/include/glm/gtx/closest_point.hpp similarity index 100% rename from external/glm/include/glm/gtx/closest_point.hpp rename to cts/external/glm/include/glm/gtx/closest_point.hpp diff --git a/external/glm/include/glm/gtx/closest_point.inl b/cts/external/glm/include/glm/gtx/closest_point.inl similarity index 100% rename from external/glm/include/glm/gtx/closest_point.inl rename to cts/external/glm/include/glm/gtx/closest_point.inl diff --git a/external/glm/include/glm/gtx/color_encoding.hpp b/cts/external/glm/include/glm/gtx/color_encoding.hpp similarity index 100% rename from external/glm/include/glm/gtx/color_encoding.hpp rename to cts/external/glm/include/glm/gtx/color_encoding.hpp diff --git a/external/glm/include/glm/gtx/color_encoding.inl b/cts/external/glm/include/glm/gtx/color_encoding.inl similarity index 100% rename from external/glm/include/glm/gtx/color_encoding.inl rename to cts/external/glm/include/glm/gtx/color_encoding.inl diff --git a/external/glm/include/glm/gtx/color_space.hpp b/cts/external/glm/include/glm/gtx/color_space.hpp similarity index 100% rename from external/glm/include/glm/gtx/color_space.hpp rename to cts/external/glm/include/glm/gtx/color_space.hpp diff --git a/external/glm/include/glm/gtx/color_space.inl b/cts/external/glm/include/glm/gtx/color_space.inl similarity index 100% rename from external/glm/include/glm/gtx/color_space.inl rename to cts/external/glm/include/glm/gtx/color_space.inl diff --git a/external/glm/include/glm/gtx/color_space_YCoCg.hpp b/cts/external/glm/include/glm/gtx/color_space_YCoCg.hpp similarity index 100% rename from external/glm/include/glm/gtx/color_space_YCoCg.hpp rename to cts/external/glm/include/glm/gtx/color_space_YCoCg.hpp diff --git a/external/glm/include/glm/gtx/color_space_YCoCg.inl b/cts/external/glm/include/glm/gtx/color_space_YCoCg.inl similarity index 100% rename from external/glm/include/glm/gtx/color_space_YCoCg.inl rename to cts/external/glm/include/glm/gtx/color_space_YCoCg.inl diff --git a/external/glm/include/glm/gtx/common.hpp b/cts/external/glm/include/glm/gtx/common.hpp similarity index 100% rename from external/glm/include/glm/gtx/common.hpp rename to cts/external/glm/include/glm/gtx/common.hpp diff --git a/external/glm/include/glm/gtx/common.inl b/cts/external/glm/include/glm/gtx/common.inl similarity index 100% rename from external/glm/include/glm/gtx/common.inl rename to cts/external/glm/include/glm/gtx/common.inl diff --git a/external/glm/include/glm/gtx/compatibility.hpp b/cts/external/glm/include/glm/gtx/compatibility.hpp similarity index 100% rename from external/glm/include/glm/gtx/compatibility.hpp rename to cts/external/glm/include/glm/gtx/compatibility.hpp diff --git a/external/glm/include/glm/gtx/compatibility.inl b/cts/external/glm/include/glm/gtx/compatibility.inl similarity index 100% rename from external/glm/include/glm/gtx/compatibility.inl rename to cts/external/glm/include/glm/gtx/compatibility.inl diff --git a/external/glm/include/glm/gtx/component_wise.hpp b/cts/external/glm/include/glm/gtx/component_wise.hpp similarity index 100% rename from external/glm/include/glm/gtx/component_wise.hpp rename to cts/external/glm/include/glm/gtx/component_wise.hpp diff --git a/external/glm/include/glm/gtx/component_wise.inl b/cts/external/glm/include/glm/gtx/component_wise.inl similarity index 100% rename from external/glm/include/glm/gtx/component_wise.inl rename to cts/external/glm/include/glm/gtx/component_wise.inl diff --git a/external/glm/include/glm/gtx/dual_quaternion.hpp b/cts/external/glm/include/glm/gtx/dual_quaternion.hpp similarity index 100% rename from external/glm/include/glm/gtx/dual_quaternion.hpp rename to cts/external/glm/include/glm/gtx/dual_quaternion.hpp diff --git a/external/glm/include/glm/gtx/dual_quaternion.inl b/cts/external/glm/include/glm/gtx/dual_quaternion.inl similarity index 100% rename from external/glm/include/glm/gtx/dual_quaternion.inl rename to cts/external/glm/include/glm/gtx/dual_quaternion.inl diff --git a/external/glm/include/glm/gtx/easing.hpp b/cts/external/glm/include/glm/gtx/easing.hpp similarity index 100% rename from external/glm/include/glm/gtx/easing.hpp rename to cts/external/glm/include/glm/gtx/easing.hpp diff --git a/external/glm/include/glm/gtx/easing.inl b/cts/external/glm/include/glm/gtx/easing.inl similarity index 100% rename from external/glm/include/glm/gtx/easing.inl rename to cts/external/glm/include/glm/gtx/easing.inl diff --git a/external/glm/include/glm/gtx/euler_angles.hpp b/cts/external/glm/include/glm/gtx/euler_angles.hpp similarity index 100% rename from external/glm/include/glm/gtx/euler_angles.hpp rename to cts/external/glm/include/glm/gtx/euler_angles.hpp diff --git a/external/glm/include/glm/gtx/euler_angles.inl b/cts/external/glm/include/glm/gtx/euler_angles.inl similarity index 100% rename from external/glm/include/glm/gtx/euler_angles.inl rename to cts/external/glm/include/glm/gtx/euler_angles.inl diff --git a/external/glm/include/glm/gtx/extend.hpp b/cts/external/glm/include/glm/gtx/extend.hpp similarity index 100% rename from external/glm/include/glm/gtx/extend.hpp rename to cts/external/glm/include/glm/gtx/extend.hpp diff --git a/external/glm/include/glm/gtx/extend.inl b/cts/external/glm/include/glm/gtx/extend.inl similarity index 100% rename from external/glm/include/glm/gtx/extend.inl rename to cts/external/glm/include/glm/gtx/extend.inl diff --git a/external/glm/include/glm/gtx/extended_min_max.hpp b/cts/external/glm/include/glm/gtx/extended_min_max.hpp similarity index 100% rename from external/glm/include/glm/gtx/extended_min_max.hpp rename to cts/external/glm/include/glm/gtx/extended_min_max.hpp diff --git a/external/glm/include/glm/gtx/extended_min_max.inl b/cts/external/glm/include/glm/gtx/extended_min_max.inl similarity index 100% rename from external/glm/include/glm/gtx/extended_min_max.inl rename to cts/external/glm/include/glm/gtx/extended_min_max.inl diff --git a/external/glm/include/glm/gtx/exterior_product.hpp b/cts/external/glm/include/glm/gtx/exterior_product.hpp similarity index 100% rename from external/glm/include/glm/gtx/exterior_product.hpp rename to cts/external/glm/include/glm/gtx/exterior_product.hpp diff --git a/external/glm/include/glm/gtx/exterior_product.inl b/cts/external/glm/include/glm/gtx/exterior_product.inl similarity index 100% rename from external/glm/include/glm/gtx/exterior_product.inl rename to cts/external/glm/include/glm/gtx/exterior_product.inl diff --git a/external/glm/include/glm/gtx/fast_exponential.hpp b/cts/external/glm/include/glm/gtx/fast_exponential.hpp similarity index 100% rename from external/glm/include/glm/gtx/fast_exponential.hpp rename to cts/external/glm/include/glm/gtx/fast_exponential.hpp diff --git a/external/glm/include/glm/gtx/fast_exponential.inl b/cts/external/glm/include/glm/gtx/fast_exponential.inl similarity index 100% rename from external/glm/include/glm/gtx/fast_exponential.inl rename to cts/external/glm/include/glm/gtx/fast_exponential.inl diff --git a/external/glm/include/glm/gtx/fast_square_root.hpp b/cts/external/glm/include/glm/gtx/fast_square_root.hpp similarity index 100% rename from external/glm/include/glm/gtx/fast_square_root.hpp rename to cts/external/glm/include/glm/gtx/fast_square_root.hpp diff --git a/external/glm/include/glm/gtx/fast_square_root.inl b/cts/external/glm/include/glm/gtx/fast_square_root.inl similarity index 100% rename from external/glm/include/glm/gtx/fast_square_root.inl rename to cts/external/glm/include/glm/gtx/fast_square_root.inl diff --git a/external/glm/include/glm/gtx/fast_trigonometry.hpp b/cts/external/glm/include/glm/gtx/fast_trigonometry.hpp similarity index 100% rename from external/glm/include/glm/gtx/fast_trigonometry.hpp rename to cts/external/glm/include/glm/gtx/fast_trigonometry.hpp diff --git a/external/glm/include/glm/gtx/fast_trigonometry.inl b/cts/external/glm/include/glm/gtx/fast_trigonometry.inl similarity index 100% rename from external/glm/include/glm/gtx/fast_trigonometry.inl rename to cts/external/glm/include/glm/gtx/fast_trigonometry.inl diff --git a/external/glm/include/glm/gtx/float_notmalize.inl b/cts/external/glm/include/glm/gtx/float_notmalize.inl similarity index 100% rename from external/glm/include/glm/gtx/float_notmalize.inl rename to cts/external/glm/include/glm/gtx/float_notmalize.inl diff --git a/external/glm/include/glm/gtx/functions.hpp b/cts/external/glm/include/glm/gtx/functions.hpp similarity index 100% rename from external/glm/include/glm/gtx/functions.hpp rename to cts/external/glm/include/glm/gtx/functions.hpp diff --git a/external/glm/include/glm/gtx/functions.inl b/cts/external/glm/include/glm/gtx/functions.inl similarity index 100% rename from external/glm/include/glm/gtx/functions.inl rename to cts/external/glm/include/glm/gtx/functions.inl diff --git a/external/glm/include/glm/gtx/gradient_paint.hpp b/cts/external/glm/include/glm/gtx/gradient_paint.hpp similarity index 100% rename from external/glm/include/glm/gtx/gradient_paint.hpp rename to cts/external/glm/include/glm/gtx/gradient_paint.hpp diff --git a/external/glm/include/glm/gtx/gradient_paint.inl b/cts/external/glm/include/glm/gtx/gradient_paint.inl similarity index 100% rename from external/glm/include/glm/gtx/gradient_paint.inl rename to cts/external/glm/include/glm/gtx/gradient_paint.inl diff --git a/external/glm/include/glm/gtx/handed_coordinate_space.hpp b/cts/external/glm/include/glm/gtx/handed_coordinate_space.hpp similarity index 100% rename from external/glm/include/glm/gtx/handed_coordinate_space.hpp rename to cts/external/glm/include/glm/gtx/handed_coordinate_space.hpp diff --git a/external/glm/include/glm/gtx/handed_coordinate_space.inl b/cts/external/glm/include/glm/gtx/handed_coordinate_space.inl similarity index 100% rename from external/glm/include/glm/gtx/handed_coordinate_space.inl rename to cts/external/glm/include/glm/gtx/handed_coordinate_space.inl diff --git a/external/glm/include/glm/gtx/hash.hpp b/cts/external/glm/include/glm/gtx/hash.hpp similarity index 100% rename from external/glm/include/glm/gtx/hash.hpp rename to cts/external/glm/include/glm/gtx/hash.hpp diff --git a/external/glm/include/glm/gtx/hash.inl b/cts/external/glm/include/glm/gtx/hash.inl similarity index 100% rename from external/glm/include/glm/gtx/hash.inl rename to cts/external/glm/include/glm/gtx/hash.inl diff --git a/external/glm/include/glm/gtx/integer.hpp b/cts/external/glm/include/glm/gtx/integer.hpp similarity index 100% rename from external/glm/include/glm/gtx/integer.hpp rename to cts/external/glm/include/glm/gtx/integer.hpp diff --git a/external/glm/include/glm/gtx/integer.inl b/cts/external/glm/include/glm/gtx/integer.inl similarity index 100% rename from external/glm/include/glm/gtx/integer.inl rename to cts/external/glm/include/glm/gtx/integer.inl diff --git a/external/glm/include/glm/gtx/intersect.hpp b/cts/external/glm/include/glm/gtx/intersect.hpp similarity index 100% rename from external/glm/include/glm/gtx/intersect.hpp rename to cts/external/glm/include/glm/gtx/intersect.hpp diff --git a/external/glm/include/glm/gtx/intersect.inl b/cts/external/glm/include/glm/gtx/intersect.inl similarity index 100% rename from external/glm/include/glm/gtx/intersect.inl rename to cts/external/glm/include/glm/gtx/intersect.inl diff --git a/external/glm/include/glm/gtx/io.hpp b/cts/external/glm/include/glm/gtx/io.hpp similarity index 100% rename from external/glm/include/glm/gtx/io.hpp rename to cts/external/glm/include/glm/gtx/io.hpp diff --git a/external/glm/include/glm/gtx/io.inl b/cts/external/glm/include/glm/gtx/io.inl similarity index 100% rename from external/glm/include/glm/gtx/io.inl rename to cts/external/glm/include/glm/gtx/io.inl diff --git a/external/glm/include/glm/gtx/log_base.hpp b/cts/external/glm/include/glm/gtx/log_base.hpp similarity index 100% rename from external/glm/include/glm/gtx/log_base.hpp rename to cts/external/glm/include/glm/gtx/log_base.hpp diff --git a/external/glm/include/glm/gtx/log_base.inl b/cts/external/glm/include/glm/gtx/log_base.inl similarity index 100% rename from external/glm/include/glm/gtx/log_base.inl rename to cts/external/glm/include/glm/gtx/log_base.inl diff --git a/external/glm/include/glm/gtx/matrix_cross_product.hpp b/cts/external/glm/include/glm/gtx/matrix_cross_product.hpp similarity index 100% rename from external/glm/include/glm/gtx/matrix_cross_product.hpp rename to cts/external/glm/include/glm/gtx/matrix_cross_product.hpp diff --git a/external/glm/include/glm/gtx/matrix_cross_product.inl b/cts/external/glm/include/glm/gtx/matrix_cross_product.inl similarity index 100% rename from external/glm/include/glm/gtx/matrix_cross_product.inl rename to cts/external/glm/include/glm/gtx/matrix_cross_product.inl diff --git a/external/glm/include/glm/gtx/matrix_decompose.hpp b/cts/external/glm/include/glm/gtx/matrix_decompose.hpp similarity index 100% rename from external/glm/include/glm/gtx/matrix_decompose.hpp rename to cts/external/glm/include/glm/gtx/matrix_decompose.hpp diff --git a/external/glm/include/glm/gtx/matrix_decompose.inl b/cts/external/glm/include/glm/gtx/matrix_decompose.inl similarity index 100% rename from external/glm/include/glm/gtx/matrix_decompose.inl rename to cts/external/glm/include/glm/gtx/matrix_decompose.inl diff --git a/external/glm/include/glm/gtx/matrix_factorisation.hpp b/cts/external/glm/include/glm/gtx/matrix_factorisation.hpp similarity index 100% rename from external/glm/include/glm/gtx/matrix_factorisation.hpp rename to cts/external/glm/include/glm/gtx/matrix_factorisation.hpp diff --git a/external/glm/include/glm/gtx/matrix_factorisation.inl b/cts/external/glm/include/glm/gtx/matrix_factorisation.inl similarity index 100% rename from external/glm/include/glm/gtx/matrix_factorisation.inl rename to cts/external/glm/include/glm/gtx/matrix_factorisation.inl diff --git a/external/glm/include/glm/gtx/matrix_interpolation.hpp b/cts/external/glm/include/glm/gtx/matrix_interpolation.hpp similarity index 100% rename from external/glm/include/glm/gtx/matrix_interpolation.hpp rename to cts/external/glm/include/glm/gtx/matrix_interpolation.hpp diff --git a/external/glm/include/glm/gtx/matrix_interpolation.inl b/cts/external/glm/include/glm/gtx/matrix_interpolation.inl similarity index 100% rename from external/glm/include/glm/gtx/matrix_interpolation.inl rename to cts/external/glm/include/glm/gtx/matrix_interpolation.inl diff --git a/external/glm/include/glm/gtx/matrix_major_storage.hpp b/cts/external/glm/include/glm/gtx/matrix_major_storage.hpp similarity index 100% rename from external/glm/include/glm/gtx/matrix_major_storage.hpp rename to cts/external/glm/include/glm/gtx/matrix_major_storage.hpp diff --git a/external/glm/include/glm/gtx/matrix_major_storage.inl b/cts/external/glm/include/glm/gtx/matrix_major_storage.inl similarity index 100% rename from external/glm/include/glm/gtx/matrix_major_storage.inl rename to cts/external/glm/include/glm/gtx/matrix_major_storage.inl diff --git a/external/glm/include/glm/gtx/matrix_operation.hpp b/cts/external/glm/include/glm/gtx/matrix_operation.hpp similarity index 100% rename from external/glm/include/glm/gtx/matrix_operation.hpp rename to cts/external/glm/include/glm/gtx/matrix_operation.hpp diff --git a/external/glm/include/glm/gtx/matrix_operation.inl b/cts/external/glm/include/glm/gtx/matrix_operation.inl similarity index 100% rename from external/glm/include/glm/gtx/matrix_operation.inl rename to cts/external/glm/include/glm/gtx/matrix_operation.inl diff --git a/external/glm/include/glm/gtx/matrix_query.hpp b/cts/external/glm/include/glm/gtx/matrix_query.hpp similarity index 100% rename from external/glm/include/glm/gtx/matrix_query.hpp rename to cts/external/glm/include/glm/gtx/matrix_query.hpp diff --git a/external/glm/include/glm/gtx/matrix_query.inl b/cts/external/glm/include/glm/gtx/matrix_query.inl similarity index 100% rename from external/glm/include/glm/gtx/matrix_query.inl rename to cts/external/glm/include/glm/gtx/matrix_query.inl diff --git a/external/glm/include/glm/gtx/matrix_transform_2d.hpp b/cts/external/glm/include/glm/gtx/matrix_transform_2d.hpp similarity index 100% rename from external/glm/include/glm/gtx/matrix_transform_2d.hpp rename to cts/external/glm/include/glm/gtx/matrix_transform_2d.hpp diff --git a/external/glm/include/glm/gtx/matrix_transform_2d.inl b/cts/external/glm/include/glm/gtx/matrix_transform_2d.inl similarity index 100% rename from external/glm/include/glm/gtx/matrix_transform_2d.inl rename to cts/external/glm/include/glm/gtx/matrix_transform_2d.inl diff --git a/external/glm/include/glm/gtx/mixed_product.hpp b/cts/external/glm/include/glm/gtx/mixed_product.hpp similarity index 100% rename from external/glm/include/glm/gtx/mixed_product.hpp rename to cts/external/glm/include/glm/gtx/mixed_product.hpp diff --git a/external/glm/include/glm/gtx/mixed_product.inl b/cts/external/glm/include/glm/gtx/mixed_product.inl similarity index 100% rename from external/glm/include/glm/gtx/mixed_product.inl rename to cts/external/glm/include/glm/gtx/mixed_product.inl diff --git a/external/glm/include/glm/gtx/norm.hpp b/cts/external/glm/include/glm/gtx/norm.hpp similarity index 100% rename from external/glm/include/glm/gtx/norm.hpp rename to cts/external/glm/include/glm/gtx/norm.hpp diff --git a/external/glm/include/glm/gtx/norm.inl b/cts/external/glm/include/glm/gtx/norm.inl similarity index 100% rename from external/glm/include/glm/gtx/norm.inl rename to cts/external/glm/include/glm/gtx/norm.inl diff --git a/external/glm/include/glm/gtx/normal.hpp b/cts/external/glm/include/glm/gtx/normal.hpp similarity index 100% rename from external/glm/include/glm/gtx/normal.hpp rename to cts/external/glm/include/glm/gtx/normal.hpp diff --git a/external/glm/include/glm/gtx/normal.inl b/cts/external/glm/include/glm/gtx/normal.inl similarity index 100% rename from external/glm/include/glm/gtx/normal.inl rename to cts/external/glm/include/glm/gtx/normal.inl diff --git a/external/glm/include/glm/gtx/normalize_dot.hpp b/cts/external/glm/include/glm/gtx/normalize_dot.hpp similarity index 100% rename from external/glm/include/glm/gtx/normalize_dot.hpp rename to cts/external/glm/include/glm/gtx/normalize_dot.hpp diff --git a/external/glm/include/glm/gtx/normalize_dot.inl b/cts/external/glm/include/glm/gtx/normalize_dot.inl similarity index 100% rename from external/glm/include/glm/gtx/normalize_dot.inl rename to cts/external/glm/include/glm/gtx/normalize_dot.inl diff --git a/external/glm/include/glm/gtx/number_precision.hpp b/cts/external/glm/include/glm/gtx/number_precision.hpp similarity index 100% rename from external/glm/include/glm/gtx/number_precision.hpp rename to cts/external/glm/include/glm/gtx/number_precision.hpp diff --git a/external/glm/include/glm/gtx/number_precision.inl b/cts/external/glm/include/glm/gtx/number_precision.inl similarity index 100% rename from external/glm/include/glm/gtx/number_precision.inl rename to cts/external/glm/include/glm/gtx/number_precision.inl diff --git a/external/glm/include/glm/gtx/optimum_pow.hpp b/cts/external/glm/include/glm/gtx/optimum_pow.hpp similarity index 100% rename from external/glm/include/glm/gtx/optimum_pow.hpp rename to cts/external/glm/include/glm/gtx/optimum_pow.hpp diff --git a/external/glm/include/glm/gtx/optimum_pow.inl b/cts/external/glm/include/glm/gtx/optimum_pow.inl similarity index 100% rename from external/glm/include/glm/gtx/optimum_pow.inl rename to cts/external/glm/include/glm/gtx/optimum_pow.inl diff --git a/external/glm/include/glm/gtx/orthonormalize.hpp b/cts/external/glm/include/glm/gtx/orthonormalize.hpp similarity index 100% rename from external/glm/include/glm/gtx/orthonormalize.hpp rename to cts/external/glm/include/glm/gtx/orthonormalize.hpp diff --git a/external/glm/include/glm/gtx/orthonormalize.inl b/cts/external/glm/include/glm/gtx/orthonormalize.inl similarity index 100% rename from external/glm/include/glm/gtx/orthonormalize.inl rename to cts/external/glm/include/glm/gtx/orthonormalize.inl diff --git a/external/glm/include/glm/gtx/pca.hpp b/cts/external/glm/include/glm/gtx/pca.hpp similarity index 100% rename from external/glm/include/glm/gtx/pca.hpp rename to cts/external/glm/include/glm/gtx/pca.hpp diff --git a/external/glm/include/glm/gtx/pca.inl b/cts/external/glm/include/glm/gtx/pca.inl similarity index 100% rename from external/glm/include/glm/gtx/pca.inl rename to cts/external/glm/include/glm/gtx/pca.inl diff --git a/external/glm/include/glm/gtx/perpendicular.hpp b/cts/external/glm/include/glm/gtx/perpendicular.hpp similarity index 100% rename from external/glm/include/glm/gtx/perpendicular.hpp rename to cts/external/glm/include/glm/gtx/perpendicular.hpp diff --git a/external/glm/include/glm/gtx/perpendicular.inl b/cts/external/glm/include/glm/gtx/perpendicular.inl similarity index 100% rename from external/glm/include/glm/gtx/perpendicular.inl rename to cts/external/glm/include/glm/gtx/perpendicular.inl diff --git a/external/glm/include/glm/gtx/polar_coordinates.hpp b/cts/external/glm/include/glm/gtx/polar_coordinates.hpp similarity index 100% rename from external/glm/include/glm/gtx/polar_coordinates.hpp rename to cts/external/glm/include/glm/gtx/polar_coordinates.hpp diff --git a/external/glm/include/glm/gtx/polar_coordinates.inl b/cts/external/glm/include/glm/gtx/polar_coordinates.inl similarity index 100% rename from external/glm/include/glm/gtx/polar_coordinates.inl rename to cts/external/glm/include/glm/gtx/polar_coordinates.inl diff --git a/external/glm/include/glm/gtx/projection.hpp b/cts/external/glm/include/glm/gtx/projection.hpp similarity index 100% rename from external/glm/include/glm/gtx/projection.hpp rename to cts/external/glm/include/glm/gtx/projection.hpp diff --git a/external/glm/include/glm/gtx/projection.inl b/cts/external/glm/include/glm/gtx/projection.inl similarity index 100% rename from external/glm/include/glm/gtx/projection.inl rename to cts/external/glm/include/glm/gtx/projection.inl diff --git a/external/glm/include/glm/gtx/quaternion.hpp b/cts/external/glm/include/glm/gtx/quaternion.hpp similarity index 100% rename from external/glm/include/glm/gtx/quaternion.hpp rename to cts/external/glm/include/glm/gtx/quaternion.hpp diff --git a/external/glm/include/glm/gtx/quaternion.inl b/cts/external/glm/include/glm/gtx/quaternion.inl similarity index 100% rename from external/glm/include/glm/gtx/quaternion.inl rename to cts/external/glm/include/glm/gtx/quaternion.inl diff --git a/external/glm/include/glm/gtx/range.hpp b/cts/external/glm/include/glm/gtx/range.hpp similarity index 100% rename from external/glm/include/glm/gtx/range.hpp rename to cts/external/glm/include/glm/gtx/range.hpp diff --git a/external/glm/include/glm/gtx/raw_data.hpp b/cts/external/glm/include/glm/gtx/raw_data.hpp similarity index 100% rename from external/glm/include/glm/gtx/raw_data.hpp rename to cts/external/glm/include/glm/gtx/raw_data.hpp diff --git a/external/glm/include/glm/gtx/raw_data.inl b/cts/external/glm/include/glm/gtx/raw_data.inl similarity index 100% rename from external/glm/include/glm/gtx/raw_data.inl rename to cts/external/glm/include/glm/gtx/raw_data.inl diff --git a/external/glm/include/glm/gtx/rotate_normalized_axis.hpp b/cts/external/glm/include/glm/gtx/rotate_normalized_axis.hpp similarity index 100% rename from external/glm/include/glm/gtx/rotate_normalized_axis.hpp rename to cts/external/glm/include/glm/gtx/rotate_normalized_axis.hpp diff --git a/external/glm/include/glm/gtx/rotate_normalized_axis.inl b/cts/external/glm/include/glm/gtx/rotate_normalized_axis.inl similarity index 100% rename from external/glm/include/glm/gtx/rotate_normalized_axis.inl rename to cts/external/glm/include/glm/gtx/rotate_normalized_axis.inl diff --git a/external/glm/include/glm/gtx/rotate_vector.hpp b/cts/external/glm/include/glm/gtx/rotate_vector.hpp similarity index 100% rename from external/glm/include/glm/gtx/rotate_vector.hpp rename to cts/external/glm/include/glm/gtx/rotate_vector.hpp diff --git a/external/glm/include/glm/gtx/rotate_vector.inl b/cts/external/glm/include/glm/gtx/rotate_vector.inl similarity index 100% rename from external/glm/include/glm/gtx/rotate_vector.inl rename to cts/external/glm/include/glm/gtx/rotate_vector.inl diff --git a/external/glm/include/glm/gtx/scalar_multiplication.hpp b/cts/external/glm/include/glm/gtx/scalar_multiplication.hpp similarity index 100% rename from external/glm/include/glm/gtx/scalar_multiplication.hpp rename to cts/external/glm/include/glm/gtx/scalar_multiplication.hpp diff --git a/external/glm/include/glm/gtx/scalar_relational.hpp b/cts/external/glm/include/glm/gtx/scalar_relational.hpp similarity index 100% rename from external/glm/include/glm/gtx/scalar_relational.hpp rename to cts/external/glm/include/glm/gtx/scalar_relational.hpp diff --git a/external/glm/include/glm/gtx/scalar_relational.inl b/cts/external/glm/include/glm/gtx/scalar_relational.inl similarity index 100% rename from external/glm/include/glm/gtx/scalar_relational.inl rename to cts/external/glm/include/glm/gtx/scalar_relational.inl diff --git a/external/glm/include/glm/gtx/spline.hpp b/cts/external/glm/include/glm/gtx/spline.hpp similarity index 100% rename from external/glm/include/glm/gtx/spline.hpp rename to cts/external/glm/include/glm/gtx/spline.hpp diff --git a/external/glm/include/glm/gtx/spline.inl b/cts/external/glm/include/glm/gtx/spline.inl similarity index 100% rename from external/glm/include/glm/gtx/spline.inl rename to cts/external/glm/include/glm/gtx/spline.inl diff --git a/external/glm/include/glm/gtx/std_based_type.hpp b/cts/external/glm/include/glm/gtx/std_based_type.hpp similarity index 100% rename from external/glm/include/glm/gtx/std_based_type.hpp rename to cts/external/glm/include/glm/gtx/std_based_type.hpp diff --git a/external/glm/include/glm/gtx/std_based_type.inl b/cts/external/glm/include/glm/gtx/std_based_type.inl similarity index 100% rename from external/glm/include/glm/gtx/std_based_type.inl rename to cts/external/glm/include/glm/gtx/std_based_type.inl diff --git a/external/glm/include/glm/gtx/string_cast.hpp b/cts/external/glm/include/glm/gtx/string_cast.hpp similarity index 100% rename from external/glm/include/glm/gtx/string_cast.hpp rename to cts/external/glm/include/glm/gtx/string_cast.hpp diff --git a/external/glm/include/glm/gtx/string_cast.inl b/cts/external/glm/include/glm/gtx/string_cast.inl similarity index 100% rename from external/glm/include/glm/gtx/string_cast.inl rename to cts/external/glm/include/glm/gtx/string_cast.inl diff --git a/external/glm/include/glm/gtx/texture.hpp b/cts/external/glm/include/glm/gtx/texture.hpp similarity index 100% rename from external/glm/include/glm/gtx/texture.hpp rename to cts/external/glm/include/glm/gtx/texture.hpp diff --git a/external/glm/include/glm/gtx/texture.inl b/cts/external/glm/include/glm/gtx/texture.inl similarity index 100% rename from external/glm/include/glm/gtx/texture.inl rename to cts/external/glm/include/glm/gtx/texture.inl diff --git a/external/glm/include/glm/gtx/transform.hpp b/cts/external/glm/include/glm/gtx/transform.hpp similarity index 100% rename from external/glm/include/glm/gtx/transform.hpp rename to cts/external/glm/include/glm/gtx/transform.hpp diff --git a/external/glm/include/glm/gtx/transform.inl b/cts/external/glm/include/glm/gtx/transform.inl similarity index 100% rename from external/glm/include/glm/gtx/transform.inl rename to cts/external/glm/include/glm/gtx/transform.inl diff --git a/external/glm/include/glm/gtx/transform2.hpp b/cts/external/glm/include/glm/gtx/transform2.hpp similarity index 100% rename from external/glm/include/glm/gtx/transform2.hpp rename to cts/external/glm/include/glm/gtx/transform2.hpp diff --git a/external/glm/include/glm/gtx/transform2.inl b/cts/external/glm/include/glm/gtx/transform2.inl similarity index 100% rename from external/glm/include/glm/gtx/transform2.inl rename to cts/external/glm/include/glm/gtx/transform2.inl diff --git a/external/glm/include/glm/gtx/type_aligned.hpp b/cts/external/glm/include/glm/gtx/type_aligned.hpp similarity index 100% rename from external/glm/include/glm/gtx/type_aligned.hpp rename to cts/external/glm/include/glm/gtx/type_aligned.hpp diff --git a/external/glm/include/glm/gtx/type_aligned.inl b/cts/external/glm/include/glm/gtx/type_aligned.inl similarity index 100% rename from external/glm/include/glm/gtx/type_aligned.inl rename to cts/external/glm/include/glm/gtx/type_aligned.inl diff --git a/external/glm/include/glm/gtx/type_trait.hpp b/cts/external/glm/include/glm/gtx/type_trait.hpp similarity index 100% rename from external/glm/include/glm/gtx/type_trait.hpp rename to cts/external/glm/include/glm/gtx/type_trait.hpp diff --git a/external/glm/include/glm/gtx/type_trait.inl b/cts/external/glm/include/glm/gtx/type_trait.inl similarity index 100% rename from external/glm/include/glm/gtx/type_trait.inl rename to cts/external/glm/include/glm/gtx/type_trait.inl diff --git a/external/glm/include/glm/gtx/vec_swizzle.hpp b/cts/external/glm/include/glm/gtx/vec_swizzle.hpp similarity index 100% rename from external/glm/include/glm/gtx/vec_swizzle.hpp rename to cts/external/glm/include/glm/gtx/vec_swizzle.hpp diff --git a/external/glm/include/glm/gtx/vector_angle.hpp b/cts/external/glm/include/glm/gtx/vector_angle.hpp similarity index 100% rename from external/glm/include/glm/gtx/vector_angle.hpp rename to cts/external/glm/include/glm/gtx/vector_angle.hpp diff --git a/external/glm/include/glm/gtx/vector_angle.inl b/cts/external/glm/include/glm/gtx/vector_angle.inl similarity index 100% rename from external/glm/include/glm/gtx/vector_angle.inl rename to cts/external/glm/include/glm/gtx/vector_angle.inl diff --git a/external/glm/include/glm/gtx/vector_query.hpp b/cts/external/glm/include/glm/gtx/vector_query.hpp similarity index 100% rename from external/glm/include/glm/gtx/vector_query.hpp rename to cts/external/glm/include/glm/gtx/vector_query.hpp diff --git a/external/glm/include/glm/gtx/vector_query.inl b/cts/external/glm/include/glm/gtx/vector_query.inl similarity index 100% rename from external/glm/include/glm/gtx/vector_query.inl rename to cts/external/glm/include/glm/gtx/vector_query.inl diff --git a/external/glm/include/glm/gtx/wrap.hpp b/cts/external/glm/include/glm/gtx/wrap.hpp similarity index 100% rename from external/glm/include/glm/gtx/wrap.hpp rename to cts/external/glm/include/glm/gtx/wrap.hpp diff --git a/external/glm/include/glm/gtx/wrap.inl b/cts/external/glm/include/glm/gtx/wrap.inl similarity index 100% rename from external/glm/include/glm/gtx/wrap.inl rename to cts/external/glm/include/glm/gtx/wrap.inl diff --git a/external/glm/include/glm/integer.hpp b/cts/external/glm/include/glm/integer.hpp similarity index 100% rename from external/glm/include/glm/integer.hpp rename to cts/external/glm/include/glm/integer.hpp diff --git a/external/glm/include/glm/mat2x2.hpp b/cts/external/glm/include/glm/mat2x2.hpp similarity index 100% rename from external/glm/include/glm/mat2x2.hpp rename to cts/external/glm/include/glm/mat2x2.hpp diff --git a/external/glm/include/glm/mat2x3.hpp b/cts/external/glm/include/glm/mat2x3.hpp similarity index 100% rename from external/glm/include/glm/mat2x3.hpp rename to cts/external/glm/include/glm/mat2x3.hpp diff --git a/external/glm/include/glm/mat2x4.hpp b/cts/external/glm/include/glm/mat2x4.hpp similarity index 100% rename from external/glm/include/glm/mat2x4.hpp rename to cts/external/glm/include/glm/mat2x4.hpp diff --git a/external/glm/include/glm/mat3x2.hpp b/cts/external/glm/include/glm/mat3x2.hpp similarity index 100% rename from external/glm/include/glm/mat3x2.hpp rename to cts/external/glm/include/glm/mat3x2.hpp diff --git a/external/glm/include/glm/mat3x3.hpp b/cts/external/glm/include/glm/mat3x3.hpp similarity index 100% rename from external/glm/include/glm/mat3x3.hpp rename to cts/external/glm/include/glm/mat3x3.hpp diff --git a/external/glm/include/glm/mat3x4.hpp b/cts/external/glm/include/glm/mat3x4.hpp similarity index 100% rename from external/glm/include/glm/mat3x4.hpp rename to cts/external/glm/include/glm/mat3x4.hpp diff --git a/external/glm/include/glm/mat4x2.hpp b/cts/external/glm/include/glm/mat4x2.hpp similarity index 100% rename from external/glm/include/glm/mat4x2.hpp rename to cts/external/glm/include/glm/mat4x2.hpp diff --git a/external/glm/include/glm/mat4x3.hpp b/cts/external/glm/include/glm/mat4x3.hpp similarity index 100% rename from external/glm/include/glm/mat4x3.hpp rename to cts/external/glm/include/glm/mat4x3.hpp diff --git a/external/glm/include/glm/mat4x4.hpp b/cts/external/glm/include/glm/mat4x4.hpp similarity index 100% rename from external/glm/include/glm/mat4x4.hpp rename to cts/external/glm/include/glm/mat4x4.hpp diff --git a/external/glm/include/glm/matrix.hpp b/cts/external/glm/include/glm/matrix.hpp similarity index 100% rename from external/glm/include/glm/matrix.hpp rename to cts/external/glm/include/glm/matrix.hpp diff --git a/external/glm/include/glm/packing.hpp b/cts/external/glm/include/glm/packing.hpp similarity index 100% rename from external/glm/include/glm/packing.hpp rename to cts/external/glm/include/glm/packing.hpp diff --git a/external/glm/include/glm/simd/common.h b/cts/external/glm/include/glm/simd/common.h similarity index 100% rename from external/glm/include/glm/simd/common.h rename to cts/external/glm/include/glm/simd/common.h diff --git a/external/glm/include/glm/simd/exponential.h b/cts/external/glm/include/glm/simd/exponential.h similarity index 100% rename from external/glm/include/glm/simd/exponential.h rename to cts/external/glm/include/glm/simd/exponential.h diff --git a/external/glm/include/glm/simd/geometric.h b/cts/external/glm/include/glm/simd/geometric.h similarity index 100% rename from external/glm/include/glm/simd/geometric.h rename to cts/external/glm/include/glm/simd/geometric.h diff --git a/external/glm/include/glm/simd/integer.h b/cts/external/glm/include/glm/simd/integer.h similarity index 100% rename from external/glm/include/glm/simd/integer.h rename to cts/external/glm/include/glm/simd/integer.h diff --git a/external/glm/include/glm/simd/matrix.h b/cts/external/glm/include/glm/simd/matrix.h similarity index 100% rename from external/glm/include/glm/simd/matrix.h rename to cts/external/glm/include/glm/simd/matrix.h diff --git a/external/glm/include/glm/simd/neon.h b/cts/external/glm/include/glm/simd/neon.h similarity index 100% rename from external/glm/include/glm/simd/neon.h rename to cts/external/glm/include/glm/simd/neon.h diff --git a/external/glm/include/glm/simd/packing.h b/cts/external/glm/include/glm/simd/packing.h similarity index 100% rename from external/glm/include/glm/simd/packing.h rename to cts/external/glm/include/glm/simd/packing.h diff --git a/external/glm/include/glm/simd/platform.h b/cts/external/glm/include/glm/simd/platform.h similarity index 100% rename from external/glm/include/glm/simd/platform.h rename to cts/external/glm/include/glm/simd/platform.h diff --git a/external/glm/include/glm/simd/trigonometric.h b/cts/external/glm/include/glm/simd/trigonometric.h similarity index 100% rename from external/glm/include/glm/simd/trigonometric.h rename to cts/external/glm/include/glm/simd/trigonometric.h diff --git a/external/glm/include/glm/simd/vector_relational.h b/cts/external/glm/include/glm/simd/vector_relational.h similarity index 100% rename from external/glm/include/glm/simd/vector_relational.h rename to cts/external/glm/include/glm/simd/vector_relational.h diff --git a/external/glm/include/glm/trigonometric.hpp b/cts/external/glm/include/glm/trigonometric.hpp similarity index 100% rename from external/glm/include/glm/trigonometric.hpp rename to cts/external/glm/include/glm/trigonometric.hpp diff --git a/external/glm/include/glm/vec2.hpp b/cts/external/glm/include/glm/vec2.hpp similarity index 100% rename from external/glm/include/glm/vec2.hpp rename to cts/external/glm/include/glm/vec2.hpp diff --git a/external/glm/include/glm/vec3.hpp b/cts/external/glm/include/glm/vec3.hpp similarity index 100% rename from external/glm/include/glm/vec3.hpp rename to cts/external/glm/include/glm/vec3.hpp diff --git a/external/glm/include/glm/vec4.hpp b/cts/external/glm/include/glm/vec4.hpp similarity index 100% rename from external/glm/include/glm/vec4.hpp rename to cts/external/glm/include/glm/vec4.hpp diff --git a/external/glm/include/glm/vector_relational.hpp b/cts/external/glm/include/glm/vector_relational.hpp similarity index 100% rename from external/glm/include/glm/vector_relational.hpp rename to cts/external/glm/include/glm/vector_relational.hpp diff --git a/external/glm/lib/cmake/glm/glmConfig.cmake b/cts/external/glm/lib/cmake/glm/glmConfig.cmake similarity index 100% rename from external/glm/lib/cmake/glm/glmConfig.cmake rename to cts/external/glm/lib/cmake/glm/glmConfig.cmake diff --git a/external/glm/lib/cmake/glm/glmConfigVersion.cmake b/cts/external/glm/lib/cmake/glm/glmConfigVersion.cmake similarity index 100% rename from external/glm/lib/cmake/glm/glmConfigVersion.cmake rename to cts/external/glm/lib/cmake/glm/glmConfigVersion.cmake diff --git a/examples/viewer/CMakeLists.txt b/examples/viewer/CMakeLists.txt index 05dbb97b..fe2ff5d8 100644 --- a/examples/viewer/CMakeLists.txt +++ b/examples/viewer/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.11) project(anariViewer LANGUAGES C CXX) if (NOT TARGET anari::anari) - find_package(anari REQUIRED) + find_package(anari REQUIRED COMPONENTS viewer) endif() project_add_executable(main.cpp ui_layout.cpp) diff --git a/libs/anari/CMakeLists.txt b/libs/anari/CMakeLists.txt index e778f120..7b2d4db3 100644 --- a/libs/anari/CMakeLists.txt +++ b/libs/anari/CMakeLists.txt @@ -1,14 +1,9 @@ ## Copyright 2021 The Khronos Group ## SPDX-License-Identifier: Apache-2.0 -set(CMAKE_THREAD_PREFER_PTHREAD TRUE) -set(THREADS_PREFER_PTHREAD_FLAG TRUE) -find_package(Threads REQUIRED) - project_add_library( - anari_cpp_std_defs.cpp anari_cpp_linalg_defs.cpp - anari_cpp_glm_defs.cpp + anari_cpp_std_defs.cpp API.cpp DeviceImpl.cpp LibraryImpl.cpp @@ -31,13 +26,7 @@ PUBLIC $ ) -project_link_libraries( -PUBLIC - ${CMAKE_DL_LIBS} -PRIVATE - Threads::Threads - $ -) +project_link_libraries(PUBLIC ${CMAKE_DL_LIBS}) ## Create version header @@ -46,7 +35,10 @@ configure_file(anari_sdk_version.h.in include/anari/frontend/anari_sdk_version.h ## Install library + targets set_target_properties(${PROJECT_NAME} - PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) + PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} +) install(TARGETS ${PROJECT_NAME} EXPORT anari_Exports @@ -67,7 +59,8 @@ install(TARGETS anari ## Install headers -install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/anari +install( + DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/anari DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) diff --git a/libs/anari/anari_cpp_glm_defs.cpp b/libs/anari/anari_cpp_glm_defs.cpp deleted file mode 100644 index e9f7fdb7..00000000 --- a/libs/anari/anari_cpp_glm_defs.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2021 The Khronos Group -// SPDX-License-Identifier: Apache-2.0 - -#define ANARI_GLM_DEFINITIONS -#include "anari/anari_cpp/ext/glm.h" diff --git a/libs/anari_viewer/CMakeLists.txt b/libs/anari_viewer/CMakeLists.txt index 6329b6f9..46cafb69 100644 --- a/libs/anari_viewer/CMakeLists.txt +++ b/libs/anari_viewer/CMakeLists.txt @@ -40,6 +40,7 @@ if (INSTALL_VIEWER_LIBRARY) set(SRC_INSTALL_ROOT ${CMAKE_INSTALL_DATAROOTDIR}/anari/anari_viewer) install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR} DESTINATION ${SRC_INSTALL_ROOT}/.. + COMPONENT viewer FILES_MATCHING PATTERN *.h PATTERN *.c diff --git a/libs/anari_viewer/external/glad/CMakeLists.txt b/libs/anari_viewer/external/glad/CMakeLists.txt index 61dd76a6..e3e7ad33 100644 --- a/libs/anari_viewer/external/glad/CMakeLists.txt +++ b/libs/anari_viewer/external/glad/CMakeLists.txt @@ -1,12 +1,8 @@ ## Copyright 2023 The Khronos Group ## SPDX-License-Identifier: Apache-2.0 -project(anari_viewer_glad VERSION ${PROJECT_VERSION} LANGUAGES C) - +project(anari_viewer_glad LANGUAGES C) project_add_library(INTERFACE) -project_sources(INTERFACE $) -project_include_directories( -INTERFACE - $ -) +project_sources(INTERFACE ${CMAKE_CURRENT_LIST_DIR}/glad.c) +project_include_directories(INTERFACE ${CMAKE_CURRENT_LIST_DIR}/..) project_link_libraries(INTERFACE ${CMAKE_DL_LIBS}) diff --git a/libs/anari_viewer/external/imgui/CMakeLists.txt b/libs/anari_viewer/external/imgui/CMakeLists.txt index 849cadea..939c2174 100644 --- a/libs/anari_viewer/external/imgui/CMakeLists.txt +++ b/libs/anari_viewer/external/imgui/CMakeLists.txt @@ -1,7 +1,7 @@ ## Copyright 2023 The Khronos Group ## SPDX-License-Identifier: Apache-2.0 -project(anari_viewer_imgui_glfw VERSION ${PROJECT_VERSION} LANGUAGES CXX) +project(anari_viewer_imgui_glfw LANGUAGES CXX) anari_sdk_fetch_project( NAME ${PROJECT_NAME} @@ -20,23 +20,21 @@ project_add_library(INTERFACE) project_sources( INTERFACE - $ - $ - $ - $ - $ - - $ - $ - - $ + ${anari_viewer_imgui_glfw_LOCATION}/imgui.cpp + ${anari_viewer_imgui_glfw_LOCATION}/imgui_draw.cpp + ${anari_viewer_imgui_glfw_LOCATION}/imgui_demo.cpp + ${anari_viewer_imgui_glfw_LOCATION}/imgui_tables.cpp + ${anari_viewer_imgui_glfw_LOCATION}/imgui_widgets.cpp + ${anari_viewer_imgui_glfw_LOCATION}/backends/imgui_impl_glfw.cpp + ${anari_viewer_imgui_glfw_LOCATION}/backends/imgui_impl_opengl2.cpp + ${anari_viewer_imgui_glfw_LOCATION}/misc/cpp/imgui_stdlib.cpp ) project_link_libraries(INTERFACE glfw OpenGL::GL) project_include_directories( INTERFACE - $ - $ - $ + ${anari_viewer_imgui_glfw_LOCATION} + ${anari_viewer_imgui_glfw_LOCATION}/backends + ${anari_viewer_imgui_glfw_LOCATION}/misc/cpp ) diff --git a/libs/anari_viewer/external/nativefiledialog/CMakeLists.txt b/libs/anari_viewer/external/nativefiledialog/CMakeLists.txt index 5856faac..fb50004b 100644 --- a/libs/anari_viewer/external/nativefiledialog/CMakeLists.txt +++ b/libs/anari_viewer/external/nativefiledialog/CMakeLists.txt @@ -1,7 +1,7 @@ ## Copyright 2023 The Khronos Group ## SPDX-License-Identifier: Apache-2.0 -project(anari_viewer_nfd VERSION ${PROJECT_VERSION} LANGUAGES CXX) +project(anari_viewer_nfd LANGUAGES CXX) set(BUILD_SHARED_LIBS OFF) anari_sdk_fetch_project( From fdc471434d0847e9a952e35a58f6a2b154e8d4c7 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Fri, 3 Nov 2023 10:23:48 -0500 Subject: [PATCH 18/34] fix issue when the viewer component is found multiple times downstream --- cmake/anariConfig.cmake.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmake/anariConfig.cmake.in b/cmake/anariConfig.cmake.in index cfcab4dc..a3fdf5c6 100644 --- a/cmake/anariConfig.cmake.in +++ b/cmake/anariConfig.cmake.in @@ -33,7 +33,9 @@ endif() include(${CMAKE_CURRENT_LIST_DIR}/cmake/anari_sdk_fetch_project.cmake) include(${CMAKE_CURRENT_LIST_DIR}/cmake/cmake_project_commands.cmake) -if (anari_FIND_REQUIRED_viewer AND @INSTALL_VIEWER_LIBRARY@) +if (TARGET anari::anari_viewer) + set(anari_viewer_FOUND 1) +elseif (anari_FIND_REQUIRED_viewer AND @INSTALL_VIEWER_LIBRARY@) add_subdirectory( ${ANARI_DATAROOTDIR}/anari_viewer ${CMAKE_CURRENT_BINARY_DIR}/anari_viewer From 062cdb6fd0c8e08b4c6072f825d00e2594a66641 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Fri, 3 Nov 2023 11:57:42 -0500 Subject: [PATCH 19/34] remove unnecessary NAMELINK_SKIP from various device installs --- libs/debug_device/CMakeLists.txt | 1 - libs/helide/CMakeLists.txt | 1 - libs/remote_device/CMakeLists.txt | 1 - libs/sink_device/CMakeLists.txt | 1 - 4 files changed, 4 deletions(-) diff --git a/libs/debug_device/CMakeLists.txt b/libs/debug_device/CMakeLists.txt index 5cf575c8..2951a586 100644 --- a/libs/debug_device/CMakeLists.txt +++ b/libs/debug_device/CMakeLists.txt @@ -36,5 +36,4 @@ install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - NAMELINK_SKIP ) diff --git a/libs/helide/CMakeLists.txt b/libs/helide/CMakeLists.txt index 0166e651..b5f8df54 100644 --- a/libs/helide/CMakeLists.txt +++ b/libs/helide/CMakeLists.txt @@ -125,7 +125,6 @@ install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - NAMELINK_SKIP ) install( diff --git a/libs/remote_device/CMakeLists.txt b/libs/remote_device/CMakeLists.txt index ec42f959..f909f3eb 100644 --- a/libs/remote_device/CMakeLists.txt +++ b/libs/remote_device/CMakeLists.txt @@ -99,5 +99,4 @@ install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - NAMELINK_SKIP ) diff --git a/libs/sink_device/CMakeLists.txt b/libs/sink_device/CMakeLists.txt index 108ca6a9..011d702d 100644 --- a/libs/sink_device/CMakeLists.txt +++ b/libs/sink_device/CMakeLists.txt @@ -23,5 +23,4 @@ install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - NAMELINK_SKIP ) From 7fcedd26f3a2e0d75b3a51b035892f47e26a7164 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Fri, 3 Nov 2023 18:13:44 -0500 Subject: [PATCH 20/34] INSTALL_VIEWER_LIBRARY does not depend on examples being built --- CMakeLists.txt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e36fff8..05a63326 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,12 +51,7 @@ cmake_dependent_option(BUILD_VIEWER "BUILD_EXAMPLES" OFF ) -cmake_dependent_option(INSTALL_VIEWER_LIBRARY - "Install anari::anari_viewer library target" - OFF - "BUILD_EXAMPLES;BUILD_VIEWER" - OFF -) +option(INSTALL_VIEWER_LIBRARY "Install anari::anari_viewer library target" ON) option(INSTALL_VIEWER "Install anariViewer app" OFF) mark_as_advanced(INSTALL_VIEWER) From ef8f5e53d24d48ec7be04deb9e49957d31061688 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Fri, 3 Nov 2023 22:50:25 -0500 Subject: [PATCH 21/34] make sure frames are not in-flight when arrays are mapped in helide --- libs/helide/HelideDevice.cpp | 6 ++++++ libs/helide/HelideDevice.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/libs/helide/HelideDevice.cpp b/libs/helide/HelideDevice.cpp index 85d1885b..23d014c1 100644 --- a/libs/helide/HelideDevice.cpp +++ b/libs/helide/HelideDevice.cpp @@ -55,6 +55,12 @@ inline HANDLE_T createObjectForAPI(HelideGlobalState *s, Args &&...args) // Data Arrays //////////////////////////////////////////////////////////////// +void *HelideDevice::mapArray(ANARIArray a) +{ + deviceState()->waitOnCurrentFrame(); + return helium::BaseDevice::mapArray(a); +} + ANARIArray1D HelideDevice::newArray1D(const void *appMemory, ANARIMemoryDeleter deleter, const void *userData, diff --git a/libs/helide/HelideDevice.h b/libs/helide/HelideDevice.h index e4b78f91..95781d84 100644 --- a/libs/helide/HelideDevice.h +++ b/libs/helide/HelideDevice.h @@ -19,6 +19,8 @@ struct HelideDevice : public helium::BaseDevice // Data Arrays ////////////////////////////////////////////////////////////// + void *mapArray(ANARIArray) override; + ANARIArray1D newArray1D(const void *appMemory, ANARIMemoryDeleter deleter, const void *userdata, From 041a73de2dbb21ca13815f80ee9a79a9dd91de91 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Tue, 7 Nov 2023 23:17:50 -0700 Subject: [PATCH 22/34] Various small improvements (#168) * add radians-to-degrees conversion function * make sure python headers are found when CTS is built * add CMake option to allow libanari to leak exceptions if desired --- cts/CMakeLists.txt | 2 +- libs/anari/API.cpp | 5 +++++ libs/anari/CMakeLists.txt | 7 +++++++ libs/anari/include/anari/anari_cpp/ext/linalg.h | 5 +++++ 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/cts/CMakeLists.txt b/cts/CMakeLists.txt index ad07f7f9..4e064d4b 100644 --- a/cts/CMakeLists.txt +++ b/cts/CMakeLists.txt @@ -42,7 +42,7 @@ PUBLIC target_link_libraries(${PROJECT_NAME} PUBLIC glm::glm helium anari_test_scenes) -find_package(Python3 REQUIRED COMPONENTS Interpreter) +find_package(Python3 REQUIRED COMPONENTS Interpreter Development) file(GLOB python_files ${CMAKE_CURRENT_LIST_DIR}/*.py) diff --git a/libs/anari/API.cpp b/libs/anari/API.cpp index 80ab549a..c2a8e5d5 100644 --- a/libs/anari/API.cpp +++ b/libs/anari/API.cpp @@ -15,6 +15,7 @@ #include #include +#ifdef ANARI_FRONTEND_CATCH_EXCEPTIONS #define ANARI_CATCH_BEGIN try { #define ANARI_CATCH_END(a) \ } \ @@ -33,6 +34,10 @@ std::terminate(); \ return a; \ } +#else +#define ANARI_CATCH_BEGIN { +#define ANARI_CATCH_END(a) } +#endif #define ANARI_NORETURN /**/ #define ANARI_CATCH_END_NORETURN() ANARI_CATCH_END(ANARI_NORETURN) diff --git a/libs/anari/CMakeLists.txt b/libs/anari/CMakeLists.txt index 7b2d4db3..85974650 100644 --- a/libs/anari/CMakeLists.txt +++ b/libs/anari/CMakeLists.txt @@ -1,6 +1,9 @@ ## Copyright 2021 The Khronos Group ## SPDX-License-Identifier: Apache-2.0 +option(ANARI_FRONTEND_CATCH_EXCEPTIONS "Have libanari catch all exceptions" ON) +mark_as_advanced(ANARI_FRONTEND_CATCH_EXCEPTIONS) + project_add_library( anari_cpp_linalg_defs.cpp anari_cpp_std_defs.cpp @@ -17,6 +20,10 @@ if (WIN32) project_compile_definitions(PUBLIC -D_USE_MATH_DEFINES) endif() +if (ANARI_FRONTEND_CATCH_EXCEPTIONS) + project_compile_definitions(PRIVATE -DANARI_FRONTEND_CATCH_EXCEPTIONS) +endif() + project_include_directories( PUBLIC $ diff --git a/libs/anari/include/anari/anari_cpp/ext/linalg.h b/libs/anari/include/anari/anari_cpp/ext/linalg.h index f502f25a..2b2eac63 100644 --- a/libs/anari/include/anari/anari_cpp/ext/linalg.h +++ b/libs/anari/include/anari/anari_cpp/ext/linalg.h @@ -767,6 +767,11 @@ inline float radians(float degrees) return degrees * float(M_PI) / 180.f; } +inline float degrees(float radians) +{ + return radians * 180.f / float(M_PI); +} + } // namespace anari #endif From 1477a074ec16738a495ad6a28bec66bc0a780af8 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Wed, 8 Nov 2023 09:52:15 -0700 Subject: [PATCH 23/34] do not generate negative radii in random cylinders scene --- libs/anari_test_scenes/scenes/test/random_cylinders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/anari_test_scenes/scenes/test/random_cylinders.cpp b/libs/anari_test_scenes/scenes/test/random_cylinders.cpp index 787f7be6..36edace1 100644 --- a/libs/anari_test_scenes/scenes/test/random_cylinders.cpp +++ b/libs/anari_test_scenes/scenes/test/random_cylinders.cpp @@ -108,7 +108,7 @@ void RandomCylinders::commit() std::vector cylinderRadii((size_t(numCylinders))); for (auto &r : cylinderRadii) - r = radii_dist(rng); + r = std::abs(radii_dist(rng)); anari::setAndReleaseParameter(d, geom, From c97472073d81868cfa587ec27de298f54679e556 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Wed, 8 Nov 2023 17:06:05 -0700 Subject: [PATCH 24/34] use unit cube as default bounds in viewport --- libs/anari_viewer/windows/Viewport.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/libs/anari_viewer/windows/Viewport.cpp b/libs/anari_viewer/windows/Viewport.cpp index 15300bcc..b6d922e1 100644 --- a/libs/anari_viewer/windows/Viewport.cpp +++ b/libs/anari_viewer/windows/Viewport.cpp @@ -141,15 +141,17 @@ void Viewport::setWorld(anari::World world, bool resetCameraView) void Viewport::resetView(bool resetAzEl) { - anari::math::float3 bounds[2]; + anari::math::float3 bounds[2] = {{0.f, 0.f, 0.f}, {1.f, 1.f, 1.f}}; - anariGetProperty(m_device, - m_world, - "bounds", - ANARI_FLOAT32_BOX3, - &bounds[0], - sizeof(bounds), - ANARI_WAIT); + if (!anariGetProperty(m_device, + m_world, + "bounds", + ANARI_FLOAT32_BOX3, + &bounds[0], + sizeof(bounds), + ANARI_WAIT)) { + printf("WARNING: bounds not returned by the device! Using unit cube.\n"); + } auto center = 0.5f * (bounds[0] + bounds[1]); auto diag = bounds[1] - bounds[0]; @@ -200,7 +202,8 @@ void Viewport::startNewFrame() void Viewport::updateFrame() { - anari::setParameter(m_device, m_frame, "size", anari::math::uint2(m_viewportSize)); + anari::setParameter( + m_device, m_frame, "size", anari::math::uint2(m_viewportSize)); anari::setParameter( m_device, m_frame, "channel.color", ANARI_UFIXED8_RGBA_SRGB); anari::setParameter(m_device, m_frame, "accumulation", true); @@ -331,7 +334,8 @@ void Viewport::ui_handleInput() const anari::math::float2 mouseFrom = prev * 2.f / anari::math::float2(m_viewportSize); - const anari::math::float2 mouseTo = mouse * 2.f / anari::math::float2(m_viewportSize); + const anari::math::float2 mouseTo = + mouse * 2.f / anari::math::float2(m_viewportSize); const anari::math::float2 mouseDelta = mouseTo - mouseFrom; From 383c1e52eb8efd3b70333b206457abd13cff4db8 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Fri, 10 Nov 2023 18:25:53 -0600 Subject: [PATCH 25/34] add missing ANARI_KHR_FRAME_ACCUMULATION extension definition (#169) --- code_gen/api/khr_frame_accumulation.json | 21 +++++++ code_gen/devices/experimental_device.json | 1 + .../anari/frontend/anari_extension_utility.h | 58 ++++++++++--------- 3 files changed, 52 insertions(+), 28 deletions(-) create mode 100644 code_gen/api/khr_frame_accumulation.json diff --git a/code_gen/api/khr_frame_accumulation.json b/code_gen/api/khr_frame_accumulation.json new file mode 100644 index 00000000..f8596740 --- /dev/null +++ b/code_gen/api/khr_frame_accumulation.json @@ -0,0 +1,21 @@ +{ + "info" : { + "name" : "KHR_FRAME_ACCUMULATION", + "type" : "extension", + "dependencies" : ["anari_core_1_0"] + }, + + "objects" : [ + { + "type" : "ANARI_FRAME", + "parameters" : [ + { + "name" : "accumulation", + "types" : ["ANARI_BOOL"], + "tags" : [], + "description" : "enable device internal buffers for frame accumulation" + } + ] + } + ] +} diff --git a/code_gen/devices/experimental_device.json b/code_gen/devices/experimental_device.json index 80eb339a..5d0983cf 100644 --- a/code_gen/devices/experimental_device.json +++ b/code_gen/devices/experimental_device.json @@ -20,6 +20,7 @@ "khr_camera_rolling_shutter", "khr_camera_stereo", "khr_device_synchronization", + "khr_frame_accumulation", "khr_frame_channel_albedo", "khr_frame_channel_instance_id", "khr_frame_channel_normal", diff --git a/libs/anari/include/anari/frontend/anari_extension_utility.h b/libs/anari/include/anari/frontend/anari_extension_utility.h index bfb484e5..11fc518a 100644 --- a/libs/anari/include/anari/frontend/anari_extension_utility.h +++ b/libs/anari/include/anari/frontend/anari_extension_utility.h @@ -26,6 +26,7 @@ typedef struct { int ANARI_KHR_CAMERA_PERSPECTIVE; int ANARI_KHR_CAMERA_STEREO; int ANARI_KHR_DEVICE_SYNCHRONIZATION; + int ANARI_KHR_FRAME_ACCUMULATION; int ANARI_KHR_FRAME_CHANNEL_ALBEDO; int ANARI_KHR_FRAME_CHANNEL_INSTANCE_ID; int ANARI_KHR_FRAME_CHANNEL_NORMAL; @@ -60,7 +61,7 @@ int anariGetInstanceExtensionStruct(ANARIExtensions *extensions, ANARIDevice dev #ifdef ANARI_EXTENSION_UTILITY_IMPL #include static int extension_hash(const char *str) { - static const uint32_t table[] = {0x4f4e0001u,0x42410002u,0x53520003u,0x4a490004u,0x605f0005u,0x4c450006u,0x5958000du,0x0u,0x0u,0x0u,0x0u,0x0u,0x49480023u,0x5150000eu,0x605f000fu,0x57560010u,0x504f0011u,0x4d4c0012u,0x56550013u,0x4e4d0014u,0x46450015u,0x605f0016u,0x54530017u,0x42410018u,0x4e4d0019u,0x5150001au,0x4d4c001bu,0x4645001cu,0x605f001du,0x5352001eu,0x4241001fu,0x55540020u,0x46450021u,0x1000022u,0x8000002du,0x53520024u,0x605f0025u,0x57410026u,0x5352003cu,0x0u,0x42410060u,0x464500dbu,0x0u,0x535200f1u,0x46450153u,0x0u,0x4f4e027cu,0x0u,0x0u,0x4a4902c0u,0x424102f5u,0x0u,0x0u,0x0u,0x0u,0x46450316u,0x51410348u,0x0u,0x0u,0x504f03a8u,0x5345003du,0x4241004bu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x42410054u,0x605f004cu,0x4d4c004du,0x4a49004eu,0x4847004fu,0x49480050u,0x55540051u,0x54530052u,0x1000053u,0x8000000au,0x5a590055u,0x32310056u,0x45440057u,0x605f0058u,0x53520059u,0x4645005au,0x4847005bu,0x4a49005cu,0x504f005du,0x4f4e005eu,0x100005fu,0x8000000bu,0x4e4d0061u,0x46450062u,0x53520063u,0x42410064u,0x605f0065u,0x54440066u,0x46450076u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x504f0084u,0x0u,0x534d0099u,0x464500b8u,0x0u,0x0u,0x554800c3u,0x51500077u,0x55540078u,0x49480079u,0x605f007au,0x504f007bu,0x4746007cu,0x605f007du,0x4746007eu,0x4a49007fu,0x46450080u,0x4d4c0081u,0x45440082u,0x1000083u,0x8000000cu,0x55540085u,0x4a490086u,0x504f0087u,0x4f4e0088u,0x605f0089u,0x5554008au,0x5352008bu,0x4241008cu,0x4f4e008du,0x5453008eu,0x4746008fu,0x504f0090u,0x53520091u,0x4e4d0092u,0x42410093u,0x55540094u,0x4a490095u,0x504f0096u,0x4f4e0097u,0x1000098u,0x8000000du,0x4f4e009fu,0x0u,0x0u,0x0u,0x0u,0x555400adu,0x4a4900a0u,0x454400a1u,0x4a4900a2u,0x535200a3u,0x464500a4u,0x444300a5u,0x555400a6u,0x4a4900a7u,0x504f00a8u,0x4f4e00a9u,0x424100aau,0x4d4c00abu,0x10000acu,0x8000000eu,0x494800aeu,0x504f00afu,0x484700b0u,0x535200b1u,0x424100b2u,0x515000b3u,0x494800b4u,0x4a4900b5u,0x444300b6u,0x10000b7u,0x8000000fu,0x535200b9u,0x545300bau,0x515000bbu,0x464500bcu,0x444300bdu,0x555400beu,0x4a4900bfu,0x575600c0u,0x464500c1u,0x10000c2u,0x80000010u,0x565500d0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x464500d6u,0x555400d1u,0x555400d2u,0x464500d3u,0x535200d4u,0x10000d5u,0x80000005u,0x535200d7u,0x464500d8u,0x504f00d9u,0x10000dau,0x80000011u,0x575600dcu,0x4a4900ddu,0x444300deu,0x464500dfu,0x605f00e0u,0x545300e1u,0x5a5900e2u,0x4f4e00e3u,0x444300e4u,0x494800e5u,0x535200e6u,0x504f00e7u,0x4f4e00e8u,0x4a4900e9u,0x5b5a00eau,0x424100ebu,0x555400ecu,0x4a4900edu,0x504f00eeu,0x4f4e00efu,0x10000f0u,0x80000012u,0x424100f2u,0x4e4d00f3u,0x464500f4u,0x605f00f5u,0x444300f6u,0x504800f7u,0x424100ffu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x4e4d0141u,0x4f4e0100u,0x4f4e0101u,0x46450102u,0x4d4c0103u,0x605f0104u,0x51410105u,0x4d4c0115u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x4f4e011bu,0x0u,0x0u,0x0u,0x0u,0x504f0126u,0x4342012cu,0x53520135u,0x43420116u,0x46450117u,0x45440118u,0x504f0119u,0x100011au,0x80000013u,0x5453011cu,0x5554011du,0x4241011eu,0x4f4e011fu,0x44430120u,0x46450121u,0x605f0122u,0x4a490123u,0x45440124u,0x1000125u,0x80000014u,0x53520127u,0x4e4d0128u,0x42410129u,0x4d4c012au,0x100012bu,0x80000015u,0x4b4a012du,0x4645012eu,0x4443012fu,0x55540130u,0x605f0131u,0x4a490132u,0x45440133u,0x1000134u,0x80000016u,0x4a490136u,0x4e4d0137u,0x4a490138u,0x55540139u,0x4a49013au,0x5756013bu,0x4645013cu,0x605f013du,0x4a49013eu,0x4544013fu,0x1000140u,0x80000017u,0x51500142u,0x4d4c0143u,0x46450144u,0x55540145u,0x4a490146u,0x504f0147u,0x4f4e0148u,0x605f0149u,0x4443014au,0x4241014bu,0x4d4c014cu,0x4d4c014du,0x4342014eu,0x4241014fu,0x44430150u,0x4c4b0151u,0x1000152u,0x80000018u,0x504f0154u,0x4e4d0155u,0x46450156u,0x55540157u,0x53520158u,0x5a590159u,0x605f015au,0x5543015bu,0x5a4f016du,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x56550186u,0x0u,0x515001fcu,0x53520202u,0x4f4e0178u,0x0u,0x0u,0x0u,0x0u,0x0u,0x5352017bu,0x0u,0x0u,0x0u,0x4d4c017fu,0x46450179u,0x100017au,0x80000019u,0x5756017cu,0x4645017du,0x100017eu,0x8000001au,0x4a490180u,0x4f4e0181u,0x45440182u,0x46450183u,0x53520184u,0x1000185u,0x8000001bu,0x42410187u,0x45440188u,0x60000189u,0x8000001cu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x4e4d01e9u,0x504f01eau,0x555401ebu,0x4a4901ecu,0x504f01edu,0x4f4e01eeu,0x605f01efu,0x454401f0u,0x464501f1u,0x474601f2u,0x504f01f3u,0x535201f4u,0x4e4d01f5u,0x424101f6u,0x555401f7u,0x4a4901f8u,0x504f01f9u,0x4f4e01fau,0x10001fbu,0x8000001du,0x494801fdu,0x464501feu,0x535201ffu,0x46450200u,0x1000201u,0x8000001eu,0x4a490203u,0x42410204u,0x4f4e0205u,0x48470206u,0x4d4c0207u,0x46450208u,0x60000209u,0x8000001fu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x4e4d0269u,0x504f026au,0x5554026bu,0x4a49026cu,0x504f026du,0x4f4e026eu,0x605f026fu,0x45440270u,0x46450271u,0x47460272u,0x504f0273u,0x53520274u,0x4e4d0275u,0x42410276u,0x55540277u,0x4a490278u,0x504f0279u,0x4f4e027au,0x100027bu,0x80000020u,0x5453027du,0x5554027eu,0x4241027fu,0x4f4e0280u,0x44430281u,0x46450282u,0x605f0283u,0x554d0284u,0x504f028cu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x535202b7u,0x5554028du,0x4a49028eu,0x504f028fu,0x4f4e0290u,0x605f0291u,0x55530292u,0x44430294u,0x535202aeu,0x42410295u,0x4d4c0296u,0x46450297u,0x605f0298u,0x53520299u,0x504f029au,0x5554029bu,0x4241029cu,0x5554029du,0x4a49029eu,0x504f029fu,0x4f4e02a0u,0x605f02a1u,0x555402a2u,0x535202a3u,0x424102a4u,0x4f4e02a5u,0x545302a6u,0x4d4c02a7u,0x424102a8u,0x555402a9u,0x4a4902aau,0x504f02abu,0x4f4e02acu,0x10002adu,0x80000006u,0x424102afu,0x4f4e02b0u,0x545302b1u,0x474602b2u,0x504f02b3u,0x535202b4u,0x4e4d02b5u,0x10002b6u,0x80000007u,0x424102b8u,0x4f4e02b9u,0x545302bau,0x474602bbu,0x504f02bcu,0x535202bdu,0x4e4d02beu,0x10002bfu,0x80000008u,0x484702c1u,0x494802c2u,0x555402c3u,0x605f02c4u,0x544402c5u,0x4a4902d5u,0x0u,0x0u,0x0u,0x454402e0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x504f02e4u,0x565502e9u,0x4a4902edu,0x515002f1u,0x535202d6u,0x464502d7u,0x444302d8u,0x555402d9u,0x4a4902dau,0x504f02dbu,0x4f4e02dcu,0x424102ddu,0x4d4c02deu,0x10002dfu,0x80000000u,0x535202e1u,0x4a4902e2u,0x10002e3u,0x80000004u,0x4a4902e5u,0x4f4e02e6u,0x555402e7u,0x10002e8u,0x80000001u,0x424102eau,0x454402ebu,0x10002ecu,0x80000003u,0x4f4e02eeu,0x484702efu,0x10002f0u,0x80000002u,0x504f02f2u,0x555402f3u,0x10002f4u,0x80000021u,0x555402f6u,0x464502f7u,0x535202f8u,0x4a4902f9u,0x424102fau,0x4d4c02fbu,0x605f02fcu,0x514d02fdu,0x42410301u,0x0u,0x0u,0x49480306u,0x55540302u,0x55540303u,0x46450304u,0x1000305u,0x80000022u,0x5a590307u,0x54530308u,0x4a490309u,0x4443030au,0x4241030bu,0x4d4c030cu,0x4d4c030du,0x5a59030eu,0x605f030fu,0x43420310u,0x42410311u,0x54530312u,0x46450313u,0x45440314u,0x1000315u,0x80000023u,0x4f4e0317u,0x45440318u,0x46450319u,0x5352031au,0x4645031bu,0x5352031cu,0x605f031du,0x4341031eu,0x4e4d0320u,0x4241032du,0x43420321u,0x4a490322u,0x46450323u,0x4f4e0324u,0x55540325u,0x605f0326u,0x4d4c0327u,0x4a490328u,0x48470329u,0x4948032au,0x5554032bu,0x100032cu,0x80000024u,0x4443032eu,0x4c4b032fu,0x48470330u,0x53520331u,0x504f0332u,0x56550333u,0x4f4e0334u,0x45440335u,0x605f0336u,0x4a430337u,0x504f033eu,0x0u,0x0u,0x0u,0x0u,0x0u,0x4e4d0343u,0x4d4c033fu,0x504f0340u,0x53520341u,0x1000342u,0x80000025u,0x42410344u,0x48470345u,0x46450346u,0x1000347u,0x80000026u,0x4e4d0358u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x42410389u,0x51500359u,0x4d4c035au,0x4645035bu,0x5352035cu,0x605f035du,0x5549035eu,0x4e4d036au,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x53520377u,0x0u,0x0u,0x0u,0x53520380u,0x4241036bu,0x4847036cu,0x4645036du,0x3431036eu,0x45440371u,0x45440373u,0x45440375u,0x1000372u,0x80000027u,0x1000374u,0x80000028u,0x1000376u,0x80000029u,0x4a490378u,0x4e4d0379u,0x4a49037au,0x5554037bu,0x4a49037cu,0x5756037du,0x4645037eu,0x100037fu,0x8000002au,0x42410381u,0x4f4e0382u,0x54530383u,0x47460384u,0x504f0385u,0x53520386u,0x4e4d0387u,0x1000388u,0x8000002bu,0x5554038au,0x4a49038bu,0x4241038cu,0x4d4c038du,0x605f038eu,0x4746038fu,0x4a490390u,0x46450391u,0x4d4c0392u,0x45440393u,0x605f0394u,0x54530395u,0x55540396u,0x53520397u,0x56550398u,0x44430399u,0x5554039au,0x5655039bu,0x5352039cu,0x4645039du,0x4544039eu,0x605f039fu,0x535203a0u,0x464503a1u,0x484703a2u,0x565503a3u,0x4d4c03a4u,0x424103a5u,0x535203a6u,0x10003a7u,0x8000002cu,0x4d4c03a9u,0x565503aau,0x4e4d03abu,0x464503acu,0x605f03adu,0x555403aeu,0x535203afu,0x424103b0u,0x4f4e03b1u,0x545303b2u,0x474603b3u,0x464503b4u,0x535203b5u,0x605f03b6u,0x474603b7u,0x565503b8u,0x4f4e03b9u,0x444303bau,0x555403bbu,0x4a4903bcu,0x504f03bdu,0x4f4e03beu,0x323103bfu,0x454403c0u,0x10003c1u,0x80000009u}; + static const uint32_t table[] = {0x4f4e0001u,0x42410002u,0x53520003u,0x4a490004u,0x605f0005u,0x4c450006u,0x5958000du,0x0u,0x0u,0x0u,0x0u,0x0u,0x49480023u,0x5150000eu,0x605f000fu,0x57560010u,0x504f0011u,0x4d4c0012u,0x56550013u,0x4e4d0014u,0x46450015u,0x605f0016u,0x54530017u,0x42410018u,0x4e4d0019u,0x5150001au,0x4d4c001bu,0x4645001cu,0x605f001du,0x5352001eu,0x4241001fu,0x55540020u,0x46450021u,0x1000022u,0x8000002eu,0x53520024u,0x605f0025u,0x57410026u,0x5352003cu,0x0u,0x42410060u,0x464500dbu,0x0u,0x535200f1u,0x46450161u,0x0u,0x4f4e028au,0x0u,0x0u,0x4a4902ceu,0x42410303u,0x0u,0x0u,0x0u,0x0u,0x46450324u,0x51410356u,0x0u,0x0u,0x504f03b6u,0x5345003du,0x4241004bu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x42410054u,0x605f004cu,0x4d4c004du,0x4a49004eu,0x4847004fu,0x49480050u,0x55540051u,0x54530052u,0x1000053u,0x8000000au,0x5a590055u,0x32310056u,0x45440057u,0x605f0058u,0x53520059u,0x4645005au,0x4847005bu,0x4a49005cu,0x504f005du,0x4f4e005eu,0x100005fu,0x8000000bu,0x4e4d0061u,0x46450062u,0x53520063u,0x42410064u,0x605f0065u,0x54440066u,0x46450076u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x504f0084u,0x0u,0x534d0099u,0x464500b8u,0x0u,0x0u,0x554800c3u,0x51500077u,0x55540078u,0x49480079u,0x605f007au,0x504f007bu,0x4746007cu,0x605f007du,0x4746007eu,0x4a49007fu,0x46450080u,0x4d4c0081u,0x45440082u,0x1000083u,0x8000000cu,0x55540085u,0x4a490086u,0x504f0087u,0x4f4e0088u,0x605f0089u,0x5554008au,0x5352008bu,0x4241008cu,0x4f4e008du,0x5453008eu,0x4746008fu,0x504f0090u,0x53520091u,0x4e4d0092u,0x42410093u,0x55540094u,0x4a490095u,0x504f0096u,0x4f4e0097u,0x1000098u,0x8000000du,0x4f4e009fu,0x0u,0x0u,0x0u,0x0u,0x555400adu,0x4a4900a0u,0x454400a1u,0x4a4900a2u,0x535200a3u,0x464500a4u,0x444300a5u,0x555400a6u,0x4a4900a7u,0x504f00a8u,0x4f4e00a9u,0x424100aau,0x4d4c00abu,0x10000acu,0x8000000eu,0x494800aeu,0x504f00afu,0x484700b0u,0x535200b1u,0x424100b2u,0x515000b3u,0x494800b4u,0x4a4900b5u,0x444300b6u,0x10000b7u,0x8000000fu,0x535200b9u,0x545300bau,0x515000bbu,0x464500bcu,0x444300bdu,0x555400beu,0x4a4900bfu,0x575600c0u,0x464500c1u,0x10000c2u,0x80000010u,0x565500d0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x464500d6u,0x555400d1u,0x555400d2u,0x464500d3u,0x535200d4u,0x10000d5u,0x80000005u,0x535200d7u,0x464500d8u,0x504f00d9u,0x10000dau,0x80000011u,0x575600dcu,0x4a4900ddu,0x444300deu,0x464500dfu,0x605f00e0u,0x545300e1u,0x5a5900e2u,0x4f4e00e3u,0x444300e4u,0x494800e5u,0x535200e6u,0x504f00e7u,0x4f4e00e8u,0x4a4900e9u,0x5b5a00eau,0x424100ebu,0x555400ecu,0x4a4900edu,0x504f00eeu,0x4f4e00efu,0x10000f0u,0x80000012u,0x424100f2u,0x4e4d00f3u,0x464500f4u,0x605f00f5u,0x444100f6u,0x444300f9u,0x0u,0x50480105u,0x444300fau,0x565500fbu,0x4e4d00fcu,0x565500fdu,0x4d4c00feu,0x424100ffu,0x55540100u,0x4a490101u,0x504f0102u,0x4f4e0103u,0x1000104u,0x80000013u,0x4241010du,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x4e4d014fu,0x4f4e010eu,0x4f4e010fu,0x46450110u,0x4d4c0111u,0x605f0112u,0x51410113u,0x4d4c0123u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x4f4e0129u,0x0u,0x0u,0x0u,0x0u,0x504f0134u,0x4342013au,0x53520143u,0x43420124u,0x46450125u,0x45440126u,0x504f0127u,0x1000128u,0x80000014u,0x5453012au,0x5554012bu,0x4241012cu,0x4f4e012du,0x4443012eu,0x4645012fu,0x605f0130u,0x4a490131u,0x45440132u,0x1000133u,0x80000015u,0x53520135u,0x4e4d0136u,0x42410137u,0x4d4c0138u,0x1000139u,0x80000016u,0x4b4a013bu,0x4645013cu,0x4443013du,0x5554013eu,0x605f013fu,0x4a490140u,0x45440141u,0x1000142u,0x80000017u,0x4a490144u,0x4e4d0145u,0x4a490146u,0x55540147u,0x4a490148u,0x57560149u,0x4645014au,0x605f014bu,0x4a49014cu,0x4544014du,0x100014eu,0x80000018u,0x51500150u,0x4d4c0151u,0x46450152u,0x55540153u,0x4a490154u,0x504f0155u,0x4f4e0156u,0x605f0157u,0x44430158u,0x42410159u,0x4d4c015au,0x4d4c015bu,0x4342015cu,0x4241015du,0x4443015eu,0x4c4b015fu,0x1000160u,0x80000019u,0x504f0162u,0x4e4d0163u,0x46450164u,0x55540165u,0x53520166u,0x5a590167u,0x605f0168u,0x55430169u,0x5a4f017bu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x56550194u,0x0u,0x5150020au,0x53520210u,0x4f4e0186u,0x0u,0x0u,0x0u,0x0u,0x0u,0x53520189u,0x0u,0x0u,0x0u,0x4d4c018du,0x46450187u,0x1000188u,0x8000001au,0x5756018au,0x4645018bu,0x100018cu,0x8000001bu,0x4a49018eu,0x4f4e018fu,0x45440190u,0x46450191u,0x53520192u,0x1000193u,0x8000001cu,0x42410195u,0x45440196u,0x60000197u,0x8000001du,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x4e4d01f7u,0x504f01f8u,0x555401f9u,0x4a4901fau,0x504f01fbu,0x4f4e01fcu,0x605f01fdu,0x454401feu,0x464501ffu,0x47460200u,0x504f0201u,0x53520202u,0x4e4d0203u,0x42410204u,0x55540205u,0x4a490206u,0x504f0207u,0x4f4e0208u,0x1000209u,0x8000001eu,0x4948020bu,0x4645020cu,0x5352020du,0x4645020eu,0x100020fu,0x8000001fu,0x4a490211u,0x42410212u,0x4f4e0213u,0x48470214u,0x4d4c0215u,0x46450216u,0x60000217u,0x80000020u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x4e4d0277u,0x504f0278u,0x55540279u,0x4a49027au,0x504f027bu,0x4f4e027cu,0x605f027du,0x4544027eu,0x4645027fu,0x47460280u,0x504f0281u,0x53520282u,0x4e4d0283u,0x42410284u,0x55540285u,0x4a490286u,0x504f0287u,0x4f4e0288u,0x1000289u,0x80000021u,0x5453028bu,0x5554028cu,0x4241028du,0x4f4e028eu,0x4443028fu,0x46450290u,0x605f0291u,0x554d0292u,0x504f029au,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x535202c5u,0x5554029bu,0x4a49029cu,0x504f029du,0x4f4e029eu,0x605f029fu,0x555302a0u,0x444302a2u,0x535202bcu,0x424102a3u,0x4d4c02a4u,0x464502a5u,0x605f02a6u,0x535202a7u,0x504f02a8u,0x555402a9u,0x424102aau,0x555402abu,0x4a4902acu,0x504f02adu,0x4f4e02aeu,0x605f02afu,0x555402b0u,0x535202b1u,0x424102b2u,0x4f4e02b3u,0x545302b4u,0x4d4c02b5u,0x424102b6u,0x555402b7u,0x4a4902b8u,0x504f02b9u,0x4f4e02bau,0x10002bbu,0x80000006u,0x424102bdu,0x4f4e02beu,0x545302bfu,0x474602c0u,0x504f02c1u,0x535202c2u,0x4e4d02c3u,0x10002c4u,0x80000007u,0x424102c6u,0x4f4e02c7u,0x545302c8u,0x474602c9u,0x504f02cau,0x535202cbu,0x4e4d02ccu,0x10002cdu,0x80000008u,0x484702cfu,0x494802d0u,0x555402d1u,0x605f02d2u,0x544402d3u,0x4a4902e3u,0x0u,0x0u,0x0u,0x454402eeu,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x504f02f2u,0x565502f7u,0x4a4902fbu,0x515002ffu,0x535202e4u,0x464502e5u,0x444302e6u,0x555402e7u,0x4a4902e8u,0x504f02e9u,0x4f4e02eau,0x424102ebu,0x4d4c02ecu,0x10002edu,0x80000000u,0x535202efu,0x4a4902f0u,0x10002f1u,0x80000004u,0x4a4902f3u,0x4f4e02f4u,0x555402f5u,0x10002f6u,0x80000001u,0x424102f8u,0x454402f9u,0x10002fau,0x80000003u,0x4f4e02fcu,0x484702fdu,0x10002feu,0x80000002u,0x504f0300u,0x55540301u,0x1000302u,0x80000022u,0x55540304u,0x46450305u,0x53520306u,0x4a490307u,0x42410308u,0x4d4c0309u,0x605f030au,0x514d030bu,0x4241030fu,0x0u,0x0u,0x49480314u,0x55540310u,0x55540311u,0x46450312u,0x1000313u,0x80000023u,0x5a590315u,0x54530316u,0x4a490317u,0x44430318u,0x42410319u,0x4d4c031au,0x4d4c031bu,0x5a59031cu,0x605f031du,0x4342031eu,0x4241031fu,0x54530320u,0x46450321u,0x45440322u,0x1000323u,0x80000024u,0x4f4e0325u,0x45440326u,0x46450327u,0x53520328u,0x46450329u,0x5352032au,0x605f032bu,0x4341032cu,0x4e4d032eu,0x4241033bu,0x4342032fu,0x4a490330u,0x46450331u,0x4f4e0332u,0x55540333u,0x605f0334u,0x4d4c0335u,0x4a490336u,0x48470337u,0x49480338u,0x55540339u,0x100033au,0x80000025u,0x4443033cu,0x4c4b033du,0x4847033eu,0x5352033fu,0x504f0340u,0x56550341u,0x4f4e0342u,0x45440343u,0x605f0344u,0x4a430345u,0x504f034cu,0x0u,0x0u,0x0u,0x0u,0x0u,0x4e4d0351u,0x4d4c034du,0x504f034eu,0x5352034fu,0x1000350u,0x80000026u,0x42410352u,0x48470353u,0x46450354u,0x1000355u,0x80000027u,0x4e4d0366u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x42410397u,0x51500367u,0x4d4c0368u,0x46450369u,0x5352036au,0x605f036bu,0x5549036cu,0x4e4d0378u,0x0u,0x0u,0x0u,0x0u,0x0u,0x0u,0x53520385u,0x0u,0x0u,0x0u,0x5352038eu,0x42410379u,0x4847037au,0x4645037bu,0x3431037cu,0x4544037fu,0x45440381u,0x45440383u,0x1000380u,0x80000028u,0x1000382u,0x80000029u,0x1000384u,0x8000002au,0x4a490386u,0x4e4d0387u,0x4a490388u,0x55540389u,0x4a49038au,0x5756038bu,0x4645038cu,0x100038du,0x8000002bu,0x4241038fu,0x4f4e0390u,0x54530391u,0x47460392u,0x504f0393u,0x53520394u,0x4e4d0395u,0x1000396u,0x8000002cu,0x55540398u,0x4a490399u,0x4241039au,0x4d4c039bu,0x605f039cu,0x4746039du,0x4a49039eu,0x4645039fu,0x4d4c03a0u,0x454403a1u,0x605f03a2u,0x545303a3u,0x555403a4u,0x535203a5u,0x565503a6u,0x444303a7u,0x555403a8u,0x565503a9u,0x535203aau,0x464503abu,0x454403acu,0x605f03adu,0x535203aeu,0x464503afu,0x484703b0u,0x565503b1u,0x4d4c03b2u,0x424103b3u,0x535203b4u,0x10003b5u,0x8000002du,0x4d4c03b7u,0x565503b8u,0x4e4d03b9u,0x464503bau,0x605f03bbu,0x555403bcu,0x535203bdu,0x424103beu,0x4f4e03bfu,0x545303c0u,0x474603c1u,0x464503c2u,0x535203c3u,0x605f03c4u,0x474603c5u,0x565503c6u,0x4f4e03c7u,0x444303c8u,0x555403c9u,0x4a4903cau,0x504f03cbu,0x4f4e03ccu,0x323103cdu,0x454403ceu,0x10003cfu,0x80000009u}; uint32_t cur = 0x42410000u; for(int i = 0;cur!=0;++i) { uint32_t idx = cur&0xFFFFu; @@ -104,33 +105,34 @@ static void fillExtensionStruct(ANARIExtensions *extensions, const char *const * case 16: extensions->ANARI_KHR_CAMERA_PERSPECTIVE = 1; break; case 17: extensions->ANARI_KHR_CAMERA_STEREO = 1; break; case 18: extensions->ANARI_KHR_DEVICE_SYNCHRONIZATION = 1; break; - case 19: extensions->ANARI_KHR_FRAME_CHANNEL_ALBEDO = 1; break; - case 20: extensions->ANARI_KHR_FRAME_CHANNEL_INSTANCE_ID = 1; break; - case 21: extensions->ANARI_KHR_FRAME_CHANNEL_NORMAL = 1; break; - case 22: extensions->ANARI_KHR_FRAME_CHANNEL_OBJECT_ID = 1; break; - case 23: extensions->ANARI_KHR_FRAME_CHANNEL_PRIMITIVE_ID = 1; break; - case 24: extensions->ANARI_KHR_FRAME_COMPLETION_CALLBACK = 1; break; - case 25: extensions->ANARI_KHR_GEOMETRY_CONE = 1; break; - case 26: extensions->ANARI_KHR_GEOMETRY_CURVE = 1; break; - case 27: extensions->ANARI_KHR_GEOMETRY_CYLINDER = 1; break; - case 28: extensions->ANARI_KHR_GEOMETRY_QUAD = 1; break; - case 29: extensions->ANARI_KHR_GEOMETRY_QUAD_MOTION_DEFORMATION = 1; break; - case 30: extensions->ANARI_KHR_GEOMETRY_SPHERE = 1; break; - case 31: extensions->ANARI_KHR_GEOMETRY_TRIANGLE = 1; break; - case 32: extensions->ANARI_KHR_GEOMETRY_TRIANGLE_MOTION_DEFORMATION = 1; break; - case 33: extensions->ANARI_KHR_LIGHT_SPOT = 1; break; - case 34: extensions->ANARI_KHR_MATERIAL_MATTE = 1; break; - case 35: extensions->ANARI_KHR_MATERIAL_PHYSICALLY_BASED = 1; break; - case 36: extensions->ANARI_KHR_RENDERER_AMBIENT_LIGHT = 1; break; - case 37: extensions->ANARI_KHR_RENDERER_BACKGROUND_COLOR = 1; break; - case 38: extensions->ANARI_KHR_RENDERER_BACKGROUND_IMAGE = 1; break; - case 39: extensions->ANARI_KHR_SAMPLER_IMAGE1D = 1; break; - case 40: extensions->ANARI_KHR_SAMPLER_IMAGE2D = 1; break; - case 41: extensions->ANARI_KHR_SAMPLER_IMAGE3D = 1; break; - case 42: extensions->ANARI_KHR_SAMPLER_PRIMITIVE = 1; break; - case 43: extensions->ANARI_KHR_SAMPLER_TRANSFORM = 1; break; - case 44: extensions->ANARI_KHR_SPATIAL_FIELD_STRUCTURED_REGULAR = 1; break; - case 45: extensions->ANARI_EXP_VOLUME_SAMPLE_RATE = 1; break; + case 19: extensions->ANARI_KHR_FRAME_ACCUMULATION = 1; break; + case 20: extensions->ANARI_KHR_FRAME_CHANNEL_ALBEDO = 1; break; + case 21: extensions->ANARI_KHR_FRAME_CHANNEL_INSTANCE_ID = 1; break; + case 22: extensions->ANARI_KHR_FRAME_CHANNEL_NORMAL = 1; break; + case 23: extensions->ANARI_KHR_FRAME_CHANNEL_OBJECT_ID = 1; break; + case 24: extensions->ANARI_KHR_FRAME_CHANNEL_PRIMITIVE_ID = 1; break; + case 25: extensions->ANARI_KHR_FRAME_COMPLETION_CALLBACK = 1; break; + case 26: extensions->ANARI_KHR_GEOMETRY_CONE = 1; break; + case 27: extensions->ANARI_KHR_GEOMETRY_CURVE = 1; break; + case 28: extensions->ANARI_KHR_GEOMETRY_CYLINDER = 1; break; + case 29: extensions->ANARI_KHR_GEOMETRY_QUAD = 1; break; + case 30: extensions->ANARI_KHR_GEOMETRY_QUAD_MOTION_DEFORMATION = 1; break; + case 31: extensions->ANARI_KHR_GEOMETRY_SPHERE = 1; break; + case 32: extensions->ANARI_KHR_GEOMETRY_TRIANGLE = 1; break; + case 33: extensions->ANARI_KHR_GEOMETRY_TRIANGLE_MOTION_DEFORMATION = 1; break; + case 34: extensions->ANARI_KHR_LIGHT_SPOT = 1; break; + case 35: extensions->ANARI_KHR_MATERIAL_MATTE = 1; break; + case 36: extensions->ANARI_KHR_MATERIAL_PHYSICALLY_BASED = 1; break; + case 37: extensions->ANARI_KHR_RENDERER_AMBIENT_LIGHT = 1; break; + case 38: extensions->ANARI_KHR_RENDERER_BACKGROUND_COLOR = 1; break; + case 39: extensions->ANARI_KHR_RENDERER_BACKGROUND_IMAGE = 1; break; + case 40: extensions->ANARI_KHR_SAMPLER_IMAGE1D = 1; break; + case 41: extensions->ANARI_KHR_SAMPLER_IMAGE2D = 1; break; + case 42: extensions->ANARI_KHR_SAMPLER_IMAGE3D = 1; break; + case 43: extensions->ANARI_KHR_SAMPLER_PRIMITIVE = 1; break; + case 44: extensions->ANARI_KHR_SAMPLER_TRANSFORM = 1; break; + case 45: extensions->ANARI_KHR_SPATIAL_FIELD_STRUCTURED_REGULAR = 1; break; + case 46: extensions->ANARI_EXP_VOLUME_SAMPLE_RATE = 1; break; default: break; } } From 7f14623644ad31c52a50c151dea3c0cba80fa15d Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Tue, 14 Nov 2023 15:58:49 -0600 Subject: [PATCH 26/34] make helium devices more robust to being called by multiple API threads (#170) --- libs/helide/HelideDevice.cpp | 122 ++++++++++++-------------- libs/helide/HelideDevice.h | 59 ++++--------- libs/helide/HelideGlobalState.h | 30 ++++--- libs/helide/frame/Frame.cpp | 4 +- libs/helide/scene/Group.cpp | 2 +- libs/helide/scene/World.cpp | 2 +- libs/helium/BaseDevice.cpp | 59 +++++++++---- libs/helium/BaseDevice.h | 28 +++--- libs/helium/BaseGlobalDeviceState.cpp | 24 +++++ libs/helium/BaseGlobalDeviceState.h | 14 ++- libs/helium/BaseObject.h | 3 +- libs/helium/LockableObject.h | 29 ++++++ libs/helium/array/Array.cpp | 2 +- libs/helium/utility/IntrusivePtr.h | 41 ++++----- 14 files changed, 242 insertions(+), 177 deletions(-) create mode 100644 libs/helium/LockableObject.h diff --git a/libs/helide/HelideDevice.cpp b/libs/helide/HelideDevice.cpp index 23d014c1..4e99d167 100644 --- a/libs/helide/HelideDevice.cpp +++ b/libs/helide/HelideDevice.cpp @@ -61,6 +61,8 @@ void *HelideDevice::mapArray(ANARIArray a) return helium::BaseDevice::mapArray(a); } +// API Objects //////////////////////////////////////////////////////////////// + ANARIArray1D HelideDevice::newArray1D(const void *appMemory, ANARIMemoryDeleter deleter, const void *userData, @@ -124,20 +126,17 @@ ANARIArray3D HelideDevice::newArray3D(const void *appMemory, return createObjectForAPI(deviceState(), md); } -// Renderable Objects ///////////////////////////////////////////////////////// - -ANARILight HelideDevice::newLight(const char *subtype) +ANARICamera HelideDevice::newCamera(const char *subtype) { initDevice(); - return getHandleForAPI( - Light::createInstance(subtype, deviceState())); + return getHandleForAPI( + Camera::createInstance(subtype, deviceState())); } -ANARICamera HelideDevice::newCamera(const char *subtype) +ANARIFrame HelideDevice::newFrame() { initDevice(); - return getHandleForAPI( - Camera::createInstance(subtype, deviceState())); + return createObjectForAPI(deviceState()); } ANARIGeometry HelideDevice::newGeometry(const char *subtype) @@ -147,28 +146,25 @@ ANARIGeometry HelideDevice::newGeometry(const char *subtype) Geometry::createInstance(subtype, deviceState())); } -ANARISpatialField HelideDevice::newSpatialField(const char *subtype) +ANARIGroup HelideDevice::newGroup() { initDevice(); - return getHandleForAPI( - SpatialField::createInstance(subtype, deviceState())); + return createObjectForAPI(deviceState()); } -ANARISurface HelideDevice::newSurface() +ANARIInstance HelideDevice::newInstance(const char * /*subtype*/) { initDevice(); - return createObjectForAPI(deviceState()); + return createObjectForAPI(deviceState()); } -ANARIVolume HelideDevice::newVolume(const char *subtype) +ANARILight HelideDevice::newLight(const char *subtype) { initDevice(); - return getHandleForAPI( - Volume::createInstance(subtype, deviceState())); + return getHandleForAPI( + Light::createInstance(subtype, deviceState())); } -// Surface Meta-Data ////////////////////////////////////////////////////////// - ANARIMaterial HelideDevice::newMaterial(const char *subtype) { initDevice(); @@ -176,6 +172,13 @@ ANARIMaterial HelideDevice::newMaterial(const char *subtype) Material::createInstance(subtype, deviceState())); } +ANARIRenderer HelideDevice::newRenderer(const char *subtype) +{ + initDevice(); + return getHandleForAPI( + Renderer::createInstance(subtype, deviceState())); +} + ANARISampler HelideDevice::newSampler(const char *subtype) { initDevice(); @@ -183,21 +186,25 @@ ANARISampler HelideDevice::newSampler(const char *subtype) Sampler::createInstance(subtype, deviceState())); } -// Instancing ///////////////////////////////////////////////////////////////// - -ANARIGroup HelideDevice::newGroup() +ANARISpatialField HelideDevice::newSpatialField(const char *subtype) { initDevice(); - return createObjectForAPI(deviceState()); + return getHandleForAPI( + SpatialField::createInstance(subtype, deviceState())); } -ANARIInstance HelideDevice::newInstance(const char * /*subtype*/) +ANARISurface HelideDevice::newSurface() { initDevice(); - return createObjectForAPI(deviceState()); + return createObjectForAPI(deviceState()); } -// Top-level Worlds /////////////////////////////////////////////////////////// +ANARIVolume HelideDevice::newVolume(const char *subtype) +{ + initDevice(); + return getHandleForAPI( + Volume::createInstance(subtype, deviceState())); +} ANARIWorld HelideDevice::newWorld() { @@ -245,42 +252,12 @@ int HelideDevice::getProperty(ANARIObject object, uint64_t size, uint32_t mask) { - if (handleIsDevice(object)) { - std::string_view prop = name; - if (prop == "extension" && type == ANARI_STRING_LIST) { - helium::writeToVoidP(mem, query_extensions()); - return 1; - } else if (prop == "helide" && type == ANARI_BOOL) { - helium::writeToVoidP(mem, true); - return 1; - } - } else { - if (mask == ANARI_WAIT) { - deviceState()->waitOnCurrentFrame(); - flushCommitBuffer(); - } - return helium::referenceFromHandle(object).getProperty( - name, type, mem, mask); + if (mask == ANARI_WAIT) { + auto lock = scopeLockObject(); + deviceState()->waitOnCurrentFrame(); } - return 0; -} - -// Frame Manipulation ///////////////////////////////////////////////////////// - -ANARIFrame HelideDevice::newFrame() -{ - initDevice(); - return createObjectForAPI(deviceState()); -} - -// Frame Rendering //////////////////////////////////////////////////////////// - -ANARIRenderer HelideDevice::newRenderer(const char *subtype) -{ - initDevice(); - return getHandleForAPI( - Renderer::createInstance(subtype, deviceState())); + return helium::BaseDevice::getProperty(object, name, type, mem, size, mask); } // Other HelideDevice definitions ///////////////////////////////////////////// @@ -302,7 +279,7 @@ HelideDevice::~HelideDevice() { auto &state = *deviceState(); - state.commitBuffer.clear(); + state.commitBufferClear(); reportMessage(ANARI_SEVERITY_DEBUG, "destroying helide device (%p)", this); @@ -315,11 +292,12 @@ HelideDevice::~HelideDevice() // really add substantial code complexity, so they are provided out of // convenience. - auto reportLeaks = [&](size_t &count, const char *handleType) { - if (count != 0) { + auto reportLeaks = [&](auto &count, const char *handleType) { + auto c = count.load(); + if (c != 0) { reportMessage(ANARI_SEVERITY_WARNING, "detected %zu leaked %s objects", - count, + c, handleType); } }; @@ -338,10 +316,10 @@ HelideDevice::~HelideDevice() reportLeaks(state.objectCounts.spatialFields, "ANARISpatialField"); reportLeaks(state.objectCounts.arrays, "ANARIArray"); - if (state.objectCounts.unknown != 0) { + if (state.objectCounts.unknown.load() != 0) { reportMessage(ANARI_SEVERITY_WARNING, "detected %zu leaked ANARIObject objects created by unknown subtypes", - state.objectCounts.unknown); + state.objectCounts.unknown.load()); } } @@ -391,6 +369,20 @@ void HelideDevice::deviceCommitParameters() helium::BaseDevice::deviceCommitParameters(); } +int HelideDevice::deviceGetProperty( + const char *name, ANARIDataType type, void *mem, uint64_t size) +{ + std::string_view prop = name; + if (prop == "extension" && type == ANARI_STRING_LIST) { + helium::writeToVoidP(mem, query_extensions()); + return 1; + } else if (prop == "helide" && type == ANARI_BOOL) { + helium::writeToVoidP(mem, true); + return 1; + } + return 0; +} + HelideGlobalState *HelideDevice::deviceState() const { return (HelideGlobalState *)helium::BaseDevice::m_state.get(); diff --git a/libs/helide/HelideDevice.h b/libs/helide/HelideDevice.h index 95781d84..c89ae8ad 100644 --- a/libs/helide/HelideDevice.h +++ b/libs/helide/HelideDevice.h @@ -21,19 +21,19 @@ struct HelideDevice : public helium::BaseDevice void *mapArray(ANARIArray) override; + // API Objects ////////////////////////////////////////////////////////////// + ANARIArray1D newArray1D(const void *appMemory, ANARIMemoryDeleter deleter, const void *userdata, ANARIDataType, uint64_t numItems1) override; - ANARIArray2D newArray2D(const void *appMemory, ANARIMemoryDeleter deleter, const void *userdata, ANARIDataType, uint64_t numItems1, uint64_t numItems2) override; - ANARIArray3D newArray3D(const void *appMemory, ANARIMemoryDeleter deleter, const void *userdata, @@ -41,47 +41,32 @@ struct HelideDevice : public helium::BaseDevice uint64_t numItems1, uint64_t numItems2, uint64_t numItems3) override; - - // Renderable Objects /////////////////////////////////////////////////////// - - ANARILight newLight(const char *type) override; - ANARICamera newCamera(const char *type) override; - + ANARIFrame newFrame() override; ANARIGeometry newGeometry(const char *type) override; + ANARIGroup newGroup() override; + ANARIInstance newInstance(const char *type) override; + ANARILight newLight(const char *type) override; + ANARIMaterial newMaterial(const char *material_type) override; + ANARIRenderer newRenderer(const char *type) override; + ANARISampler newSampler(const char *type) override; ANARISpatialField newSpatialField(const char *type) override; - ANARISurface newSurface() override; ANARIVolume newVolume(const char *type) override; - - // Surface Meta-Data //////////////////////////////////////////////////////// - - ANARIMaterial newMaterial(const char *material_type) override; - - ANARISampler newSampler(const char *type) override; - - // Instancing /////////////////////////////////////////////////////////////// - - ANARIGroup newGroup() override; - - ANARIInstance newInstance(const char *type) override; - - // Top-level Worlds ///////////////////////////////////////////////////////// - ANARIWorld newWorld() override; // Query functions ////////////////////////////////////////////////////////// - const char ** getObjectSubtypes(ANARIDataType objectType) override; - const void* getObjectInfo(ANARIDataType objectType, - const char* objectSubtype, - const char* infoName, + const char **getObjectSubtypes(ANARIDataType objectType) override; + const void *getObjectInfo(ANARIDataType objectType, + const char *objectSubtype, + const char *infoName, ANARIDataType infoType) override; - const void* getParameterInfo(ANARIDataType objectType, - const char* objectSubtype, - const char* parameterName, + const void *getParameterInfo(ANARIDataType objectType, + const char *objectSubtype, + const char *parameterName, ANARIDataType parameterType, - const char* infoName, + const char *infoName, ANARIDataType infoType) override; // Object + Parameter Lifetime Management /////////////////////////////////// @@ -93,14 +78,6 @@ struct HelideDevice : public helium::BaseDevice uint64_t size, uint32_t mask) override; - // FrameBuffer Manipulation ///////////////////////////////////////////////// - - ANARIFrame newFrame() override; - - // Frame Rendering ////////////////////////////////////////////////////////// - - ANARIRenderer newRenderer(const char *type) override; - ///////////////////////////////////////////////////////////////////////////// // Helper/other functions and data members ///////////////////////////////////////////////////////////////////////////// @@ -112,6 +89,8 @@ struct HelideDevice : public helium::BaseDevice void initDevice(); void deviceCommitParameters() override; + int deviceGetProperty( + const char *name, ANARIDataType type, void *mem, uint64_t size) override; private: HelideGlobalState *deviceState() const; diff --git a/libs/helide/HelideGlobalState.h b/libs/helide/HelideGlobalState.h index 25cb3b8d..2af3aec7 100644 --- a/libs/helide/HelideGlobalState.h +++ b/libs/helide/HelideGlobalState.h @@ -8,6 +8,8 @@ #include "helium/BaseGlobalDeviceState.h" // embree #include "embree3/rtcore.h" +// std +#include namespace helide { @@ -19,20 +21,20 @@ struct HelideGlobalState : public helium::BaseGlobalDeviceState struct ObjectCounts { - size_t frames{0}; - size_t cameras{0}; - size_t renderers{0}; - size_t worlds{0}; - size_t instances{0}; - size_t groups{0}; - size_t surfaces{0}; - size_t geometries{0}; - size_t materials{0}; - size_t samplers{0}; - size_t volumes{0}; - size_t spatialFields{0}; - size_t arrays{0}; - size_t unknown{0}; + std::atomic frames{0}; + std::atomic cameras{0}; + std::atomic renderers{0}; + std::atomic worlds{0}; + std::atomic instances{0}; + std::atomic groups{0}; + std::atomic surfaces{0}; + std::atomic geometries{0}; + std::atomic materials{0}; + std::atomic samplers{0}; + std::atomic volumes{0}; + std::atomic spatialFields{0}; + std::atomic arrays{0}; + std::atomic unknown{0}; } objectCounts; struct ObjectUpdates diff --git a/libs/helide/frame/Frame.cpp b/libs/helide/frame/Frame.cpp index 2ac0a91c..853d5271 100644 --- a/libs/helide/frame/Frame.cpp +++ b/libs/helide/frame/Frame.cpp @@ -153,7 +153,7 @@ void Frame::renderFrame() auto start = std::chrono::steady_clock::now(); - state->commitBuffer.flush(); + state->commitBufferFlush(); if (!isValid()) { reportMessage( @@ -163,7 +163,7 @@ void Frame::renderFrame() return; } - if (state->commitBuffer.lastFlush() <= m_frameLastRendered) { + if (state->commitBufferLastFlush() <= m_frameLastRendered) { this->refDec(helium::RefType::INTERNAL); return; } diff --git a/libs/helide/scene/Group.cpp b/libs/helide/scene/Group.cpp index e0a3ce42..d1a97b75 100644 --- a/libs/helide/scene/Group.cpp +++ b/libs/helide/scene/Group.cpp @@ -24,7 +24,7 @@ bool Group::getProperty( if (name == "bounds" && type == ANARI_FLOAT32_BOX3) { if (flags & ANARI_WAIT) { deviceState()->waitOnCurrentFrame(); - deviceState()->commitBuffer.flush(); + deviceState()->commitBufferFlush(); embreeSceneConstruct(); embreeSceneCommit(); } diff --git a/libs/helide/scene/World.cpp b/libs/helide/scene/World.cpp index ce4beffb..c6168a72 100644 --- a/libs/helide/scene/World.cpp +++ b/libs/helide/scene/World.cpp @@ -30,7 +30,7 @@ bool World::getProperty( if (name == "bounds" && type == ANARI_FLOAT32_BOX3) { if (flags & ANARI_WAIT) { deviceState()->waitOnCurrentFrame(); - deviceState()->commitBuffer.flush(); + deviceState()->commitBufferFlush(); embreeSceneUpdate(); } auto bounds = getEmbreeSceneBounds(m_embreeScene); diff --git a/libs/helium/BaseDevice.cpp b/libs/helium/BaseDevice.cpp index 0f2d57c8..5a17c903 100644 --- a/libs/helium/BaseDevice.cpp +++ b/libs/helium/BaseDevice.cpp @@ -13,11 +13,13 @@ namespace helium { void *BaseDevice::mapArray(ANARIArray a) { + auto lock = getObjectLock(a); return referenceFromHandle(a).map(); } void BaseDevice::unmapArray(ANARIArray a) { + auto lock = getObjectLock(a); referenceFromHandle(a).unmap(); } @@ -32,9 +34,11 @@ int BaseDevice::getProperty(ANARIObject object, { if (!handleIsDevice(object)) { if (mask == ANARI_WAIT) - flushCommitBuffer(); + m_state->commitBufferFlush(); + auto lock = getObjectLock(object); return referenceFromHandle(object).getProperty(name, type, mem, mask); - } + } else + return deviceGetProperty(name, type, mem, mask); return 0; } @@ -44,6 +48,8 @@ int BaseDevice::getProperty(ANARIObject object, void BaseDevice::setParameter( ANARIObject object, const char *name, ANARIDataType type, const void *mem) { + auto lock = getObjectLock(object); + if (handleIsDevice(object)) { deviceSetParameter(name, type, mem); return; @@ -58,6 +64,8 @@ void BaseDevice::setParameter( void BaseDevice::unsetParameter(ANARIObject o, const char *name) { + auto lock = getObjectLock(o); + if (handleIsDevice(o)) deviceUnsetParameter(name); else { @@ -69,6 +77,8 @@ void BaseDevice::unsetParameter(ANARIObject o, const char *name) void BaseDevice::unsetAllParameters(ANARIObject o) { + auto lock = getObjectLock(o); + if (handleIsDevice(o)) deviceUnsetAllParameters(); else { @@ -129,6 +139,8 @@ void *BaseDevice::mapParameterArray3D(ANARIObject o, void BaseDevice::unmapParameterArray(ANARIObject o, const char *name) { + auto lock = getObjectLock(o); + auto *obj = (BaseObject *)o; auto *array = obj->getParamObject(name); array->unmap(); @@ -136,17 +148,21 @@ void BaseDevice::unmapParameterArray(ANARIObject o, const char *name) void BaseDevice::commitParameters(ANARIObject o) { - if (handleIsDevice(o)) + if (handleIsDevice(o)) { + auto lock = scopeLockObject(); deviceCommitParameters(); - else - m_state->commitBuffer.addObject((BaseObject *)o); + } else + m_state->commitBufferAddObject((BaseObject *)o); } void BaseDevice::release(ANARIObject o) { if (o == nullptr) return; - else if (handleIsDevice(o)) { + + auto lock = getObjectLock(o); + + if (handleIsDevice(o)) { if (--m_refCount == 0) delete this; return; @@ -176,6 +192,8 @@ void BaseDevice::release(ANARIObject o) void BaseDevice::retain(ANARIObject o) { + auto lock = getObjectLock(o); + if (handleIsDevice(o)) m_refCount++; else @@ -190,11 +208,13 @@ const void *BaseDevice::frameBufferMap(ANARIFrame f, uint32_t *h, ANARIDataType *pixelType) { + auto lock = getObjectLock(f); return referenceFromHandle(f).map(channel, w, h, pixelType); } void BaseDevice::frameBufferUnmap(ANARIFrame f, const char *channel) { + auto lock = getObjectLock(f); return referenceFromHandle(f).unmap(channel); } @@ -202,16 +222,19 @@ void BaseDevice::frameBufferUnmap(ANARIFrame f, const char *channel) void BaseDevice::renderFrame(ANARIFrame f) { + auto lock = getObjectLock(f); referenceFromHandle(f).renderFrame(); } int BaseDevice::frameReady(ANARIFrame f, ANARIWaitMask m) { + auto lock = getObjectLock(f); return referenceFromHandle(f).frameReady(m); } void BaseDevice::discardFrame(ANARIFrame f) { + auto lock = getObjectLock(f); referenceFromHandle(f).discard(); } @@ -225,16 +248,6 @@ BaseDevice::BaseDevice(ANARIStatusCallback defaultCallback, const void *userPtr) BaseDevice::BaseDevice(ANARILibrary l) : DeviceImpl(l) {} -void BaseDevice::flushCommitBuffer() -{ - m_state->commitBuffer.flush(); -} - -void BaseDevice::clearCommitBuffer() -{ - m_state->commitBuffer.clear(); -} - void BaseDevice::deviceCommitParameters() { m_state->statusCB = @@ -243,6 +256,12 @@ void BaseDevice::deviceCommitParameters() "statusCallbackUserData", defaultStatusCallbackUserPtr()); } +int BaseDevice::deviceGetProperty( + const char *name, ANARIDataType type, void *mem, uint64_t size) +{ + return 0; +} + void BaseDevice::deviceSetParameter( const char *id, ANARIDataType type, const void *mem) { @@ -259,4 +278,12 @@ void BaseDevice::deviceUnsetAllParameters() removeAllParams(); } +std::scoped_lock BaseDevice::getObjectLock(ANARIObject object) +{ + if (handleIsDevice(object)) + return referenceFromHandle(object).scopeLockObject(); + else + return referenceFromHandle(object).scopeLockObject(); +} + } // namespace helium diff --git a/libs/helium/BaseDevice.h b/libs/helium/BaseDevice.h index 18cdb781..3b88e8b1 100644 --- a/libs/helium/BaseDevice.h +++ b/libs/helium/BaseDevice.h @@ -4,6 +4,7 @@ #pragma once #include "BaseGlobalDeviceState.h" +#include "LockableObject.h" #include "utility/IntrusivePtr.h" #include "utility/ParameterizedObject.h" // anari @@ -11,7 +12,9 @@ namespace helium { -struct BaseDevice : public anari::DeviceImpl, public ParameterizedObject +struct BaseDevice : public anari::DeviceImpl, + ParameterizedObject, + LockableObject { // Data Arrays ////////////////////////////////////////////////////////////// @@ -35,26 +38,25 @@ struct BaseDevice : public anari::DeviceImpl, public ParameterizedObject void unsetParameter(ANARIObject o, const char *name) override; void unsetAllParameters(ANARIObject o) override; - void* mapParameterArray1D(ANARIObject o, - const char* name, + void *mapParameterArray1D(ANARIObject o, + const char *name, ANARIDataType dataType, uint64_t numElements1, uint64_t *elementStride) override; - void* mapParameterArray2D(ANARIObject o, - const char* name, + void *mapParameterArray2D(ANARIObject o, + const char *name, ANARIDataType dataType, uint64_t numElements1, uint64_t numElements2, uint64_t *elementStride) override; - void* mapParameterArray3D(ANARIObject o, - const char* name, + void *mapParameterArray3D(ANARIObject o, + const char *name, ANARIDataType dataType, uint64_t numElements1, uint64_t numElements2, uint64_t numElements3, uint64_t *elementStride) override; - void unmapParameterArray(ANARIObject o, - const char* name) override; + void unmapParameterArray(ANARIObject o, const char *name) override; void commitParameters(ANARIObject o) override; @@ -90,14 +92,16 @@ struct BaseDevice : public anari::DeviceImpl, public ParameterizedObject void reportMessage( ANARIStatusSeverity, const char *fmt, Args &&...args) const; - void flushCommitBuffer(); - void clearCommitBuffer(); - virtual void deviceCommitParameters(); + virtual int deviceGetProperty( + const char *name, ANARIDataType type, void *mem, uint64_t size); std::unique_ptr m_state; private: + std::scoped_lock getObjectLock(ANARIObject object); + + void deviceGetProperty(const char *id, ANARIDataType type, const void *mem); void deviceSetParameter(const char *id, ANARIDataType type, const void *mem); void deviceUnsetParameter(const char *id); void deviceUnsetAllParameters(); diff --git a/libs/helium/BaseGlobalDeviceState.cpp b/libs/helium/BaseGlobalDeviceState.cpp index 1bdf285b..f499eec7 100644 --- a/libs/helium/BaseGlobalDeviceState.cpp +++ b/libs/helium/BaseGlobalDeviceState.cpp @@ -23,4 +23,28 @@ BaseGlobalDeviceState::BaseGlobalDeviceState(ANARIDevice d) }; } +void BaseGlobalDeviceState::commitBufferAddObject(BaseObject *o) +{ + std::lock_guard guard(m_mutex); + m_commitBuffer.addObject(o); +} + +void BaseGlobalDeviceState::commitBufferFlush() +{ + std::lock_guard guard(m_mutex); + m_commitBuffer.flush(); +} + +void BaseGlobalDeviceState::commitBufferClear() +{ + std::lock_guard guard(m_mutex); + m_commitBuffer.clear(); +} + +TimeStamp BaseGlobalDeviceState::commitBufferLastFlush() const +{ + std::lock_guard guard(m_mutex); + return m_commitBuffer.lastFlush(); +} + } // namespace helium diff --git a/libs/helium/BaseGlobalDeviceState.h b/libs/helium/BaseGlobalDeviceState.h index eb0e3a5b..f53ad872 100644 --- a/libs/helium/BaseGlobalDeviceState.h +++ b/libs/helium/BaseGlobalDeviceState.h @@ -9,6 +9,7 @@ #include // std #include +#include #include namespace helium { @@ -18,13 +19,24 @@ using mat4 = float4x4; struct BaseGlobalDeviceState { + void commitBufferAddObject(BaseObject *o); + void commitBufferFlush(); + void commitBufferClear(); + TimeStamp commitBufferLastFlush() const; + + // Data // + ANARIStatusCallback statusCB{nullptr}; const void *statusCBUserPtr{nullptr}; - DeferredCommitBuffer commitBuffer; + std::function messageFunction; BaseGlobalDeviceState(ANARIDevice d); virtual ~BaseGlobalDeviceState() = default; + + private: + DeferredCommitBuffer m_commitBuffer; + mutable std::mutex m_mutex; }; } // namespace helium diff --git a/libs/helium/BaseObject.h b/libs/helium/BaseObject.h index 9471915c..1f2d3810 100644 --- a/libs/helium/BaseObject.h +++ b/libs/helium/BaseObject.h @@ -3,6 +3,7 @@ #pragma once +#include "LockableObject.h" #include "utility/TimeStamp.h" // anari_cpp #include @@ -15,7 +16,7 @@ namespace helium { -struct BaseObject : public RefCounted, ParameterizedObject +struct BaseObject : public RefCounted, ParameterizedObject, LockableObject { // Construct BaseObject(ANARIDataType type, BaseGlobalDeviceState *state); diff --git a/libs/helium/LockableObject.h b/libs/helium/LockableObject.h new file mode 100644 index 00000000..d0d8ed9f --- /dev/null +++ b/libs/helium/LockableObject.h @@ -0,0 +1,29 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +// std +#include + +namespace helium { + +struct LockableObject +{ + LockableObject() = default; + virtual ~LockableObject() = default; + + std::scoped_lock scopeLockObject(); + + private: + std::mutex m_objectMutex; +}; + +// Inlined definitions //////////////////////////////////////////////////////// + +inline std::scoped_lock LockableObject::scopeLockObject() +{ + return std::scoped_lock(m_objectMutex); +} + +} // namespace helium diff --git a/libs/helium/array/Array.cpp b/libs/helium/array/Array.cpp index f979f5a3..cc284ed8 100644 --- a/libs/helium/array/Array.cpp +++ b/libs/helium/array/Array.cpp @@ -220,7 +220,7 @@ void Array::initManagedMemory() void Array::notifyObserver(BaseObject *o) const { o->markUpdated(); - deviceState()->commitBuffer.addObject(o); + deviceState()->commitBufferAddObject(o); } } // namespace helium diff --git a/libs/helium/utility/IntrusivePtr.h b/libs/helium/utility/IntrusivePtr.h index 413d67de..b8a5c3db 100644 --- a/libs/helium/utility/IntrusivePtr.h +++ b/libs/helium/utility/IntrusivePtr.h @@ -30,15 +30,11 @@ class RefCounted void refInc(RefType = PUBLIC) const; void refDec(RefType = PUBLIC) const; - uint64_t useCount(RefType = ALL) const; + uint32_t useCount(RefType = ALL) const; private: - uint64_t internalRefCount() const; - - static constexpr uint64_t m_publicRefMask = 0x00000000FFFFFFFF; - static constexpr uint64_t m_internalRefMask = 0xFFFFFFFF00000000; - - mutable std::atomic m_refCounter{1}; + mutable std::atomic m_internalRefs{0}; + mutable std::atomic m_publicRefs{1}; }; // Inlined definitions // @@ -46,38 +42,37 @@ class RefCounted inline void RefCounted::refInc(RefType type) const { if (type == RefType::PUBLIC) - m_refCounter++; + m_publicRefs++; else if (type == RefType::INTERNAL) - m_refCounter = ((internalRefCount() + 1) << 32) + useCount(RefType::PUBLIC); + m_internalRefs++; + else { + m_publicRefs++; + m_internalRefs++; + } } inline void RefCounted::refDec(RefType type) const { if (type == RefType::PUBLIC && useCount(RefType::PUBLIC) > 0) - m_refCounter--; - else if (type == RefType::INTERNAL && internalRefCount() > 0) - m_refCounter = ((internalRefCount() - 1) << 32) + useCount(RefType::PUBLIC); + m_publicRefs--; + else if (type == RefType::INTERNAL && useCount(RefType::INTERNAL) > 0) + m_internalRefs--; if (useCount(RefType::ALL) == 0) delete this; } -inline uint64_t RefCounted::useCount(RefType type) const +inline uint32_t RefCounted::useCount(RefType type) const { - auto publicCount = m_refCounter.load() & m_publicRefMask; - auto internalCount = internalRefCount(); + auto publicRefs = m_publicRefs.load(); + auto internalRefs = m_internalRefs.load(); if (type == RefType::PUBLIC) - return publicCount; + return publicRefs; else if (type == RefType::INTERNAL) - return internalCount; + return internalRefs; else - return publicCount + internalCount; -} - -inline uint64_t RefCounted::internalRefCount() const -{ - return (m_refCounter.load() & m_internalRefMask) >> 32; + return publicRefs + internalRefs; } /////////////////////////////////////////////////////////////////////////////// From ba8ab2a790085d510c30a42e8d4895e4bfaea862 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Thu, 16 Nov 2023 09:10:41 -0600 Subject: [PATCH 27/34] use a semaphore to make sure array updates and rendering do not overlap (#171) --- libs/helide/HelideDevice.cpp | 8 ++++- libs/helide/HelideDevice.h | 1 + libs/helide/HelideGlobalState.h | 3 ++ libs/helide/RenderingSemaphore.h | 59 ++++++++++++++++++++++++++++++++ libs/helide/frame/Frame.cpp | 36 ++++++++++--------- libs/helium/BaseDevice.cpp | 2 +- 6 files changed, 90 insertions(+), 19 deletions(-) create mode 100644 libs/helide/RenderingSemaphore.h diff --git a/libs/helide/HelideDevice.cpp b/libs/helide/HelideDevice.cpp index 4e99d167..5fe26213 100644 --- a/libs/helide/HelideDevice.cpp +++ b/libs/helide/HelideDevice.cpp @@ -57,10 +57,16 @@ inline HANDLE_T createObjectForAPI(HelideGlobalState *s, Args &&...args) void *HelideDevice::mapArray(ANARIArray a) { - deviceState()->waitOnCurrentFrame(); + deviceState()->renderingSemaphore.arrayMapAcquire(); return helium::BaseDevice::mapArray(a); } +void HelideDevice::unmapArray(ANARIArray a) +{ + helium::BaseDevice::unmapArray(a); + deviceState()->renderingSemaphore.arrayMapRelease(); +} + // API Objects //////////////////////////////////////////////////////////////// ANARIArray1D HelideDevice::newArray1D(const void *appMemory, diff --git a/libs/helide/HelideDevice.h b/libs/helide/HelideDevice.h index c89ae8ad..96d230ce 100644 --- a/libs/helide/HelideDevice.h +++ b/libs/helide/HelideDevice.h @@ -20,6 +20,7 @@ struct HelideDevice : public helium::BaseDevice // Data Arrays ////////////////////////////////////////////////////////////// void *mapArray(ANARIArray) override; + void unmapArray(ANARIArray) override; // API Objects ////////////////////////////////////////////////////////////// diff --git a/libs/helide/HelideGlobalState.h b/libs/helide/HelideGlobalState.h index 2af3aec7..8b76fc24 100644 --- a/libs/helide/HelideGlobalState.h +++ b/libs/helide/HelideGlobalState.h @@ -3,6 +3,7 @@ #pragma once +#include "RenderingSemaphore.h" #include "helide_math.h" // helium #include "helium/BaseGlobalDeviceState.h" @@ -10,6 +11,7 @@ #include "embree3/rtcore.h" // std #include +#include namespace helide { @@ -44,6 +46,7 @@ struct HelideGlobalState : public helium::BaseGlobalDeviceState helium::TimeStamp lastTLSReconstructSceneRequest{0}; } objectUpdates; + RenderingSemaphore renderingSemaphore; Frame *currentFrame{nullptr}; RTCDevice embreeDevice{nullptr}; diff --git a/libs/helide/RenderingSemaphore.h b/libs/helide/RenderingSemaphore.h new file mode 100644 index 00000000..d8a8b565 --- /dev/null +++ b/libs/helide/RenderingSemaphore.h @@ -0,0 +1,59 @@ +// Copyright 2023 The Khronos Group +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include +#include + +namespace helide { + +struct RenderingSemaphore +{ + RenderingSemaphore() = default; + + void arrayMapAcquire(); + void arrayMapRelease(); + + void frameStart(); + void frameEnd(); + + private: + std::mutex m_mutex; + std::condition_variable m_conditionArrays; + std::condition_variable m_conditionFrame; + unsigned long m_arraysMapped{0}; + bool m_frameInFlight{false}; +}; + +// Inlined definitions //////////////////////////////////////////////////////// + +inline void RenderingSemaphore::arrayMapAcquire() +{ + std::unique_lock frameLock(m_mutex); + m_conditionFrame.wait(frameLock, [&]() { return !m_frameInFlight; }); + m_arraysMapped++; +} + +inline void RenderingSemaphore::arrayMapRelease() +{ + std::lock_guard lock(m_mutex); + m_arraysMapped--; + if (m_arraysMapped == 0) + m_conditionArrays.notify_one(); +} + +inline void RenderingSemaphore::frameStart() +{ + std::unique_lock arraysLock(m_mutex); + m_conditionArrays.wait(arraysLock, [&]() { return m_arraysMapped == 0; }); + m_frameInFlight = true; +} + +inline void RenderingSemaphore::frameEnd() +{ + m_frameInFlight = false; + m_conditionFrame.notify_all(); +} + +} // namespace helide diff --git a/libs/helide/frame/Frame.cpp b/libs/helide/frame/Frame.cpp index 853d5271..9dce286e 100644 --- a/libs/helide/frame/Frame.cpp +++ b/libs/helide/frame/Frame.cpp @@ -150,28 +150,28 @@ void Frame::renderFrame() auto *state = deviceState(); state->waitOnCurrentFrame(); + state->currentFrame = this; - auto start = std::chrono::steady_clock::now(); + m_future = async([&, state]() { + auto start = std::chrono::steady_clock::now(); + state->renderingSemaphore.frameStart(); + state->commitBufferFlush(); - state->commitBufferFlush(); + if (!isValid()) { + reportMessage( + ANARI_SEVERITY_ERROR, "skipping render of incomplete frame object"); + std::fill(m_pixelBuffer.begin(), m_pixelBuffer.end(), 0); + state->renderingSemaphore.frameEnd(); + return; + } - if (!isValid()) { - reportMessage( - ANARI_SEVERITY_ERROR, "skipping render of incomplete frame object"); - std::fill(m_pixelBuffer.begin(), m_pixelBuffer.end(), 0); - this->refDec(helium::RefType::INTERNAL); - return; - } + if (state->commitBufferLastFlush() <= m_frameLastRendered) { + state->renderingSemaphore.frameEnd(); + return; + } - if (state->commitBufferLastFlush() <= m_frameLastRendered) { - this->refDec(helium::RefType::INTERNAL); - return; - } - - m_frameLastRendered = helium::newTimeStamp(); - state->currentFrame = this; + m_frameLastRendered = helium::newTimeStamp(); - m_future = async([&, state, start]() { m_world->embreeSceneUpdate(); const auto &size = m_frameData.size; @@ -186,6 +186,8 @@ void Frame::renderFrame() }); }); + state->renderingSemaphore.frameEnd(); + auto end = std::chrono::steady_clock::now(); m_duration = std::chrono::duration(end - start).count(); }); diff --git a/libs/helium/BaseDevice.cpp b/libs/helium/BaseDevice.cpp index 5a17c903..93422a81 100644 --- a/libs/helium/BaseDevice.cpp +++ b/libs/helium/BaseDevice.cpp @@ -143,7 +143,7 @@ void BaseDevice::unmapParameterArray(ANARIObject o, const char *name) auto *obj = (BaseObject *)o; auto *array = obj->getParamObject(name); - array->unmap(); + unmapArray((ANARIArray)array); } void BaseDevice::commitParameters(ANARIObject o) From a48e734bc4d9a75415d37d026ccc565acc76e22b Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Thu, 16 Nov 2023 10:07:41 -0600 Subject: [PATCH 28/34] advertise KHR_DEVICE_SYNCHRONIZATION for helide --- libs/helide/HelideDeviceQueries.cpp | 349 ++++++++++++++-------------- libs/helide/HelideDeviceQueries.h | 2 +- libs/helide/helide_device.json | 1 + 3 files changed, 178 insertions(+), 174 deletions(-) diff --git a/libs/helide/HelideDeviceQueries.cpp b/libs/helide/HelideDeviceQueries.cpp index 0b6461cd..9b9e307e 100644 --- a/libs/helide/HelideDeviceQueries.cpp +++ b/libs/helide/HelideDeviceQueries.cpp @@ -81,6 +81,7 @@ const char ** query_extensions() { "ANARI_KHR_INSTANCE_TRANSFORM", "ANARI_KHR_CAMERA_ORTHOGRAPHIC", "ANARI_KHR_CAMERA_PERSPECTIVE", + "ANARI_KHR_DEVICE_SYNCHRONIZATION", "ANARI_KHR_FRAME_CHANNEL_PRIMITIVE_ID", "ANARI_KHR_FRAME_CHANNEL_OBJECT_ID", "ANARI_KHR_FRAME_CHANNEL_INSTANCE_ID", @@ -610,7 +611,7 @@ static const void * ANARI_FRAME_channel_primitiveId_info(ANARIDataType paramType static const char *extension = "KHR_FRAME_CHANNEL_PRIMITIVE_ID"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 3; + static const int32_t value = 4; return &value; } default: return nullptr; @@ -642,7 +643,7 @@ static const void * ANARI_FRAME_channel_objectId_info(ANARIDataType paramType, i static const char *extension = "KHR_FRAME_CHANNEL_OBJECT_ID"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 5; return &value; } default: return nullptr; @@ -674,7 +675,7 @@ static const void * ANARI_FRAME_channel_instanceId_info(ANARIDataType paramType, static const char *extension = "KHR_FRAME_CHANNEL_INSTANCE_ID"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -1008,7 +1009,7 @@ static const void * ANARI_SURFACE_id_info(ANARIDataType paramType, int infoName, static const char *extension = "KHR_FRAME_CHANNEL_OBJECT_ID"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 5; return &value; } default: return nullptr; @@ -1129,7 +1130,7 @@ static const void * ANARI_INSTANCE_transform_id_info(ANARIDataType paramType, in static const char *extension = "KHR_FRAME_CHANNEL_INSTANCE_ID"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 5; + static const int32_t value = 6; return &value; } default: return nullptr; @@ -1786,7 +1787,7 @@ static const void * ANARI_VOLUME__id_info(ANARIDataType paramType, int infoName, static const char *extension = "KHR_FRAME_CHANNEL_OBJECT_ID"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 4; + static const int32_t value = 5; return &value; } default: return nullptr; @@ -1819,7 +1820,7 @@ static const void * ANARI_GEOMETRY_cone_name_info(ANARIDataType paramType, int i static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -1851,7 +1852,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_color_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -1883,7 +1884,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_attribute0_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -1915,7 +1916,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_attribute1_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -1947,7 +1948,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_attribute2_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -1979,7 +1980,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_attribute3_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2011,7 +2012,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_id_info(ANARIDataType paramTyp static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2043,7 +2044,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_position_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2075,7 +2076,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_radius_info(ANARIDataType paramTy static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2107,7 +2108,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_cap_info(ANARIDataType paramType, static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2139,7 +2140,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_color_info(ANARIDataType paramTyp static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2171,7 +2172,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_attribute0_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2203,7 +2204,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_attribute1_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2235,7 +2236,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_attribute2_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2267,7 +2268,7 @@ static const void * ANARI_GEOMETRY_cone_vertex_attribute3_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2299,7 +2300,7 @@ static const void * ANARI_GEOMETRY_cone_primitive_index_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2338,7 +2339,7 @@ static const void * ANARI_GEOMETRY_cone_caps_info(ANARIDataType paramType, int i static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 6; + static const int32_t value = 7; return &value; } default: return nullptr; @@ -2403,7 +2404,7 @@ static const void * ANARI_GEOMETRY_curve_name_info(ANARIDataType paramType, int static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2435,7 +2436,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_color_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2467,7 +2468,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_attribute0_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2499,7 +2500,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_attribute1_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2531,7 +2532,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_attribute2_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2563,7 +2564,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_attribute3_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2595,7 +2596,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_id_info(ANARIDataType paramTy static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2627,7 +2628,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_position_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2659,7 +2660,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_radius_info(ANARIDataType paramT static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2691,7 +2692,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_color_info(ANARIDataType paramTy static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2723,7 +2724,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_attribute0_info(ANARIDataType pa static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2755,7 +2756,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_attribute1_info(ANARIDataType pa static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2787,7 +2788,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_attribute2_info(ANARIDataType pa static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2819,7 +2820,7 @@ static const void * ANARI_GEOMETRY_curve_vertex_attribute3_info(ANARIDataType pa static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2851,7 +2852,7 @@ static const void * ANARI_GEOMETRY_curve_primitive_index_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2876,7 +2877,7 @@ static const void * ANARI_GEOMETRY_curve_radius_info(ANARIDataType paramType, in static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 7; + static const int32_t value = 8; return &value; } default: return nullptr; @@ -2939,7 +2940,7 @@ static const void * ANARI_GEOMETRY_cylinder_name_info(ANARIDataType paramType, i static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -2971,7 +2972,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_color_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3003,7 +3004,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_attribute0_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3035,7 +3036,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_attribute1_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3067,7 +3068,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_attribute2_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3099,7 +3100,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_attribute3_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3131,7 +3132,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_id_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3163,7 +3164,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_position_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3195,7 +3196,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_cap_info(ANARIDataType paramT static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3227,7 +3228,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_color_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3259,7 +3260,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_attribute0_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3291,7 +3292,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_attribute1_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3323,7 +3324,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_attribute2_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3355,7 +3356,7 @@ static const void * ANARI_GEOMETRY_cylinder_vertex_attribute3_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3387,7 +3388,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_index_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3419,7 +3420,7 @@ static const void * ANARI_GEOMETRY_cylinder_primitive_radius_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3444,7 +3445,7 @@ static const void * ANARI_GEOMETRY_cylinder_radius_info(ANARIDataType paramType, static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3483,7 +3484,7 @@ static const void * ANARI_GEOMETRY_cylinder_caps_info(ANARIDataType paramType, i static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 8; + static const int32_t value = 9; return &value; } default: return nullptr; @@ -3550,7 +3551,7 @@ static const void * ANARI_GEOMETRY_quad_name_info(ANARIDataType paramType, int i static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3582,7 +3583,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_color_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3614,7 +3615,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_attribute0_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3646,7 +3647,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_attribute1_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3678,7 +3679,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_attribute2_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3710,7 +3711,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_attribute3_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3742,7 +3743,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_id_info(ANARIDataType paramTyp static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3774,7 +3775,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_position_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3806,7 +3807,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_normal_info(ANARIDataType paramTy static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3838,7 +3839,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_tangent_info(ANARIDataType paramT static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3870,7 +3871,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_color_info(ANARIDataType paramTyp static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3902,7 +3903,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_attribute0_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3934,7 +3935,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_attribute1_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3966,7 +3967,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_attribute2_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -3998,7 +3999,7 @@ static const void * ANARI_GEOMETRY_quad_vertex_attribute3_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4030,7 +4031,7 @@ static const void * ANARI_GEOMETRY_quad_primitive_index_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 9; + static const int32_t value = 10; return &value; } default: return nullptr; @@ -4093,7 +4094,7 @@ static const void * ANARI_GEOMETRY_sphere_name_info(ANARIDataType paramType, int static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4125,7 +4126,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_color_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4157,7 +4158,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_attribute0_info(ANARIDataTyp static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4189,7 +4190,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_attribute1_info(ANARIDataTyp static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4221,7 +4222,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_attribute2_info(ANARIDataTyp static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4253,7 +4254,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_attribute3_info(ANARIDataTyp static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4285,7 +4286,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_id_info(ANARIDataType paramT static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4317,7 +4318,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_position_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4349,7 +4350,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_radius_info(ANARIDataType param static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4381,7 +4382,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_color_info(ANARIDataType paramT static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4413,7 +4414,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_attribute0_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4445,7 +4446,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_attribute1_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4477,7 +4478,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_attribute2_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4509,7 +4510,7 @@ static const void * ANARI_GEOMETRY_sphere_vertex_attribute3_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4541,7 +4542,7 @@ static const void * ANARI_GEOMETRY_sphere_primitive_index_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4566,7 +4567,7 @@ static const void * ANARI_GEOMETRY_sphere_radius_info(ANARIDataType paramType, i static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 10; + static const int32_t value = 11; return &value; } default: return nullptr; @@ -4629,7 +4630,7 @@ static const void * ANARI_GEOMETRY_triangle_name_info(ANARIDataType paramType, i static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -4661,7 +4662,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_color_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -4693,7 +4694,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_attribute0_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -4725,7 +4726,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_attribute1_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -4757,7 +4758,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_attribute2_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -4789,7 +4790,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_attribute3_info(ANARIDataT static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -4821,7 +4822,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_id_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -4853,7 +4854,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_position_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -4885,7 +4886,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_normal_info(ANARIDataType par static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -4917,7 +4918,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_tangent_info(ANARIDataType pa static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -4949,7 +4950,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_color_info(ANARIDataType para static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -4981,7 +4982,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_attribute0_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -5013,7 +5014,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_attribute1_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -5045,7 +5046,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_attribute2_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -5077,7 +5078,7 @@ static const void * ANARI_GEOMETRY_triangle_vertex_attribute3_info(ANARIDataType static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -5109,7 +5110,7 @@ static const void * ANARI_GEOMETRY_triangle_primitive_index_info(ANARIDataType p static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 11; + static const int32_t value = 12; return &value; } default: return nullptr; @@ -5172,7 +5173,7 @@ static const void * ANARI_MATERIAL_matte_name_info(ANARIDataType paramType, int static const char *extension = "KHR_MATERIAL_MATTE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5217,7 +5218,7 @@ static const void * ANARI_MATERIAL_matte_color_info(ANARIDataType paramType, int static const char *extension = "KHR_MATERIAL_MATTE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5256,7 +5257,7 @@ static const void * ANARI_MATERIAL_matte_opacity_info(ANARIDataType paramType, i static const char *extension = "KHR_MATERIAL_MATTE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5295,7 +5296,7 @@ static const void * ANARI_MATERIAL_matte_alphaMode_info(ANARIDataType paramType, static const char *extension = "KHR_MATERIAL_MATTE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5327,7 +5328,7 @@ static const void * ANARI_MATERIAL_matte_alphaCutoff_info(ANARIDataType paramTyp static const char *extension = "KHR_MATERIAL_MATTE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 12; + static const int32_t value = 13; return &value; } default: return nullptr; @@ -5368,7 +5369,7 @@ static const void * ANARI_SAMPLER_image1D_name_info(ANARIDataType paramType, int static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 13; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5400,7 +5401,7 @@ static const void * ANARI_SAMPLER_image1D_image_info(ANARIDataType paramType, in static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 13; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5439,7 +5440,7 @@ static const void * ANARI_SAMPLER_image1D_inAttribute_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 13; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5478,7 +5479,7 @@ static const void * ANARI_SAMPLER_image1D_filter_info(ANARIDataType paramType, i static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 13; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5517,7 +5518,7 @@ static const void * ANARI_SAMPLER_image1D_wrapMode1_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 13; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5549,7 +5550,7 @@ static const void * ANARI_SAMPLER_image1D_inTransform_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 13; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5581,7 +5582,7 @@ static const void * ANARI_SAMPLER_image1D_inOffset_info(ANARIDataType paramType, static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 13; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5613,7 +5614,7 @@ static const void * ANARI_SAMPLER_image1D_outTransform_info(ANARIDataType paramT static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 13; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5645,7 +5646,7 @@ static const void * ANARI_SAMPLER_image1D_outOffset_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 13; + static const int32_t value = 14; return &value; } default: return nullptr; @@ -5694,7 +5695,7 @@ static const void * ANARI_SAMPLER_image2D_name_info(ANARIDataType paramType, int static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -5726,7 +5727,7 @@ static const void * ANARI_SAMPLER_image2D_image_info(ANARIDataType paramType, in static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -5765,7 +5766,7 @@ static const void * ANARI_SAMPLER_image2D_inAttribute_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -5804,7 +5805,7 @@ static const void * ANARI_SAMPLER_image2D_filter_info(ANARIDataType paramType, i static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -5843,7 +5844,7 @@ static const void * ANARI_SAMPLER_image2D_wrapMode1_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -5882,7 +5883,7 @@ static const void * ANARI_SAMPLER_image2D_wrapMode2_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -5914,7 +5915,7 @@ static const void * ANARI_SAMPLER_image2D_inTransform_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -5946,7 +5947,7 @@ static const void * ANARI_SAMPLER_image2D_inOffset_info(ANARIDataType paramType, static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -5978,7 +5979,7 @@ static const void * ANARI_SAMPLER_image2D_outTransform_info(ANARIDataType paramT static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -6010,7 +6011,7 @@ static const void * ANARI_SAMPLER_image2D_outOffset_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 14; + static const int32_t value = 15; return &value; } default: return nullptr; @@ -6061,7 +6062,7 @@ static const void * ANARI_SAMPLER_image3D_name_info(ANARIDataType paramType, int static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6093,7 +6094,7 @@ static const void * ANARI_SAMPLER_image3D_image_info(ANARIDataType paramType, in static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6132,7 +6133,7 @@ static const void * ANARI_SAMPLER_image3D_inAttribute_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6171,7 +6172,7 @@ static const void * ANARI_SAMPLER_image3D_filter_info(ANARIDataType paramType, i static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6210,7 +6211,7 @@ static const void * ANARI_SAMPLER_image3D_wrapMode1_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6249,7 +6250,7 @@ static const void * ANARI_SAMPLER_image3D_wrapMode2_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6288,7 +6289,7 @@ static const void * ANARI_SAMPLER_image3D_wrapMode3_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6320,7 +6321,7 @@ static const void * ANARI_SAMPLER_image3D_inTransform_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6352,7 +6353,7 @@ static const void * ANARI_SAMPLER_image3D_inOffset_info(ANARIDataType paramType, static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6384,7 +6385,7 @@ static const void * ANARI_SAMPLER_image3D_outTransform_info(ANARIDataType paramT static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6416,7 +6417,7 @@ static const void * ANARI_SAMPLER_image3D_outOffset_info(ANARIDataType paramType static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 15; + static const int32_t value = 16; return &value; } default: return nullptr; @@ -6469,7 +6470,7 @@ static const void * ANARI_SAMPLER_primitive_name_info(ANARIDataType paramType, i static const char *extension = "KHR_SAMPLER_PRIMITIVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 16; + static const int32_t value = 17; return &value; } default: return nullptr; @@ -6501,7 +6502,7 @@ static const void * ANARI_SAMPLER_primitive_array_info(ANARIDataType paramType, static const char *extension = "KHR_SAMPLER_PRIMITIVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 16; + static const int32_t value = 17; return &value; } default: return nullptr; @@ -6533,7 +6534,7 @@ static const void * ANARI_SAMPLER_primitive_inOffset_info(ANARIDataType paramTyp static const char *extension = "KHR_SAMPLER_PRIMITIVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 16; + static const int32_t value = 17; return &value; } default: return nullptr; @@ -6570,7 +6571,7 @@ static const void * ANARI_SAMPLER_transform_name_info(ANARIDataType paramType, i static const char *extension = "KHR_SAMPLER_TRANSFORM"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 17; + static const int32_t value = 18; return &value; } default: return nullptr; @@ -6609,7 +6610,7 @@ static const void * ANARI_SAMPLER_transform_inAttribute_info(ANARIDataType param static const char *extension = "KHR_SAMPLER_TRANSFORM"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 17; + static const int32_t value = 18; return &value; } default: return nullptr; @@ -6641,7 +6642,7 @@ static const void * ANARI_SAMPLER_transform_outTransform_info(ANARIDataType para static const char *extension = "KHR_SAMPLER_TRANSFORM"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 17; + static const int32_t value = 18; return &value; } default: return nullptr; @@ -6673,7 +6674,7 @@ static const void * ANARI_SAMPLER_transform_outOffset_info(ANARIDataType paramTy static const char *extension = "KHR_SAMPLER_TRANSFORM"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 17; + static const int32_t value = 18; return &value; } default: return nullptr; @@ -6712,7 +6713,7 @@ static const void * ANARI_SPATIAL_FIELD_structuredRegular_name_info(ANARIDataTyp static const char *extension = "KHR_SPATIAL_FIELD_STRUCTURED_REGULAR"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 18; + static const int32_t value = 19; return &value; } default: return nullptr; @@ -6744,7 +6745,7 @@ static const void * ANARI_SPATIAL_FIELD_structuredRegular_data_info(ANARIDataTyp static const char *extension = "KHR_SPATIAL_FIELD_STRUCTURED_REGULAR"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 18; + static const int32_t value = 19; return &value; } default: return nullptr; @@ -6776,7 +6777,7 @@ static const void * ANARI_SPATIAL_FIELD_structuredRegular_origin_info(ANARIDataT static const char *extension = "KHR_SPATIAL_FIELD_STRUCTURED_REGULAR"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 18; + static const int32_t value = 19; return &value; } default: return nullptr; @@ -6808,7 +6809,7 @@ static const void * ANARI_SPATIAL_FIELD_structuredRegular_spacing_info(ANARIData static const char *extension = "KHR_SPATIAL_FIELD_STRUCTURED_REGULAR"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 18; + static const int32_t value = 19; return &value; } default: return nullptr; @@ -6847,7 +6848,7 @@ static const void * ANARI_SPATIAL_FIELD_structuredRegular_filter_info(ANARIDataT static const char *extension = "KHR_SPATIAL_FIELD_STRUCTURED_REGULAR"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 18; + static const int32_t value = 19; return &value; } default: return nullptr; @@ -6888,7 +6889,7 @@ static const void * ANARI_VOLUME_transferFunction1D_name_info(ANARIDataType para static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 19; + static const int32_t value = 20; return &value; } default: return nullptr; @@ -6913,7 +6914,7 @@ static const void * ANARI_VOLUME_transferFunction1D_value_info(ANARIDataType par static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 19; + static const int32_t value = 20; return &value; } default: return nullptr; @@ -6945,7 +6946,7 @@ static const void * ANARI_VOLUME_transferFunction1D_valueRange_info(ANARIDataTyp static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 19; + static const int32_t value = 20; return &value; } default: return nullptr; @@ -6977,7 +6978,7 @@ static const void * ANARI_VOLUME_transferFunction1D_color_info(ANARIDataType par static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 19; + static const int32_t value = 20; return &value; } default: return nullptr; @@ -7009,7 +7010,7 @@ static const void * ANARI_VOLUME_transferFunction1D_opacity_info(ANARIDataType p static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 19; + static const int32_t value = 20; return &value; } default: return nullptr; @@ -7041,7 +7042,7 @@ static const void * ANARI_VOLUME_transferFunction1D_unitDistance_info(ANARIDataT static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int32_t value = 19; + static const int32_t value = 20; return &value; } default: return nullptr; @@ -7220,6 +7221,7 @@ static const void * ANARI_DEVICE_info(int infoName, ANARIDataType infoType) { "ANARI_KHR_INSTANCE_TRANSFORM", "ANARI_KHR_CAMERA_ORTHOGRAPHIC", "ANARI_KHR_CAMERA_PERSPECTIVE", + "ANARI_KHR_DEVICE_SYNCHRONIZATION", "ANARI_KHR_FRAME_CHANNEL_PRIMITIVE_ID", "ANARI_KHR_FRAME_CHANNEL_OBJECT_ID", "ANARI_KHR_FRAME_CHANNEL_INSTANCE_ID", @@ -7272,6 +7274,7 @@ static const void * ANARI_RENDERER_default_info(int infoName, ANARIDataType info "ANARI_KHR_INSTANCE_TRANSFORM", "ANARI_KHR_CAMERA_ORTHOGRAPHIC", "ANARI_KHR_CAMERA_PERSPECTIVE", + "ANARI_KHR_DEVICE_SYNCHRONIZATION", "ANARI_KHR_FRAME_CHANNEL_PRIMITIVE_ID", "ANARI_KHR_FRAME_CHANNEL_OBJECT_ID", "ANARI_KHR_FRAME_CHANNEL_INSTANCE_ID", @@ -7597,7 +7600,7 @@ static const void * ANARI_VOLUME__info(int infoName, ANARIDataType infoType) { static const char *extension = "KHR_FRAME_CHANNEL_OBJECT_ID"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 4; + static const int value = 5; return &value; } else { return nullptr; @@ -7643,7 +7646,7 @@ static const void * ANARI_GEOMETRY_cone_info(int infoName, ANARIDataType infoTyp static const char *extension = "KHR_GEOMETRY_CONE"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 6; + static const int value = 7; return &value; } else { return nullptr; @@ -7688,7 +7691,7 @@ static const void * ANARI_GEOMETRY_curve_info(int infoName, ANARIDataType infoTy static const char *extension = "KHR_GEOMETRY_CURVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 7; + static const int value = 8; return &value; } else { return nullptr; @@ -7735,7 +7738,7 @@ static const void * ANARI_GEOMETRY_cylinder_info(int infoName, ANARIDataType inf static const char *extension = "KHR_GEOMETRY_CYLINDER"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 8; + static const int value = 9; return &value; } else { return nullptr; @@ -7780,7 +7783,7 @@ static const void * ANARI_GEOMETRY_quad_info(int infoName, ANARIDataType infoTyp static const char *extension = "KHR_GEOMETRY_QUAD"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 9; + static const int value = 10; return &value; } else { return nullptr; @@ -7825,7 +7828,7 @@ static const void * ANARI_GEOMETRY_sphere_info(int infoName, ANARIDataType infoT static const char *extension = "KHR_GEOMETRY_SPHERE"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 10; + static const int value = 11; return &value; } else { return nullptr; @@ -7870,7 +7873,7 @@ static const void * ANARI_GEOMETRY_triangle_info(int infoName, ANARIDataType inf static const char *extension = "KHR_GEOMETRY_TRIANGLE"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 11; + static const int value = 12; return &value; } else { return nullptr; @@ -7908,7 +7911,7 @@ static const void * ANARI_MATERIAL_matte_info(int infoName, ANARIDataType infoTy static const char *extension = "KHR_MATERIAL_MATTE"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 12; + static const int value = 13; return &value; } else { return nullptr; @@ -7946,7 +7949,7 @@ static const void * ANARI_SAMPLER_image1D_info(int infoName, ANARIDataType infoT static const char *extension = "KHR_SAMPLER_IMAGE1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 13; + static const int value = 14; return &value; } else { return nullptr; @@ -7985,7 +7988,7 @@ static const void * ANARI_SAMPLER_image2D_info(int infoName, ANARIDataType infoT static const char *extension = "KHR_SAMPLER_IMAGE2D"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 14; + static const int value = 15; return &value; } else { return nullptr; @@ -8025,7 +8028,7 @@ static const void * ANARI_SAMPLER_image3D_info(int infoName, ANARIDataType infoT static const char *extension = "KHR_SAMPLER_IMAGE3D"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 15; + static const int value = 16; return &value; } else { return nullptr; @@ -8057,7 +8060,7 @@ static const void * ANARI_SAMPLER_primitive_info(int infoName, ANARIDataType inf static const char *extension = "KHR_SAMPLER_PRIMITIVE"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 16; + static const int value = 17; return &value; } else { return nullptr; @@ -8090,7 +8093,7 @@ static const void * ANARI_SAMPLER_transform_info(int infoName, ANARIDataType inf static const char *extension = "KHR_SAMPLER_TRANSFORM"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 17; + static const int value = 18; return &value; } else { return nullptr; @@ -8124,7 +8127,7 @@ static const void * ANARI_SPATIAL_FIELD_structuredRegular_info(int infoName, ANA static const char *extension = "KHR_SPATIAL_FIELD_STRUCTURED_REGULAR"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 18; + static const int value = 19; return &value; } else { return nullptr; @@ -8163,7 +8166,7 @@ static const void * ANARI_VOLUME_transferFunction1D_info(int infoName, ANARIData static const char *extension = "KHR_VOLUME_TRANSFER_FUNCTION1D"; return extension; } else if(infoType == ANARI_INT32) { - static const int value = 19; + static const int value = 20; return &value; } else { return nullptr; diff --git a/libs/helide/HelideDeviceQueries.h b/libs/helide/HelideDeviceQueries.h index 3b6c7f0d..a0af4d36 100644 --- a/libs/helide/HelideDeviceQueries.h +++ b/libs/helide/HelideDeviceQueries.h @@ -18,7 +18,7 @@ namespace helide { #define ANARI_INFO_parameter 9 #define ANARI_INFO_channel 10 #define ANARI_INFO_use 11 -const int extension_count = 20; +const int extension_count = 21; const char ** query_extensions(); const char ** query_object_types(ANARIDataType type); const ANARIParameter * query_params(ANARIDataType type, const char *subtype); diff --git a/libs/helide/helide_device.json b/libs/helide/helide_device.json index 4fb681fa..2847690d 100644 --- a/libs/helide/helide_device.json +++ b/libs/helide/helide_device.json @@ -8,6 +8,7 @@ "khr_instance_transform", "khr_camera_orthographic", "khr_camera_perspective", + "khr_device_synchronization", "khr_frame_channel_primitive_id", "khr_frame_channel_object_id", "khr_frame_channel_instance_id", From 5491351c62393e7aa28590f77174e2e78b356b60 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Mon, 20 Nov 2023 21:35:03 -0600 Subject: [PATCH 29/34] remove extra synchronization/flush calls in helide --- libs/helide/frame/Frame.cpp | 2 -- libs/helide/scene/Group.cpp | 2 -- libs/helide/scene/World.cpp | 5 +---- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/libs/helide/frame/Frame.cpp b/libs/helide/frame/Frame.cpp index 9dce286e..d6bab565 100644 --- a/libs/helide/frame/Frame.cpp +++ b/libs/helide/frame/Frame.cpp @@ -135,8 +135,6 @@ bool Frame::getProperty( const std::string_view &name, ANARIDataType type, void *ptr, uint32_t flags) { if (type == ANARI_FLOAT32 && name == "duration") { - if (flags & ANARI_WAIT) - wait(); helium::writeToVoidP(ptr, m_duration); return true; } diff --git a/libs/helide/scene/Group.cpp b/libs/helide/scene/Group.cpp index d1a97b75..a06aa908 100644 --- a/libs/helide/scene/Group.cpp +++ b/libs/helide/scene/Group.cpp @@ -23,8 +23,6 @@ bool Group::getProperty( { if (name == "bounds" && type == ANARI_FLOAT32_BOX3) { if (flags & ANARI_WAIT) { - deviceState()->waitOnCurrentFrame(); - deviceState()->commitBufferFlush(); embreeSceneConstruct(); embreeSceneCommit(); } diff --git a/libs/helide/scene/World.cpp b/libs/helide/scene/World.cpp index c6168a72..f60280f4 100644 --- a/libs/helide/scene/World.cpp +++ b/libs/helide/scene/World.cpp @@ -28,11 +28,8 @@ bool World::getProperty( const std::string_view &name, ANARIDataType type, void *ptr, uint32_t flags) { if (name == "bounds" && type == ANARI_FLOAT32_BOX3) { - if (flags & ANARI_WAIT) { - deviceState()->waitOnCurrentFrame(); - deviceState()->commitBufferFlush(); + if (flags & ANARI_WAIT) embreeSceneUpdate(); - } auto bounds = getEmbreeSceneBounds(m_embreeScene); for (auto *i : instances()) { for (auto *v : i->group()->volumes()) { From e3c7d1800bae56d1836b5ce4bd88b8d6850e8e8d Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Tue, 21 Nov 2023 21:34:32 -0600 Subject: [PATCH 30/34] update Dear ImGui to v1.90 --- libs/anari_viewer/external/imgui/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/anari_viewer/external/imgui/CMakeLists.txt b/libs/anari_viewer/external/imgui/CMakeLists.txt index 939c2174..82abc4df 100644 --- a/libs/anari_viewer/external/imgui/CMakeLists.txt +++ b/libs/anari_viewer/external/imgui/CMakeLists.txt @@ -5,9 +5,9 @@ project(anari_viewer_imgui_glfw LANGUAGES CXX) anari_sdk_fetch_project( NAME ${PROJECT_NAME} - # v1.89 docking branch - URL https://github.com/ocornut/imgui/archive/9964740a47fda96ee937cfea272ccac85dc6a500.zip - MD5 8294d2fbceafcda4ebddf38f4ea2d4e8 + # v1.90 docking branch + URL https://github.com/ocornut/imgui/archive/ce0d0ac8298ce164b5d862577e8b087d92f6e90e.zip + MD5 40f838f4235dfc17a9ab5b3b96b33c6c ) include(CMakeFindDependencyMacro) From c166cd7f2a87f0486a237bef9dd9758074573fda Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Tue, 21 Nov 2023 21:38:22 -0600 Subject: [PATCH 31/34] update nfd to v1.1.1 --- libs/anari_viewer/external/nativefiledialog/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/anari_viewer/external/nativefiledialog/CMakeLists.txt b/libs/anari_viewer/external/nativefiledialog/CMakeLists.txt index fb50004b..af15a741 100644 --- a/libs/anari_viewer/external/nativefiledialog/CMakeLists.txt +++ b/libs/anari_viewer/external/nativefiledialog/CMakeLists.txt @@ -6,8 +6,8 @@ project(anari_viewer_nfd LANGUAGES CXX) set(BUILD_SHARED_LIBS OFF) anari_sdk_fetch_project( NAME ${PROJECT_NAME} - URL https://github.com/btzy/nativefiledialog-extended/archive/refs/tags/v1.0.3.zip - MD5 7fd07c47f60a6db4798c705d075e610f + URL https://github.com/btzy/nativefiledialog-extended/archive/refs/tags/v1.1.1.zip + MD5 e1f5d8ec9af4ea160b55fbef1a646e95 ADD_SUBDIR ) From b73621e57fb8677e844a3189eb426b11bebccb3c Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Wed, 22 Nov 2023 23:08:59 -0500 Subject: [PATCH 32/34] Blender 4.x add-on (#173) * initial Blender add-on * Add per device custom renderers in blender * Add anari object to blender property translator * Generate per device property panels dynamically * Fix library loading and add renderer enum selector in ui * Fix issue of custom renderers accidentally referring to the same name * Add renderer parameters on device level * Block name parameter from being shown in blender ui * grey out inactive options * Renderer selection from new parameters * Blender UI actually updates renderer params * Try to fix renderer switching * Actually fix renderer switching * Add some more material parameters and handle material updates * Add readme and move library list to the top * allow Blender 4.x * "Fix" principled material for blender 4 and roll back some questionable material support --------- Co-authored-by: Jakob Progsch --- code_gen/pyanari_build.py | 14 +- examples/CMakeLists.txt | 1 + examples/blender/CMakeLists.txt | 32 + examples/blender/CustomAnariRender.py | 1029 +++++++++++++++++++++++++ examples/blender/README.md | 26 + 5 files changed, 1096 insertions(+), 6 deletions(-) create mode 100644 examples/blender/CMakeLists.txt create mode 100644 examples/blender/CustomAnariRender.py create mode 100644 examples/blender/README.md diff --git a/code_gen/pyanari_build.py b/code_gen/pyanari_build.py index 8467d7a6..b5fbd4ad 100644 --- a/code_gen/pyanari_build.py +++ b/code_gen/pyanari_build.py @@ -168,8 +168,6 @@ def _from_type_list(x): def _from_parameter_list(x): result = [] if x != ffi.NULL: - print(x) - print(x[0].name) i = 0 while x[i].name != ffi.NULL: result.append((str(ffi.string(x[i].name), 'utf-8'), x[i].type)) @@ -189,7 +187,7 @@ def _convert_pointer(dataType, x): elif dataType == lib.ANARI_PARAMETER_LIST: return _from_parameter_list(x) elif dataType == lib.ANARI_STRING: - return str(ffi.string(x[i]), 'utf-8') + return str(ffi.string(x), 'utf-8') elif _elements[dataType]==1: return x[0] elif _elements[dataType]==2: @@ -219,9 +217,13 @@ def _convert_pointer(dataType, x): ''', 'anariLoadLibrary' : - '''def anariLoadLibrary(name, callback): - device = lib.anariLoadLibrary(name.encode('utf-8'), lib.ANARIStatusCallback_python, callback) - return ffi.gc(device, lib.anariUnloadLibrary) + '''def anariLoadLibrary(name, callback = ffi.NULL): + cbwrapper = ffi.NULL if callback == ffi.NULL else lib.ANARIStatusCallback_python + device = lib.anariLoadLibrary(name.encode('utf-8'), cbwrapper, callback) + if device == ffi.NULL: + return None + else: + return ffi.gc(device, lib.anariUnloadLibrary) ''', 'anariNewArray1D' : diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index a6b1adde..459aefa1 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -9,3 +9,4 @@ option(BUILD_VIEWER "Build interactive viewer app (requires GLFW)" OFF) if (BUILD_VIEWER) add_subdirectory(viewer) endif() +add_subdirectory(blender) diff --git a/examples/blender/CMakeLists.txt b/examples/blender/CMakeLists.txt new file mode 100644 index 00000000..3890e0d9 --- /dev/null +++ b/examples/blender/CMakeLists.txt @@ -0,0 +1,32 @@ +## Copyright 2021 The Khronos Group +## SPDX-License-Identifier: Apache-2.0 + +set(BLENDER_DIR "" CACHE PATH "Blender Directory") + +if(BLENDER_DIR) + file(GLOB BLENDER_VERSION_DIR ${BLENDER_DIR}/[2-4].[0-9]) + if(BLENDER_VERSION_DIR) + file(GLOB BLENDER_PYTHON_EXECUTABLE ${BLENDER_VERSION_DIR}/python/bin/python3.*) + file(GLOB BLENDER_PYTHON_LIBS ${BLENDER_VERSION_DIR}/python/lib/python3.*) + + add_custom_target(blender_anari ALL + COMMAND + ${BLENDER_PYTHON_EXECUTABLE} -m ensurepip && + ${BLENDER_PYTHON_EXECUTABLE} -m pip install cffi + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS python_bindings + ) + + install( + FILES + ${CMAKE_BINARY_DIR}/code_gen/anari.py + ${CMAKE_BINARY_DIR}/code_gen/pyanari.so + DESTINATION ${BLENDER_PYTHON_LIBS} + ) + install( + FILES + CustomAnariRender.py + DESTINATION ${BLENDER_VERSION_DIR}/scripts/addons/ + ) + endif() +endif() diff --git a/examples/blender/CustomAnariRender.py b/examples/blender/CustomAnariRender.py new file mode 100644 index 00000000..b56d4b8b --- /dev/null +++ b/examples/blender/CustomAnariRender.py @@ -0,0 +1,1029 @@ +# Copyright 2021 The Khronos Group +# SPDX-License-Identifier: Apache-2.0 + +import bpy +import array +import gpu +import math +import dataclasses +import copy +from mathutils import Vector +from gpu_extras.presets import draw_texture_2d +from bl_ui.properties_render import RenderButtonsPanel +from bpy.types import Panel +import numpy as np +from anari import * + +# the plugin will attempt to use these anari library names +librarynames = ['helide', 'visrtx', 'visgl'] + +bl_info = { + "name": "Custom ANARI renderer", + "blender": (3, 5, 0), + "Description": "ANARI renderer integration", + "category": "Render", +} + +prefixes = { + lib.ANARI_SEVERITY_FATAL_ERROR : "FATAL", + lib.ANARI_SEVERITY_ERROR : "ERROR", + lib.ANARI_SEVERITY_WARNING : "WARNING", + lib.ANARI_SEVERITY_PERFORMANCE_WARNING : "PERFORMANCE", + lib.ANARI_SEVERITY_INFO : "INFO", + lib.ANARI_SEVERITY_DEBUG : "DEBUG" +} + +renderer_enum_info = [("default", "default", "default")] +anari_in_use = 0 + +def anari_status(device, source, sourceType, severity, code, message): + print('[%s]: '%prefixes[severity]+message) + +def get_renderer_enum_info(self, context): + global renderer_enum_info + return renderer_enum_info + +status_handle = ffi.new_handle(anari_status) #something needs to keep this handle alive + +class ANARISceneProperties(bpy.types.PropertyGroup): + debug: bpy.props.BoolProperty(name = "debug", default = False) + trace: bpy.props.BoolProperty(name = "trace", default = False) + + accumulation: bpy.props.BoolProperty(name = "accumulation", default = False) + iterations: bpy.props.IntProperty(name = "iterations", default = 8) + + @classmethod + def register(cls): + bpy.types.Scene.anari = bpy.props.PointerProperty( + name="ANARI Scene Settings", + description="ANARI scene settings", + type=cls, + ) + + @classmethod + def unregister(cls): + del bpy.types.Scene.anari + + + + +class RENDER_PT_anari(RenderButtonsPanel, Panel): + bl_label = "ANARI" + COMPAT_ENGINES = set() + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + global anari_in_use + col = layout.column() + col.enabled = anari_in_use == 0 + col.prop(context.scene.anari, 'debug') + if context.scene.anari.debug: + col.prop(context.scene.anari, 'trace') + + col = layout.column() + col.prop(context.scene.anari, 'accumulation') + + col = layout.column() + col.enabled = context.scene.anari.accumulation + col.prop(context.scene.anari, 'iterations') + + + +class ANARIRenderEngine(bpy.types.RenderEngine): + # These three members are used by blender to set up the + # RenderEngine; define its internal name, visible name and capabilities. + bl_use_preview = True + bl_use_shading_nodes_custom=False + + # Init is called whenever a new render engine instance is created. Multiple + # instances may exist at the same time, for example for a viewport and final + # render. + def __init__(self): + dummy = gpu.types.GPUFrameBuffer() + dummy.bind() + + self.scene_data = None + self.draw_data = None + + global anari_in_use + anari_in_use = anari_in_use + 1 + + self.library = anariLoadLibrary(self.anari_library_name, status_handle) + if not self.library: + #if loading the library fails substitute the sink device + self.library = anariLoadLibrary('sink', status_handle) + + self.device = anariNewDevice(self.library, self.anari_device_name) + anariCommitParameters(self.device, self.device) + + features = anariGetDeviceExtensions(self.library, "default") + + rendererParameters = anariGetObjectInfo(self.device, ANARI_RENDERER, "default", "parameter", ANARI_PARAMETER_LIST) + + if bpy.context.scene.anari.debug: + nested = self.device + self.debug = anariLoadLibrary('debug', status_handle) + self.device = anariNewDevice(self.debug, 'debug') + anariSetParameter(self.device, self.device, 'wrappedDevice', ANARI_DEVICE, nested) + if bpy.context.scene.anari.debug: + anariSetParameter(self.device, self.device, 'traceMode', ANARI_STRING, 'code') + anariCommitParameters(self.device, self.device) + + self.width = 0 + self.height = 0 + self.frame = None + self.camera = None + self.camera_data = None + self.perspective = anariNewCamera(self.device, 'perspective') + self.ortho = anariNewCamera(self.device, 'orthographic') + self.world = anariNewWorld(self.device) + self.current_renderer = "default" + self.renderer = anariNewRenderer(self.device, self.current_renderer) + anariCommitParameters(self.device, self.renderer) + + self.default_material = anariNewMaterial(self.device, 'matte') + anariCommitParameters(self.device, self.default_material) + + self.meshes = dict() + self.lights = dict() + self.arrays = dict() + self.images = dict() + self.samplers = dict() + self.materials = dict() + + self.scene_instances = [] + + self.gputexture = None + self.rendering = False + self.scene_updated = False + self.iteration = 0 + self.epoch = 0 + self.rendered_epoch = 0 + + # When the render engine instance is destroyed, this is called. Clean up any + # render engine data here, for example stopping running render threads. + def __del__(self): + global anari_in_use + anari_in_use = anari_in_use - 1 + + def scene_changed(self): + self.scene_updated = True + self.iteration = 0 + self.epoch += 1 + + def render_converged(self): + threshold = 1 + if bpy.context.scene.anari.accumulation: + threshold = bpy.context.scene.anari.iterations + + return self.iteration >= threshold + + def anari_frame(self, width=0, height=0): + if not self.frame: + self.frame = anariNewFrame(self.device) + anariSetParameter(self.device, self.frame, 'channel.color', ANARI_DATA_TYPE, ANARI_UFIXED8_VEC4) + + if width != 0 and height != 0: + anariSetParameter(self.device, self.frame, 'size', ANARI_UINT32_VEC2, [width, height]) + + return self.frame + + scene_data = dict() + + def project_bounds(self, origin, axis): + values = (1e20, -1.e20) + for i in range(0, 8): + corner = Vector(( + self.bounds_min[0] if (i&1)==0 else self.bounds_max[0], + self.bounds_min[1] if (i&2)==0 else self.bounds_max[1], + self.bounds_min[2] if (i&4)==0 else self.bounds_max[2], + ))-origin + v = corner.dot(axis) + values = (min(values[0], v), max(values[1], v)) + return values + + def extract_camera(self, depsgraph, width, height, region_view=None, space_view=None): + scene = depsgraph.scene + + camera = None + transform = None + fovx = 1 + zoom = 1 + + if region_view: + zoom = 4 / ((math.sqrt(2) + region_view.view_camera_zoom / 50) ** 2) + if region_view.view_perspective == 'CAMERA': + if space_view and space_view.use_local_camera: + camera = region_view.camera + else: + camera = scene.objects['Camera'] + else: + camera = scene.objects['Camera'] + + if camera: + transform = camera.matrix_world + if camera.data.type == "ORTHO": + fovx = 0 + zoom = camera.data.ortho_scale + else: + fovx = camera.data.angle_x + zoom = 1 + else: + transform = region_view.view_matrix.inverted() + if region_view.view_perspective == "ORTHO": + fovx = 0 + zoom = 1.0275 * region_view.view_distance * 35 / space_view.lens + else: + fovx = 2.0 * math.atan(36 / space_view.lens) + zoom = 1 + + cam_transform = transform.transposed() + cam_pos = cam_transform[3][0:3] + cam_view = (-cam_transform[2])[0:3] + cam_up = cam_transform[1][0:3] + + camera_data = (fovx, zoom) + tuple(cam_pos) + tuple(cam_view) + tuple(cam_up) + + # only updated if the camera actually changed + if camera_data == self.camera_data: + return None + else: + self.camera_data = camera_data + + if fovx > 0: + self.camera = self.perspective + fovy = 2.0*math.atan(math.tan(0.5*fovx)/width*height*zoom) + anariSetParameter(self.device, self.camera, 'fovy', ANARI_FLOAT32, fovy) + else: + bounds = self.project_bounds(Vector(cam_pos), Vector(cam_view)) + cam_pos = (Vector(cam_pos) + bounds[0]*Vector(cam_view))[:] + self.camera = self.ortho + anariSetParameter(self.device, self.camera, 'height', ANARI_FLOAT32, 2.0*zoom/width*height) + + + anariSetParameter(self.device, self.camera, 'aspect', ANARI_FLOAT32, width/height) + anariSetParameter(self.device, self.camera, 'position', ANARI_FLOAT32_VEC3, cam_pos) + anariSetParameter(self.device, self.camera, 'direction', ANARI_FLOAT32_VEC3, cam_view) + anariSetParameter(self.device, self.camera, 'up', ANARI_FLOAT32_VEC3, cam_up) + + anariCommitParameters(self.device, self.camera) + + return self.camera + + def get_mesh(self, name): + if name in self.meshes: + return self.meshes[name] + else: + mesh = anariNewGeometry(self.device, 'triangle') + surface = anariNewSurface(self.device) + group = anariNewGroup(self.device) + instance = anariNewInstance(self.device, "transform") + material = self.default_material + + anariSetParameter(self.device, surface, 'geometry', ANARI_GEOMETRY, mesh) + anariSetParameter(self.device, surface, 'material', ANARI_MATERIAL, material) + anariCommitParameters(self.device, surface) + + surfaces = ffi.new('ANARISurface[]', [surface]) + array = anariNewArray1D(self.device, surfaces, ANARI_SURFACE, 1) + anariSetParameter(self.device, group, 'surface', ANARI_ARRAY1D, array) + anariCommitParameters(self.device, group) + + anariSetParameter(self.device, instance, 'group', ANARI_GROUP, group) + anariCommitParameters(self.device, instance) + + result = (mesh, material, surface, group, instance) + self.meshes[name] = result + return result + + + def get_light(self, name, subtype): + if name in self.lights and self.lights[name][1] == subtype: + return self.lights[name][0] + else: + light = anariNewLight(self.device, subtype) + self.lights[name] = (light, subtype) + return light + + + def set_array(self, obj, name, atype, count, arr): + (ptr, stride) = anariMapParameterArray1D(self.device, obj, name, atype, count) + ffi.memmove(ptr, ffi.from_buffer(arr), arr.size*arr.itemsize) + anariUnmapParameterArray(self.device, obj, name) + + + def mesh_to_geometry(self, objmesh, name, mesh): + objmesh.calc_loop_triangles() + objmesh.calc_normals_split() + + indexcount = len(objmesh.loop_triangles) + npindex = np.zeros([indexcount*3], dtype=np.uint32) + objmesh.loop_triangles.foreach_get('vertices', npindex) + + loopindexcount = len(objmesh.loop_triangles) + nploopindex = np.zeros([loopindexcount*3], dtype=np.uint32) + objmesh.loop_triangles.foreach_get('loops', nploopindex) + + flatten = not np.array_equal(npindex, nploopindex) + + if not flatten: + self.set_array(mesh, 'primitive.index', ANARI_UINT32_VEC3, indexcount, npindex) + + vertexcount = len(objmesh.vertices) + npvert = np.zeros([vertexcount*3], dtype=np.float32) + objmesh.vertices.foreach_get('co', npvert) + if flatten: + npvert = npvert.reshape((vertexcount, 3)) + npvert = npvert[npindex] + vertexcount = 3*indexcount + + self.set_array(mesh, 'vertex.position', ANARI_FLOAT32_VEC3, vertexcount, npvert) + + normalcount = len(objmesh.loops) + npnormal = np.zeros([normalcount*3], dtype=np.float32) + objmesh.loops.foreach_get('normal', npnormal) + if flatten: + npnormal = npnormal.reshape((normalcount, 3)) + npnormal = npnormal[nploopindex] + normalcount = 3*loopindexcount + + self.set_array(mesh, 'vertex.normal', ANARI_FLOAT32_VEC3, normalcount, npnormal) + + if objmesh.uv_layers.active: + uvcount = len(objmesh.uv_layers.active.uv) + npuv = np.zeros([uvcount*2], dtype=np.float32) + objmesh.uv_layers.active.uv.foreach_get('vector', npuv) + if flatten: + npuv = npuv.reshape((uvcount, 2)) + npuv = npuv[nploopindex] + uvcount = 3*loopindexcount + + self.set_array(mesh, 'vertex.attribute0', ANARI_FLOAT32_VEC2, uvcount, npuv) + + + if objmesh.color_attributes: + colorcount = len(objmesh.color_attributes[0].data) + npcolor = np.zeros([colorcount*4], dtype=np.float32) + objmesh.color_attributes[0].data.foreach_get('color', npcolor) + if flatten: + npcolor = npcolor.reshape((colorcount, 4)) + npcolor = npcolor[nploopindex] + colorcount = 3*loopindexcount + + self.set_array(mesh, 'vertex.color', ANARI_FLOAT32_VEC4, colorcount, npcolor) + + anariCommitParameters(self.device, mesh) + + return mesh + + def image_handle(self, image): + if image.name in self.images: + return self.images[image.name] + else: + image.update() + if image.has_data: + atype = None + #pixbuf = np.array(image.pixels, dtype=np.float32) + pixbuf = np.empty((len(image.pixels)), dtype=np.float32) + image.pixels.foreach_get(pixbuf) + if image.depth//image.channels <= 8: + atype = [ANARI_UFIXED8, ANARI_UFIXED8_VEC2, ANARI_UFIXED8_VEC3, ANARI_UFIXED8_VEC4][image.channels-1] + pixbuf = (pixbuf*255).astype(np.ubyte) + else: + atype = [ANARI_FLOAT32, ANARI_FLOAT32_VEC2, ANARI_FLOAT32_VEC3, ANARI_FLOAT32_VEC4][image.channels-1] + + pixels = anariNewArray2D(self.device, ffi.from_buffer(pixbuf), atype, image.size[0], image.size[1]) + self.images[image.name] = pixels + return pixels + else: + return None + + def sampler_handle(self, material, paramname): + key = (material, paramname) + if key in self.samplers: + return self.samplers[key] + else: + sampler = anariNewSampler(self.device, "image2D") + self.samplers[key] = sampler + return sampler + + def parse_source_node(self, material, paramname, atype, input): + if input.links: + link = input.links[0] + node = link.from_node + if node.type == 'VERTEX_COLOR': + anariSetParameter(self.device, material, paramname, ANARI_STRING, 'color') + return + elif node.type == 'TEX_IMAGE' and node.image: + image = node.image + pixels = self.image_handle(image) + if pixels: + sampler = self.sampler_handle(material, paramname) + anariSetParameter(self.device, sampler, 'image', ANARI_ARRAY2D, pixels) + anariSetParameter(self.device, sampler, 'inAttribute', ANARI_STRING, "attribute0") + if link.from_socket.name == "Alpha": + #swizzle alpha into first position + anariSetParameter(self.device, sampler, 'outTransform', ANARI_FLOAT32_MAT4, [0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0]) + elif link.from_socket.name == "Color": + #make sure we don't accidentally side channel alpha + anariSetParameter(self.device, sampler, 'outTransform', ANARI_FLOAT32_MAT4, [1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0]) + anariSetParameter(self.device, sampler, 'outOffset', ANARI_FLOAT32_VEC4, [0,0,0,1]) + + repeatMode = None + if node.extension == 'REPEAT': + repeatMode = 'repeat' + elif node.extension == 'MIRROR': + repeatMode = 'mirrorRepeat' + elif node.extension == 'EXTEND': + repeatMode = 'clampToEdge' + + if repeatMode: + anariSetParameter(self.device, sampler, 'wrapMode1', ANARI_STRING, repeatMode) + anariSetParameter(self.device, sampler, 'wrapMode2', ANARI_STRING, repeatMode) + + filterMode = None + if node.interpolation == 'LINEAR': + filterMode = 'linear' + elif node.interpolation == 'CLOSEST': + filterMode = 'nearest' + + if filterMode: + anariSetParameter(self.device, sampler, 'filter', ANARI_STRING, filterMode) + + + anariCommitParameters(self.device, sampler) + anariSetParameter(self.device, material, paramname, ANARI_SAMPLER, sampler) + return + else: + print("no pixels") + + # use the default value if none of the previous ones worked + if atype == ANARI_FLOAT32: + anariSetParameter(self.device, material, paramname, atype, input.default_value) + elif atype == ANARI_FLOAT32_VEC2: + anariSetParameter(self.device, material, paramname, atype, input.default_value[:2]) + elif atype == ANARI_FLOAT32_VEC3: + anariSetParameter(self.device, material, paramname, atype, input.default_value[:3]) + elif atype == ANARI_FLOAT32_VEC4: + anariSetParameter(self.device, material, paramname, atype, input.default_value[:4]) + else: + anariSetParameter(self.device, material, paramname, atype, input.default_value[:]) + + def parse_material(self, material): + nodes = material.node_tree.nodes + + #look for an output node + out = None + for n in nodes: + if n.type == 'OUTPUT_MATERIAL': + out = n + + if not out: + return self.default_material + + shader = out.inputs['Surface'].links[0].from_node + if shader.type == 'BSDF_PRINCIPLED': + material = anariNewMaterial(self.device, 'physicallyBased') + self.parse_source_node(material, 'baseColor', ANARI_FLOAT32_VEC3, shader.inputs['Base Color']) + self.parse_source_node(material, 'normal', ANARI_FLOAT32_VEC3, shader.inputs['Normal']) + anariSetParameter(self.device, material, "alphaMode", ANARI_STRING, "blend") + self.parse_source_node(material, 'opacity', ANARI_FLOAT32, shader.inputs['Alpha']) + self.parse_source_node(material, 'metallic', ANARI_FLOAT32, shader.inputs['Metallic']) + self.parse_source_node(material, 'roughness', ANARI_FLOAT32, shader.inputs['Roughness']) + if bpy.app.version < (4,0,0): + self.parse_source_node(material, 'emissive', ANARI_FLOAT32_VEC3, shader.inputs['Emission']) + self.parse_source_node(material, 'clearcoat', ANARI_FLOAT32, shader.inputs['Clearcoat']) + self.parse_source_node(material, 'clearcoatRoughness', ANARI_FLOAT32, shader.inputs['Clearcoat Roughness']) + self.parse_source_node(material, 'clearcoatNormal', ANARI_FLOAT32_VEC3, shader.inputs['Clearcoat Normal']) + else: + self.parse_source_node(material, 'emissive', ANARI_FLOAT32_VEC3, shader.inputs['Emission Color']) + self.parse_source_node(material, 'sheenRoughness', ANARI_FLOAT32, shader.inputs['Sheen Roughness']) + self.parse_source_node(material, 'clearcoat', ANARI_FLOAT32, shader.inputs['Coat Weight']) + self.parse_source_node(material, 'clearcoatRoughness', ANARI_FLOAT32, shader.inputs['Coat Roughness']) + self.parse_source_node(material, 'clearcoatNormal', ANARI_FLOAT32_VEC3, shader.inputs['Coat Normal']) + + self.parse_source_node(material, 'ior', ANARI_FLOAT32, shader.inputs['IOR']) + anariCommitParameters(self.device, material) + return material + else: + return self.default_material + + + def read_meshes(self, depsgraph): + + for update in depsgraph.updates: + obj = update.id + name = obj.name + + if isinstance(obj, bpy.types.Scene): + continue + elif isinstance(obj, bpy.types.Material): + meshname = self.materials[name] + (mesh, material, surface, group, instance) = self.meshes[meshname] + material = self.parse_material(obj) + anariSetParameter(self.device, surface, 'material', ANARI_MATERIAL, material) + anariCommitParameters(self.device, surface) + self.meshes[name] = (mesh, material, surface, group, instance) + elif hasattr(obj, 'type') and obj.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META'}: + objmesh = obj.to_mesh() + is_new = name not in self.meshes + + (mesh, material, surface, group, instance) = self.get_mesh(name) + + if is_new or update.is_updated_geometry: + self.mesh_to_geometry(objmesh, name, mesh) + + if is_new or update.is_updated_shading: + if obj.material_slots: + material = self.parse_material(obj.material_slots[0].material) + anariSetParameter(self.device, surface, 'material', ANARI_MATERIAL, material) + anariCommitParameters(self.device, surface) + self.meshes[name] = (mesh, material, surface, group, instance) + + if is_new or update.is_updated_transform: + transform = [x for v in obj.matrix_world.transposed() for x in v] + anariSetParameter(self.device, instance, 'transform', ANARI_FLOAT32_MAT4, transform) + anariCommitParameters(self.device, instance) + + + + self.bounds_min = np.array([1.e20, 1.e20, 1.e20]) + self.bounds_max = np.array([-1.e20, -1.e20, -1.e20]) + + + scene_instances = [] + for obj in depsgraph.objects: + name = obj.name + + if name not in self.meshes: + if obj.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META'}: + objmesh = obj.to_mesh() + else: + continue + + (mesh, material, surface, group, instance) = self.get_mesh(name) + self.mesh_to_geometry(objmesh, name, mesh) + + if obj.material_slots: + objmaterial = obj.material_slots[0].material + material = self.parse_material(objmaterial) + anariSetParameter(self.device, surface, 'material', ANARI_MATERIAL, material) + anariCommitParameters(self.device, surface) + self.materials[objmaterial.name] = name + self.meshes[name] = (mesh, material, surface, group, instance) + + transform = [x for v in obj.matrix_world.transposed() for x in v] + anariSetParameter(self.device, instance, 'transform', ANARI_FLOAT32_MAT4, transform) + anariCommitParameters(self.device, instance) + + for v in obj.bound_box[:]: + corner = obj.matrix_world@Vector(v) + val = np.array(corner[:]) + self.bounds_min = np.minimum(self.bounds_min, val) + self.bounds_max = np.maximum(self.bounds_max, val) + + (mesh, material, surface, group, instance) = self.get_mesh(name) + + scene_instances.append(instance) + + (ptr, stride) = anariMapParameterArray1D(self.device, self.world, 'instance', ANARI_INSTANCE, len(scene_instances)) + for i, instance in enumerate(scene_instances): + ptr[i] = instance + anariUnmapParameterArray(self.device, self.world, 'instance') + anariCommitParameters(self.device, self.world) + + + def read_lights(self, depsgraph): + scene_lights = [] + + for key, obj in depsgraph.objects.items(): + if obj.hide_render or obj.type != 'LIGHT': + continue + + name = obj.name + + transform = obj.matrix_world.transposed() + direction = (-transform[2])[0:3] + position = transform[3][0:3] + + if obj.data.type == 'POINT': + light = self.get_light(name, 'point') + anariSetParameter(self.device, light, 'color', ANARI_FLOAT32_VEC3, obj.data.color[:]) + #blender uses total watts while anari uses watts/sr + anariSetParameter(self.device, light, 'intensity', ANARI_FLOAT32, obj.data.energy/(4.0*math.pi)) + anariSetParameter(self.device, light, 'position', ANARI_FLOAT32_VEC3, position) + anariCommitParameters(self.device, light) + scene_lights.append(light) + elif obj.data.type == 'SUN': + light = self.get_light(name, 'directional') + anariSetParameter(self.device, light, 'color', ANARI_FLOAT32_VEC3, obj.data.color[:]) + anariSetParameter(self.device, light, 'irradiance', ANARI_FLOAT32, obj.data.energy) + anariSetParameter(self.device, light, 'direction', ANARI_FLOAT32_VEC3, direction) + anariCommitParameters(self.device, light) + scene_lights.append(light) + + + (ptr, stride) = anariMapParameterArray1D(self.device, self.world, 'light', ANARI_LIGHT, len(scene_lights)) + for i, light in enumerate(scene_lights): + ptr[i] = light + anariUnmapParameterArray(self.device, self.world, 'light') + anariCommitParameters(self.device, self.world) + + + def read_scene(self, depsgraph): + renderer_params = getattr(depsgraph.scene.anari, self.anari_library_name) + + if self.current_renderer != renderer_params.renderer: + self.renderer = anariNewRenderer(self.device, renderer_params.renderer) + self.current_renderer = renderer_params.renderer + + params = self.param_selections[self.current_renderer] + + for p, t in params.items(): + if hasattr(renderer_params, p): + v = getattr(renderer_params, p) + if t == ANARI_FLOAT32_VEC3: + v = v[:] + anariSetParameter(self.device, self.renderer, p, t, v) + + bg_color = depsgraph.scene.world.color[:]+(1.0,) + anariSetParameter(self.device, self.renderer, 'background', ANARI_FLOAT32_VEC4, bg_color) + + anariCommitParameters(self.device, self.renderer) + + + + self.read_meshes(depsgraph) + self.read_lights(depsgraph) + + + # This is the method called by Blender for both final renders (F12) and + # small preview for materials, world and lights. + def render(self, depsgraph): + scene = depsgraph.scene + scale = scene.render.resolution_percentage / 100.0 + width = int(scene.render.resolution_x * scale) + height = int(scene.render.resolution_y * scale) + + self.extract_camera(depsgraph, width, height) + self.read_scene(depsgraph) + + frame = self.anari_frame(width, height) + anariSetParameter(self.device, frame, 'renderer', ANARI_RENDERER, self.renderer) + anariSetParameter(self.device, frame, 'camera', ANARI_CAMERA, self.camera) + anariSetParameter(self.device, frame, 'world', ANARI_WORLD, self.world) + anariCommitParameters(self.device, frame) + + anariRenderFrame(self.device, frame) + anariFrameReady(self.device, frame, ANARI_WAIT) + void_pixels, frame_width, frame_height, frame_type = anariMapFrame(self.device, frame, 'channel.color') + + unpacked_pixels = ffi.buffer(void_pixels, frame_width*frame_height*4) + pixels = np.array(unpacked_pixels).astype(np.float32)*(1.0/255.0) + rect = pixels.reshape((width*height, 4)) + anariUnmapFrame(self.device, frame, 'channel.color') + + # Here we write the pixel values to the RenderResult + result = self.begin_result(0, 0, width, height) + layer = result.layers[0].passes["Combined"] + layer.rect = rect + self.end_result(result) + + + + # For viewport renders, this method gets called once at the start and + # whenever the scene or 3D viewport changes. This method is where data + # should be read from Blender in the same thread. + def view_update(self, context, depsgraph): + region = context.region + scene = depsgraph.scene + + width = region.width + height = region.height + + self.read_scene(depsgraph) + + frame = self.anari_frame(width, height) + self.extract_camera(depsgraph, width, height, region_view=context.region_data, space_view=context.space_data) + + anariSetParameter(self.device, frame, 'renderer', ANARI_RENDERER, self.renderer) + anariSetParameter(self.device, frame, 'camera', ANARI_CAMERA, self.camera) + anariSetParameter(self.device, frame, 'world', ANARI_WORLD, self.world) + anariCommitParameters(self.device, frame) + + self.scene_changed() + + + + # For viewport renders, this method is called whenever Blender redraws + # the 3D viewport. + def view_draw(self, context, depsgraph): + + #pull some data + region = context.region + scene = depsgraph.scene + + # see if something about the viewport or camera has changed + if self.width != region.width or self.height != region.height: + self.width = region.width + self.height = region.height + self.scene_changed() + + frame = self.anari_frame(self.width, self.height) + + if self.extract_camera(depsgraph, self.width, self.height, region_view=context.region_data, space_view=context.space_data): + anariSetParameter(self.device, frame, 'camera', ANARI_CAMERA, self.camera) + anariCommitParameters(self.device, frame) + self.scene_changed() + + + require_redraw = self.scene_updated + self.scene_updated = False + + # hard render if we don't have a preexisting image + if not self.gputexture: + anariRenderFrame(self.device, frame) + anariFrameReady(self.device, frame, ANARI_WAIT) + self.rendering = True + require_redraw = False + + # pull new data if a render has completed + if self.rendering and anariFrameReady(self.device, frame, ANARI_NO_WAIT): + void_pixels, frame_width, frame_height, frame_type = anariMapFrame(self.device, frame, 'channel.color') + unpacked_pixels = ffi.buffer(void_pixels, frame_width*frame_height*4) + pixels = np.array(unpacked_pixels).astype(np.float32)*(1.0/255.0) + anariUnmapFrame(self.device, frame, 'channel.color') + + self.gpupixels = gpu.types.Buffer('FLOAT', frame_width * frame_height * 4, pixels) + self.gputexture = gpu.types.GPUTexture((frame_width, frame_height), format='RGBA16F', data=self.gpupixels) + + self.rendering = False + self.iteration += 1 + + if not self.render_converged(): + require_redraw = True + + if self.rendered_epoch < self.epoch: + require_redraw = True + + # present + gpu.state.blend_set('ALPHA_PREMULT') + self.bind_display_space_shader(scene) + draw_texture_2d(self.gputexture, (0, 0), region.width, region.height) + self.unbind_display_space_shader() + gpu.state.blend_set('NONE') + + + # continue drawing as long as changes happen + if require_redraw and not self.rendering: + anariRenderFrame(self.device, frame) + self.rendered_epoch = self.epoch + self.rendering = True + + # make blender call us again while we wait in the render to complete + if self.rendering: + self.tag_redraw() + + + + +# RenderEngines also need to tell UI Panels that they are compatible with. +def get_panels(): + exclude_panels = { + 'VIEWLAYER_PT_filter', + 'VIEWLAYER_PT_layer_passes', + 'RENDER_PT_eevee_ambient_occlusion', + 'RENDER_PT_eevee_motion_blur', + 'RENDER_PT_eevee_next_motion_blur', + 'RENDER_PT_motion_blur_curve', + 'RENDER_PT_eevee_depth_of_field', + 'RENDER_PT_eevee_next_depth_of_field', + 'RENDER_PT_eevee_bloom', + 'RENDER_PT_eevee_volumetric', + 'RENDER_PT_eevee_volumetric_lighting', + 'RENDER_PT_eevee_volumetric_shadows', + 'RENDER_PT_eevee_subsurface_scattering', + 'RENDER_PT_eevee_screen_space_reflections', + 'RENDER_PT_eevee_shadows', + 'RENDER_PT_eevee_next_shadows', + 'RENDER_PT_eevee_sampling', + 'RENDER_PT_eevee_indirect_lighting', + 'RENDER_PT_eevee_indirect_lighting_display', + 'RENDER_PT_eevee_film', + 'RENDER_PT_eevee_hair', + 'RENDER_PT_eevee_performance', + } + panels = [] + for panel in bpy.types.Panel.__subclasses__(): + if hasattr(panel, 'COMPAT_ENGINES') and ('BLENDER_RENDER' in panel.COMPAT_ENGINES or 'BLENDER_EEVEE' in panel.COMPAT_ENGINES): + if panel.__name__ not in exclude_panels: + panels.append(panel) + + return panels + + +classes = [ + ANARISceneProperties, + RENDER_PT_anari +] + +panel_names = [] + + +def anari_type_to_property(device, objtype, subtype, paramname, atype): + value = anariGetParameterInfo(device, objtype, subtype, paramname, atype, "default", atype) + if atype == ANARI_BOOL: + if value: + return bpy.props.BoolProperty(name = paramname, default = value) + else: + return bpy.props.BoolProperty(name = paramname) + elif atype == ANARI_INT32: + if value: + return bpy.props.IntProperty(name = paramname, default = value) + else: + return bpy.props.IntProperty(name = paramname) + elif atype == ANARI_FLOAT32: + if value: + return bpy.props.FloatProperty(name = paramname, default = value) + else: + return bpy.props.FloatProperty(name = paramname) + elif atype == ANARI_FLOAT32_VEC3: + if value: + return bpy.props.FloatVectorProperty(name = paramname, subtype='COLOR', default = value) + else: + return bpy.props.FloatVectorProperty(name = paramname, subtype='COLOR') + elif atype == ANARI_STRING: + selection = anariGetParameterInfo(device, objtype, subtype, paramname, atype, "value", ANARI_STRING_LIST) + if selection: + return bpy.props.EnumProperty( + name=paramname, + items = {(s, s, '') for s in selection}, + default = value + ) + else: + if value: + return bpy.props.StringProperty(name = paramname, default = value) + else: + return bpy.props.StringProperty(name = paramname) + else: + return None + +def device_to_propertygroup(engine, idname, scenename, device, objtype, subtype): + parameters = anariGetObjectInfo(device, objtype, subtype, "parameter", ANARI_PARAMETER_LIST) + properties = [] + names = {'name'} # exclude name from the displayed options + for paramname, atype in parameters: + if paramname in names: + continue + else: + names.add(paramname) + + prop = anari_type_to_property(device, objtype, subtype, paramname, atype) + if prop: + properties.append((paramname, prop)) + + renderers = anariGetObjectSubtypes(device, ANARI_RENDERER) + properties.append(('renderer', bpy.props.EnumProperty( + name='renderer', + items = {(s, s, 'the %s renderer'%s) for s in renderers}, + default = renderers[0]) + )) + + param_selections = dict() + for renderer_name in renderers: + renderer_parameters = anariGetObjectInfo(device, ANARI_RENDERER, renderer_name, "parameter", ANARI_PARAMETER_LIST) + param_selections[renderer_name] = {x[0]:x[1] for x in renderer_parameters} + for paramname, atype in renderer_parameters: + if paramname in names: + continue + else: + names.add(paramname) + prop = anari_type_to_property(device, ANARI_RENDERER, renderer_name, paramname, atype) + if prop: + properties.append((paramname, prop)) + + @classmethod + def register(cls): + setattr(ANARISceneProperties, scenename, bpy.props.PointerProperty( + name="ANARI %s Scene Settings"%scenename, + description="ANARI %s scene settings"%scenename, + type=cls, + )) + + @classmethod + def unregister(cls): + delattr(ANARISceneProperties, scenename) + + property_group = dataclasses.make_dataclass( + idname+'_properties', + properties, + bases=(bpy.types.PropertyGroup,), + namespace={ + 'register':register, + 'unregister':unregister, + }) + + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES) + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + col = layout.column() + props = getattr(context.scene.anari, self.scenename) + current_renderer = props.renderer + selection = self.param_selections[current_renderer] + col.prop(props, "renderer") + for paramname, prop in self.panel_props: + if paramname == "renderer": + continue + row = col.row() + row.enabled = paramname in selection or paramname in self.device_params + row.prop(props, paramname) + + RENDER_PT_anari_device = type('RENDER_PT_%s_panel'%idname, (RenderButtonsPanel, Panel),{ + 'bl_idname': 'RENDER_PT_%s_panel'%idname, + 'bl_label': "%s Device Properties"%idname, + 'bl_parent_id' : "RENDER_PT_anari", + 'COMPAT_ENGINES' : {engine}, + 'panel_props' : properties, + 'poll' : poll, + 'draw' : draw, + 'device_params' : names, + 'param_selections' : param_selections, + 'scenename' : copy.copy(scenename) + }) + + return (property_group, RENDER_PT_anari_device, param_selections) + +def register(): + # Register the RenderEngine + for c in classes: + bpy.utils.register_class(c) + + for name in librarynames: + library = anariLoadLibrary(name) + if library: + devices = anariGetDeviceSubtypes(library) + + for devicename in devices: + label = "%s %s (Anari)"%(name, devicename) + idname = "ANARI_%s_%s"%(name, devicename) + class ANARIDeviceRenderEngine(ANARIRenderEngine): + # These three members are used by blender to set up the + # RenderEngine; define its internal name, visible name and capabilities. + bl_idname = copy.copy(idname) + bl_label = copy.copy(label) + anari_library_name = copy.copy(name) + anari_device_name = copy.copy(devicename) + + def __init__(self): + super().__init__() + self.props = device_to_propertygroup(self.bl_idname, self.bl_idname, self.anari_library_name, self.device, ANARI_DEVICE, 'default') + self.param_selections = self.props[2] + + if not hasattr(ANARISceneProperties, self.anari_library_name): + bpy.utils.register_class(self.props[0]) + bpy.utils.register_class(self.props[1]) + classes.append(self.props[0]) + classes.append(self.props[1]) + + bpy.utils.register_class(ANARIDeviceRenderEngine) + classes.append(ANARIDeviceRenderEngine) + panel_names.append(label) + + for panel in get_panels(): + panel.COMPAT_ENGINES.add(idname) + + RENDER_PT_anari.COMPAT_ENGINES.add(idname) + + + + + + + + +def unregister(): + for c in classes: + bpy.utils.unregister_class(c) + + for panel in get_panels(): + for p in panel_names: + if p in panel.COMPAT_ENGINES: + panel.COMPAT_ENGINES.remove(p) + + +if __name__ == "__main__": + register() diff --git a/examples/blender/README.md b/examples/blender/README.md new file mode 100644 index 00000000..aa8533f9 --- /dev/null +++ b/examples/blender/README.md @@ -0,0 +1,26 @@ +Blender add-on +============== + +This add-on makes anari backends available as renderers in blender. + +It is work in progress should be treated as experimental. + +## Installing +The plugin will install itself if the blender install directory is +set as `BLENDER_DIR` in the sdk cmake configuration (only tested on linux). +The add-on can then be enabled in the blender preferences. + +Alternatively, after building the SDK including Python bindings, the add-on +(`CustomAnariRender.py`) and the Python bindings can be manually copied to a +location where Blender Python sees them. Additionally the cffi module needs +to be installed to the Python install Blender uses. +See the `CMakeLists.txt` in this directory for inspiration. + +When launching Blender the anari install directory needs to be in the library +search path for it to find the actual anari library and devices. + +## Limitations +* Supports only objects that can be converted to meshes +* Only supports part of the principled material shader +* Only supports directional (Sun) and Point lights +* The renderings are subject to limitations of the anari backends From cd110145f97cb948d2bd451bc131723d309b9729 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Mon, 27 Nov 2023 09:43:18 -0600 Subject: [PATCH 33/34] additional documentation + remove unused code (#174) --- README.md | 5 +- libs/anari/README.md | 114 ++++++++++++++++++ libs/anari/include/anari/backend/DeviceImpl.h | 110 ++++++++++------- .../anari/include/anari/backend/LibraryImpl.h | 9 ++ libs/anari_viewer/README.md | 13 +- 5 files changed, 201 insertions(+), 50 deletions(-) create mode 100644 libs/anari/README.md diff --git a/README.md b/README.md index 160513f2..c02c9148 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,11 @@ ANARI-SDK This repository contains the source for the ANARI API SDK. This includes: -- [Front-end library](libs/anari) +- [Front-end library + implementation guide](libs/anari) - [Device implementation utilties for implementations](libs/helium) - [Example device implementation](libs/helide) (not intended for production use) - [Example applications](examples/) - [Interactive sample viewer](examples/viewer) -- [Unit tests](tests/unit) - [Render tests](tests/render) The 1.0 ANARI specification can be found on the Khronos website @@ -109,7 +108,7 @@ get the library to load. For example it can be run with: ```bash % export ANARI_LIBRARY=helide -% ./anariViewer /path/to/some/file.obj +% ./anariViewer ``` Alternatively, either `--library` or `-l` can be used on the viewer's command diff --git a/libs/anari/README.md b/libs/anari/README.md new file mode 100644 index 00000000..e08bfcd2 --- /dev/null +++ b/libs/anari/README.md @@ -0,0 +1,114 @@ +# The ANARI Device Implementation Guide + +This directory contains the ANARI frontend library (`libanari`) which is the +core C API which applications directly use. This document will outline the +details of what is necessary in order to _implement_ a device, as using the +API itself is detailed at length in the ANARI specification. + +The primary function of this library is to dispatch +[ANARI C API function calls](include/anari/anari.h) to the corresponding ANARI +devcie implementing the API (designated by an `ANARIDevice` handle in the +functioin signature). There are two core concepts that implementations must +implement, along with optional additional tools which can aid in implementing +various ANARI features. + +The headers used to implement the required components of a device for this +frontend library are found in the [backend directory](include/anari/backend) of +the core installed headers. Implementations are primarily expected to build +their devices against an installation of the ANARI-SDK. + +## Implementing ANARILibrary + +The first required item that must be implemented is `ANARILibrary`. This is done +by subclassing [`LibraryImpl`](include/anari/backend/LibraryImpl.h) and +providing the required method definitions. `LibraryImpl` acts as the concrete +representation of `ANARILibrary`, where the frontend library uses this class to +manage all C API calls which are done on `ANARILibrary` (where the function's +first argument is the library). + +Note that `anariLoadLibrary()` uses the follwing naming convention for +dynamically loading an `ANARILibrary` at runtime: `anari_library_[name]`, where +`[name]` matches the string passed to `anariLoadLibrary`. `[name]` is used to +construct a C function name which is looked up as the entry point needed to +create an instance of `LibraryImpl`. Implementations should use the +`ANARI_DEFINE_LIBRARY_ENTRYPOINT` macro at the bottom of `LibraryImpl.h` to +define this entrypoint function, where it is necessary to match the first macro +argument with `[name]` in the physical shared library file. For example, the +provided [`helide`](../helide) device on linux is compiles into the shared +library `libanari_library_helide.so`, and `helide` is the first argument to +`ANARI_DEFINE_LIBRARY_ENTRYPOINT`, as seen [here](../helide/HelideLibrary.cpp). + +It is possible to directly construct a device if client applications directly +link your library itself, but it is highly recommended to always provide the +dynamic path via `anariLoadLibrary()` and `LibraryImpl` as this is the most +common way to create ANARI devices. The alternate method of directly +constructing a device via linking is show by the +[`anariTutorialDirectLink`](../../examples/simple/anariTutorialDirectLink.c) +sample app which includes a custom header created by `helide` to directly +create an instance of the `helide` device. + +## Implementing ANARIDevice + +The majority of the ANARI C API is implemented by subclassing +[`DeviceImpl`](include/anari/backend/DeviceImpl.h). Similar to implementing +`ANARILibrary`, `ANARIDevice` directly represents an instance of `DeviceImpl` +where the methods of the class correspond to functions in the ANARI API handled +by the device (where the function's first argument is the device). Device +implementations should always seek to make each instance of `DeviceImpl` +independent from each other by avoiding any shared state between them (i.e. +static state within the class or shared library). + +Almost the entirety of `DeviceImpl` corresponds directly to functions found +in [`anari.h`](include/anari/anari.h). The only state held by `DeviceImpl` are +the default status callback and callback user pointer. `DeviceImpl` is intended +to be very minimal -- implementors who desire SDK-provided implementations of +much of the API should use the [`helium`](../helium) layer, which implements +many common concepts, but requires implementations to opt-in to various `helium` +abstractions and classes. The provided [`helide`](../helide) device demonstrates +ultimately how to implement `DeviceImpl` through using +[`helium::BaseDevice`](../helium/BaseDevice.h). Device implementors can use the +sum of `helium::BaseDevice` and +[`helide::HelideDevice`](../helide/HelideDevice.h) as a full example of +implementing ANARI. Further documentation of what functionality `helium` +provides can be found in its [README](../helium/README.md). + +## Object query code generation + +Devices should implement the device and object queries offered by the ANARI API +in order for applications to introspect what extensions (and their details) are +offered. However, these functions can be quite tedius and repetitive to +implement, so Python-based code generation tools are offered to let library and +device authors minimize the effort in writing them. They use JSON definition +files to generate C++ which can then be used to implement various query +functions. + +All of the Python tooling is installed when `INSTALL_CODE_GEN_SCRIPTS` is +enabled when the SDK is installed. This can then be consumed by including the +`code_gen` component name in find package: + +```cmake +find_package(anari REQUIRED COMPONENTS code_gen) +``` + +This brings the `anari_generate_queries()` CMake function into scope downstream, +which has the following signature: + +```cmake +anari_generate_queries( + NAME [device_name] + PREFIX [device_prefix] + CPP_NAMESPACE [namespace] + JSON_DEFINITIONS_FILE [path/to/device/definitions.json] +) +``` + +This CMake function will create a target called `generate_[device_name]_device`, +which must be built manually in order to generate any C++. By invoking this +targets, a `[device_prefix]Queries.cpp/.h` are created, which can be included +in the local device build's source. Please refer to [helide](../helide) as an +example of how these components all go together. + +Note that all core spec extensions are defined in a collection of +[JSON files](../../code_gen/api) that are referenced in the downstream JSON +definitions. It is recommened to copy an existing JSON definitions file and +modify it accordingly. diff --git a/libs/anari/include/anari/backend/DeviceImpl.h b/libs/anari/include/anari/backend/DeviceImpl.h index 2301870c..cd458c47 100644 --- a/libs/anari/include/anari/backend/DeviceImpl.h +++ b/libs/anari/include/anari/backend/DeviceImpl.h @@ -9,43 +9,24 @@ #include "anari/backend/LibraryImpl.h" -// std -#include -#include -#include - namespace anari { -template -using FactoryFcn = T *(*)(Args...); - -template -using FactoryMap = std::map>; - -template -using FactoryVector = std::vector>; - -// should this use Args&&... and forwarding? -template -inline B *allocate_object(Args... args) -{ - return new T(args...); -} - struct ANARI_INTERFACE DeviceImpl { ///////////////////////////////////////////////////////////////////////////// // Main virtual interface to accepting API calls ///////////////////////////////////////////////////////////////////////////// - // Data Arrays ////////////////////////////////////////////////////////////// + // Object creation ////////////////////////////////////////////////////////// + // Implement anariNewArray1D() virtual ANARIArray1D newArray1D(const void *appMemory, ANARIMemoryDeleter deleter, const void *userdata, ANARIDataType, uint64_t numItems1) = 0; + // Implement anariNewArray2D() virtual ANARIArray2D newArray2D(const void *appMemory, ANARIMemoryDeleter deleter, const void *userdata, @@ -53,6 +34,7 @@ struct ANARI_INTERFACE DeviceImpl uint64_t numItems1, uint64_t numItems2) = 0; + // Implement anariNewArray3D() virtual ANARIArray3D newArray3D(const void *appMemory, ANARIMemoryDeleter deleter, const void *userdata, @@ -61,58 +43,75 @@ struct ANARI_INTERFACE DeviceImpl uint64_t numItems2, uint64_t numItems3) = 0; - virtual void *mapArray(ANARIArray) = 0; - virtual void unmapArray(ANARIArray) = 0; + // Implement anariNewGeometry() + virtual ANARIGeometry newGeometry(const char *type) = 0; - // Renderable Objects /////////////////////////////////////////////////////// + // Implement anariNewMaterial() + virtual ANARIMaterial newMaterial(const char *material_type) = 0; - virtual ANARILight newLight(const char *type) = 0; + // Implement anariNewSampler() + virtual ANARISampler newSampler(const char *type) = 0; - virtual ANARICamera newCamera(const char *type) = 0; + // Implement anariNewSurface() + virtual ANARISurface newSurface() = 0; - virtual ANARIGeometry newGeometry(const char *type) = 0; + // Implement anariNewSpatialField() virtual ANARISpatialField newSpatialField(const char *type) = 0; - virtual ANARISurface newSurface() = 0; + // Implement anariNewVolume() virtual ANARIVolume newVolume(const char *type) = 0; - // Surface Meta-Data //////////////////////////////////////////////////////// - - virtual ANARIMaterial newMaterial(const char *material_type) = 0; - - virtual ANARISampler newSampler(const char *type) = 0; - - // Instancing /////////////////////////////////////////////////////////////// + // Implement anariNewLight() + virtual ANARILight newLight(const char *type) = 0; + // Implement anariGroup() virtual ANARIGroup newGroup() = 0; + // Implement anariNewInstance() virtual ANARIInstance newInstance(const char *type) = 0; - // Top-level Worlds ///////////////////////////////////////////////////////// - + // Implement anariNewWorld() virtual ANARIWorld newWorld() = 0; + // Implement anariNewCamera() + virtual ANARICamera newCamera(const char *type) = 0; + + // Implement anariNewRenderer() + virtual ANARIRenderer newRenderer(const char *type) = 0; + + // Implement anariNewFrame() + virtual ANARIFrame newFrame() = 0; + // Object + Parameter Lifetime Management /////////////////////////////////// + // Implement anariSetParameter() virtual void setParameter(ANARIObject object, const char *name, ANARIDataType type, const void *mem) = 0; + // Implement anariUnsetParameter() virtual void unsetParameter(ANARIObject object, const char *name) = 0; + + // Implement anariUnsetAllParameters() virtual void unsetAllParameters(ANARIObject object) = 0; + // Implement anariMapParameterArray1D() virtual void *mapParameterArray1D(ANARIObject object, const char *name, ANARIDataType dataType, uint64_t numElements1, uint64_t *elementStride) = 0; + + // Implement anariMapParameterArray2D() virtual void *mapParameterArray2D(ANARIObject object, const char *name, ANARIDataType dataType, uint64_t numElements1, uint64_t numElements2, uint64_t *elementStride) = 0; + + // Implement anariMapParameterArray3D() virtual void *mapParameterArray3D(ANARIObject object, const char *name, ANARIDataType dataType, @@ -120,15 +119,26 @@ struct ANARI_INTERFACE DeviceImpl uint64_t numElements2, uint64_t numElements3, uint64_t *elementStride) = 0; + + // Implement anariUnmapParameterArray() virtual void unmapParameterArray(ANARIObject object, const char *name) = 0; + // Implement anariCommitParameters() virtual void commitParameters(ANARIObject object) = 0; + // Implement anariRelease() virtual void release(ANARIObject _obj) = 0; + + // Implement anariRetain() virtual void retain(ANARIObject _obj) = 0; - // Object Query Interface /////////////////////////////////////////////////// + // Implement anariMapArray() + virtual void *mapArray(ANARIArray) = 0; + // Implement anariUnmapArray() + virtual void unmapArray(ANARIArray) = 0; + + // Implement anariGetProperty() virtual int getProperty(ANARIObject object, const char *name, ANARIDataType type, @@ -136,11 +146,18 @@ struct ANARI_INTERFACE DeviceImpl uint64_t size, ANARIWaitMask mask) = 0; + // Object Query Interface /////////////////////////////////////////////////// + + // Implement anariGetObjectSubtypes() virtual const char **getObjectSubtypes(ANARIDataType objectType) = 0; + + // Implement anariGetObjectInfo() virtual const void *getObjectInfo(ANARIDataType objectType, const char *objectSubtype, const char *infoName, ANARIDataType infoType) = 0; + + // Implement anariGetParameterInfo() virtual const void *getParameterInfo(ANARIDataType objectType, const char *objectSubtype, const char *parameterName, @@ -150,30 +167,36 @@ struct ANARI_INTERFACE DeviceImpl // FrameBuffer Manipulation ///////////////////////////////////////////////// - virtual ANARIFrame newFrame() = 0; - + // Implement anariFrameBufferMap virtual const void *frameBufferMap(ANARIFrame fb, const char *channel, uint32_t *width, uint32_t *height, ANARIDataType *pixelType) = 0; + // Implement anariFrameBufferUnmap virtual void frameBufferUnmap(ANARIFrame fb, const char *channel) = 0; // Frame Rendering ////////////////////////////////////////////////////////// - virtual ANARIRenderer newRenderer(const char *type) = 0; - + // Implement anariRenderFrame() virtual void renderFrame(ANARIFrame) = 0; + + // Implement anariFrameReady() virtual int frameReady(ANARIFrame, ANARIWaitMask) = 0; + + // Implement anariDiscardFrame() virtual void discardFrame(ANARIFrame) = 0; ///////////////////////////////////////////////////////////////////////////// // Extension interface ///////////////////////////////////////////////////////////////////////////// + // Optionally allow creation of extension objects that do not fit any core + // handle types. virtual ANARIObject newObject(const char *objectType, const char *type); + // Optionally allow dynamic lookup of special extension functions virtual void (*getProcAddress(const char *name))(void); ///////////////////////////////////////////////////////////////////////////// @@ -184,6 +207,7 @@ struct ANARI_INTERFACE DeviceImpl DeviceImpl() = default; virtual ~DeviceImpl() = default; + // Utility to get 'this' as an ANARIDevice handle ANARIDevice this_device() const; ANARIStatusCallback m_defaultStatusCB{nullptr}; diff --git a/libs/anari/include/anari/backend/LibraryImpl.h b/libs/anari/include/anari/backend/LibraryImpl.h index 63d8da4e..1a9e6ba9 100644 --- a/libs/anari/include/anari/backend/LibraryImpl.h +++ b/libs/anari/include/anari/backend/LibraryImpl.h @@ -11,6 +11,7 @@ namespace anari { +// Function prototypes for misc. library functions needed by API.cpp void *loadANARILibrary(const std::string &libName); void freeLibrary(void *lib); void *getSymbolAddress(void *lib, const std::string &symbol); @@ -21,16 +22,24 @@ struct ANARI_INTERFACE LibraryImpl void *lib, ANARIStatusCallback defaultStatusCB, const void *statusCBPtr); virtual ~LibraryImpl(); + // Create an instance of anari::DeviceImpl, typically using the 'new' operator virtual ANARIDevice newDevice(const char *subtype) = 0; + // Implement anariGetDevcieExtensions() virtual const char **getDeviceExtensions(const char *deviceType) = 0; + // Optionally implement anariGetDeviceSubtypes(), get {"default", 0} otherwise virtual const char **getDeviceSubtypes(); + // Optionally implement anariLoadModule() virtual void loadModule(const char *name); + // Optionally implement anariUnloadModule() virtual void unloadModule(const char *name); + // Get the default callback passed to anariLoadLibrary() ANARIStatusCallback defaultStatusCB() const; + // Get the default callback user pointer passed to anariLoadLibrary() const void *defaultStatusCBUserPtr() const; + // Utility to get 'this' pointer as an ANARILibrary handle ANARILibrary this_library() const; private: diff --git a/libs/anari_viewer/README.md b/libs/anari_viewer/README.md index 0583dc53..87aeca72 100644 --- a/libs/anari_viewer/README.md +++ b/libs/anari_viewer/README.md @@ -22,10 +22,15 @@ target_link_libraries(myViewer anari::anari_viewer) ``` Note that this target is only installed if `INSTALL_VIEWER_LIBRARY` is enabled -when installing the SDK, which also requires enabling both `BUILD_EXAMPLES` and -`BUILD_VIEWER`. Behind the scenes, this library target is a pure `INTERFACE` -target that will import all the `.cpp` files necessary to use the viewer -components. +when installing the SDK _and_ the downstream CMake `find_package` includes the +`viewer` component: + +```cmake +find_package(anari REQUIRED COMPONENTS viewer) +``` + +Behind the scenes, this library target is a pure `INTERFACE` target that will +import all the `.cpp` files necessary to use the viewer components. Given that this is not a stable library, it is assumed that users will read code in order to understand how to use it. The provided [example From d95b167021a35fb2fc6e31ace9e3851b86d0bdb6 Mon Sep 17 00:00:00 2001 From: Jefferson Amstutz Date: Mon, 27 Nov 2023 10:12:28 -0600 Subject: [PATCH 34/34] fix typos --- libs/anari/README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libs/anari/README.md b/libs/anari/README.md index e08bfcd2..638a4121 100644 --- a/libs/anari/README.md +++ b/libs/anari/README.md @@ -26,7 +26,7 @@ representation of `ANARILibrary`, where the frontend library uses this class to manage all C API calls which are done on `ANARILibrary` (where the function's first argument is the library). -Note that `anariLoadLibrary()` uses the follwing naming convention for +Note that `anariLoadLibrary()` uses the following naming convention for dynamically loading an `ANARILibrary` at runtime: `anari_library_[name]`, where `[name]` matches the string passed to `anariLoadLibrary`. `[name]` is used to construct a C function name which is looked up as the entry point needed to @@ -34,12 +34,12 @@ create an instance of `LibraryImpl`. Implementations should use the `ANARI_DEFINE_LIBRARY_ENTRYPOINT` macro at the bottom of `LibraryImpl.h` to define this entrypoint function, where it is necessary to match the first macro argument with `[name]` in the physical shared library file. For example, the -provided [`helide`](../helide) device on linux is compiles into the shared -library `libanari_library_helide.so`, and `helide` is the first argument to +provided [`helide`](../helide) device on linux compiles into the shared library +`libanari_library_helide.so`, and `helide` is the first argument to `ANARI_DEFINE_LIBRARY_ENTRYPOINT`, as seen [here](../helide/HelideLibrary.cpp). It is possible to directly construct a device if client applications directly -link your library itself, but it is highly recommended to always provide the +links your library itself, but it is highly recommended to always provide the dynamic path via `anariLoadLibrary()` and `LibraryImpl` as this is the most common way to create ANARI devices. The alternate method of directly constructing a device via linking is show by the @@ -58,12 +58,12 @@ implementations should always seek to make each instance of `DeviceImpl` independent from each other by avoiding any shared state between them (i.e. static state within the class or shared library). -Almost the entirety of `DeviceImpl` corresponds directly to functions found +Almost the entirety of `DeviceImpl` directly corresponds to functions found in [`anari.h`](include/anari/anari.h). The only state held by `DeviceImpl` are the default status callback and callback user pointer. `DeviceImpl` is intended to be very minimal -- implementors who desire SDK-provided implementations of -much of the API should use the [`helium`](../helium) layer, which implements -many common concepts, but requires implementations to opt-in to various `helium` +much of the API should use the [`helium`](../helium) layer which implements many +common concepts, but requires implementations to opt-in to various `helium` abstractions and classes. The provided [`helide`](../helide) device demonstrates ultimately how to implement `DeviceImpl` through using [`helium::BaseDevice`](../helium/BaseDevice.h). Device implementors can use the @@ -79,7 +79,7 @@ in order for applications to introspect what extensions (and their details) are offered. However, these functions can be quite tedius and repetitive to implement, so Python-based code generation tools are offered to let library and device authors minimize the effort in writing them. They use JSON definition -files to generate C++ which can then be used to implement various query +files to generate C++ which can then be used to implement the various query functions. All of the Python tooling is installed when `INSTALL_CODE_GEN_SCRIPTS` is