From cfdf2c749fce76f342e7f4f2652b00cdb63f8516 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Thu, 12 Mar 2026 01:57:20 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E9=99=A4Unity=E5=8F=82=E8=80=83?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unity/NanoVDB/NanoVolumeCustomPass.cs | 61 - unity/NanoVDB/NanoVolumeCustomPass.cs.meta | 11 - unity/NanoVDB/NanoVolumeCustomPass.shader | 42 - .../NanoVDB/NanoVolumeCustomPass.shader.meta | 9 - unity/NanoVDB/NanoVolumeLoader.cs | 118 - unity/NanoVDB/NanoVolumeLoader.cs.meta | 11 - unity/NanoVDB/NanoVolumePass.hlsl | 276 -- unity/NanoVDB/NanoVolumePass.hlsl.meta | 7 - unity/NanoVDB/NanoVolumeSettings.cs | 35 - unity/NanoVDB/NanoVolumeSettings.cs.meta | 11 - unity/NanoVDB/PNanoVDB.hlsl | 3454 ----------------- unity/NanoVDB/PNanoVDB.hlsl.meta | 46 - unity/NanoVDB/PseudoRandom.hlsl | 19 - unity/NanoVDB/PseudoRandom.hlsl.meta | 7 - unity/Plugins/NanoVDBWrapper.cpp | 67 - unity/Plugins/NanoVDBWrapper.cpp.meta | 46 - unity/Plugins/NanoVDBWrapper.dll | Bin 578560 -> 0 bytes unity/Plugins/NanoVDBWrapper.dll.meta | 27 - unity/Plugins/README.md | 24 - unity/Plugins/README.md.meta | 7 - 20 files changed, 4278 deletions(-) delete mode 100644 unity/NanoVDB/NanoVolumeCustomPass.cs delete mode 100644 unity/NanoVDB/NanoVolumeCustomPass.cs.meta delete mode 100644 unity/NanoVDB/NanoVolumeCustomPass.shader delete mode 100644 unity/NanoVDB/NanoVolumeCustomPass.shader.meta delete mode 100644 unity/NanoVDB/NanoVolumeLoader.cs delete mode 100644 unity/NanoVDB/NanoVolumeLoader.cs.meta delete mode 100644 unity/NanoVDB/NanoVolumePass.hlsl delete mode 100644 unity/NanoVDB/NanoVolumePass.hlsl.meta delete mode 100644 unity/NanoVDB/NanoVolumeSettings.cs delete mode 100644 unity/NanoVDB/NanoVolumeSettings.cs.meta delete mode 100644 unity/NanoVDB/PNanoVDB.hlsl delete mode 100644 unity/NanoVDB/PNanoVDB.hlsl.meta delete mode 100644 unity/NanoVDB/PseudoRandom.hlsl delete mode 100644 unity/NanoVDB/PseudoRandom.hlsl.meta delete mode 100644 unity/Plugins/NanoVDBWrapper.cpp delete mode 100644 unity/Plugins/NanoVDBWrapper.cpp.meta delete mode 100644 unity/Plugins/NanoVDBWrapper.dll delete mode 100644 unity/Plugins/NanoVDBWrapper.dll.meta delete mode 100644 unity/Plugins/README.md delete mode 100644 unity/Plugins/README.md.meta diff --git a/unity/NanoVDB/NanoVolumeCustomPass.cs b/unity/NanoVDB/NanoVolumeCustomPass.cs deleted file mode 100644 index d507f165..00000000 --- a/unity/NanoVDB/NanoVolumeCustomPass.cs +++ /dev/null @@ -1,61 +0,0 @@ -using UnityEngine; -using UnityEngine.Rendering.HighDefinition; -using UnityEngine.Rendering; - -class NanoVolumeCustomPass : CustomPass -{ - const int NANO_VOLUME_PASS_ID = 0; - - public NanoVolumeLoader nanoVolumeLoaderComponent; - public NanoVolumeSettings nanoVolumeSettings; - - Material mat; - - // To make sure the shader ends up in the build, we keep a reference to it - [SerializeField, HideInInspector] - Shader volumeShader; - - protected override void Setup(ScriptableRenderContext renderContext, CommandBuffer cmd) - { - volumeShader = Shader.Find("FullScreen/NanoVolumePass"); - mat = CoreUtils.CreateEngineMaterial(volumeShader); - } - - protected override void Execute(CustomPassContext ctx) - { - if (!nanoVolumeLoaderComponent.IsLoaded()) - { - return; - } - - SetUniforms(); - - CoreUtils.SetRenderTarget(ctx.cmd, ctx.cameraColorBuffer, ClearFlag.Color); - CoreUtils.DrawFullScreen(ctx.cmd, mat, ctx.propertyBlock, shaderPassId: NANO_VOLUME_PASS_ID); - } - - protected override void Cleanup() - { - CoreUtils.Destroy(mat); - } - - void SetUniforms() - { - mat.SetBuffer("buf", nanoVolumeLoaderComponent.GetGPUBuffer()); - mat.SetFloat("_ClipPlaneMin", 0.01f); - mat.SetFloat("_ClipPlaneMax", 1500.0f); - - mat.SetVector("_LightDir", nanoVolumeSettings.directionalLight.transform.forward); - - mat.SetVector("_Light", nanoVolumeSettings.directionalLight.color); - mat.SetVector("_Scattering", nanoVolumeSettings.scatteringColor); - - mat.SetFloat("_DensityScale", nanoVolumeSettings.DensitySlider.value); - mat.SetFloat("_LightAbsorbation", nanoVolumeSettings.LightAbsorbation.value); - - mat.SetInt("_RayMarchSamples", (int)nanoVolumeSettings.RaymarchSamples.value); - mat.SetInt("_LightSamples", (int)nanoVolumeSettings.LightSteps.value); - - mat.SetInt("_VisualizeSteps", nanoVolumeSettings.visualizeSteps); - } -} \ No newline at end of file diff --git a/unity/NanoVDB/NanoVolumeCustomPass.cs.meta b/unity/NanoVDB/NanoVolumeCustomPass.cs.meta deleted file mode 100644 index dac7bc02..00000000 --- a/unity/NanoVDB/NanoVolumeCustomPass.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: d93f84fcf6aa8704d91b42aced4fa025 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/unity/NanoVDB/NanoVolumeCustomPass.shader b/unity/NanoVDB/NanoVolumeCustomPass.shader deleted file mode 100644 index c516e7cc..00000000 --- a/unity/NanoVDB/NanoVolumeCustomPass.shader +++ /dev/null @@ -1,42 +0,0 @@ -Shader "FullScreen/NanoVolumePass" -{ - HLSLINCLUDE - - #pragma vertex Vert - - #pragma target 5.0 - #pragma use_dxc - - // Commons, includes many others - #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/RenderPass/CustomPass/CustomPassCommon.hlsl" - - #include "Assets/NanoVDB/PseudoRandom.hlsl" - #include "Assets/NanoVDB/NanoVolumePass.hlsl" - - float4 FullScreenPass(Varyings varyings) : SV_Target - { - UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(varyings); - float depth = LoadCameraDepth(varyings.positionCS.xy); - PositionInputs posInput = GetPositionInput(varyings.positionCS.xy, _ScreenSize.zw, depth, UNITY_MATRIX_I_VP, UNITY_MATRIX_V); - float3 viewDirection = GetWorldSpaceNormalizeViewDir(posInput.positionWS); - - float4 color = NanoVolumePass(_WorldSpaceCameraPos, -viewDirection); - return float4(color.rgb, color.a); - } - - ENDHLSL - - SubShader - { - Tags{ "RenderPipeline" = "HDRenderPipeline" } - Pass - { - Name "Nano Volume Pass" - ZWrite Off Cull Off Blend One OneMinusSrcAlpha - - HLSLPROGRAM - #pragma fragment FullScreenPass - ENDHLSL - } - } -} diff --git a/unity/NanoVDB/NanoVolumeCustomPass.shader.meta b/unity/NanoVDB/NanoVolumeCustomPass.shader.meta deleted file mode 100644 index f8cc92b6..00000000 --- a/unity/NanoVDB/NanoVolumeCustomPass.shader.meta +++ /dev/null @@ -1,9 +0,0 @@ -fileFormatVersion: 2 -guid: a3e61447f8553dc419567904d4bede14 -ShaderImporter: - externalObjects: {} - defaultTextures: [] - nonModifiableTextures: [] - userData: - assetBundleName: - assetBundleVariant: diff --git a/unity/NanoVDB/NanoVolumeLoader.cs b/unity/NanoVDB/NanoVolumeLoader.cs deleted file mode 100644 index 89336acb..00000000 --- a/unity/NanoVDB/NanoVolumeLoader.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using UnityEngine; - -public class NanoVolumeLoader : MonoBehaviour -{ - [StructLayout(LayoutKind.Sequential)] - private unsafe struct NanoVolume - { - public uint* buf; - public ulong byteSize; - public ulong elementCount; - public ulong structStride; - }; - unsafe NanoVolume* nanoVolume; - - [Header("Assets/path/to/volume.nvdb")] - - public string volumePath; - - private ComputeBuffer gpuBuffer; - private uint[] buf; - private bool ok; - private bool loaded = false; - - private void Awake() - { - SetDebugLogCallback(DebugLogCallback); - - ok = PrepareVolume(); - if (!ok) return; - - unsafe - { - int bufferSize = (int)nanoVolume->elementCount; - int stride = (int)nanoVolume->structStride; - - buf = new uint[bufferSize]; - - // Go through each element in nanoVolume buf and copy it to the buf array - for (int i = 0; i < bufferSize; i++) - { - buf[i] = nanoVolume->buf[i]; - } - - gpuBuffer = new ComputeBuffer( - bufferSize, - stride, - ComputeBufferType.Default - ); - gpuBuffer.SetData(buf); - - Debug.Log("GPU Buffer initialized"); - loaded = true; - } - } - - private unsafe bool PrepareVolume() - { - LoadNVDB(volumePath, out nanoVolume); - - if (nanoVolume != null) - { - Debug.Log($"NanoVDB initialized successfully. size={nanoVolume->byteSize} bytes, " + - $"array length={nanoVolume->elementCount}, stride={nanoVolume->structStride}"); - - return true; - } - else - { - Debug.LogError("Failed to create NanoVolume, aborting."); - return false; - } - } - - private void OnDestroy() - { - gpuBuffer?.Dispose(); - - unsafe - { - if (nanoVolume != null) - { - FreeNVDB(nanoVolume); - nanoVolume = null; - } - } - } - - public ComputeBuffer GetGPUBuffer() - { - if (gpuBuffer == null) - { - Debug.LogError("Buffer is null. Make sure the NanoLoader is finished before accessing this buffer."); - return null; - } - - return gpuBuffer; - } - - public bool IsLoaded() - { - return loaded; - } - - private delegate void DebugLogDelegate(IntPtr message); - - private static void DebugLogCallback(IntPtr message) { Debug.Log($"[NanoVDBWrapper.dll]: {Marshal.PtrToStringAnsi(message)}"); } - - [DllImport("NanoVDBWrapper", EntryPoint = "SetDebugLogCallback")] - private static extern void SetDebugLogCallback(DebugLogDelegate callback); - - [DllImport("NanoVDBWrapper", EntryPoint = "LoadNVDB")] - private unsafe static extern void LoadNVDB(string path, out NanoVolume* ptrToStruct); - - [DllImport("NanoVDBWrapper", EntryPoint = "FreeNVDB")] - private unsafe static extern void FreeNVDB(NanoVolume* ptrToStruct); -} diff --git a/unity/NanoVDB/NanoVolumeLoader.cs.meta b/unity/NanoVDB/NanoVolumeLoader.cs.meta deleted file mode 100644 index 97ed7498..00000000 --- a/unity/NanoVDB/NanoVolumeLoader.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f8652d7dda47bd74ba2fe1af0981c096 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/unity/NanoVDB/NanoVolumePass.hlsl b/unity/NanoVDB/NanoVolumePass.hlsl deleted file mode 100644 index 6cef8238..00000000 --- a/unity/NanoVDB/NanoVolumePass.hlsl +++ /dev/null @@ -1,276 +0,0 @@ -#ifndef NANO_VOLUME_PASS -#define NANO_VOLUME_PASS - -#define MIN_TRANSMITTANCE 0.05 -#define MIN_DENSITY 0.01 -#define CLOUD_COLOR float3(1, 1, 1) - -#define COLOR_NONE float4(0, 0, 0, 0) -#define COLOR_RED float4(1, 0, 0, 1) -#define COLOR_GREEN float4(0, 1, 0, 1) -#define COLOR_BLUE float4(0, 0, 1, 1) - -#define PNANOVDB_HLSL -#include "PNanoVDB.hlsl" - -uniform pnanovdb_buf_t buf : register(t1); - -uniform float4 _LightDir; // directionalLight.transform.forward - -uniform float3 _Light; -uniform float3 _Scattering; - -uniform float _DensityScale; -uniform float _LightRayLength; -uniform float _LightAbsorbation; -uniform float _ClipPlaneMin; -uniform float _ClipPlaneMax; - -uniform int _RayMarchSamples; -uniform int _LightSamples; - -uniform int _VisualizeSteps; - -struct Ray -{ - float3 origin; - float3 direction; - float tmin; - float tmax; -}; - -struct NanoVolume -{ - pnanovdb_grid_handle_t grid; - pnanovdb_grid_type_t grid_type; - pnanovdb_readaccessor_t acc; -}; - -void initVolume(inout NanoVolume volume) -{ - pnanovdb_grid_handle_t grid = { {0} }; - pnanovdb_grid_type_t grid_type = pnanovdb_buf_read_uint32(buf, PNANOVDB_GRID_OFF_GRID_TYPE); - pnanovdb_tree_handle_t tree = pnanovdb_grid_get_tree(buf, grid); - pnanovdb_root_handle_t root = pnanovdb_tree_get_root(buf, tree); - pnanovdb_readaccessor_t acc; - pnanovdb_readaccessor_init(acc, root); - - volume.grid = grid; - volume.grid_type = grid_type; - volume.acc = acc; -} - -float get_value_coord(inout pnanovdb_readaccessor_t acc, pnanovdb_vec3_t pos) -{ - pnanovdb_coord_t ijk = pnanovdb_hdda_pos_to_ijk(pos); - pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, ijk); - return pnanovdb_read_float(buf, address); -} - -uint get_dim_coord(inout pnanovdb_readaccessor_t acc, pnanovdb_vec3_t pos) -{ - pnanovdb_coord_t ijk = pnanovdb_hdda_pos_to_ijk(pos); - return pnanovdb_readaccessor_get_dim(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, ijk); -} - -bool get_hdda_hit(inout pnanovdb_readaccessor_t acc, inout Ray ray, inout float valueAtHit) -{ - float thit; - bool hit = pnanovdb_hdda_tree_marcher( - PNANOVDB_GRID_TYPE_FLOAT, - buf, - acc, - ray.origin, ray.tmin, - ray.direction, ray.tmax, - thit, - valueAtHit - ); - ray.tmin = thit; - return hit; -} - -void get_participating_media(out float sigmaS, out float sigmaE, float3 pos, inout pnanovdb_readaccessor_t acc) -{ - sigmaS = get_value_coord(acc, pos) * _DensityScale; - sigmaE = max(0.000001, sigmaS); -} - -// No inout to avoid breaking cache for main ray (Gaida 2022) -float volumetric_shadow(float3 pos, pnanovdb_readaccessor_t acc) -{ - if (_LightSamples < 1) { return 0; } - - float light_dir = -(_LightDir.xyz); - - float shadow = 1; - float sigmaS = 0.0; - float sigmaE = 0.0; - - int step = 0; - int steps = 10; - float step_size = 1; - while (step < steps) - { - float3 sample_pos = pos + step_size * light_dir; - - get_participating_media(sigmaS, sigmaE, sample_pos, acc); - shadow *= exp(-sigmaE * step_size); - - if (shadow < MIN_TRANSMITTANCE) - { - shadow = 0; - break; - } - - step_size *= 2; - step++; - } - return shadow; -} - -// Exp step with jitter -float volumetric_shadow_2(float3 pos, pnanovdb_readaccessor_t acc, float3 view_dir) -{ - if (_LightSamples < 1) { return 0; } - - float light_dir = -(_LightDir.xyz); - - float shadow = 1.0; - float sigmaS = 0.0; - float sigmaE = 0.0; - - float step_size = 1.0; - float jitter = 0; - - int step = 0; - int steps = 10; - while (step < steps) - { - float3 sample_pos = pos + (jitter + step_size) * light_dir; - - get_participating_media(sigmaS, sigmaE, sample_pos, acc); - sigmaE *= 0.3; - shadow *= exp(-sigmaE * step_size); - - step++; - step_size *= (2 + random_float(sample_pos)); - } - - return shadow; -} - -float phase_function() -{ - return 1.0;///(4.0*3.14); -} - -float4 raymarch_volume(Ray ray, inout NanoVolume volume, float step_size) -{ - float transmittance = 1.0; - float sigmaS = 0.0; - float sigmaE = 0.0; - float acc_density = 0.0; - float3 direct_light = 0.0; - float3 ambient_light = 0.005; - - float not_used; - bool hit = get_hdda_hit(volume.acc, ray, not_used); - if (!hit) { return COLOR_NONE; } - - int step = 0; - float skip = 0; - while (step < _RayMarchSamples) - { - if (ray.tmin >= ray.tmax) - { - break; - } - - // read density from ray position - float3 pos = ray.origin + ray.direction * ray.tmin; - get_participating_media(sigmaS, sigmaE, pos, volume.acc); - - // Skip empty space. - uint dim = get_dim_coord(volume.acc, pos); - if (dim > 1) - { - step++; - float skip_step = 15; - ray.tmin += skip_step; - skip = skip_step; - continue; - } - if (sigmaS < MIN_DENSITY) - { - step++; - float skip_step = 5; - ray.tmin += skip_step; - skip = skip_step; - continue; - } - - if (skip > 0) { - // backtrack a little bit - ray.tmin -= skip * 0.8; - pos = ray.origin + ray.direction * ray.tmin; - skip = 0; - } - - acc_density += sigmaS; - - // float3 S = sigmaS * phase_function() * volumetric_shadow_2(pos, volume.acc); - float3 S = sigmaS * phase_function() * volumetric_shadow_2(pos, volume.acc, ray.direction); - float3 Sint = (S - S * exp(-sigmaE * step_size)) / sigmaE; - direct_light += transmittance * Sint; - - transmittance *= exp(-sigmaE * step_size); - - if (acc_density > 1.0) - { - break; - } - - // Early out if no more light is reaching this point - if (transmittance < MIN_TRANSMITTANCE) - { - transmittance = 0; - break; - } - - step++; - ray.tmin += step_size; - } - - // Low step count will be blue, high red. - if (_VisualizeSteps == 1) - { - float t = float(step) / float(_RayMarchSamples); - if (step <= 0) - { - return COLOR_NONE; - } - float3 final_color = lerp(COLOR_BLUE, COLOR_RED, t); - return float4(final_color, 1); - } - - float3 final_color = (direct_light + ambient_light) * acc_density; - final_color = pow(final_color, 1.0 / 2.2); - return float4(final_color, acc_density); -} - -float4 NanoVolumePass(float3 origin, float3 direction) -{ - NanoVolume volume; initVolume(volume); - - Ray ray; - ray.origin = origin; - ray.direction = direction; - ray.tmin = _ClipPlaneMin; - ray.tmax = _ClipPlaneMax; - - float step_size = 0.57; - float4 final_color = raymarch_volume(ray, volume, step_size); - return final_color; -} - -#endif // NANO_VOLUME_PASS diff --git a/unity/NanoVDB/NanoVolumePass.hlsl.meta b/unity/NanoVDB/NanoVolumePass.hlsl.meta deleted file mode 100644 index 22cce232..00000000 --- a/unity/NanoVDB/NanoVolumePass.hlsl.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 47dfc462aec4e4d46939d91412958fe4 -ShaderIncludeImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/unity/NanoVDB/NanoVolumeSettings.cs b/unity/NanoVDB/NanoVolumeSettings.cs deleted file mode 100644 index 682325e0..00000000 --- a/unity/NanoVDB/NanoVolumeSettings.cs +++ /dev/null @@ -1,35 +0,0 @@ -using TMPro; -using UnityEngine; -using UnityEngine.UI; - -public class NanoVolumeSettings : MonoBehaviour -{ - public Light directionalLight; - public TMP_Text vdbNameText; - public Slider RaymarchSamples; - public Slider TemporalFrames; - public Slider DensitySlider; - public Slider LightSteps; - public Slider LightAbsorbation; - public Color scatteringColor; - public int visualizeSteps = 0; - - // Called from UI Button - public void VisualizeSteps() - { - if (visualizeSteps == 0) - { - visualizeSteps = 1; - } - else - { - visualizeSteps = 0; - } - } - - // When clicking reset button - public void StopVisualizeSteps() - { - visualizeSteps = 0; - } -} diff --git a/unity/NanoVDB/NanoVolumeSettings.cs.meta b/unity/NanoVDB/NanoVolumeSettings.cs.meta deleted file mode 100644 index 3dcc0f22..00000000 --- a/unity/NanoVDB/NanoVolumeSettings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 04a3f5c1a0e0ba240ae40af9f0fcce17 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/unity/NanoVDB/PNanoVDB.hlsl b/unity/NanoVDB/PNanoVDB.hlsl deleted file mode 100644 index 67c93b08..00000000 --- a/unity/NanoVDB/PNanoVDB.hlsl +++ /dev/null @@ -1,3454 +0,0 @@ - -// Copyright Contributors to the OpenVDB Project -// SPDX-License-Identifier: MPL-2.0 - -/*! - \file PNanoVDB.h - - \author Andrew Reidmeyer - - \brief This file is a portable (e.g. pointer-less) C99/GLSL/HLSL port - of NanoVDB.h, which is compatible with most graphics APIs. -*/ - -#ifndef NANOVDB_PNANOVDB_H_HAS_BEEN_INCLUDED -#define NANOVDB_PNANOVDB_H_HAS_BEEN_INCLUDED - -// ------------------------------------------------ Configuration ----------------------------------------------------------- - -// platforms -//#define PNANOVDB_C -//#define PNANOVDB_HLSL -//#define PNANOVDB_GLSL - -// addressing mode -// PNANOVDB_ADDRESS_32 -// PNANOVDB_ADDRESS_64 -#if defined(PNANOVDB_C) -#ifndef PNANOVDB_ADDRESS_32 -#define PNANOVDB_ADDRESS_64 -#endif -#elif defined(PNANOVDB_HLSL) -#ifndef PNANOVDB_ADDRESS_64 -#define PNANOVDB_ADDRESS_32 -#endif -#elif defined(PNANOVDB_GLSL) -#ifndef PNANOVDB_ADDRESS_64 -#define PNANOVDB_ADDRESS_32 -#endif -#endif - -// bounds checking -//#define PNANOVDB_BUF_BOUNDS_CHECK - -// enable HDDA by default on HLSL/GLSL, make explicit on C -#if defined(PNANOVDB_C) -//#define PNANOVDB_HDDA -#ifdef PNANOVDB_HDDA -#ifndef PNANOVDB_CMATH -#define PNANOVDB_CMATH -#endif -#endif -#elif defined(PNANOVDB_HLSL) -#define PNANOVDB_HDDA -#elif defined(PNANOVDB_GLSL) -#define PNANOVDB_HDDA -#endif - -#ifdef PNANOVDB_CMATH -#ifndef __CUDACC_RTC__ -#include -#endif -#endif - -// ------------------------------------------------ Buffer ----------------------------------------------------------- - -#if defined(PNANOVDB_BUF_CUSTOM) -// NOP -#elif defined(PNANOVDB_C) -#define PNANOVDB_BUF_C -#elif defined(PNANOVDB_HLSL) -#define PNANOVDB_BUF_HLSL -#elif defined(PNANOVDB_GLSL) -#define PNANOVDB_BUF_GLSL -#endif - -#if defined(PNANOVDB_BUF_C) -#ifndef __CUDACC_RTC__ -#include -#endif -#if defined(__CUDACC__) -#define PNANOVDB_BUF_FORCE_INLINE static __host__ __device__ __forceinline__ -#elif defined(_WIN32) -#define PNANOVDB_BUF_FORCE_INLINE static inline __forceinline -#else -#define PNANOVDB_BUF_FORCE_INLINE static inline __attribute__((always_inline)) -#endif -typedef struct pnanovdb_buf_t -{ - uint32_t* data; -#ifdef PNANOVDB_BUF_BOUNDS_CHECK - uint64_t size_in_words; -#endif -}pnanovdb_buf_t; -PNANOVDB_BUF_FORCE_INLINE pnanovdb_buf_t pnanovdb_make_buf(uint32_t* data, uint64_t size_in_words) -{ - pnanovdb_buf_t ret; - ret.data = data; -#ifdef PNANOVDB_BUF_BOUNDS_CHECK - ret.size_in_words = size_in_words; -#endif - return ret; -} -#if defined(PNANOVDB_ADDRESS_32) -PNANOVDB_BUF_FORCE_INLINE uint32_t pnanovdb_buf_read_uint32(pnanovdb_buf_t buf, uint32_t byte_offset) -{ - uint32_t wordaddress = (byte_offset >> 2u); -#ifdef PNANOVDB_BUF_BOUNDS_CHECK - return wordaddress < buf.size_in_words ? buf.data[wordaddress] : 0u; -#else - return buf.data[wordaddress]; -#endif -} -PNANOVDB_BUF_FORCE_INLINE uint64_t pnanovdb_buf_read_uint64(pnanovdb_buf_t buf, uint32_t byte_offset) -{ - uint64_t* data64 = (uint64_t*)buf.data; - uint32_t wordaddress64 = (byte_offset >> 3u); -#ifdef PNANOVDB_BUF_BOUNDS_CHECK - uint64_t size_in_words64 = buf.size_in_words >> 1u; - return wordaddress64 < size_in_words64 ? data64[wordaddress64] : 0llu; -#else - return data64[wordaddress64]; -#endif -} -PNANOVDB_BUF_FORCE_INLINE void pnanovdb_buf_write_uint32(pnanovdb_buf_t buf, uint32_t byte_offset, uint32_t value) -{ - uint32_t wordaddress = (byte_offset >> 2u); -#ifdef PNANOVDB_BUF_BOUNDS_CHECK - if (wordaddress < buf.size_in_words) - { - buf.data[wordaddress] = value; -} -#else - buf.data[wordaddress] = value; -#endif -} -PNANOVDB_BUF_FORCE_INLINE void pnanovdb_buf_write_uint64(pnanovdb_buf_t buf, uint32_t byte_offset, uint64_t value) -{ - uint64_t* data64 = (uint64_t*)buf.data; - uint32_t wordaddress64 = (byte_offset >> 3u); -#ifdef PNANOVDB_BUF_BOUNDS_CHECK - uint64_t size_in_words64 = buf.size_in_words >> 1u; - if (wordaddress64 < size_in_words64) - { - data64[wordaddress64] = value; - } -#else - data64[wordaddress64] = value; -#endif -} -#elif defined(PNANOVDB_ADDRESS_64) -PNANOVDB_BUF_FORCE_INLINE uint32_t pnanovdb_buf_read_uint32(pnanovdb_buf_t buf, uint64_t byte_offset) -{ - uint64_t wordaddress = (byte_offset >> 2u); -#ifdef PNANOVDB_BUF_BOUNDS_CHECK - return wordaddress < buf.size_in_words ? buf.data[wordaddress] : 0u; -#else - return buf.data[wordaddress]; -#endif -} -PNANOVDB_BUF_FORCE_INLINE uint64_t pnanovdb_buf_read_uint64(pnanovdb_buf_t buf, uint64_t byte_offset) -{ - uint64_t* data64 = (uint64_t*)buf.data; - uint64_t wordaddress64 = (byte_offset >> 3u); -#ifdef PNANOVDB_BUF_BOUNDS_CHECK - uint64_t size_in_words64 = buf.size_in_words >> 1u; - return wordaddress64 < size_in_words64 ? data64[wordaddress64] : 0llu; -#else - return data64[wordaddress64]; -#endif -} -PNANOVDB_BUF_FORCE_INLINE void pnanovdb_buf_write_uint32(pnanovdb_buf_t buf, uint64_t byte_offset, uint32_t value) -{ - uint64_t wordaddress = (byte_offset >> 2u); -#ifdef PNANOVDB_BUF_BOUNDS_CHECK - if (wordaddress < buf.size_in_words) - { - buf.data[wordaddress] = value; - } -#else - buf.data[wordaddress] = value; -#endif -} -PNANOVDB_BUF_FORCE_INLINE void pnanovdb_buf_write_uint64(pnanovdb_buf_t buf, uint64_t byte_offset, uint64_t value) -{ - uint64_t* data64 = (uint64_t*)buf.data; - uint64_t wordaddress64 = (byte_offset >> 3u); -#ifdef PNANOVDB_BUF_BOUNDS_CHECK - uint64_t size_in_words64 = buf.size_in_words >> 1u; - if (wordaddress64 < size_in_words64) - { - data64[wordaddress64] = value; - } -#else - data64[wordaddress64] = value; -#endif -} -#endif -typedef uint32_t pnanovdb_grid_type_t; -#define PNANOVDB_GRID_TYPE_GET(grid_typeIn, nameIn) pnanovdb_grid_type_constants[grid_typeIn].nameIn -#elif defined(PNANOVDB_BUF_HLSL) -#if defined(PNANOVDB_ADDRESS_32) -#define pnanovdb_buf_t StructuredBuffer -uint pnanovdb_buf_read_uint32(pnanovdb_buf_t buf, uint byte_offset) -{ - return buf[(byte_offset >> 2u)]; -} -uint2 pnanovdb_buf_read_uint64(pnanovdb_buf_t buf, uint byte_offset) -{ - uint2 ret; - ret.x = pnanovdb_buf_read_uint32(buf, byte_offset + 0u); - ret.y = pnanovdb_buf_read_uint32(buf, byte_offset + 4u); - return ret; -} -void pnanovdb_buf_write_uint32(pnanovdb_buf_t buf, uint byte_offset, uint value) -{ - // NOP, by default no write in HLSL -} -void pnanovdb_buf_write_uint64(pnanovdb_buf_t buf, uint byte_offset, uint2 value) -{ - // NOP, by default no write in HLSL -} -#elif defined(PNANOVDB_ADDRESS_64) -#define pnanovdb_buf_t StructuredBuffer -uint pnanovdb_buf_read_uint32(pnanovdb_buf_t buf, uint64_t byte_offset) -{ - return buf[uint(byte_offset >> 2u)]; -} -uint64_t pnanovdb_buf_read_uint64(pnanovdb_buf_t buf, uint64_t byte_offset) -{ - uint64_t ret; - ret = pnanovdb_buf_read_uint32(buf, byte_offset + 0u); - ret = ret + (uint64_t(pnanovdb_buf_read_uint32(buf, byte_offset + 4u)) << 32u); - return ret; -} -void pnanovdb_buf_write_uint32(pnanovdb_buf_t buf, uint64_t byte_offset, uint value) -{ - // NOP, by default no write in HLSL -} -void pnanovdb_buf_write_uint64(pnanovdb_buf_t buf, uint64_t byte_offset, uint64_t value) -{ - // NOP, by default no write in HLSL -} -#endif -#define pnanovdb_grid_type_t uint -#define PNANOVDB_GRID_TYPE_GET(grid_typeIn, nameIn) pnanovdb_grid_type_constants[grid_typeIn].nameIn -#elif defined(PNANOVDB_BUF_GLSL) -struct pnanovdb_buf_t -{ - uint unused; // to satisfy min struct size? -}; -uint pnanovdb_buf_read_uint32(pnanovdb_buf_t buf, uint byte_offset) -{ - return pnanovdb_buf_data[(byte_offset >> 2u)]; -} -uvec2 pnanovdb_buf_read_uint64(pnanovdb_buf_t buf, uint byte_offset) -{ - uvec2 ret; - ret.x = pnanovdb_buf_read_uint32(buf, byte_offset + 0u); - ret.y = pnanovdb_buf_read_uint32(buf, byte_offset + 4u); - return ret; -} -void pnanovdb_buf_write_uint32(pnanovdb_buf_t buf, uint byte_offset, uint value) -{ - // NOP, by default no write in HLSL -} -void pnanovdb_buf_write_uint64(pnanovdb_buf_t buf, uint byte_offset, uvec2 value) -{ - // NOP, by default no write in HLSL -} -#define pnanovdb_grid_type_t uint -#define PNANOVDB_GRID_TYPE_GET(grid_typeIn, nameIn) pnanovdb_grid_type_constants[grid_typeIn].nameIn -#endif - -// ------------------------------------------------ Basic Types ----------------------------------------------------------- - -// force inline -#if defined(PNANOVDB_C) -#if defined(__CUDACC__) -#define PNANOVDB_FORCE_INLINE static __host__ __device__ __forceinline__ -#elif defined(_WIN32) -#define PNANOVDB_FORCE_INLINE static inline __forceinline -#else -#define PNANOVDB_FORCE_INLINE static inline __attribute__((always_inline)) -#endif -#elif defined(PNANOVDB_HLSL) -#define PNANOVDB_FORCE_INLINE -#elif defined(PNANOVDB_GLSL) -#define PNANOVDB_FORCE_INLINE -#endif - -// struct typedef, static const, inout -#if defined(PNANOVDB_C) -#define PNANOVDB_STRUCT_TYPEDEF(X) typedef struct X X; -#define PNANOVDB_STATIC_CONST static const -#define PNANOVDB_INOUT(X) X* -#define PNANOVDB_IN(X) const X* -#define PNANOVDB_DEREF(X) (*X) -#define PNANOVDB_REF(X) &X -#elif defined(PNANOVDB_HLSL) -#define PNANOVDB_STRUCT_TYPEDEF(X) -#define PNANOVDB_STATIC_CONST static const -#define PNANOVDB_INOUT(X) inout X -#define PNANOVDB_IN(X) X -#define PNANOVDB_DEREF(X) X -#define PNANOVDB_REF(X) X -#elif defined(PNANOVDB_GLSL) -#define PNANOVDB_STRUCT_TYPEDEF(X) -#define PNANOVDB_STATIC_CONST const -#define PNANOVDB_INOUT(X) inout X -#define PNANOVDB_IN(X) X -#define PNANOVDB_DEREF(X) X -#define PNANOVDB_REF(X) X -#endif - -// basic types, type conversion -#if defined(PNANOVDB_C) -#define PNANOVDB_NATIVE_64 -#ifndef __CUDACC_RTC__ -#include -#endif -#if !defined(PNANOVDB_MEMCPY_CUSTOM) -#ifndef __CUDACC_RTC__ -#include -#endif -#define pnanovdb_memcpy memcpy -#endif -typedef uint32_t pnanovdb_uint32_t; -typedef int32_t pnanovdb_int32_t; -typedef int32_t pnanovdb_bool_t; -#define PNANOVDB_FALSE 0 -#define PNANOVDB_TRUE 1 -typedef uint64_t pnanovdb_uint64_t; -typedef int64_t pnanovdb_int64_t; -typedef struct pnanovdb_coord_t -{ - pnanovdb_int32_t x, y, z; -}pnanovdb_coord_t; -typedef struct pnanovdb_vec3_t -{ - float x, y, z; -}pnanovdb_vec3_t; -PNANOVDB_FORCE_INLINE pnanovdb_int32_t pnanovdb_uint32_as_int32(pnanovdb_uint32_t v) { return (pnanovdb_int32_t)v; } -PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_uint64_as_int64(pnanovdb_uint64_t v) { return (pnanovdb_int64_t)v; } -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_int64_as_uint64(pnanovdb_int64_t v) { return (pnanovdb_uint64_t)v; } -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_int32_as_uint32(pnanovdb_int32_t v) { return (pnanovdb_uint32_t)v; } -PNANOVDB_FORCE_INLINE float pnanovdb_uint32_as_float(pnanovdb_uint32_t v) { float vf; pnanovdb_memcpy(&vf, &v, sizeof(vf)); return vf; } -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_float_as_uint32(float v) { return *((pnanovdb_uint32_t*)(&v)); } -PNANOVDB_FORCE_INLINE double pnanovdb_uint64_as_double(pnanovdb_uint64_t v) { double vf; pnanovdb_memcpy(&vf, &v, sizeof(vf)); return vf; } -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_double_as_uint64(double v) { return *((pnanovdb_uint64_t*)(&v)); } -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_uint64_low(pnanovdb_uint64_t v) { return (pnanovdb_uint32_t)v; } -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_uint64_high(pnanovdb_uint64_t v) { return (pnanovdb_uint32_t)(v >> 32u); } -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint32_as_uint64(pnanovdb_uint32_t x, pnanovdb_uint32_t y) { return ((pnanovdb_uint64_t)x) | (((pnanovdb_uint64_t)y) << 32u); } -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint32_as_uint64_low(pnanovdb_uint32_t x) { return ((pnanovdb_uint64_t)x); } -PNANOVDB_FORCE_INLINE pnanovdb_int32_t pnanovdb_uint64_is_equal(pnanovdb_uint64_t a, pnanovdb_uint64_t b) { return a == b; } -PNANOVDB_FORCE_INLINE pnanovdb_int32_t pnanovdb_int64_is_zero(pnanovdb_int64_t a) { return a == 0; } -#ifdef PNANOVDB_CMATH -PNANOVDB_FORCE_INLINE float pnanovdb_floor(float v) { return floorf(v); } -#endif -PNANOVDB_FORCE_INLINE pnanovdb_int32_t pnanovdb_float_to_int32(float v) { return (pnanovdb_int32_t)v; } -PNANOVDB_FORCE_INLINE float pnanovdb_int32_to_float(pnanovdb_int32_t v) { return (float)v; } -PNANOVDB_FORCE_INLINE float pnanovdb_uint32_to_float(pnanovdb_uint32_t v) { return (float)v; } -PNANOVDB_FORCE_INLINE float pnanovdb_min(float a, float b) { return a < b ? a : b; } -PNANOVDB_FORCE_INLINE float pnanovdb_max(float a, float b) { return a > b ? a : b; } -#elif defined(PNANOVDB_HLSL) -typedef uint pnanovdb_uint32_t; -typedef int pnanovdb_int32_t; -typedef bool pnanovdb_bool_t; -#define PNANOVDB_FALSE false -#define PNANOVDB_TRUE true -typedef int3 pnanovdb_coord_t; -typedef float3 pnanovdb_vec3_t; -pnanovdb_int32_t pnanovdb_uint32_as_int32(pnanovdb_uint32_t v) { return int(v); } -pnanovdb_uint32_t pnanovdb_int32_as_uint32(pnanovdb_int32_t v) { return uint(v); } -float pnanovdb_uint32_as_float(pnanovdb_uint32_t v) { return asfloat(v); } -pnanovdb_uint32_t pnanovdb_float_as_uint32(float v) { return asuint(v); } -float pnanovdb_floor(float v) { return floor(v); } -pnanovdb_int32_t pnanovdb_float_to_int32(float v) { return int(v); } -float pnanovdb_int32_to_float(pnanovdb_int32_t v) { return float(v); } -float pnanovdb_uint32_to_float(pnanovdb_uint32_t v) { return float(v); } -float pnanovdb_min(float a, float b) { return min(a, b); } -float pnanovdb_max(float a, float b) { return max(a, b); } -#if defined(PNANOVDB_ADDRESS_32) -typedef uint2 pnanovdb_uint64_t; -typedef int2 pnanovdb_int64_t; -pnanovdb_int64_t pnanovdb_uint64_as_int64(pnanovdb_uint64_t v) { return int2(v); } -pnanovdb_uint64_t pnanovdb_int64_as_uint64(pnanovdb_int64_t v) { return uint2(v); } -double pnanovdb_uint64_as_double(pnanovdb_uint64_t v) { return asdouble(v.x, v.y); } -pnanovdb_uint64_t pnanovdb_double_as_uint64(double v) { uint2 ret; asuint(v, ret.x, ret.y); return ret; } -pnanovdb_uint32_t pnanovdb_uint64_low(pnanovdb_uint64_t v) { return v.x; } -pnanovdb_uint32_t pnanovdb_uint64_high(pnanovdb_uint64_t v) { return v.y; } -pnanovdb_uint64_t pnanovdb_uint32_as_uint64(pnanovdb_uint32_t x, pnanovdb_uint32_t y) { return uint2(x, y); } -pnanovdb_uint64_t pnanovdb_uint32_as_uint64_low(pnanovdb_uint32_t x) { return uint2(x, 0); } -bool pnanovdb_uint64_is_equal(pnanovdb_uint64_t a, pnanovdb_uint64_t b) { return (a.x == b.x) && (a.y == b.y); } -bool pnanovdb_int64_is_zero(pnanovdb_int64_t a) { return a.x == 0 && a.y == 0; } -#else -typedef uint64_t pnanovdb_uint64_t; -typedef int64_t pnanovdb_int64_t; -pnanovdb_int64_t pnanovdb_uint64_as_int64(pnanovdb_uint64_t v) { return int64_t(v); } -pnanovdb_uint64_t pnanovdb_int64_as_uint64(pnanovdb_int64_t v) { return uint64_t(v); } -double pnanovdb_uint64_as_double(pnanovdb_uint64_t v) { return asdouble(uint(v), uint(v >> 32u)); } -pnanovdb_uint64_t pnanovdb_double_as_uint64(double v) { uint2 ret; asuint(v, ret.x, ret.y); return uint64_t(ret.x) + (uint64_t(ret.y) << 32u); } -pnanovdb_uint32_t pnanovdb_uint64_low(pnanovdb_uint64_t v) { return uint(v); } -pnanovdb_uint32_t pnanovdb_uint64_high(pnanovdb_uint64_t v) { return uint(v >> 32u); } -pnanovdb_uint64_t pnanovdb_uint32_as_uint64(pnanovdb_uint32_t x, pnanovdb_uint32_t y) { return uint64_t(x) + (uint64_t(y) << 32u); } -pnanovdb_uint64_t pnanovdb_uint32_as_uint64_low(pnanovdb_uint32_t x) { return uint64_t(x); } -bool pnanovdb_uint64_is_equal(pnanovdb_uint64_t a, pnanovdb_uint64_t b) { return a == b; } -bool pnanovdb_int64_is_zero(pnanovdb_int64_t a) { return a == 0; } -#endif -#elif defined(PNANOVDB_GLSL) -#define pnanovdb_uint32_t uint -#define pnanovdb_int32_t int -#define pnanovdb_bool_t bool -#define PNANOVDB_FALSE false -#define PNANOVDB_TRUE true -#define pnanovdb_uint64_t uvec2 -#define pnanovdb_int64_t ivec2 -#define pnanovdb_coord_t ivec3 -#define pnanovdb_vec3_t vec3 -pnanovdb_int32_t pnanovdb_uint32_as_int32(pnanovdb_uint32_t v) { return int(v); } -pnanovdb_int64_t pnanovdb_uint64_as_int64(pnanovdb_uint64_t v) { return ivec2(v); } -pnanovdb_uint64_t pnanovdb_int64_as_uint64(pnanovdb_int64_t v) { return uvec2(v); } -pnanovdb_uint32_t pnanovdb_int32_as_uint32(pnanovdb_int32_t v) { return uint(v); } -float pnanovdb_uint32_as_float(pnanovdb_uint32_t v) { return uintBitsToFloat(v); } -pnanovdb_uint32_t pnanovdb_float_as_uint32(float v) { return floatBitsToUint(v); } -double pnanovdb_uint64_as_double(pnanovdb_uint64_t v) { return packDouble2x32(uvec2(v.x, v.y)); } -pnanovdb_uint64_t pnanovdb_double_as_uint64(double v) { return unpackDouble2x32(v); } -pnanovdb_uint32_t pnanovdb_uint64_low(pnanovdb_uint64_t v) { return v.x; } -pnanovdb_uint32_t pnanovdb_uint64_high(pnanovdb_uint64_t v) { return v.y; } -pnanovdb_uint64_t pnanovdb_uint32_as_uint64(pnanovdb_uint32_t x, pnanovdb_uint32_t y) { return uvec2(x, y); } -pnanovdb_uint64_t pnanovdb_uint32_as_uint64_low(pnanovdb_uint32_t x) { return uvec2(x, 0); } -bool pnanovdb_uint64_is_equal(pnanovdb_uint64_t a, pnanovdb_uint64_t b) { return (a.x == b.x) && (a.y == b.y); } -bool pnanovdb_int64_is_zero(pnanovdb_int64_t a) { return a.x == 0 && a.y == 0; } -float pnanovdb_floor(float v) { return floor(v); } -pnanovdb_int32_t pnanovdb_float_to_int32(float v) { return int(v); } -float pnanovdb_int32_to_float(pnanovdb_int32_t v) { return float(v); } -float pnanovdb_uint32_to_float(pnanovdb_uint32_t v) { return float(v); } -float pnanovdb_min(float a, float b) { return min(a, b); } -float pnanovdb_max(float a, float b) { return max(a, b); } -#endif - -// ------------------------------------------------ Coord/Vec3 Utilties ----------------------------------------------------------- - -#if defined(PNANOVDB_C) -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_uniform(float a) -{ - pnanovdb_vec3_t v; - v.x = a; - v.y = a; - v.z = a; - return v; -} -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_add(const pnanovdb_vec3_t a, const pnanovdb_vec3_t b) -{ - pnanovdb_vec3_t v; - v.x = a.x + b.x; - v.y = a.y + b.y; - v.z = a.z + b.z; - return v; -} -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_sub(const pnanovdb_vec3_t a, const pnanovdb_vec3_t b) -{ - pnanovdb_vec3_t v; - v.x = a.x - b.x; - v.y = a.y - b.y; - v.z = a.z - b.z; - return v; -} -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_mul(const pnanovdb_vec3_t a, const pnanovdb_vec3_t b) -{ - pnanovdb_vec3_t v; - v.x = a.x * b.x; - v.y = a.y * b.y; - v.z = a.z * b.z; - return v; -} -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_div(const pnanovdb_vec3_t a, const pnanovdb_vec3_t b) -{ - pnanovdb_vec3_t v; - v.x = a.x / b.x; - v.y = a.y / b.y; - v.z = a.z / b.z; - return v; -} -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_min(const pnanovdb_vec3_t a, const pnanovdb_vec3_t b) -{ - pnanovdb_vec3_t v; - v.x = a.x < b.x ? a.x : b.x; - v.y = a.y < b.y ? a.y : b.y; - v.z = a.z < b.z ? a.z : b.z; - return v; -} -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_vec3_max(const pnanovdb_vec3_t a, const pnanovdb_vec3_t b) -{ - pnanovdb_vec3_t v; - v.x = a.x > b.x ? a.x : b.x; - v.y = a.y > b.y ? a.y : b.y; - v.z = a.z > b.z ? a.z : b.z; - return v; -} -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_coord_to_vec3(const pnanovdb_coord_t coord) -{ - pnanovdb_vec3_t v; - v.x = pnanovdb_int32_to_float(coord.x); - v.y = pnanovdb_int32_to_float(coord.y); - v.z = pnanovdb_int32_to_float(coord.z); - return v; -} -PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_coord_uniform(const pnanovdb_int32_t a) -{ - pnanovdb_coord_t v; - v.x = a; - v.y = a; - v.z = a; - return v; -} -PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_coord_add(pnanovdb_coord_t a, pnanovdb_coord_t b) -{ - pnanovdb_coord_t v; - v.x = a.x + b.x; - v.y = a.y + b.y; - v.z = a.z + b.z; - return v; -} -#elif defined(PNANOVDB_HLSL) -pnanovdb_vec3_t pnanovdb_vec3_uniform(float a) { return float3(a, a, a); } -pnanovdb_vec3_t pnanovdb_vec3_add(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a + b; } -pnanovdb_vec3_t pnanovdb_vec3_sub(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a - b; } -pnanovdb_vec3_t pnanovdb_vec3_mul(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a * b; } -pnanovdb_vec3_t pnanovdb_vec3_div(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a / b; } -pnanovdb_vec3_t pnanovdb_vec3_min(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return min(a, b); } -pnanovdb_vec3_t pnanovdb_vec3_max(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return max(a, b); } -pnanovdb_vec3_t pnanovdb_coord_to_vec3(pnanovdb_coord_t coord) { return float3(coord); } -pnanovdb_coord_t pnanovdb_coord_uniform(pnanovdb_int32_t a) { return int3(a, a, a); } -pnanovdb_coord_t pnanovdb_coord_add(pnanovdb_coord_t a, pnanovdb_coord_t b) { return a + b; } -#elif defined(PNANOVDB_GLSL) -pnanovdb_vec3_t pnanovdb_vec3_uniform(float a) { return vec3(a, a, a); } -pnanovdb_vec3_t pnanovdb_vec3_add(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a + b; } -pnanovdb_vec3_t pnanovdb_vec3_sub(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a - b; } -pnanovdb_vec3_t pnanovdb_vec3_mul(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a * b; } -pnanovdb_vec3_t pnanovdb_vec3_div(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return a / b; } -pnanovdb_vec3_t pnanovdb_vec3_min(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return min(a, b); } -pnanovdb_vec3_t pnanovdb_vec3_max(pnanovdb_vec3_t a, pnanovdb_vec3_t b) { return max(a, b); } -pnanovdb_vec3_t pnanovdb_coord_to_vec3(const pnanovdb_coord_t coord) { return vec3(coord); } -pnanovdb_coord_t pnanovdb_coord_uniform(pnanovdb_int32_t a) { return ivec3(a, a, a); } -pnanovdb_coord_t pnanovdb_coord_add(pnanovdb_coord_t a, pnanovdb_coord_t b) { return a + b; } -#endif - -// ------------------------------------------------ Uint64 Utils ----------------------------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_uint32_countbits(pnanovdb_uint32_t value) -{ -#if defined(PNANOVDB_C) -#if defined(_MSC_VER) && (_MSC_VER >= 1928) && defined(PNANOVDB_USE_INTRINSICS) - return __popcnt(value); -#elif (defined(__GNUC__) || defined(__clang__)) && defined(PNANOVDB_USE_INTRINSICS) - return __builtin_popcount(value); -#else - value = value - ((value >> 1) & 0x55555555); - value = (value & 0x33333333) + ((value >> 2) & 0x33333333); - value = (value + (value >> 4)) & 0x0F0F0F0F; - return (value * 0x01010101) >> 24; -#endif -#elif defined(PNANOVDB_HLSL) - return countbits(value); -#elif defined(PNANOVDB_GLSL) - return bitCount(value); -#endif -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_uint64_countbits(pnanovdb_uint64_t value) -{ - return pnanovdb_uint32_countbits(pnanovdb_uint64_low(value)) + pnanovdb_uint32_countbits(pnanovdb_uint64_high(value)); -} - -#if defined(PNANOVDB_ADDRESS_32) -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_offset(pnanovdb_uint64_t a, pnanovdb_uint32_t b) -{ - pnanovdb_uint32_t low = pnanovdb_uint64_low(a); - pnanovdb_uint32_t high = pnanovdb_uint64_high(a); - low += b; - if (low < b) - { - high += 1u; - } - return pnanovdb_uint32_as_uint64(low, high); -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_dec(pnanovdb_uint64_t a) -{ - pnanovdb_uint32_t low = pnanovdb_uint64_low(a); - pnanovdb_uint32_t high = pnanovdb_uint64_high(a); - if (low == 0u) - { - high -= 1u; - } - low -= 1u; - return pnanovdb_uint32_as_uint64(low, high); -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_uint64_to_uint32_lsr(pnanovdb_uint64_t a, pnanovdb_uint32_t b) -{ - pnanovdb_uint32_t low = pnanovdb_uint64_low(a); - pnanovdb_uint32_t high = pnanovdb_uint64_high(a); - return (b >= 32u) ? - (high >> (b - 32)) : - ((low >> b) | ((b > 0) ? (high << (32u - b)) : 0u)); -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_bit_mask(pnanovdb_uint32_t bit_idx) -{ - pnanovdb_uint32_t mask_low = bit_idx < 32u ? 1u << bit_idx : 0u; - pnanovdb_uint32_t mask_high = bit_idx >= 32u ? 1u << (bit_idx - 32u) : 0u; - return pnanovdb_uint32_as_uint64(mask_low, mask_high); -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_and(pnanovdb_uint64_t a, pnanovdb_uint64_t b) -{ - return pnanovdb_uint32_as_uint64( - pnanovdb_uint64_low(a) & pnanovdb_uint64_low(b), - pnanovdb_uint64_high(a) & pnanovdb_uint64_high(b) - ); -} - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_uint64_any_bit(pnanovdb_uint64_t a) -{ - return pnanovdb_uint64_low(a) != 0u || pnanovdb_uint64_high(a) != 0u; -} - -#else -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_offset(pnanovdb_uint64_t a, pnanovdb_uint32_t b) -{ - return a + b; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_dec(pnanovdb_uint64_t a) -{ - return a - 1u; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_uint64_to_uint32_lsr(pnanovdb_uint64_t a, pnanovdb_uint32_t b) -{ - return pnanovdb_uint64_low(a >> b); -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_bit_mask(pnanovdb_uint32_t bit_idx) -{ - return 1llu << bit_idx; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_uint64_and(pnanovdb_uint64_t a, pnanovdb_uint64_t b) -{ - return a & b; -} - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_uint64_any_bit(pnanovdb_uint64_t a) -{ - return a != 0llu; -} -#endif - -// ------------------------------------------------ Address Type ----------------------------------------------------------- - -#if defined(PNANOVDB_ADDRESS_32) -struct pnanovdb_address_t -{ - pnanovdb_uint32_t byte_offset; -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_address_t) - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset(pnanovdb_address_t address, pnanovdb_uint32_t byte_offset) -{ - pnanovdb_address_t ret = address; - ret.byte_offset += byte_offset; - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset_neg(pnanovdb_address_t address, pnanovdb_uint32_t byte_offset) -{ - pnanovdb_address_t ret = address; - ret.byte_offset -= byte_offset; - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset_product(pnanovdb_address_t address, pnanovdb_uint32_t byte_offset, pnanovdb_uint32_t multiplier) -{ - pnanovdb_address_t ret = address; - ret.byte_offset += byte_offset * multiplier; - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset64(pnanovdb_address_t address, pnanovdb_uint64_t byte_offset) -{ - pnanovdb_address_t ret = address; - // lose high bits on 32-bit - ret.byte_offset += pnanovdb_uint64_low(byte_offset); - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset64_product(pnanovdb_address_t address, pnanovdb_uint64_t byte_offset, pnanovdb_uint32_t multiplier) -{ - pnanovdb_address_t ret = address; - ret.byte_offset += pnanovdb_uint64_low(byte_offset) * multiplier; - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_address_mask(pnanovdb_address_t address, pnanovdb_uint32_t mask) -{ - return address.byte_offset & mask; -} -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_mask_inv(pnanovdb_address_t address, pnanovdb_uint32_t mask) -{ - pnanovdb_address_t ret = address; - ret.byte_offset &= (~mask); - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_null() -{ - pnanovdb_address_t ret = { 0 }; - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_address_is_null(pnanovdb_address_t address) -{ - return address.byte_offset == 0u; -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_address_in_interval(pnanovdb_address_t address, pnanovdb_address_t min_address, pnanovdb_address_t max_address) -{ - return address.byte_offset >= min_address.byte_offset && address.byte_offset < max_address.byte_offset; -} -#elif defined(PNANOVDB_ADDRESS_64) -struct pnanovdb_address_t -{ - pnanovdb_uint64_t byte_offset; -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_address_t) - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset(pnanovdb_address_t address, pnanovdb_uint32_t byte_offset) -{ - pnanovdb_address_t ret = address; - ret.byte_offset += byte_offset; - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset_neg(pnanovdb_address_t address, pnanovdb_uint32_t byte_offset) -{ - pnanovdb_address_t ret = address; - ret.byte_offset -= byte_offset; - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset_product(pnanovdb_address_t address, pnanovdb_uint32_t byte_offset, pnanovdb_uint32_t multiplier) -{ - pnanovdb_address_t ret = address; - ret.byte_offset += pnanovdb_uint32_as_uint64_low(byte_offset) * pnanovdb_uint32_as_uint64_low(multiplier); - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset64(pnanovdb_address_t address, pnanovdb_uint64_t byte_offset) -{ - pnanovdb_address_t ret = address; - ret.byte_offset += byte_offset; - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_offset64_product(pnanovdb_address_t address, pnanovdb_uint64_t byte_offset, pnanovdb_uint32_t multiplier) -{ - pnanovdb_address_t ret = address; - ret.byte_offset += byte_offset * pnanovdb_uint32_as_uint64_low(multiplier); - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_address_mask(pnanovdb_address_t address, pnanovdb_uint32_t mask) -{ - return pnanovdb_uint64_low(address.byte_offset) & mask; -} -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_mask_inv(pnanovdb_address_t address, pnanovdb_uint32_t mask) -{ - pnanovdb_address_t ret = address; - ret.byte_offset &= (~pnanovdb_uint32_as_uint64_low(mask)); - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_address_null() -{ - pnanovdb_address_t ret = { 0 }; - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_address_is_null(pnanovdb_address_t address) -{ - return address.byte_offset == 0llu; -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_address_in_interval(pnanovdb_address_t address, pnanovdb_address_t min_address, pnanovdb_address_t max_address) -{ - return address.byte_offset >= min_address.byte_offset && address.byte_offset < max_address.byte_offset; -} -#endif - -// ------------------------------------------------ High Level Buffer Read ----------------------------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_read_uint32(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - return pnanovdb_buf_read_uint32(buf, address.byte_offset); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_read_uint64(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - return pnanovdb_buf_read_uint64(buf, address.byte_offset); -} -PNANOVDB_FORCE_INLINE pnanovdb_int32_t pnanovdb_read_int32(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - return pnanovdb_uint32_as_int32(pnanovdb_read_uint32(buf, address)); -} -PNANOVDB_FORCE_INLINE float pnanovdb_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - return pnanovdb_uint32_as_float(pnanovdb_read_uint32(buf, address)); -} -PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_read_int64(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - return pnanovdb_uint64_as_int64(pnanovdb_read_uint64(buf, address)); -} -PNANOVDB_FORCE_INLINE double pnanovdb_read_double(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - return pnanovdb_uint64_as_double(pnanovdb_read_uint64(buf, address)); -} -PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_read_coord(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - pnanovdb_coord_t ret; - ret.x = pnanovdb_uint32_as_int32(pnanovdb_read_uint32(buf, pnanovdb_address_offset(address, 0u))); - ret.y = pnanovdb_uint32_as_int32(pnanovdb_read_uint32(buf, pnanovdb_address_offset(address, 4u))); - ret.z = pnanovdb_uint32_as_int32(pnanovdb_read_uint32(buf, pnanovdb_address_offset(address, 8u))); - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_read_vec3(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - pnanovdb_vec3_t ret; - ret.x = pnanovdb_read_float(buf, pnanovdb_address_offset(address, 0u)); - ret.y = pnanovdb_read_float(buf, pnanovdb_address_offset(address, 4u)); - ret.z = pnanovdb_read_float(buf, pnanovdb_address_offset(address, 8u)); - return ret; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_read_uint16(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - pnanovdb_uint32_t raw = pnanovdb_read_uint32(buf, pnanovdb_address_mask_inv(address, 3u)); - return (raw >> (pnanovdb_address_mask(address, 2) << 3)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_read_uint8(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - pnanovdb_uint32_t raw = pnanovdb_read_uint32(buf, pnanovdb_address_mask_inv(address, 3u)); - return (raw >> (pnanovdb_address_mask(address, 3) << 3)) & 255; -} -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_read_vec3u16(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - pnanovdb_vec3_t ret; - const float scale = 1.f / 65535.f; - ret.x = scale * pnanovdb_uint32_to_float(pnanovdb_read_uint16(buf, pnanovdb_address_offset(address, 0u))) - 0.5f; - ret.y = scale * pnanovdb_uint32_to_float(pnanovdb_read_uint16(buf, pnanovdb_address_offset(address, 2u))) - 0.5f; - ret.z = scale * pnanovdb_uint32_to_float(pnanovdb_read_uint16(buf, pnanovdb_address_offset(address, 4u))) - 0.5f; - return ret; -} -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_read_vec3u8(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - pnanovdb_vec3_t ret; - const float scale = 1.f / 255.f; - ret.x = scale * pnanovdb_uint32_to_float(pnanovdb_read_uint8(buf, pnanovdb_address_offset(address, 0u))) - 0.5f; - ret.y = scale * pnanovdb_uint32_to_float(pnanovdb_read_uint8(buf, pnanovdb_address_offset(address, 1u))) - 0.5f; - ret.z = scale * pnanovdb_uint32_to_float(pnanovdb_read_uint8(buf, pnanovdb_address_offset(address, 2u))) - 0.5f; - return ret; -} - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_read_bit(pnanovdb_buf_t buf, pnanovdb_address_t address, pnanovdb_uint32_t bit_offset) -{ - pnanovdb_address_t word_address = pnanovdb_address_mask_inv(address, 3u); - pnanovdb_uint32_t bit_index = (pnanovdb_address_mask(address, 3u) << 3u) + bit_offset; - pnanovdb_uint32_t value_word = pnanovdb_buf_read_uint32(buf, word_address.byte_offset); - return ((value_word >> bit_index) & 1) != 0u; -} - -#if defined(PNANOVDB_C) -PNANOVDB_FORCE_INLINE short pnanovdb_read_half(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - pnanovdb_uint32_t raw = pnanovdb_read_uint32(buf, address); - return (short)(raw >> (pnanovdb_address_mask(address, 2) << 3)); -} -#elif defined(PNANOVDB_HLSL) -PNANOVDB_FORCE_INLINE float pnanovdb_read_half(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - pnanovdb_uint32_t raw = pnanovdb_read_uint32(buf, address); - return f16tof32(raw >> (pnanovdb_address_mask(address, 2) << 3)); -} -#elif defined(PNANOVDB_GLSL) -PNANOVDB_FORCE_INLINE float pnanovdb_read_half(pnanovdb_buf_t buf, pnanovdb_address_t address) -{ - pnanovdb_uint32_t raw = pnanovdb_read_uint32(buf, address); - return unpackHalf2x16(raw >> (pnanovdb_address_mask(address, 2) << 3)).x; -} -#endif - -// ------------------------------------------------ High Level Buffer Write ----------------------------------------------------------- - -PNANOVDB_FORCE_INLINE void pnanovdb_write_uint32(pnanovdb_buf_t buf, pnanovdb_address_t address, pnanovdb_uint32_t value) -{ - pnanovdb_buf_write_uint32(buf, address.byte_offset, value); -} -PNANOVDB_FORCE_INLINE void pnanovdb_write_uint64(pnanovdb_buf_t buf, pnanovdb_address_t address, pnanovdb_uint64_t value) -{ - pnanovdb_buf_write_uint64(buf, address.byte_offset, value); -} -PNANOVDB_FORCE_INLINE void pnanovdb_write_int32(pnanovdb_buf_t buf, pnanovdb_address_t address, pnanovdb_int32_t value) -{ - pnanovdb_write_uint32(buf, address, pnanovdb_int32_as_uint32(value)); -} -PNANOVDB_FORCE_INLINE void pnanovdb_write_int64(pnanovdb_buf_t buf, pnanovdb_address_t address, pnanovdb_int64_t value) -{ - pnanovdb_buf_write_uint64(buf, address.byte_offset, pnanovdb_int64_as_uint64(value)); -} -PNANOVDB_FORCE_INLINE void pnanovdb_write_float(pnanovdb_buf_t buf, pnanovdb_address_t address, float value) -{ - pnanovdb_write_uint32(buf, address, pnanovdb_float_as_uint32(value)); -} -PNANOVDB_FORCE_INLINE void pnanovdb_write_double(pnanovdb_buf_t buf, pnanovdb_address_t address, double value) -{ - pnanovdb_write_uint64(buf, address, pnanovdb_double_as_uint64(value)); -} -PNANOVDB_FORCE_INLINE void pnanovdb_write_coord(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) value) -{ - pnanovdb_write_uint32(buf, pnanovdb_address_offset(address, 0u), pnanovdb_int32_as_uint32(PNANOVDB_DEREF(value).x)); - pnanovdb_write_uint32(buf, pnanovdb_address_offset(address, 4u), pnanovdb_int32_as_uint32(PNANOVDB_DEREF(value).y)); - pnanovdb_write_uint32(buf, pnanovdb_address_offset(address, 8u), pnanovdb_int32_as_uint32(PNANOVDB_DEREF(value).z)); -} -PNANOVDB_FORCE_INLINE void pnanovdb_write_vec3(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_vec3_t) value) -{ - pnanovdb_write_float(buf, pnanovdb_address_offset(address, 0u), PNANOVDB_DEREF(value).x); - pnanovdb_write_float(buf, pnanovdb_address_offset(address, 4u), PNANOVDB_DEREF(value).y); - pnanovdb_write_float(buf, pnanovdb_address_offset(address, 8u), PNANOVDB_DEREF(value).z); -} - -// ------------------------------------------------ Core Structures ----------------------------------------------------------- - -#define PNANOVDB_MAGIC_NUMBER 0x304244566f6e614eUL// "NanoVDB0" in hex - little endian (uint64_t) -#define PNANOVDB_MAGIC_GRID 0x314244566f6e614eUL// "NanoVDB1" in hex - little endian (uint64_t) -#define PNANOVDB_MAGIC_FILE 0x324244566f6e614eUL// "NanoVDB2" in hex - little endian (uint64_t) - -#define PNANOVDB_MAJOR_VERSION_NUMBER 32// reflects changes to the ABI -#define PNANOVDB_MINOR_VERSION_NUMBER 6// reflects changes to the API but not ABI -#define PNANOVDB_PATCH_VERSION_NUMBER 0// reflects bug-fixes with no ABI or API changes - -#define PNANOVDB_GRID_TYPE_UNKNOWN 0 -#define PNANOVDB_GRID_TYPE_FLOAT 1 -#define PNANOVDB_GRID_TYPE_DOUBLE 2 -#define PNANOVDB_GRID_TYPE_INT16 3 -#define PNANOVDB_GRID_TYPE_INT32 4 -#define PNANOVDB_GRID_TYPE_INT64 5 -#define PNANOVDB_GRID_TYPE_VEC3F 6 -#define PNANOVDB_GRID_TYPE_VEC3D 7 -#define PNANOVDB_GRID_TYPE_MASK 8 -#define PNANOVDB_GRID_TYPE_HALF 9 -#define PNANOVDB_GRID_TYPE_UINT32 10 -#define PNANOVDB_GRID_TYPE_BOOLEAN 11 -#define PNANOVDB_GRID_TYPE_RGBA8 12 -#define PNANOVDB_GRID_TYPE_FP4 13 -#define PNANOVDB_GRID_TYPE_FP8 14 -#define PNANOVDB_GRID_TYPE_FP16 15 -#define PNANOVDB_GRID_TYPE_FPN 16 -#define PNANOVDB_GRID_TYPE_VEC4F 17 -#define PNANOVDB_GRID_TYPE_VEC4D 18 -#define PNANOVDB_GRID_TYPE_INDEX 19 -#define PNANOVDB_GRID_TYPE_ONINDEX 20 -#define PNANOVDB_GRID_TYPE_INDEXMASK 21 -#define PNANOVDB_GRID_TYPE_ONINDEXMASK 22 -#define PNANOVDB_GRID_TYPE_POINTINDEX 23 -#define PNANOVDB_GRID_TYPE_VEC3U8 24 -#define PNANOVDB_GRID_TYPE_VEC3U16 25 -#define PNANOVDB_GRID_TYPE_END 26 - -#define PNANOVDB_GRID_CLASS_UNKNOWN 0 -#define PNANOVDB_GRID_CLASS_LEVEL_SET 1 // narrow band level set, e.g. SDF -#define PNANOVDB_GRID_CLASS_FOG_VOLUME 2 // fog volume, e.g. density -#define PNANOVDB_GRID_CLASS_STAGGERED 3 // staggered MAC grid, e.g. velocity -#define PNANOVDB_GRID_CLASS_POINT_INDEX 4 // point index grid -#define PNANOVDB_GRID_CLASS_POINT_DATA 5 // point data grid -#define PNANOVDB_GRID_CLASS_TOPOLOGY 6 // grid with active states only (no values) -#define PNANOVDB_GRID_CLASS_VOXEL_VOLUME 7 // volume of geometric cubes, e.g. minecraft -#define PNANOVDB_GRID_CLASS_INDEX_GRID 8 // grid whose values are offsets, e.g. into an external array -#define PNANOVDB_GRID_CLASS_TENSOR_GRID 9 // grid which can have extra metadata and features -#define PNANOVDB_GRID_CLASS_END 10 - -#define PNANOVDB_GRID_FLAGS_HAS_LONG_GRID_NAME (1 << 0) -#define PNANOVDB_GRID_FLAGS_HAS_BBOX (1 << 1) -#define PNANOVDB_GRID_FLAGS_HAS_MIN_MAX (1 << 2) -#define PNANOVDB_GRID_FLAGS_HAS_AVERAGE (1 << 3) -#define PNANOVDB_GRID_FLAGS_HAS_STD_DEVIATION (1 << 4) -#define PNANOVDB_GRID_FLAGS_IS_BREADTH_FIRST (1 << 5) -#define PNANOVDB_GRID_FLAGS_END (1 << 6) - -#define PNANOVDB_LEAF_TYPE_DEFAULT 0 -#define PNANOVDB_LEAF_TYPE_LITE 1 -#define PNANOVDB_LEAF_TYPE_FP 2 -#define PNANOVDB_LEAF_TYPE_INDEX 3 -#define PNANOVDB_LEAF_TYPE_INDEXMASK 4 -#define PNANOVDB_LEAF_TYPE_POINTINDEX 5 - -// BuildType = Unknown, float, double, int16_t, int32_t, int64_t, Vec3f, Vec3d, Mask, ... -// bit count of values in leaf nodes, i.e. 8*sizeof(*nanovdb::LeafNode::mValues) or zero if no values are stored -PNANOVDB_STATIC_CONST pnanovdb_uint32_t pnanovdb_grid_type_value_strides_bits[PNANOVDB_GRID_TYPE_END] = { 0, 32, 64, 16, 32, 64, 96, 192, 0, 16, 32, 1, 32, 4, 8, 16, 0, 128, 256, 0, 0, 0, 0, 16, 24, 48 }; -// bit count of the Tile union in InternalNodes, i.e. 8*sizeof(nanovdb::InternalData::Tile) -PNANOVDB_STATIC_CONST pnanovdb_uint32_t pnanovdb_grid_type_table_strides_bits[PNANOVDB_GRID_TYPE_END] = { 64, 64, 64, 64, 64, 64, 128, 192, 64, 64, 64, 64, 64, 64, 64, 64, 64, 128, 256, 64, 64, 64, 64, 64, 64, 64 }; -// bit count of min/max values, i.e. 8*sizeof(nanovdb::LeafData::mMinimum) or zero if no min/max exists -PNANOVDB_STATIC_CONST pnanovdb_uint32_t pnanovdb_grid_type_minmax_strides_bits[PNANOVDB_GRID_TYPE_END] = { 0, 32, 64, 16, 32, 64, 96, 192, 8, 16, 32, 8, 32, 32, 32, 32, 32, 128, 256, 64, 64, 64, 64, 64, 24, 48 }; -// bit alignment of the value type, controlled by the smallest native type, which is why it is always 0, 8, 16, 32, or 64, e.g. for Vec3f it is 32 -PNANOVDB_STATIC_CONST pnanovdb_uint32_t pnanovdb_grid_type_minmax_aligns_bits[PNANOVDB_GRID_TYPE_END] = { 0, 32, 64, 16, 32, 64, 32, 64, 8, 16, 32, 8, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 8, 16 }; -// bit alignment of the stats (avg/std-dev) types, e.g. 8*sizeof(nanovdb::LeafData::mAverage) -PNANOVDB_STATIC_CONST pnanovdb_uint32_t pnanovdb_grid_type_stat_strides_bits[PNANOVDB_GRID_TYPE_END] = { 0, 32, 64, 32, 32, 64, 32, 64, 8, 32, 32, 8, 32, 32, 32, 32, 32, 32, 64, 64, 64, 64, 64, 64, 32, 32 }; -// one of the 4 leaf types defined above, e.g. PNANOVDB_LEAF_TYPE_INDEX = 3 -PNANOVDB_STATIC_CONST pnanovdb_uint32_t pnanovdb_grid_type_leaf_type[PNANOVDB_GRID_TYPE_END] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 2, 2, 2, 2, 0, 0, 3, 3, 4, 4, 5, 0, 0 }; - -struct pnanovdb_map_t -{ - float matf[9]; - float invmatf[9]; - float vecf[3]; - float taperf; - double matd[9]; - double invmatd[9]; - double vecd[3]; - double taperd; -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_map_t) -struct pnanovdb_map_handle_t { pnanovdb_address_t address; }; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_map_handle_t) - -#define PNANOVDB_MAP_SIZE 264 - -#define PNANOVDB_MAP_OFF_MATF 0 -#define PNANOVDB_MAP_OFF_INVMATF 36 -#define PNANOVDB_MAP_OFF_VECF 72 -#define PNANOVDB_MAP_OFF_TAPERF 84 -#define PNANOVDB_MAP_OFF_MATD 88 -#define PNANOVDB_MAP_OFF_INVMATD 160 -#define PNANOVDB_MAP_OFF_VECD 232 -#define PNANOVDB_MAP_OFF_TAPERD 256 - -PNANOVDB_FORCE_INLINE float pnanovdb_map_get_matf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { - return pnanovdb_read_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_MATF + 4u * index)); -} -PNANOVDB_FORCE_INLINE float pnanovdb_map_get_invmatf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { - return pnanovdb_read_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_INVMATF + 4u * index)); -} -PNANOVDB_FORCE_INLINE float pnanovdb_map_get_vecf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { - return pnanovdb_read_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_VECF + 4u * index)); -} -PNANOVDB_FORCE_INLINE float pnanovdb_map_get_taperf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { - return pnanovdb_read_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_TAPERF)); -} -PNANOVDB_FORCE_INLINE double pnanovdb_map_get_matd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { - return pnanovdb_read_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_MATD + 8u * index)); -} -PNANOVDB_FORCE_INLINE double pnanovdb_map_get_invmatd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { - return pnanovdb_read_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_INVMATD + 8u * index)); -} -PNANOVDB_FORCE_INLINE double pnanovdb_map_get_vecd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { - return pnanovdb_read_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_VECD + 8u * index)); -} -PNANOVDB_FORCE_INLINE double pnanovdb_map_get_taperd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index) { - return pnanovdb_read_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_TAPERD)); -} - -PNANOVDB_FORCE_INLINE void pnanovdb_map_set_matf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, float matf) { - pnanovdb_write_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_MATF + 4u * index), matf); -} -PNANOVDB_FORCE_INLINE void pnanovdb_map_set_invmatf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, float invmatf) { - pnanovdb_write_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_INVMATF + 4u * index), invmatf); -} -PNANOVDB_FORCE_INLINE void pnanovdb_map_set_vecf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, float vecf) { - pnanovdb_write_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_VECF + 4u * index), vecf); -} -PNANOVDB_FORCE_INLINE void pnanovdb_map_set_taperf(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, float taperf) { - pnanovdb_write_float(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_TAPERF), taperf); -} -PNANOVDB_FORCE_INLINE void pnanovdb_map_set_matd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, double matd) { - pnanovdb_write_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_MATD + 8u * index), matd); -} -PNANOVDB_FORCE_INLINE void pnanovdb_map_set_invmatd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, double invmatd) { - pnanovdb_write_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_INVMATD + 8u * index), invmatd); -} -PNANOVDB_FORCE_INLINE void pnanovdb_map_set_vecd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, double vecd) { - pnanovdb_write_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_VECD + 8u * index), vecd); -} -PNANOVDB_FORCE_INLINE void pnanovdb_map_set_taperd(pnanovdb_buf_t buf, pnanovdb_map_handle_t p, pnanovdb_uint32_t index, double taperd) { - pnanovdb_write_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_MAP_OFF_TAPERD), taperd); -} - -struct pnanovdb_grid_t -{ - pnanovdb_uint64_t magic; // 8 bytes, 0 - pnanovdb_uint64_t checksum; // 8 bytes, 8 - pnanovdb_uint32_t version; // 4 bytes, 16 - pnanovdb_uint32_t flags; // 4 bytes, 20 - pnanovdb_uint32_t grid_index; // 4 bytes, 24 - pnanovdb_uint32_t grid_count; // 4 bytes, 28 - pnanovdb_uint64_t grid_size; // 8 bytes, 32 - pnanovdb_uint32_t grid_name[256 / 4]; // 256 bytes, 40 - pnanovdb_map_t map; // 264 bytes, 296 - double world_bbox[6]; // 48 bytes, 560 - double voxel_size[3]; // 24 bytes, 608 - pnanovdb_uint32_t grid_class; // 4 bytes, 632 - pnanovdb_uint32_t grid_type; // 4 bytes, 636 - pnanovdb_int64_t blind_metadata_offset; // 8 bytes, 640 - pnanovdb_uint32_t blind_metadata_count; // 4 bytes, 648 - pnanovdb_uint32_t pad[5]; // 20 bytes, 652 -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_grid_t) -struct pnanovdb_grid_handle_t { pnanovdb_address_t address; }; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_grid_handle_t) - -#define PNANOVDB_GRID_SIZE 672 - -#define PNANOVDB_GRID_OFF_MAGIC 0 -#define PNANOVDB_GRID_OFF_CHECKSUM 8 -#define PNANOVDB_GRID_OFF_VERSION 16 -#define PNANOVDB_GRID_OFF_FLAGS 20 -#define PNANOVDB_GRID_OFF_GRID_INDEX 24 -#define PNANOVDB_GRID_OFF_GRID_COUNT 28 -#define PNANOVDB_GRID_OFF_GRID_SIZE 32 -#define PNANOVDB_GRID_OFF_GRID_NAME 40 -#define PNANOVDB_GRID_OFF_MAP 296 -#define PNANOVDB_GRID_OFF_WORLD_BBOX 560 -#define PNANOVDB_GRID_OFF_VOXEL_SIZE 608 -#define PNANOVDB_GRID_OFF_GRID_CLASS 632 -#define PNANOVDB_GRID_OFF_GRID_TYPE 636 -#define PNANOVDB_GRID_OFF_BLIND_METADATA_OFFSET 640 -#define PNANOVDB_GRID_OFF_BLIND_METADATA_COUNT 648 - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_grid_get_magic(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { - return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_MAGIC)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_grid_get_checksum(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { - return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_CHECKSUM)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_version(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_VERSION)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_flags(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_FLAGS)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_grid_index(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_INDEX)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_grid_count(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_COUNT)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_grid_get_grid_size(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { - return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_SIZE)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_grid_name(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t index) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_NAME + 4u * index)); -} -PNANOVDB_FORCE_INLINE pnanovdb_map_handle_t pnanovdb_grid_get_map(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { - pnanovdb_map_handle_t ret; - ret.address = pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_MAP); - return ret; -} -PNANOVDB_FORCE_INLINE double pnanovdb_grid_get_world_bbox(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t index) { - return pnanovdb_read_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_WORLD_BBOX + 8u * index)); -} -PNANOVDB_FORCE_INLINE double pnanovdb_grid_get_voxel_size(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t index) { - return pnanovdb_read_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_VOXEL_SIZE + 8u * index)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_grid_class(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_CLASS)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_grid_type(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_TYPE)); -} -PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_grid_get_blind_metadata_offset(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { - return pnanovdb_read_int64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_BLIND_METADATA_OFFSET)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_grid_get_blind_metadata_count(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_BLIND_METADATA_COUNT)); -} - -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_magic(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint64_t magic) { - pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_MAGIC), magic); -} -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_checksum(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint64_t checksum) { - pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_CHECKSUM), checksum); -} -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_version(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t version) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_VERSION), version); -} -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_flags(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t flags) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_FLAGS), flags); -} -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_grid_index(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t grid_index) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_INDEX), grid_index); -} -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_grid_count(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t grid_count) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_COUNT), grid_count); -} -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_grid_size(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint64_t grid_size) { - pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_SIZE), grid_size); -} -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_grid_name(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t index, pnanovdb_uint32_t grid_name) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_NAME + 4u * index), grid_name); -} -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_world_bbox(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t index, double world_bbox) { - pnanovdb_write_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_WORLD_BBOX + 8u * index), world_bbox); -} -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_voxel_size(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t index, double voxel_size) { - pnanovdb_write_double(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_VOXEL_SIZE + 8u * index), voxel_size); -} -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_grid_class(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t grid_class) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_CLASS), grid_class); -} -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_grid_type(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t grid_type) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_GRID_TYPE), grid_type); -} -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_blind_metadata_offset(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint64_t blind_metadata_offset) { - pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_BLIND_METADATA_OFFSET), blind_metadata_offset); -} -PNANOVDB_FORCE_INLINE void pnanovdb_grid_set_blind_metadata_count(pnanovdb_buf_t buf, pnanovdb_grid_handle_t p, pnanovdb_uint32_t metadata_count) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRID_OFF_BLIND_METADATA_COUNT), metadata_count); -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_make_version(pnanovdb_uint32_t major, pnanovdb_uint32_t minor, pnanovdb_uint32_t patch_num) -{ - return (major << 21u) | (minor << 10u) | patch_num; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_version_get_major(pnanovdb_uint32_t version) -{ - return (version >> 21u) & ((1u << 11u) - 1u); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_version_get_minor(pnanovdb_uint32_t version) -{ - return (version >> 10u) & ((1u << 11u) - 1u); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_version_get_patch(pnanovdb_uint32_t version) -{ - return version & ((1u << 10u) - 1u); -} - -struct pnanovdb_gridblindmetadata_t -{ - pnanovdb_int64_t byte_offset; // 8 bytes, 0 - pnanovdb_uint64_t element_count; // 8 bytes, 8 - pnanovdb_uint32_t flags; // 4 bytes, 16 - pnanovdb_uint32_t semantic; // 4 bytes, 20 - pnanovdb_uint32_t data_class; // 4 bytes, 24 - pnanovdb_uint32_t data_type; // 4 bytes, 28 - pnanovdb_uint32_t name[256 / 4]; // 256 bytes, 32 -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_gridblindmetadata_t) -struct pnanovdb_gridblindmetadata_handle_t { pnanovdb_address_t address; }; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_gridblindmetadata_handle_t) - -#define PNANOVDB_GRIDBLINDMETADATA_SIZE 288 - -#define PNANOVDB_GRIDBLINDMETADATA_OFF_BYTE_OFFSET 0 -#define PNANOVDB_GRIDBLINDMETADATA_OFF_ELEMENT_COUNT 8 -#define PNANOVDB_GRIDBLINDMETADATA_OFF_FLAGS 16 -#define PNANOVDB_GRIDBLINDMETADATA_OFF_SEMANTIC 20 -#define PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_CLASS 24 -#define PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_TYPE 28 -#define PNANOVDB_GRIDBLINDMETADATA_OFF_NAME 32 - -PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_gridblindmetadata_get_byte_offset(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p) { - return pnanovdb_read_int64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_BYTE_OFFSET)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_gridblindmetadata_get_element_count(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p) { - return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_ELEMENT_COUNT)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_gridblindmetadata_get_flags(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_FLAGS)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_gridblindmetadata_get_semantic(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_SEMANTIC)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_gridblindmetadata_get_data_class(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_CLASS)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_gridblindmetadata_get_data_type(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_DATA_TYPE)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_gridblindmetadata_get_name(pnanovdb_buf_t buf, pnanovdb_gridblindmetadata_handle_t p, pnanovdb_uint32_t index) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_GRIDBLINDMETADATA_OFF_NAME + 4u * index)); -} - -struct pnanovdb_tree_t -{ - pnanovdb_uint64_t node_offset_leaf; - pnanovdb_uint64_t node_offset_lower; - pnanovdb_uint64_t node_offset_upper; - pnanovdb_uint64_t node_offset_root; - pnanovdb_uint32_t node_count_leaf; - pnanovdb_uint32_t node_count_lower; - pnanovdb_uint32_t node_count_upper; - pnanovdb_uint32_t tile_count_leaf; - pnanovdb_uint32_t tile_count_lower; - pnanovdb_uint32_t tile_count_upper; - pnanovdb_uint64_t voxel_count; -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_tree_t) -struct pnanovdb_tree_handle_t { pnanovdb_address_t address; }; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_tree_handle_t) - -#define PNANOVDB_TREE_SIZE 64 - -#define PNANOVDB_TREE_OFF_NODE_OFFSET_LEAF 0 -#define PNANOVDB_TREE_OFF_NODE_OFFSET_LOWER 8 -#define PNANOVDB_TREE_OFF_NODE_OFFSET_UPPER 16 -#define PNANOVDB_TREE_OFF_NODE_OFFSET_ROOT 24 -#define PNANOVDB_TREE_OFF_NODE_COUNT_LEAF 32 -#define PNANOVDB_TREE_OFF_NODE_COUNT_LOWER 36 -#define PNANOVDB_TREE_OFF_NODE_COUNT_UPPER 40 -#define PNANOVDB_TREE_OFF_TILE_COUNT_LEAF 44 -#define PNANOVDB_TREE_OFF_TILE_COUNT_LOWER 48 -#define PNANOVDB_TREE_OFF_TILE_COUNT_UPPER 52 -#define PNANOVDB_TREE_OFF_VOXEL_COUNT 56 - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_tree_get_node_offset_leaf(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { - return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_LEAF)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_tree_get_node_offset_lower(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { - return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_LOWER)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_tree_get_node_offset_upper(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { - return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_UPPER)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_tree_get_node_offset_root(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { - return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_ROOT)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_tree_get_node_count_leaf(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_COUNT_LEAF)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_tree_get_node_count_lower(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_COUNT_LOWER)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_tree_get_node_count_upper(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_COUNT_UPPER)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_tree_get_tile_count_leaf(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_TILE_COUNT_LEAF)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_tree_get_tile_count_lower(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_TILE_COUNT_LOWER)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_tree_get_tile_count_upper(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_TILE_COUNT_UPPER)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_tree_get_voxel_count(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p) { - return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_VOXEL_COUNT)); -} - -PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_offset_leaf(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint64_t node_offset_leaf) { - pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_LEAF), node_offset_leaf); -} -PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_offset_lower(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint64_t node_offset_lower) { - pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_LOWER), node_offset_lower); -} -PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_offset_upper(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint64_t node_offset_upper) { - pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_UPPER), node_offset_upper); -} -PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_offset_root(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint64_t node_offset_root) { - pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_OFFSET_ROOT), node_offset_root); -} -PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_count_leaf(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint32_t node_count_leaf) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_COUNT_LEAF), node_count_leaf); -} -PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_count_lower(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint32_t node_count_lower) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_COUNT_LOWER), node_count_lower); -} -PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_node_count_upper(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint32_t node_count_upper) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_NODE_COUNT_UPPER), node_count_upper); -} -PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_tile_count_leaf(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint32_t tile_count_leaf) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_TILE_COUNT_LEAF), tile_count_leaf); -} -PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_tile_count_lower(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint32_t tile_count_lower) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_TILE_COUNT_LOWER), tile_count_lower); -} -PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_tile_count_upper(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint32_t tile_count_upper) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_TILE_COUNT_UPPER), tile_count_upper); -} -PNANOVDB_FORCE_INLINE void pnanovdb_tree_set_voxel_count(pnanovdb_buf_t buf, pnanovdb_tree_handle_t p, pnanovdb_uint64_t voxel_count) { - pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_TREE_OFF_VOXEL_COUNT), voxel_count); -} - -struct pnanovdb_root_t -{ - pnanovdb_coord_t bbox_min; - pnanovdb_coord_t bbox_max; - pnanovdb_uint32_t table_size; - pnanovdb_uint32_t pad1; // background can start here - // background, min, max -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_root_t) -struct pnanovdb_root_handle_t { pnanovdb_address_t address; }; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_root_handle_t) - -#define PNANOVDB_ROOT_BASE_SIZE 28 - -#define PNANOVDB_ROOT_OFF_BBOX_MIN 0 -#define PNANOVDB_ROOT_OFF_BBOX_MAX 12 -#define PNANOVDB_ROOT_OFF_TABLE_SIZE 24 - -PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_root_get_bbox_min(pnanovdb_buf_t buf, pnanovdb_root_handle_t p) { - return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_OFF_BBOX_MIN)); -} -PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_root_get_bbox_max(pnanovdb_buf_t buf, pnanovdb_root_handle_t p) { - return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_OFF_BBOX_MAX)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_root_get_tile_count(pnanovdb_buf_t buf, pnanovdb_root_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_OFF_TABLE_SIZE)); -} - -PNANOVDB_FORCE_INLINE void pnanovdb_root_set_bbox_min(pnanovdb_buf_t buf, pnanovdb_root_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_min) { - pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_OFF_BBOX_MIN), bbox_min); -} -PNANOVDB_FORCE_INLINE void pnanovdb_root_set_bbox_max(pnanovdb_buf_t buf, pnanovdb_root_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_max) { - pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_OFF_BBOX_MAX), bbox_max); -} -PNANOVDB_FORCE_INLINE void pnanovdb_root_set_tile_count(pnanovdb_buf_t buf, pnanovdb_root_handle_t p, pnanovdb_uint32_t tile_count) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_OFF_TABLE_SIZE), tile_count); -} - -struct pnanovdb_root_tile_t -{ - pnanovdb_uint64_t key; - pnanovdb_int64_t child; // signed byte offset from root to the child node, 0 means it is a constant tile, so use value - pnanovdb_uint32_t state; - pnanovdb_uint32_t pad1; // value can start here - // value -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_root_tile_t) -struct pnanovdb_root_tile_handle_t { pnanovdb_address_t address; }; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_root_tile_handle_t) - -#define PNANOVDB_ROOT_TILE_BASE_SIZE 20 - -#define PNANOVDB_ROOT_TILE_OFF_KEY 0 -#define PNANOVDB_ROOT_TILE_OFF_CHILD 8 -#define PNANOVDB_ROOT_TILE_OFF_STATE 16 - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_root_tile_get_key(pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t p) { - return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_TILE_OFF_KEY)); -} -PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_root_tile_get_child(pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t p) { - return pnanovdb_read_int64(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_TILE_OFF_CHILD)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_root_tile_get_state(pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_TILE_OFF_STATE)); -} - -PNANOVDB_FORCE_INLINE void pnanovdb_root_tile_set_key(pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t p, pnanovdb_uint64_t key) { - pnanovdb_write_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_TILE_OFF_KEY), key); -} -PNANOVDB_FORCE_INLINE void pnanovdb_root_tile_set_child(pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t p, pnanovdb_int64_t child) { - pnanovdb_write_int64(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_TILE_OFF_CHILD), child); -} -PNANOVDB_FORCE_INLINE void pnanovdb_root_tile_set_state(pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t p, pnanovdb_uint32_t state) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_ROOT_TILE_OFF_STATE), state); -} - -struct pnanovdb_upper_t -{ - pnanovdb_coord_t bbox_min; - pnanovdb_coord_t bbox_max; - pnanovdb_uint64_t flags; - pnanovdb_uint32_t value_mask[1024]; - pnanovdb_uint32_t child_mask[1024]; - // min, max - // alignas(32) pnanovdb_uint32_t table[]; -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_upper_t) -struct pnanovdb_upper_handle_t { pnanovdb_address_t address; }; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_upper_handle_t) - -#define PNANOVDB_UPPER_TABLE_COUNT 32768 -#define PNANOVDB_UPPER_BASE_SIZE 8224 - -#define PNANOVDB_UPPER_OFF_BBOX_MIN 0 -#define PNANOVDB_UPPER_OFF_BBOX_MAX 12 -#define PNANOVDB_UPPER_OFF_FLAGS 24 -#define PNANOVDB_UPPER_OFF_VALUE_MASK 32 -#define PNANOVDB_UPPER_OFF_CHILD_MASK 4128 - -PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_upper_get_bbox_min(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p) { - return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_BBOX_MIN)); -} -PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_upper_get_bbox_max(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p) { - return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_BBOX_MAX)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_upper_get_flags(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p) { - return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_FLAGS)); -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_upper_get_value_mask(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p, pnanovdb_uint32_t bit_index) { - pnanovdb_uint32_t value = pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_VALUE_MASK + 4u * (bit_index >> 5u))); - return ((value >> (bit_index & 31u)) & 1) != 0u; -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_upper_get_child_mask(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p, pnanovdb_uint32_t bit_index) { - pnanovdb_uint32_t value = pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_CHILD_MASK + 4u * (bit_index >> 5u))); - return ((value >> (bit_index & 31u)) & 1) != 0u; -} - -PNANOVDB_FORCE_INLINE void pnanovdb_upper_set_bbox_min(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_min) { - pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_BBOX_MIN), bbox_min); -} -PNANOVDB_FORCE_INLINE void pnanovdb_upper_set_bbox_max(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_max) { - pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_BBOX_MAX), bbox_max); -} -PNANOVDB_FORCE_INLINE void pnanovdb_upper_set_child_mask(pnanovdb_buf_t buf, pnanovdb_upper_handle_t p, pnanovdb_uint32_t bit_index, pnanovdb_bool_t value) { - pnanovdb_address_t addr = pnanovdb_address_offset(p.address, PNANOVDB_UPPER_OFF_CHILD_MASK + 4u * (bit_index >> 5u)); - pnanovdb_uint32_t valueMask = pnanovdb_read_uint32(buf, addr); - if (!value) { valueMask &= ~(1u << (bit_index & 31u)); } - if (value) valueMask |= (1u << (bit_index & 31u)); - pnanovdb_write_uint32(buf, addr, valueMask); -} - -struct pnanovdb_lower_t -{ - pnanovdb_coord_t bbox_min; - pnanovdb_coord_t bbox_max; - pnanovdb_uint64_t flags; - pnanovdb_uint32_t value_mask[128]; - pnanovdb_uint32_t child_mask[128]; - // min, max - // alignas(32) pnanovdb_uint32_t table[]; -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_lower_t) -struct pnanovdb_lower_handle_t { pnanovdb_address_t address; }; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_lower_handle_t) - -#define PNANOVDB_LOWER_TABLE_COUNT 4096 -#define PNANOVDB_LOWER_BASE_SIZE 1056 - -#define PNANOVDB_LOWER_OFF_BBOX_MIN 0 -#define PNANOVDB_LOWER_OFF_BBOX_MAX 12 -#define PNANOVDB_LOWER_OFF_FLAGS 24 -#define PNANOVDB_LOWER_OFF_VALUE_MASK 32 -#define PNANOVDB_LOWER_OFF_CHILD_MASK 544 - -PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_lower_get_bbox_min(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p) { - return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_BBOX_MIN)); -} -PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_lower_get_bbox_max(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p) { - return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_BBOX_MAX)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_lower_get_flags(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p) { - return pnanovdb_read_uint64(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_FLAGS)); -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_lower_get_value_mask(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p, pnanovdb_uint32_t bit_index) { - pnanovdb_uint32_t value = pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_VALUE_MASK + 4u * (bit_index >> 5u))); - return ((value >> (bit_index & 31u)) & 1) != 0u; -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_lower_get_child_mask(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p, pnanovdb_uint32_t bit_index) { - pnanovdb_uint32_t value = pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_CHILD_MASK + 4u * (bit_index >> 5u))); - return ((value >> (bit_index & 31u)) & 1) != 0u; -} - -PNANOVDB_FORCE_INLINE void pnanovdb_lower_set_bbox_min(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_min) { - pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_BBOX_MIN), bbox_min); -} -PNANOVDB_FORCE_INLINE void pnanovdb_lower_set_bbox_max(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_max) { - pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_BBOX_MAX), bbox_max); -} -PNANOVDB_FORCE_INLINE void pnanovdb_lower_set_child_mask(pnanovdb_buf_t buf, pnanovdb_lower_handle_t p, pnanovdb_uint32_t bit_index, pnanovdb_bool_t value) { - pnanovdb_address_t addr = pnanovdb_address_offset(p.address, PNANOVDB_LOWER_OFF_CHILD_MASK + 4u * (bit_index >> 5u)); - pnanovdb_uint32_t valueMask = pnanovdb_read_uint32(buf, addr); - if (!value) { valueMask &= ~(1u << (bit_index & 31u)); } - if (value) valueMask |= (1u << (bit_index & 31u)); - pnanovdb_write_uint32(buf, addr, valueMask); -} - -struct pnanovdb_leaf_t -{ - pnanovdb_coord_t bbox_min; - pnanovdb_uint32_t bbox_dif_and_flags; - pnanovdb_uint32_t value_mask[16]; - // min, max - // alignas(32) pnanovdb_uint32_t values[]; -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_leaf_t) -struct pnanovdb_leaf_handle_t { pnanovdb_address_t address; }; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_leaf_handle_t) - -#define PNANOVDB_LEAF_TABLE_COUNT 512 -#define PNANOVDB_LEAF_BASE_SIZE 80 - -#define PNANOVDB_LEAF_OFF_BBOX_MIN 0 -#define PNANOVDB_LEAF_OFF_BBOX_DIF_AND_FLAGS 12 -#define PNANOVDB_LEAF_OFF_VALUE_MASK 16 - -#define PNANOVDB_LEAF_TABLE_NEG_OFF_BBOX_DIF_AND_FLAGS 84 -#define PNANOVDB_LEAF_TABLE_NEG_OFF_MINIMUM 16 -#define PNANOVDB_LEAF_TABLE_NEG_OFF_QUANTUM 12 - -PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_leaf_get_bbox_min(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t p) { - return pnanovdb_read_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_LEAF_OFF_BBOX_MIN)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_leaf_get_bbox_dif_and_flags(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t p) { - return pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_LEAF_OFF_BBOX_DIF_AND_FLAGS)); -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_leaf_get_value_mask(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t p, pnanovdb_uint32_t bit_index) { - pnanovdb_uint32_t value = pnanovdb_read_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_LEAF_OFF_VALUE_MASK + 4u * (bit_index >> 5u))); - return ((value >> (bit_index & 31u)) & 1) != 0u; -} - -PNANOVDB_FORCE_INLINE void pnanovdb_leaf_set_bbox_min(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t p, PNANOVDB_IN(pnanovdb_coord_t) bbox_min) { - pnanovdb_write_coord(buf, pnanovdb_address_offset(p.address, PNANOVDB_LEAF_OFF_BBOX_MIN), bbox_min); -} -PNANOVDB_FORCE_INLINE void pnanovdb_leaf_set_bbox_dif_and_flags(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t p, pnanovdb_uint32_t bbox_dif_and_flags) { - pnanovdb_write_uint32(buf, pnanovdb_address_offset(p.address, PNANOVDB_LEAF_OFF_BBOX_DIF_AND_FLAGS), bbox_dif_and_flags); -} - -struct pnanovdb_grid_type_constants_t -{ - pnanovdb_uint32_t root_off_background; - pnanovdb_uint32_t root_off_min; - pnanovdb_uint32_t root_off_max; - pnanovdb_uint32_t root_off_ave; - pnanovdb_uint32_t root_off_stddev; - pnanovdb_uint32_t root_size; - pnanovdb_uint32_t value_stride_bits; - pnanovdb_uint32_t table_stride; - pnanovdb_uint32_t root_tile_off_value; - pnanovdb_uint32_t root_tile_size; - pnanovdb_uint32_t upper_off_min; - pnanovdb_uint32_t upper_off_max; - pnanovdb_uint32_t upper_off_ave; - pnanovdb_uint32_t upper_off_stddev; - pnanovdb_uint32_t upper_off_table; - pnanovdb_uint32_t upper_size; - pnanovdb_uint32_t lower_off_min; - pnanovdb_uint32_t lower_off_max; - pnanovdb_uint32_t lower_off_ave; - pnanovdb_uint32_t lower_off_stddev; - pnanovdb_uint32_t lower_off_table; - pnanovdb_uint32_t lower_size; - pnanovdb_uint32_t leaf_off_min; - pnanovdb_uint32_t leaf_off_max; - pnanovdb_uint32_t leaf_off_ave; - pnanovdb_uint32_t leaf_off_stddev; - pnanovdb_uint32_t leaf_off_table; - pnanovdb_uint32_t leaf_size; -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_grid_type_constants_t) - -// The following table with offsets will nedd to be updates as new GridTypes are added in NanoVDB.h -PNANOVDB_STATIC_CONST pnanovdb_grid_type_constants_t pnanovdb_grid_type_constants[PNANOVDB_GRID_TYPE_END] = -{ -{28, 28, 28, 28, 28, 32, 0, 8, 20, 32, 8224, 8224, 8224, 8224, 8224, 270368, 1056, 1056, 1056, 1056, 1056, 33824, 80, 80, 80, 80, 96, 96}, -{28, 32, 36, 40, 44, 64, 32, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 80, 84, 88, 92, 96, 2144}, -{32, 40, 48, 56, 64, 96, 64, 8, 24, 32, 8224, 8232, 8240, 8248, 8256, 270400, 1056, 1064, 1072, 1080, 1088, 33856, 80, 88, 96, 104, 128, 4224}, -{28, 30, 32, 36, 40, 64, 16, 8, 20, 32, 8224, 8226, 8228, 8232, 8256, 270400, 1056, 1058, 1060, 1064, 1088, 33856, 80, 82, 84, 88, 96, 1120}, -{28, 32, 36, 40, 44, 64, 32, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 80, 84, 88, 92, 96, 2144}, -{32, 40, 48, 56, 64, 96, 64, 8, 24, 32, 8224, 8232, 8240, 8248, 8256, 270400, 1056, 1064, 1072, 1080, 1088, 33856, 80, 88, 96, 104, 128, 4224}, -{28, 40, 52, 64, 68, 96, 96, 16, 20, 32, 8224, 8236, 8248, 8252, 8256, 532544, 1056, 1068, 1080, 1084, 1088, 66624, 80, 92, 104, 108, 128, 6272}, -{32, 56, 80, 104, 112, 128, 192, 24, 24, 64, 8224, 8248, 8272, 8280, 8288, 794720, 1056, 1080, 1104, 1112, 1120, 99424, 80, 104, 128, 136, 160, 12448}, -{28, 29, 30, 31, 32, 64, 0, 8, 20, 32, 8224, 8225, 8226, 8227, 8256, 270400, 1056, 1057, 1058, 1059, 1088, 33856, 80, 80, 80, 80, 96, 96}, -{28, 30, 32, 36, 40, 64, 16, 8, 20, 32, 8224, 8226, 8228, 8232, 8256, 270400, 1056, 1058, 1060, 1064, 1088, 33856, 80, 82, 84, 88, 96, 1120}, -{28, 32, 36, 40, 44, 64, 32, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 80, 84, 88, 92, 96, 2144}, -{28, 29, 30, 31, 32, 64, 1, 8, 20, 32, 8224, 8225, 8226, 8227, 8256, 270400, 1056, 1057, 1058, 1059, 1088, 33856, 80, 80, 80, 80, 96, 160}, -{28, 32, 36, 40, 44, 64, 32, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 80, 84, 88, 92, 96, 2144}, -{28, 32, 36, 40, 44, 64, 0, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 88, 90, 92, 94, 96, 352}, -{28, 32, 36, 40, 44, 64, 0, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 88, 90, 92, 94, 96, 608}, -{28, 32, 36, 40, 44, 64, 0, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 88, 90, 92, 94, 96, 1120}, -{28, 32, 36, 40, 44, 64, 0, 8, 20, 32, 8224, 8228, 8232, 8236, 8256, 270400, 1056, 1060, 1064, 1068, 1088, 33856, 88, 90, 92, 94, 96, 96}, -{28, 44, 60, 76, 80, 96, 128, 16, 20, 64, 8224, 8240, 8256, 8260, 8288, 532576, 1056, 1072, 1088, 1092, 1120, 66656, 80, 96, 112, 116, 128, 8320}, -{32, 64, 96, 128, 136, 160, 256, 32, 24, 64, 8224, 8256, 8288, 8296, 8320, 1056896, 1056, 1088, 1120, 1128, 1152, 132224, 80, 112, 144, 152, 160, 16544}, -{32, 40, 48, 56, 64, 96, 0, 8, 24, 32, 8224, 8232, 8240, 8248, 8256, 270400, 1056, 1064, 1072, 1080, 1088, 33856, 80, 80, 80, 80, 80, 96}, -{32, 40, 48, 56, 64, 96, 0, 8, 24, 32, 8224, 8232, 8240, 8248, 8256, 270400, 1056, 1064, 1072, 1080, 1088, 33856, 80, 80, 80, 80, 80, 96}, -{32, 40, 48, 56, 64, 96, 0, 8, 24, 32, 8224, 8232, 8240, 8248, 8256, 270400, 1056, 1064, 1072, 1080, 1088, 33856, 80, 80, 80, 80, 80, 160}, -{32, 40, 48, 56, 64, 96, 0, 8, 24, 32, 8224, 8232, 8240, 8248, 8256, 270400, 1056, 1064, 1072, 1080, 1088, 33856, 80, 80, 80, 80, 80, 160}, -{32, 40, 48, 56, 64, 96, 16, 8, 24, 32, 8224, 8232, 8240, 8248, 8256, 270400, 1056, 1064, 1072, 1080, 1088, 33856, 80, 88, 96, 96, 96, 1120}, -{28, 31, 34, 40, 44, 64, 24, 8, 20, 32, 8224, 8227, 8232, 8236, 8256, 270400, 1056, 1059, 1064, 1068, 1088, 33856, 80, 83, 88, 92, 96, 1632}, -{28, 34, 40, 48, 52, 64, 48, 8, 20, 32, 8224, 8230, 8236, 8240, 8256, 270400, 1056, 1062, 1068, 1072, 1088, 33856, 80, 86, 92, 96, 128, 3200}, -}; - -// ------------------------------------------------ Basic Lookup ----------------------------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_gridblindmetadata_handle_t pnanovdb_grid_get_gridblindmetadata(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid, pnanovdb_uint32_t index) -{ - pnanovdb_gridblindmetadata_handle_t meta = { grid.address }; - pnanovdb_uint64_t byte_offset = pnanovdb_grid_get_blind_metadata_offset(buf, grid); - meta.address = pnanovdb_address_offset64(meta.address, byte_offset); - meta.address = pnanovdb_address_offset_product(meta.address, PNANOVDB_GRIDBLINDMETADATA_SIZE, index); - return meta; -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_grid_get_gridblindmetadata_value_address(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid, pnanovdb_uint32_t index) -{ - pnanovdb_gridblindmetadata_handle_t meta = pnanovdb_grid_get_gridblindmetadata(buf, grid, index); - pnanovdb_int64_t byte_offset = pnanovdb_gridblindmetadata_get_byte_offset(buf, meta); - pnanovdb_address_t address = pnanovdb_address_offset64(meta.address, pnanovdb_int64_as_uint64(byte_offset)); - return address; -} - -PNANOVDB_FORCE_INLINE pnanovdb_tree_handle_t pnanovdb_grid_get_tree(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid) -{ - pnanovdb_tree_handle_t tree = { grid.address }; - tree.address = pnanovdb_address_offset(tree.address, PNANOVDB_GRID_SIZE); - return tree; -} - -PNANOVDB_FORCE_INLINE pnanovdb_root_handle_t pnanovdb_tree_get_root(pnanovdb_buf_t buf, pnanovdb_tree_handle_t tree) -{ - pnanovdb_root_handle_t root = { tree.address }; - pnanovdb_uint64_t byte_offset = pnanovdb_tree_get_node_offset_root(buf, tree); - root.address = pnanovdb_address_offset64(root.address, byte_offset); - return root; -} - -PNANOVDB_FORCE_INLINE pnanovdb_root_tile_handle_t pnanovdb_root_get_tile(pnanovdb_grid_type_t grid_type, pnanovdb_root_handle_t root, pnanovdb_uint32_t n) -{ - pnanovdb_root_tile_handle_t tile = { root.address }; - tile.address = pnanovdb_address_offset(tile.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_size)); - tile.address = pnanovdb_address_offset_product(tile.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_tile_size), n); - return tile; -} - -PNANOVDB_FORCE_INLINE pnanovdb_root_tile_handle_t pnanovdb_root_get_tile_zero(pnanovdb_grid_type_t grid_type, pnanovdb_root_handle_t root) -{ - pnanovdb_root_tile_handle_t tile = { root.address }; - tile.address = pnanovdb_address_offset(tile.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_size)); - return tile; -} - -PNANOVDB_FORCE_INLINE pnanovdb_upper_handle_t pnanovdb_root_get_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, pnanovdb_root_tile_handle_t tile) -{ - pnanovdb_upper_handle_t upper = { root.address }; - upper.address = pnanovdb_address_offset64(upper.address, pnanovdb_int64_as_uint64(pnanovdb_root_tile_get_child(buf, tile))); - return upper; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_coord_to_key(PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ -#if defined(PNANOVDB_NATIVE_64) - pnanovdb_uint64_t iu = pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).x) >> 12u; - pnanovdb_uint64_t ju = pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).y) >> 12u; - pnanovdb_uint64_t ku = pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).z) >> 12u; - return (ku) | (ju << 21u) | (iu << 42u); -#else - pnanovdb_uint32_t iu = pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).x) >> 12u; - pnanovdb_uint32_t ju = pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).y) >> 12u; - pnanovdb_uint32_t ku = pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).z) >> 12u; - pnanovdb_uint32_t key_x = ku | (ju << 21); - pnanovdb_uint32_t key_y = (iu << 10) | (ju >> 11); - return pnanovdb_uint32_as_uint64(key_x, key_y); -#endif -} - -PNANOVDB_FORCE_INLINE pnanovdb_root_tile_handle_t pnanovdb_root_find_tile(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - pnanovdb_uint32_t tile_count = pnanovdb_uint32_as_int32(pnanovdb_root_get_tile_count(buf, root)); - pnanovdb_root_tile_handle_t tile = pnanovdb_root_get_tile_zero(grid_type, root); - pnanovdb_uint64_t key = pnanovdb_coord_to_key(ijk); - for (pnanovdb_uint32_t i = 0u; i < tile_count; i++) - { - if (pnanovdb_uint64_is_equal(key, pnanovdb_root_tile_get_key(buf, tile))) - { - return tile; - } - tile.address = pnanovdb_address_offset(tile.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_tile_size)); - } - pnanovdb_root_tile_handle_t null_handle = { pnanovdb_address_null() }; - return null_handle; -} - -// ----------------------------- Leaf Node --------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_leaf_coord_to_offset(PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - return (((PNANOVDB_DEREF(ijk).x & 7) >> 0) << (2 * 3)) + - (((PNANOVDB_DEREF(ijk).y & 7) >> 0) << (3)) + - ((PNANOVDB_DEREF(ijk).z & 7) >> 0); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_min_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t node) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, leaf_off_min); - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_max_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t node) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, leaf_off_max); - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_ave_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t node) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, leaf_off_ave); - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_stddev_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t node) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, leaf_off_stddev); - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_table_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t node, pnanovdb_uint32_t n) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, leaf_off_table) + ((PNANOVDB_GRID_TYPE_GET(grid_type, value_stride_bits) * n) >> 3u); - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_value_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); - return pnanovdb_leaf_get_table_address(grid_type, buf, leaf, n); -} - -// ----------------------------- Leaf FP Types Specialization --------------------------------------- - -PNANOVDB_FORCE_INLINE float pnanovdb_leaf_fp_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t value_log_bits) -{ - // value_log_bits // 2 3 4 - pnanovdb_uint32_t value_bits = 1u << value_log_bits; // 4 8 16 - pnanovdb_uint32_t value_mask = (1u << value_bits) - 1u; // 0xF 0xFF 0xFFFF - pnanovdb_uint32_t values_per_word_bits = 5u - value_log_bits; // 3 2 1 - pnanovdb_uint32_t values_per_word_mask = (1u << values_per_word_bits) - 1u; // 7 3 1 - - pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); - float minimum = pnanovdb_read_float(buf, pnanovdb_address_offset_neg(address, PNANOVDB_LEAF_TABLE_NEG_OFF_MINIMUM)); - float quantum = pnanovdb_read_float(buf, pnanovdb_address_offset_neg(address, PNANOVDB_LEAF_TABLE_NEG_OFF_QUANTUM)); - pnanovdb_uint32_t raw = pnanovdb_read_uint32(buf, pnanovdb_address_offset(address, ((n >> values_per_word_bits) << 2u))); - pnanovdb_uint32_t value_compressed = (raw >> ((n & values_per_word_mask) << value_log_bits)) & value_mask; - return pnanovdb_uint32_to_float(value_compressed) * quantum + minimum; -} - -PNANOVDB_FORCE_INLINE float pnanovdb_leaf_fp4_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - return pnanovdb_leaf_fp_read_float(buf, address, ijk, 2u); -} - -PNANOVDB_FORCE_INLINE float pnanovdb_leaf_fp8_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - return pnanovdb_leaf_fp_read_float(buf, address, ijk, 3u); -} - -PNANOVDB_FORCE_INLINE float pnanovdb_leaf_fp16_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - return pnanovdb_leaf_fp_read_float(buf, address, ijk, 4u); -} - -PNANOVDB_FORCE_INLINE float pnanovdb_leaf_fpn_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - pnanovdb_uint32_t bbox_dif_and_flags = pnanovdb_read_uint32(buf, pnanovdb_address_offset_neg(address, PNANOVDB_LEAF_TABLE_NEG_OFF_BBOX_DIF_AND_FLAGS)); - pnanovdb_uint32_t flags = bbox_dif_and_flags >> 24u; - pnanovdb_uint32_t value_log_bits = flags >> 5; // b = 0, 1, 2, 3, 4 corresponding to 1, 2, 4, 8, 16 bits - return pnanovdb_leaf_fp_read_float(buf, address, ijk, value_log_bits); -} - -// ----------------------------- Leaf Index Specialization --------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_leaf_index_has_stats(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) -{ - return (pnanovdb_leaf_get_bbox_dif_and_flags(buf, leaf) & (1u << 28u)) != 0u; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_index_get_min_index(pnanovdb_buf_t buf, pnanovdb_address_t min_address) -{ - return pnanovdb_uint64_offset(pnanovdb_read_uint64(buf, min_address), 512u); -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_index_get_max_index(pnanovdb_buf_t buf, pnanovdb_address_t max_address) -{ - return pnanovdb_uint64_offset(pnanovdb_read_uint64(buf, max_address), 513u); -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_index_get_ave_index(pnanovdb_buf_t buf, pnanovdb_address_t ave_address) -{ - return pnanovdb_uint64_offset(pnanovdb_read_uint64(buf, ave_address), 514u); -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_index_get_dev_index(pnanovdb_buf_t buf, pnanovdb_address_t dev_address) -{ - return pnanovdb_uint64_offset(pnanovdb_read_uint64(buf, dev_address), 515u); -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_index_get_value_index(pnanovdb_buf_t buf, pnanovdb_address_t value_address, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); - pnanovdb_uint64_t offset = pnanovdb_read_uint64(buf, value_address); - return pnanovdb_uint64_offset(offset, n); -} - -// ----------------------------- Leaf IndexMask Specialization --------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_leaf_indexmask_has_stats(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) -{ - return pnanovdb_leaf_index_has_stats(buf, leaf); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_indexmask_get_min_index(pnanovdb_buf_t buf, pnanovdb_address_t min_address) -{ - return pnanovdb_leaf_index_get_min_index(buf, min_address); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_indexmask_get_max_index(pnanovdb_buf_t buf, pnanovdb_address_t max_address) -{ - return pnanovdb_leaf_index_get_max_index(buf, max_address); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_indexmask_get_ave_index(pnanovdb_buf_t buf, pnanovdb_address_t ave_address) -{ - return pnanovdb_leaf_index_get_ave_index(buf, ave_address); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_indexmask_get_dev_index(pnanovdb_buf_t buf, pnanovdb_address_t dev_address) -{ - return pnanovdb_leaf_index_get_dev_index(buf, dev_address); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_indexmask_get_value_index(pnanovdb_buf_t buf, pnanovdb_address_t value_address, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - return pnanovdb_leaf_index_get_value_index(buf, value_address, ijk); -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_leaf_indexmask_get_mask_bit(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t n) -{ - pnanovdb_uint32_t word_idx = n >> 5; - pnanovdb_uint32_t bit_idx = n & 31; - pnanovdb_uint32_t val_mask = - pnanovdb_read_uint32(buf, pnanovdb_address_offset(leaf.address, 96u + 4u * word_idx)); - return (val_mask & (1u << bit_idx)) != 0u; -} -PNANOVDB_FORCE_INLINE void pnanovdb_leaf_indexmask_set_mask_bit(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t n, pnanovdb_bool_t v) -{ - pnanovdb_uint32_t word_idx = n >> 5; - pnanovdb_uint32_t bit_idx = n & 31; - pnanovdb_uint32_t val_mask = - pnanovdb_read_uint32(buf, pnanovdb_address_offset(leaf.address, 96u + 4u * word_idx)); - if (v) - { - val_mask = val_mask | (1u << bit_idx); - } - else - { - val_mask = val_mask & ~(1u << bit_idx); - } - pnanovdb_write_uint32(buf, pnanovdb_address_offset(leaf.address, 96u + 4u * word_idx), val_mask); -} - -// ----------------------------- Leaf OnIndex Specialization --------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_leaf_onindex_get_value_count(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) -{ - pnanovdb_uint64_t val_mask = pnanovdb_read_uint64(buf, pnanovdb_address_offset(leaf.address, PNANOVDB_LEAF_OFF_VALUE_MASK + 8u * 7u)); - pnanovdb_uint64_t prefix_sum = pnanovdb_read_uint64( - buf, pnanovdb_address_offset(leaf.address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table) + 8u)); - return pnanovdb_uint64_countbits(val_mask) + (pnanovdb_uint64_to_uint32_lsr(prefix_sum, 54u) & 511u); -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindex_get_last_offset(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) -{ - return pnanovdb_uint64_offset( - pnanovdb_read_uint64(buf, pnanovdb_address_offset(leaf.address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table))), - pnanovdb_leaf_onindex_get_value_count(buf, leaf) - 1u); -} - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_leaf_onindex_has_stats(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) -{ - return (pnanovdb_leaf_get_bbox_dif_and_flags(buf, leaf) & (1u << 28u)) != 0u; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindex_get_min_index(pnanovdb_buf_t buf, pnanovdb_address_t min_address) -{ - pnanovdb_leaf_handle_t leaf = { pnanovdb_address_offset_neg(min_address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table)) }; - pnanovdb_uint64_t idx = pnanovdb_uint32_as_uint64_low(0u); - if (pnanovdb_leaf_onindex_has_stats(buf, leaf)) - { - idx = pnanovdb_uint64_offset(pnanovdb_leaf_onindex_get_last_offset(buf, leaf), 1u); - } - return idx; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindex_get_max_index(pnanovdb_buf_t buf, pnanovdb_address_t max_address) -{ - pnanovdb_leaf_handle_t leaf = { pnanovdb_address_offset_neg(max_address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table)) }; - pnanovdb_uint64_t idx = pnanovdb_uint32_as_uint64_low(0u); - if (pnanovdb_leaf_onindex_has_stats(buf, leaf)) - { - idx = pnanovdb_uint64_offset(pnanovdb_leaf_onindex_get_last_offset(buf, leaf), 2u); - } - return idx; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindex_get_ave_index(pnanovdb_buf_t buf, pnanovdb_address_t ave_address) -{ - pnanovdb_leaf_handle_t leaf = { pnanovdb_address_offset_neg(ave_address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table)) }; - pnanovdb_uint64_t idx = pnanovdb_uint32_as_uint64_low(0u); - if (pnanovdb_leaf_onindex_has_stats(buf, leaf)) - { - idx = pnanovdb_uint64_offset(pnanovdb_leaf_onindex_get_last_offset(buf, leaf), 3u); - } - return idx; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindex_get_dev_index(pnanovdb_buf_t buf, pnanovdb_address_t dev_address) -{ - pnanovdb_leaf_handle_t leaf = { pnanovdb_address_offset_neg(dev_address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table)) }; - pnanovdb_uint64_t idx = pnanovdb_uint32_as_uint64_low(0u); - if (pnanovdb_leaf_onindex_has_stats(buf, leaf)) - { - idx = pnanovdb_uint64_offset(pnanovdb_leaf_onindex_get_last_offset(buf, leaf), 4u); - } - return idx; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindex_get_value_index(pnanovdb_buf_t buf, pnanovdb_address_t value_address, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); - pnanovdb_leaf_handle_t leaf = { pnanovdb_address_offset_neg(value_address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_ONINDEX, leaf_off_table)) }; - - pnanovdb_uint32_t word_idx = n >> 6u; - pnanovdb_uint32_t bit_idx = n & 63u; - pnanovdb_uint64_t val_mask = pnanovdb_read_uint64(buf, pnanovdb_address_offset(leaf.address, PNANOVDB_LEAF_OFF_VALUE_MASK + 8u * word_idx)); - pnanovdb_uint64_t mask = pnanovdb_uint64_bit_mask(bit_idx); - pnanovdb_uint64_t value_index = pnanovdb_uint32_as_uint64_low(0u); - if (pnanovdb_uint64_any_bit(pnanovdb_uint64_and(val_mask, mask))) - { - pnanovdb_uint32_t sum = 0u; - sum += pnanovdb_uint64_countbits(pnanovdb_uint64_and(val_mask, pnanovdb_uint64_dec(mask))); - if (word_idx > 0u) - { - pnanovdb_uint64_t prefix_sum = pnanovdb_read_uint64(buf, pnanovdb_address_offset(value_address, 8u)); - sum += pnanovdb_uint64_to_uint32_lsr(prefix_sum, 9u * (word_idx - 1u)) & 511u; - } - pnanovdb_uint64_t offset = pnanovdb_read_uint64(buf, value_address); - value_index = pnanovdb_uint64_offset(offset, sum); - } - return value_index; -} - -// ----------------------------- Leaf OnIndexMask Specialization --------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_leaf_onindexmask_get_value_count(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) -{ - return pnanovdb_leaf_onindex_get_value_count(buf, leaf); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindexmask_get_last_offset(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) -{ - return pnanovdb_leaf_onindex_get_last_offset(buf, leaf); -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_leaf_onindexmask_has_stats(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) -{ - return pnanovdb_leaf_onindex_has_stats(buf, leaf); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindexmask_get_min_index(pnanovdb_buf_t buf, pnanovdb_address_t min_address) -{ - return pnanovdb_leaf_onindex_get_min_index(buf, min_address); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindexmask_get_max_index(pnanovdb_buf_t buf, pnanovdb_address_t max_address) -{ - return pnanovdb_leaf_onindex_get_max_index(buf, max_address); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindexmask_get_ave_index(pnanovdb_buf_t buf, pnanovdb_address_t ave_address) -{ - return pnanovdb_leaf_onindex_get_ave_index(buf, ave_address); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindexmask_get_dev_index(pnanovdb_buf_t buf, pnanovdb_address_t dev_address) -{ - return pnanovdb_leaf_onindex_get_dev_index(buf, dev_address); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_onindexmask_get_value_index(pnanovdb_buf_t buf, pnanovdb_address_t value_address, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - return pnanovdb_leaf_onindex_get_value_index(buf, value_address, ijk); -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_leaf_onindexmask_get_mask_bit(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t n) -{ - pnanovdb_uint32_t word_idx = n >> 5; - pnanovdb_uint32_t bit_idx = n & 31; - pnanovdb_uint32_t val_mask = - pnanovdb_read_uint32(buf, pnanovdb_address_offset(leaf.address, 96u + 4u * word_idx)); - return (val_mask & (1u << bit_idx)) != 0u; -} -PNANOVDB_FORCE_INLINE void pnanovdb_leaf_onindexmask_set_mask_bit(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t n, pnanovdb_bool_t v) -{ - pnanovdb_uint32_t word_idx = n >> 5; - pnanovdb_uint32_t bit_idx = n & 31; - pnanovdb_uint32_t val_mask = - pnanovdb_read_uint32(buf, pnanovdb_address_offset(leaf.address, 96u + 4u * word_idx)); - if (v) - { - val_mask = val_mask | (1u << bit_idx); - } - else - { - val_mask = val_mask & ~(1u << bit_idx); - } - pnanovdb_write_uint32(buf, pnanovdb_address_offset(leaf.address, 96u + 4u * word_idx), val_mask); -} - -// ----------------------------- Leaf PointIndex Specialization --------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_pointindex_get_offset(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) -{ - return pnanovdb_read_uint64(buf, pnanovdb_leaf_get_min_address(PNANOVDB_GRID_TYPE_POINTINDEX, buf, leaf)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_pointindex_get_point_count(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf) -{ - return pnanovdb_read_uint64(buf, pnanovdb_leaf_get_max_address(PNANOVDB_GRID_TYPE_POINTINDEX, buf, leaf)); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_pointindex_get_first(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t i) -{ - return pnanovdb_uint64_offset(pnanovdb_leaf_pointindex_get_offset(buf, leaf), - (i == 0u ? 0u : pnanovdb_read_uint16(buf, pnanovdb_leaf_get_table_address(PNANOVDB_GRID_TYPE_POINTINDEX, buf, leaf, i - 1u)))); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_pointindex_get_last(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t i) -{ - return pnanovdb_uint64_offset(pnanovdb_leaf_pointindex_get_offset(buf, leaf), - pnanovdb_read_uint16(buf, pnanovdb_leaf_get_table_address(PNANOVDB_GRID_TYPE_POINTINDEX, buf, leaf, i))); -} -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_leaf_pointindex_get_value(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t i) -{ - return pnanovdb_uint32_as_uint64_low(pnanovdb_read_uint16(buf, pnanovdb_leaf_get_table_address(PNANOVDB_GRID_TYPE_POINTINDEX, buf, leaf, i))); -} -PNANOVDB_FORCE_INLINE void pnanovdb_leaf_pointindex_set_value_only(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t i, pnanovdb_uint32_t value) -{ - pnanovdb_address_t addr = pnanovdb_leaf_get_table_address(PNANOVDB_GRID_TYPE_POINTINDEX, buf, leaf, i); - pnanovdb_uint32_t raw32 = pnanovdb_read_uint32(buf, pnanovdb_address_mask_inv(addr, 3u)); - if ((i & 1) == 0u) - { - raw32 = (raw32 & 0xFFFF0000) | (value & 0x0000FFFF); - } - else - { - raw32 = (raw32 & 0x0000FFFF) | (value << 16u); - } - pnanovdb_write_uint32(buf, addr, raw32); -} -PNANOVDB_FORCE_INLINE void pnanovdb_leaf_pointindex_set_on(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t i) -{ - pnanovdb_uint32_t word_idx = i >> 5; - pnanovdb_uint32_t bit_idx = i & 31; - pnanovdb_address_t addr = pnanovdb_address_offset(leaf.address, PNANOVDB_LEAF_OFF_VALUE_MASK + 4u * word_idx); - pnanovdb_uint32_t val_mask = pnanovdb_read_uint32(buf, addr); - val_mask = val_mask | (1u << bit_idx); - pnanovdb_write_uint32(buf, addr, val_mask); -} -PNANOVDB_FORCE_INLINE void pnanovdb_leaf_pointindex_set_value(pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, pnanovdb_uint32_t i, pnanovdb_uint32_t value) -{ - pnanovdb_leaf_pointindex_set_on(buf, leaf, i); - pnanovdb_leaf_pointindex_set_value_only(buf, leaf, i, value); -} - -// ------------------------------------------------ Lower Node ----------------------------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_lower_coord_to_offset(PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - return (((PNANOVDB_DEREF(ijk).x & 127) >> 3) << (2 * 4)) + - (((PNANOVDB_DEREF(ijk).y & 127) >> 3) << (4)) + - ((PNANOVDB_DEREF(ijk).z & 127) >> 3); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_min_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, lower_off_min); - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_max_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, lower_off_max); - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_ave_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, lower_off_ave); - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_stddev_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, lower_off_stddev); - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_table_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node, pnanovdb_uint32_t n) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, lower_off_table) + PNANOVDB_GRID_TYPE_GET(grid_type, table_stride) * n; - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_lower_get_table_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node, pnanovdb_uint32_t n) -{ - pnanovdb_address_t table_address = pnanovdb_lower_get_table_address(grid_type, buf, node, n); - return pnanovdb_read_int64(buf, table_address); -} - -PNANOVDB_FORCE_INLINE pnanovdb_leaf_handle_t pnanovdb_lower_get_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, pnanovdb_uint32_t n) -{ - pnanovdb_leaf_handle_t leaf = { lower.address }; - leaf.address = pnanovdb_address_offset64(leaf.address, pnanovdb_int64_as_uint64(pnanovdb_lower_get_table_child(grid_type, buf, lower, n))); - return leaf; -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_value_address_and_level(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_uint32_t) level) -{ - pnanovdb_uint32_t n = pnanovdb_lower_coord_to_offset(ijk); - pnanovdb_address_t value_address; - if (pnanovdb_lower_get_child_mask(buf, lower, n)) - { - pnanovdb_leaf_handle_t child = pnanovdb_lower_get_child(grid_type, buf, lower, n); - value_address = pnanovdb_leaf_get_value_address(grid_type, buf, child, ijk); - PNANOVDB_DEREF(level) = 0u; - } - else - { - value_address = pnanovdb_lower_get_table_address(grid_type, buf, lower, n); - PNANOVDB_DEREF(level) = 1u; - } - return value_address; -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_value_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - pnanovdb_uint32_t level; - return pnanovdb_lower_get_value_address_and_level(grid_type, buf, lower, ijk, PNANOVDB_REF(level)); -} - -// ------------------------------------------------ Upper Node ----------------------------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_upper_coord_to_offset(PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - return (((PNANOVDB_DEREF(ijk).x & 4095) >> 7) << (2 * 5)) + - (((PNANOVDB_DEREF(ijk).y & 4095) >> 7) << (5)) + - ((PNANOVDB_DEREF(ijk).z & 4095) >> 7); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_min_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, upper_off_min); - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_max_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, upper_off_max); - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_ave_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, upper_off_ave); - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_stddev_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, upper_off_stddev); - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_table_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node, pnanovdb_uint32_t n) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, upper_off_table) + PNANOVDB_GRID_TYPE_GET(grid_type, table_stride) * n; - return pnanovdb_address_offset(node.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_int64_t pnanovdb_upper_get_table_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node, pnanovdb_uint32_t n) -{ - pnanovdb_address_t bufAddress = pnanovdb_upper_get_table_address(grid_type, buf, node, n); - return pnanovdb_read_int64(buf, bufAddress); -} - -PNANOVDB_FORCE_INLINE pnanovdb_lower_handle_t pnanovdb_upper_get_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, pnanovdb_uint32_t n) -{ - pnanovdb_lower_handle_t lower = { upper.address }; - lower.address = pnanovdb_address_offset64(lower.address, pnanovdb_int64_as_uint64(pnanovdb_upper_get_table_child(grid_type, buf, upper, n))); - return lower; -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_value_address_and_level(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_uint32_t) level) -{ - pnanovdb_uint32_t n = pnanovdb_upper_coord_to_offset(ijk); - pnanovdb_address_t value_address; - if (pnanovdb_upper_get_child_mask(buf, upper, n)) - { - pnanovdb_lower_handle_t child = pnanovdb_upper_get_child(grid_type, buf, upper, n); - value_address = pnanovdb_lower_get_value_address_and_level(grid_type, buf, child, ijk, level); - } - else - { - value_address = pnanovdb_upper_get_table_address(grid_type, buf, upper, n); - PNANOVDB_DEREF(level) = 2u; - } - return value_address; -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_value_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - pnanovdb_uint32_t level; - return pnanovdb_upper_get_value_address_and_level(grid_type, buf, upper, ijk, PNANOVDB_REF(level)); -} - -PNANOVDB_FORCE_INLINE void pnanovdb_upper_set_table_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t node, pnanovdb_uint32_t n, pnanovdb_int64_t child) -{ - pnanovdb_address_t bufAddress = pnanovdb_upper_get_table_address(grid_type, buf, node, n); - pnanovdb_write_int64(buf, bufAddress, child); -} - -// ------------------------------------------------ Root ----------------------------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_min_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, root_off_min); - return pnanovdb_address_offset(root.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_max_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, root_off_max); - return pnanovdb_address_offset(root.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_ave_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, root_off_ave); - return pnanovdb_address_offset(root.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_stddev_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, root_off_stddev); - return pnanovdb_address_offset(root.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_tile_get_value_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_tile_handle_t root_tile) -{ - pnanovdb_uint32_t byte_offset = PNANOVDB_GRID_TYPE_GET(grid_type, root_tile_off_value); - return pnanovdb_address_offset(root_tile.address, byte_offset); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_value_address_and_level(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_uint32_t) level) -{ - pnanovdb_root_tile_handle_t tile = pnanovdb_root_find_tile(grid_type, buf, root, ijk); - pnanovdb_address_t ret; - if (pnanovdb_address_is_null(tile.address)) - { - ret = pnanovdb_address_offset(root.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_off_background)); - PNANOVDB_DEREF(level) = 4u; - } - else if (pnanovdb_int64_is_zero(pnanovdb_root_tile_get_child(buf, tile))) - { - ret = pnanovdb_address_offset(tile.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_tile_off_value)); - PNANOVDB_DEREF(level) = 3u; - } - else - { - pnanovdb_upper_handle_t child = pnanovdb_root_get_child(grid_type, buf, root, tile); - ret = pnanovdb_upper_get_value_address_and_level(grid_type, buf, child, ijk, level); - } - return ret; -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_value_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - pnanovdb_uint32_t level; - return pnanovdb_root_get_value_address_and_level(grid_type, buf, root, ijk, PNANOVDB_REF(level)); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_value_address_bit(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_uint32_t) bit_index) -{ - pnanovdb_uint32_t level; - pnanovdb_address_t address = pnanovdb_root_get_value_address_and_level(grid_type, buf, root, ijk, PNANOVDB_REF(level)); - PNANOVDB_DEREF(bit_index) = level == 0u ? pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).x & 7) : 0u; - return address; -} - -PNANOVDB_FORCE_INLINE float pnanovdb_root_fp4_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level) -{ - float ret; - if (level == 0) - { - ret = pnanovdb_leaf_fp4_read_float(buf, address, ijk); - } - else - { - ret = pnanovdb_read_float(buf, address); - } - return ret; -} - -PNANOVDB_FORCE_INLINE float pnanovdb_root_fp8_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level) -{ - float ret; - if (level == 0) - { - ret = pnanovdb_leaf_fp8_read_float(buf, address, ijk); - } - else - { - ret = pnanovdb_read_float(buf, address); - } - return ret; -} - -PNANOVDB_FORCE_INLINE float pnanovdb_root_fp16_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level) -{ - float ret; - if (level == 0) - { - ret = pnanovdb_leaf_fp16_read_float(buf, address, ijk); - } - else - { - ret = pnanovdb_read_float(buf, address); - } - return ret; -} - -PNANOVDB_FORCE_INLINE float pnanovdb_root_fpn_read_float(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level) -{ - float ret; - if (level == 0) - { - ret = pnanovdb_leaf_fpn_read_float(buf, address, ijk); - } - else - { - ret = pnanovdb_read_float(buf, address); - } - return ret; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_root_index_get_value_index(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level) -{ - pnanovdb_uint64_t ret; - if (level == 0) - { - ret = pnanovdb_leaf_index_get_value_index(buf, address, ijk); - } - else - { - ret = pnanovdb_read_uint64(buf, address); - } - return ret; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_root_onindex_get_value_index(pnanovdb_buf_t buf, pnanovdb_address_t address, PNANOVDB_IN(pnanovdb_coord_t) ijk, pnanovdb_uint32_t level) -{ - pnanovdb_uint64_t ret; - if (level == 0) - { - ret = pnanovdb_leaf_onindex_get_value_index(buf, address, ijk); - } - else - { - ret = pnanovdb_read_uint64(buf, address); - } - return ret; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_root_pointindex_get_point_range( - pnanovdb_buf_t buf, - pnanovdb_address_t value_address, - PNANOVDB_IN(pnanovdb_coord_t) ijk, - pnanovdb_uint32_t level, - PNANOVDB_INOUT(pnanovdb_uint64_t)range_begin, - PNANOVDB_INOUT(pnanovdb_uint64_t)range_end -) -{ - pnanovdb_uint32_t local_range_begin = 0u; - pnanovdb_uint32_t local_range_end = 0u; - pnanovdb_uint64_t offset = pnanovdb_uint32_as_uint64_low(0u); - if (level == 0) - { - pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); - // recover leaf address - pnanovdb_leaf_handle_t leaf = { pnanovdb_address_offset_neg(value_address, PNANOVDB_GRID_TYPE_GET(PNANOVDB_GRID_TYPE_POINTINDEX, leaf_off_table) + 2u * n) }; - if (n > 0u) - { - local_range_begin = pnanovdb_read_uint16(buf, pnanovdb_address_offset_neg(value_address, 2u)); - } - local_range_end = pnanovdb_read_uint16(buf, value_address); - offset = pnanovdb_leaf_pointindex_get_offset(buf, leaf); - } - PNANOVDB_DEREF(range_begin) = pnanovdb_uint64_offset(offset, local_range_begin); - PNANOVDB_DEREF(range_end) = pnanovdb_uint64_offset(offset, local_range_end); - return pnanovdb_uint32_as_uint64_low(local_range_end - local_range_begin); -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint64_t pnanovdb_root_pointindex_get_point_address_range( - pnanovdb_buf_t buf, - pnanovdb_grid_type_t value_type, - pnanovdb_address_t value_address, - pnanovdb_address_t blindmetadata_value_address, - PNANOVDB_IN(pnanovdb_coord_t) ijk, - pnanovdb_uint32_t level, - PNANOVDB_INOUT(pnanovdb_address_t)address_begin, - PNANOVDB_INOUT(pnanovdb_address_t)address_end -) -{ - pnanovdb_uint64_t range_begin; - pnanovdb_uint64_t range_end; - pnanovdb_uint64_t range_size = pnanovdb_root_pointindex_get_point_range(buf, value_address, ijk, level, PNANOVDB_REF(range_begin), PNANOVDB_REF(range_end)); - - pnanovdb_uint32_t stride = 12u; // vec3f - if (value_type == PNANOVDB_GRID_TYPE_VEC3U8) - { - stride = 3u; - } - else if (value_type == PNANOVDB_GRID_TYPE_VEC3U16) - { - stride = 6u; - } - PNANOVDB_DEREF(address_begin) = pnanovdb_address_offset64_product(blindmetadata_value_address, range_begin, stride); - PNANOVDB_DEREF(address_end) = pnanovdb_address_offset64_product(blindmetadata_value_address, range_end, stride); - return range_size; -} - -// ------------------------------------------------ ReadAccessor ----------------------------------------------------------- - -struct pnanovdb_readaccessor_t -{ - pnanovdb_coord_t key; - pnanovdb_leaf_handle_t leaf; - pnanovdb_lower_handle_t lower; - pnanovdb_upper_handle_t upper; - pnanovdb_root_handle_t root; -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_readaccessor_t) - -PNANOVDB_FORCE_INLINE void pnanovdb_readaccessor_init(PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, pnanovdb_root_handle_t root) -{ - PNANOVDB_DEREF(acc).key.x = 0x7FFFFFFF; - PNANOVDB_DEREF(acc).key.y = 0x7FFFFFFF; - PNANOVDB_DEREF(acc).key.z = 0x7FFFFFFF; - PNANOVDB_DEREF(acc).leaf.address = pnanovdb_address_null(); - PNANOVDB_DEREF(acc).lower.address = pnanovdb_address_null(); - PNANOVDB_DEREF(acc).upper.address = pnanovdb_address_null(); - PNANOVDB_DEREF(acc).root = root; -} - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_readaccessor_iscached0(PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, int dirty) -{ - if (pnanovdb_address_is_null(PNANOVDB_DEREF(acc).leaf.address)) { return PNANOVDB_FALSE; } - if ((dirty & ~((1u << 3) - 1u)) != 0) - { - PNANOVDB_DEREF(acc).leaf.address = pnanovdb_address_null(); - return PNANOVDB_FALSE; - } - return PNANOVDB_TRUE; -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_readaccessor_iscached1(PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, int dirty) -{ - if (pnanovdb_address_is_null(PNANOVDB_DEREF(acc).lower.address)) { return PNANOVDB_FALSE; } - if ((dirty & ~((1u << 7) - 1u)) != 0) - { - PNANOVDB_DEREF(acc).lower.address = pnanovdb_address_null(); - return PNANOVDB_FALSE; - } - return PNANOVDB_TRUE; -} -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_readaccessor_iscached2(PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, int dirty) -{ - if (pnanovdb_address_is_null(PNANOVDB_DEREF(acc).upper.address)) { return PNANOVDB_FALSE; } - if ((dirty & ~((1u << 12) - 1u)) != 0) - { - PNANOVDB_DEREF(acc).upper.address = pnanovdb_address_null(); - return PNANOVDB_FALSE; - } - return PNANOVDB_TRUE; -} -PNANOVDB_FORCE_INLINE int pnanovdb_readaccessor_computedirty(PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - return (PNANOVDB_DEREF(ijk).x ^ PNANOVDB_DEREF(acc).key.x) | (PNANOVDB_DEREF(ijk).y ^ PNANOVDB_DEREF(acc).key.y) | (PNANOVDB_DEREF(ijk).z ^ PNANOVDB_DEREF(acc).key.z); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_leaf_get_value_address_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) -{ - pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); - return pnanovdb_leaf_get_table_address(grid_type, buf, leaf, n); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_value_address_and_level_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_INOUT(pnanovdb_uint32_t) level) -{ - pnanovdb_uint32_t n = pnanovdb_lower_coord_to_offset(ijk); - pnanovdb_address_t value_address; - if (pnanovdb_lower_get_child_mask(buf, lower, n)) - { - pnanovdb_leaf_handle_t child = pnanovdb_lower_get_child(grid_type, buf, lower, n); - PNANOVDB_DEREF(acc).leaf = child; - PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); - value_address = pnanovdb_leaf_get_value_address_and_cache(grid_type, buf, child, ijk, acc); - PNANOVDB_DEREF(level) = 0u; - } - else - { - value_address = pnanovdb_lower_get_table_address(grid_type, buf, lower, n); - PNANOVDB_DEREF(level) = 1u; - } - return value_address; -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_lower_get_value_address_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) -{ - pnanovdb_uint32_t level; - return pnanovdb_lower_get_value_address_and_level_and_cache(grid_type, buf, lower, ijk, acc, PNANOVDB_REF(level)); -} - -PNANOVDB_FORCE_INLINE void pnanovdb_lower_set_table_child(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t node, pnanovdb_uint32_t n, pnanovdb_int64_t child) -{ - pnanovdb_address_t table_address = pnanovdb_lower_get_table_address(grid_type, buf, node, n); - pnanovdb_write_int64(buf, table_address, child); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_value_address_and_level_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_INOUT(pnanovdb_uint32_t) level) -{ - pnanovdb_uint32_t n = pnanovdb_upper_coord_to_offset(ijk); - pnanovdb_address_t value_address; - if (pnanovdb_upper_get_child_mask(buf, upper, n)) - { - pnanovdb_lower_handle_t child = pnanovdb_upper_get_child(grid_type, buf, upper, n); - PNANOVDB_DEREF(acc).lower = child; - PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); - value_address = pnanovdb_lower_get_value_address_and_level_and_cache(grid_type, buf, child, ijk, acc, level); - } - else - { - value_address = pnanovdb_upper_get_table_address(grid_type, buf, upper, n); - PNANOVDB_DEREF(level) = 2u; - } - return value_address; -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_upper_get_value_address_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) -{ - pnanovdb_uint32_t level; - return pnanovdb_upper_get_value_address_and_level_and_cache(grid_type, buf, upper, ijk, acc, PNANOVDB_REF(level)); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_value_address_and_level_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_INOUT(pnanovdb_uint32_t) level) -{ - pnanovdb_root_tile_handle_t tile = pnanovdb_root_find_tile(grid_type, buf, root, ijk); - pnanovdb_address_t ret; - if (pnanovdb_address_is_null(tile.address)) - { - ret = pnanovdb_address_offset(root.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_off_background)); - PNANOVDB_DEREF(level) = 4u; - } - else if (pnanovdb_int64_is_zero(pnanovdb_root_tile_get_child(buf, tile))) - { - ret = pnanovdb_address_offset(tile.address, PNANOVDB_GRID_TYPE_GET(grid_type, root_tile_off_value)); - PNANOVDB_DEREF(level) = 3u; - } - else - { - pnanovdb_upper_handle_t child = pnanovdb_root_get_child(grid_type, buf, root, tile); - PNANOVDB_DEREF(acc).upper = child; - PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); - ret = pnanovdb_upper_get_value_address_and_level_and_cache(grid_type, buf, child, ijk, acc, level); - } - return ret; -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_root_get_value_address_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) -{ - pnanovdb_uint32_t level; - return pnanovdb_root_get_value_address_and_level_and_cache(grid_type, buf, root, ijk, acc, PNANOVDB_REF(level)); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_readaccessor_get_value_address_and_level(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_uint32_t) level) -{ - int dirty = pnanovdb_readaccessor_computedirty(acc, ijk); - - pnanovdb_address_t value_address; - if (pnanovdb_readaccessor_iscached0(acc, dirty)) - { - value_address = pnanovdb_leaf_get_value_address_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).leaf, ijk, acc); - PNANOVDB_DEREF(level) = 0u; - } - else if (pnanovdb_readaccessor_iscached1(acc, dirty)) - { - value_address = pnanovdb_lower_get_value_address_and_level_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).lower, ijk, acc, level); - } - else if (pnanovdb_readaccessor_iscached2(acc, dirty)) - { - value_address = pnanovdb_upper_get_value_address_and_level_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).upper, ijk, acc, level); - } - else - { - value_address = pnanovdb_root_get_value_address_and_level_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).root, ijk, acc, level); - } - return value_address; -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_readaccessor_get_value_address(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - pnanovdb_uint32_t level; - return pnanovdb_readaccessor_get_value_address_and_level(grid_type, buf, acc, ijk, PNANOVDB_REF(level)); -} - -PNANOVDB_FORCE_INLINE pnanovdb_address_t pnanovdb_readaccessor_get_value_address_bit(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_uint32_t) bit_index) -{ - pnanovdb_uint32_t level; - pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address_and_level(grid_type, buf, acc, ijk, PNANOVDB_REF(level)); - PNANOVDB_DEREF(bit_index) = level == 0u ? pnanovdb_int32_as_uint32(PNANOVDB_DEREF(ijk).x & 7) : 0u; - return address; -} - -// ------------------------------------------------ ReadAccessor GetDim ----------------------------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_leaf_get_dim_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) -{ - return 1u; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_lower_get_dim_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) -{ - pnanovdb_uint32_t n = pnanovdb_lower_coord_to_offset(ijk); - pnanovdb_uint32_t ret; - if (pnanovdb_lower_get_child_mask(buf, lower, n)) - { - pnanovdb_leaf_handle_t child = pnanovdb_lower_get_child(grid_type, buf, lower, n); - PNANOVDB_DEREF(acc).leaf = child; - PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); - ret = pnanovdb_leaf_get_dim_and_cache(grid_type, buf, child, ijk, acc); - } - else - { - ret = (1u << (3u)); // node 0 dim - } - return ret; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_upper_get_dim_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) -{ - pnanovdb_uint32_t n = pnanovdb_upper_coord_to_offset(ijk); - pnanovdb_uint32_t ret; - if (pnanovdb_upper_get_child_mask(buf, upper, n)) - { - pnanovdb_lower_handle_t child = pnanovdb_upper_get_child(grid_type, buf, upper, n); - PNANOVDB_DEREF(acc).lower = child; - PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); - ret = pnanovdb_lower_get_dim_and_cache(grid_type, buf, child, ijk, acc); - } - else - { - ret = (1u << (4u + 3u)); // node 1 dim - } - return ret; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_root_get_dim_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) -{ - pnanovdb_root_tile_handle_t tile = pnanovdb_root_find_tile(grid_type, buf, root, ijk); - pnanovdb_uint32_t ret; - if (pnanovdb_address_is_null(tile.address)) - { - ret = 1u << (5u + 4u + 3u); // background, node 2 dim - } - else if (pnanovdb_int64_is_zero(pnanovdb_root_tile_get_child(buf, tile))) - { - ret = 1u << (5u + 4u + 3u); // tile value, node 2 dim - } - else - { - pnanovdb_upper_handle_t child = pnanovdb_root_get_child(grid_type, buf, root, tile); - PNANOVDB_DEREF(acc).upper = child; - PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); - ret = pnanovdb_upper_get_dim_and_cache(grid_type, buf, child, ijk, acc); - } - return ret; -} - -PNANOVDB_FORCE_INLINE pnanovdb_uint32_t pnanovdb_readaccessor_get_dim(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - int dirty = pnanovdb_readaccessor_computedirty(acc, ijk); - - pnanovdb_uint32_t dim; - if (pnanovdb_readaccessor_iscached0(acc, dirty)) - { - dim = pnanovdb_leaf_get_dim_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).leaf, ijk, acc); - } - else if (pnanovdb_readaccessor_iscached1(acc, dirty)) - { - dim = pnanovdb_lower_get_dim_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).lower, ijk, acc); - } - else if (pnanovdb_readaccessor_iscached2(acc, dirty)) - { - dim = pnanovdb_upper_get_dim_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).upper, ijk, acc); - } - else - { - dim = pnanovdb_root_get_dim_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).root, ijk, acc); - } - return dim; -} - -// ------------------------------------------------ ReadAccessor IsActive ----------------------------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_leaf_is_active_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_leaf_handle_t leaf, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) -{ - pnanovdb_uint32_t n = pnanovdb_leaf_coord_to_offset(ijk); - return pnanovdb_leaf_get_value_mask(buf, leaf, n); -} - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_lower_is_active_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_lower_handle_t lower, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) -{ - pnanovdb_uint32_t n = pnanovdb_lower_coord_to_offset(ijk); - pnanovdb_bool_t is_active; - if (pnanovdb_lower_get_child_mask(buf, lower, n)) - { - pnanovdb_leaf_handle_t child = pnanovdb_lower_get_child(grid_type, buf, lower, n); - PNANOVDB_DEREF(acc).leaf = child; - PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); - is_active = pnanovdb_leaf_is_active_and_cache(grid_type, buf, child, ijk, acc); - } - else - { - is_active = pnanovdb_lower_get_value_mask(buf, lower, n); - } - return is_active; -} - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_upper_is_active_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_upper_handle_t upper, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) -{ - pnanovdb_uint32_t n = pnanovdb_upper_coord_to_offset(ijk); - pnanovdb_bool_t is_active; - if (pnanovdb_upper_get_child_mask(buf, upper, n)) - { - pnanovdb_lower_handle_t child = pnanovdb_upper_get_child(grid_type, buf, upper, n); - PNANOVDB_DEREF(acc).lower = child; - PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); - is_active = pnanovdb_lower_is_active_and_cache(grid_type, buf, child, ijk, acc); - } - else - { - is_active = pnanovdb_upper_get_value_mask(buf, upper, n); - } - return is_active; -} - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_root_is_active_and_cache(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, pnanovdb_root_handle_t root, PNANOVDB_IN(pnanovdb_coord_t) ijk, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc) -{ - pnanovdb_root_tile_handle_t tile = pnanovdb_root_find_tile(grid_type, buf, root, ijk); - pnanovdb_bool_t is_active; - if (pnanovdb_address_is_null(tile.address)) - { - is_active = PNANOVDB_FALSE; // background - } - else if (pnanovdb_int64_is_zero(pnanovdb_root_tile_get_child(buf, tile))) - { - pnanovdb_uint32_t state = pnanovdb_root_tile_get_state(buf, tile); - is_active = state != 0u; // tile value - } - else - { - pnanovdb_upper_handle_t child = pnanovdb_root_get_child(grid_type, buf, root, tile); - PNANOVDB_DEREF(acc).upper = child; - PNANOVDB_DEREF(acc).key = PNANOVDB_DEREF(ijk); - is_active = pnanovdb_upper_is_active_and_cache(grid_type, buf, child, ijk, acc); - } - return is_active; -} - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_readaccessor_is_active(pnanovdb_grid_type_t grid_type, pnanovdb_buf_t buf, PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, PNANOVDB_IN(pnanovdb_coord_t) ijk) -{ - int dirty = pnanovdb_readaccessor_computedirty(acc, ijk); - - pnanovdb_bool_t is_active; - if (pnanovdb_readaccessor_iscached0(acc, dirty)) - { - is_active = pnanovdb_leaf_is_active_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).leaf, ijk, acc); - } - else if (pnanovdb_readaccessor_iscached1(acc, dirty)) - { - is_active = pnanovdb_lower_is_active_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).lower, ijk, acc); - } - else if (pnanovdb_readaccessor_iscached2(acc, dirty)) - { - is_active = pnanovdb_upper_is_active_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).upper, ijk, acc); - } - else - { - is_active = pnanovdb_root_is_active_and_cache(grid_type, buf, PNANOVDB_DEREF(acc).root, ijk, acc); - } - return is_active; -} - -// ------------------------------------------------ Map Transforms ----------------------------------------------------------- - -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_map_apply(pnanovdb_buf_t buf, pnanovdb_map_handle_t map, PNANOVDB_IN(pnanovdb_vec3_t) src) -{ - pnanovdb_vec3_t dst; - float sx = PNANOVDB_DEREF(src).x; - float sy = PNANOVDB_DEREF(src).y; - float sz = PNANOVDB_DEREF(src).z; - dst.x = sx * pnanovdb_map_get_matf(buf, map, 0) + sy * pnanovdb_map_get_matf(buf, map, 1) + sz * pnanovdb_map_get_matf(buf, map, 2) + pnanovdb_map_get_vecf(buf, map, 0); - dst.y = sx * pnanovdb_map_get_matf(buf, map, 3) + sy * pnanovdb_map_get_matf(buf, map, 4) + sz * pnanovdb_map_get_matf(buf, map, 5) + pnanovdb_map_get_vecf(buf, map, 1); - dst.z = sx * pnanovdb_map_get_matf(buf, map, 6) + sy * pnanovdb_map_get_matf(buf, map, 7) + sz * pnanovdb_map_get_matf(buf, map, 8) + pnanovdb_map_get_vecf(buf, map, 2); - return dst; -} - -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_map_apply_inverse(pnanovdb_buf_t buf, pnanovdb_map_handle_t map, PNANOVDB_IN(pnanovdb_vec3_t) src) -{ - pnanovdb_vec3_t dst; - float sx = PNANOVDB_DEREF(src).x - pnanovdb_map_get_vecf(buf, map, 0); - float sy = PNANOVDB_DEREF(src).y - pnanovdb_map_get_vecf(buf, map, 1); - float sz = PNANOVDB_DEREF(src).z - pnanovdb_map_get_vecf(buf, map, 2); - dst.x = sx * pnanovdb_map_get_invmatf(buf, map, 0) + sy * pnanovdb_map_get_invmatf(buf, map, 1) + sz * pnanovdb_map_get_invmatf(buf, map, 2); - dst.y = sx * pnanovdb_map_get_invmatf(buf, map, 3) + sy * pnanovdb_map_get_invmatf(buf, map, 4) + sz * pnanovdb_map_get_invmatf(buf, map, 5); - dst.z = sx * pnanovdb_map_get_invmatf(buf, map, 6) + sy * pnanovdb_map_get_invmatf(buf, map, 7) + sz * pnanovdb_map_get_invmatf(buf, map, 8); - return dst; -} - -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_map_apply_jacobi(pnanovdb_buf_t buf, pnanovdb_map_handle_t map, PNANOVDB_IN(pnanovdb_vec3_t) src) -{ - pnanovdb_vec3_t dst; - float sx = PNANOVDB_DEREF(src).x; - float sy = PNANOVDB_DEREF(src).y; - float sz = PNANOVDB_DEREF(src).z; - dst.x = sx * pnanovdb_map_get_matf(buf, map, 0) + sy * pnanovdb_map_get_matf(buf, map, 1) + sz * pnanovdb_map_get_matf(buf, map, 2); - dst.y = sx * pnanovdb_map_get_matf(buf, map, 3) + sy * pnanovdb_map_get_matf(buf, map, 4) + sz * pnanovdb_map_get_matf(buf, map, 5); - dst.z = sx * pnanovdb_map_get_matf(buf, map, 6) + sy * pnanovdb_map_get_matf(buf, map, 7) + sz * pnanovdb_map_get_matf(buf, map, 8); - return dst; -} - -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_map_apply_inverse_jacobi(pnanovdb_buf_t buf, pnanovdb_map_handle_t map, PNANOVDB_IN(pnanovdb_vec3_t) src) -{ - pnanovdb_vec3_t dst; - float sx = PNANOVDB_DEREF(src).x; - float sy = PNANOVDB_DEREF(src).y; - float sz = PNANOVDB_DEREF(src).z; - dst.x = sx * pnanovdb_map_get_invmatf(buf, map, 0) + sy * pnanovdb_map_get_invmatf(buf, map, 1) + sz * pnanovdb_map_get_invmatf(buf, map, 2); - dst.y = sx * pnanovdb_map_get_invmatf(buf, map, 3) + sy * pnanovdb_map_get_invmatf(buf, map, 4) + sz * pnanovdb_map_get_invmatf(buf, map, 5); - dst.z = sx * pnanovdb_map_get_invmatf(buf, map, 6) + sy * pnanovdb_map_get_invmatf(buf, map, 7) + sz * pnanovdb_map_get_invmatf(buf, map, 8); - return dst; -} - -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_grid_world_to_indexf(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid, PNANOVDB_IN(pnanovdb_vec3_t) src) -{ - pnanovdb_map_handle_t map = pnanovdb_grid_get_map(buf, grid); - return pnanovdb_map_apply_inverse(buf, map, src); -} - -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_grid_index_to_worldf(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid, PNANOVDB_IN(pnanovdb_vec3_t) src) -{ - pnanovdb_map_handle_t map = pnanovdb_grid_get_map(buf, grid); - return pnanovdb_map_apply(buf, map, src); -} - -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_grid_world_to_index_dirf(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid, PNANOVDB_IN(pnanovdb_vec3_t) src) -{ - pnanovdb_map_handle_t map = pnanovdb_grid_get_map(buf, grid); - return pnanovdb_map_apply_inverse_jacobi(buf, map, src); -} - -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_grid_index_to_world_dirf(pnanovdb_buf_t buf, pnanovdb_grid_handle_t grid, PNANOVDB_IN(pnanovdb_vec3_t) src) -{ - pnanovdb_map_handle_t map = pnanovdb_grid_get_map(buf, grid); - return pnanovdb_map_apply_jacobi(buf, map, src); -} - -// ------------------------------------------------ DitherLUT ----------------------------------------------------------- - -// This table was generated with -/************** - -static constexpr inline uint32 -SYSwang_inthash(uint32 key) -{ - // From http://www.concentric.net/~Ttwang/tech/inthash.htm - key += ~(key << 16); - key ^= (key >> 5); - key += (key << 3); - key ^= (key >> 13); - key += ~(key << 9); - key ^= (key >> 17); - return key; -} - -static void -ut_initDitherR(float *pattern, float offset, - int x, int y, int z, int res, int goalres) -{ - // These offsets are designed to maximize the difference between - // dither values in nearby voxels within a given 2x2x2 cell, without - // producing axis-aligned artifacts. The are organized in row-major - // order. - static const float theDitherOffset[] = {0,4,6,2,5,1,3,7}; - static const float theScale = 0.125F; - int key = (((z << res) + y) << res) + x; - - if (res == goalres) - { - pattern[key] = offset; - return; - } - - // Randomly flip (on each axis) the dithering patterns used by the - // subcells. This key is xor'd with the subcell index below before - // looking up in the dither offset list. - key = SYSwang_inthash(key) & 7; - - x <<= 1; - y <<= 1; - z <<= 1; - - offset *= theScale; - for (int i = 0; i < 8; i++) - ut_initDitherR(pattern, offset+theDitherOffset[i ^ key]*theScale, - x+(i&1), y+((i&2)>>1), z+((i&4)>>2), res+1, goalres); -} - -// This is a compact algorithm that accomplishes essentially the same thing -// as ut_initDither() above. We should eventually switch to use this and -// clean the dead code. -static fpreal32 * -ut_initDitherRecursive(int goalres) -{ - const int nfloat = 1 << (goalres*3); - float *pattern = new float[nfloat]; - ut_initDitherR(pattern, 1.0F, 0, 0, 0, 0, goalres); - - // This has built an even spacing from 1/nfloat to 1.0. - // however, our dither pattern should be 1/(nfloat+1) to nfloat/(nfloat+1) - // So we do a correction here. Note that the earlier calculations are - // done with powers of 2 so are exact, so it does make sense to delay - // the renormalization to this pass. - float correctionterm = nfloat / (nfloat+1.0F); - for (int i = 0; i < nfloat; i++) - pattern[i] *= correctionterm; - return pattern; -} - - theDitherMatrix = ut_initDitherRecursive(3); - - for (int i = 0; i < 512/8; i ++) - { - for (int j = 0; j < 8; j ++) - std::cout << theDitherMatrix[i*8+j] << "f, "; - std::cout << std::endl; - } - - **************/ - -PNANOVDB_STATIC_CONST float pnanovdb_dither_lut[512] = -{ - 0.14425f, 0.643275f, 0.830409f, 0.331384f, 0.105263f, 0.604289f, 0.167641f, 0.666667f, - 0.892788f, 0.393762f, 0.0818713f, 0.580897f, 0.853801f, 0.354776f, 0.916179f, 0.417154f, - 0.612086f, 0.11306f, 0.79922f, 0.300195f, 0.510721f, 0.0116959f, 0.947368f, 0.448343f, - 0.362573f, 0.861598f, 0.0506823f, 0.549708f, 0.261209f, 0.760234f, 0.19883f, 0.697856f, - 0.140351f, 0.639376f, 0.576998f, 0.0779727f, 0.522417f, 0.0233918f, 0.460039f, 0.959064f, - 0.888889f, 0.389864f, 0.327485f, 0.826511f, 0.272904f, 0.77193f, 0.709552f, 0.210526f, - 0.483431f, 0.982456f, 0.296296f, 0.795322f, 0.116959f, 0.615984f, 0.0545809f, 0.553606f, - 0.732943f, 0.233918f, 0.545809f, 0.0467836f, 0.865497f, 0.366472f, 0.803119f, 0.304094f, - 0.518519f, 0.0194932f, 0.45614f, 0.955166f, 0.729045f, 0.230019f, 0.54191f, 0.042885f, - 0.269006f, 0.768031f, 0.705653f, 0.206628f, 0.479532f, 0.978558f, 0.292398f, 0.791423f, - 0.237817f, 0.736842f, 0.424951f, 0.923977f, 0.136452f, 0.635478f, 0.323587f, 0.822612f, - 0.986355f, 0.487329f, 0.674464f, 0.175439f, 0.88499f, 0.385965f, 0.573099f, 0.0740741f, - 0.51462f, 0.0155945f, 0.202729f, 0.701754f, 0.148148f, 0.647174f, 0.834308f, 0.335283f, - 0.265107f, 0.764133f, 0.951267f, 0.452242f, 0.896686f, 0.397661f, 0.08577f, 0.584795f, - 0.8577f, 0.358674f, 0.920078f, 0.421053f, 0.740741f, 0.241715f, 0.678363f, 0.179337f, - 0.109162f, 0.608187f, 0.17154f, 0.670565f, 0.491228f, 0.990253f, 0.42885f, 0.927875f, - 0.0662768f, 0.565302f, 0.62768f, 0.128655f, 0.183236f, 0.682261f, 0.744639f, 0.245614f, - 0.814815f, 0.315789f, 0.378168f, 0.877193f, 0.931774f, 0.432749f, 0.495127f, 0.994152f, - 0.0350877f, 0.534113f, 0.97076f, 0.471735f, 0.214425f, 0.71345f, 0.526316f, 0.0272904f, - 0.783626f, 0.2846f, 0.222222f, 0.721248f, 0.962963f, 0.463938f, 0.276803f, 0.775828f, - 0.966862f, 0.467836f, 0.405458f, 0.904483f, 0.0701754f, 0.569201f, 0.881092f, 0.382066f, - 0.218324f, 0.717349f, 0.654971f, 0.155945f, 0.818713f, 0.319688f, 0.132554f, 0.631579f, - 0.0623782f, 0.561404f, 0.748538f, 0.249513f, 0.912281f, 0.413255f, 0.974659f, 0.475634f, - 0.810916f, 0.311891f, 0.499025f, 0.998051f, 0.163743f, 0.662768f, 0.226121f, 0.725146f, - 0.690058f, 0.191033f, 0.00389864f, 0.502924f, 0.557505f, 0.0584795f, 0.120858f, 0.619883f, - 0.440546f, 0.939571f, 0.752437f, 0.253411f, 0.307992f, 0.807018f, 0.869396f, 0.37037f, - 0.658869f, 0.159844f, 0.346979f, 0.846004f, 0.588694f, 0.0896686f, 0.152047f, 0.651072f, - 0.409357f, 0.908382f, 0.596491f, 0.0974659f, 0.339181f, 0.838207f, 0.900585f, 0.401559f, - 0.34308f, 0.842105f, 0.779727f, 0.280702f, 0.693957f, 0.194932f, 0.25731f, 0.756335f, - 0.592593f, 0.0935673f, 0.0311891f, 0.530214f, 0.444444f, 0.94347f, 0.506823f, 0.00779727f, - 0.68616f, 0.187135f, 0.124756f, 0.623782f, 0.288499f, 0.787524f, 0.350877f, 0.849903f, - 0.436647f, 0.935673f, 0.873294f, 0.374269f, 0.538012f, 0.0389864f, 0.60039f, 0.101365f, - 0.57115f, 0.0721248f, 0.758285f, 0.259259f, 0.719298f, 0.220273f, 0.532164f, 0.0331384f, - 0.321637f, 0.820663f, 0.00974659f, 0.508772f, 0.469786f, 0.968811f, 0.282651f, 0.781676f, - 0.539961f, 0.0409357f, 0.727096f, 0.22807f, 0.500975f, 0.00194932f, 0.563353f, 0.0643275f, - 0.290448f, 0.789474f, 0.477583f, 0.976608f, 0.251462f, 0.750487f, 0.31384f, 0.812865f, - 0.94152f, 0.442495f, 0.879142f, 0.380117f, 0.37232f, 0.871345f, 0.309942f, 0.808967f, - 0.192982f, 0.692008f, 0.130604f, 0.62963f, 0.621832f, 0.122807f, 0.559454f, 0.0604289f, - 0.660819f, 0.161793f, 0.723197f, 0.224172f, 0.403509f, 0.902534f, 0.840156f, 0.341131f, - 0.411306f, 0.910331f, 0.473684f, 0.97271f, 0.653021f, 0.153996f, 0.0916179f, 0.590643f, - 0.196881f, 0.695906f, 0.384016f, 0.883041f, 0.0955166f, 0.594542f, 0.157895f, 0.65692f, - 0.945419f, 0.446394f, 0.633528f, 0.134503f, 0.844055f, 0.345029f, 0.906433f, 0.407407f, - 0.165692f, 0.664717f, 0.103314f, 0.602339f, 0.126706f, 0.625731f, 0.189084f, 0.688109f, - 0.91423f, 0.415205f, 0.851852f, 0.352827f, 0.875244f, 0.376218f, 0.937622f, 0.438596f, - 0.317739f, 0.816764f, 0.255361f, 0.754386f, 0.996101f, 0.497076f, 0.933723f, 0.434698f, - 0.567251f, 0.0682261f, 0.504873f, 0.00584795f, 0.247563f, 0.746589f, 0.185185f, 0.684211f, - 0.037037f, 0.536062f, 0.0994152f, 0.598441f, 0.777778f, 0.278752f, 0.465887f, 0.964912f, - 0.785575f, 0.28655f, 0.847953f, 0.348928f, 0.0292398f, 0.528265f, 0.7154f, 0.216374f, - 0.39961f, 0.898636f, 0.961014f, 0.461988f, 0.0487329f, 0.547758f, 0.111111f, 0.610136f, - 0.649123f, 0.150097f, 0.212476f, 0.711501f, 0.797271f, 0.298246f, 0.859649f, 0.360624f, - 0.118908f, 0.617934f, 0.0565302f, 0.555556f, 0.329435f, 0.82846f, 0.516569f, 0.0175439f, - 0.867446f, 0.368421f, 0.805068f, 0.306043f, 0.578947f, 0.079922f, 0.267057f, 0.766082f, - 0.270955f, 0.76998f, 0.707602f, 0.208577f, 0.668616f, 0.169591f, 0.606238f, 0.107212f, - 0.520468f, 0.0214425f, 0.45809f, 0.957115f, 0.419103f, 0.918129f, 0.356725f, 0.855751f, - 0.988304f, 0.489279f, 0.426901f, 0.925926f, 0.450292f, 0.949318f, 0.512671f, 0.0136452f, - 0.239766f, 0.738791f, 0.676413f, 0.177388f, 0.699805f, 0.20078f, 0.263158f, 0.762183f, - 0.773879f, 0.274854f, 0.337232f, 0.836257f, 0.672515f, 0.173489f, 0.734893f, 0.235867f, - 0.0253411f, 0.524366f, 0.586745f, 0.0877193f, 0.423002f, 0.922027f, 0.48538f, 0.984405f, - 0.74269f, 0.243665f, 0.680312f, 0.181287f, 0.953216f, 0.454191f, 0.1423f, 0.641326f, - 0.493177f, 0.992203f, 0.430799f, 0.929825f, 0.204678f, 0.703704f, 0.890838f, 0.391813f, - 0.894737f, 0.395712f, 0.0838207f, 0.582846f, 0.0448343f, 0.54386f, 0.231969f, 0.730994f, - 0.146199f, 0.645224f, 0.832359f, 0.333333f, 0.793372f, 0.294347f, 0.980507f, 0.481481f, - 0.364522f, 0.863548f, 0.80117f, 0.302144f, 0.824561f, 0.325536f, 0.138402f, 0.637427f, - 0.614035f, 0.11501f, 0.0526316f, 0.551657f, 0.0760234f, 0.575049f, 0.88694f, 0.387914f, -}; - -PNANOVDB_FORCE_INLINE float pnanovdb_dither_lookup(pnanovdb_bool_t enabled, int offset) -{ - return enabled ? pnanovdb_dither_lut[offset & 511] : 0.5f; -} - -// ------------------------------------------------ HDDA ----------------------------------------------------------- - -#ifdef PNANOVDB_HDDA - -// Comment out to disable this explicit round-off check -#define PNANOVDB_ENFORCE_FORWARD_STEPPING - -#define PNANOVDB_HDDA_FLOAT_MAX 1e38f - -struct pnanovdb_hdda_t -{ - pnanovdb_int32_t dim; - float tmin; - float tmax; - pnanovdb_coord_t voxel; - pnanovdb_coord_t step; - pnanovdb_vec3_t delta; - pnanovdb_vec3_t next; -}; -PNANOVDB_STRUCT_TYPEDEF(pnanovdb_hdda_t) - -PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_hdda_pos_to_ijk(PNANOVDB_IN(pnanovdb_vec3_t) pos) -{ - pnanovdb_coord_t voxel; - voxel.x = pnanovdb_float_to_int32(pnanovdb_floor(PNANOVDB_DEREF(pos).x)); - voxel.y = pnanovdb_float_to_int32(pnanovdb_floor(PNANOVDB_DEREF(pos).y)); - voxel.z = pnanovdb_float_to_int32(pnanovdb_floor(PNANOVDB_DEREF(pos).z)); - return voxel; -} - -PNANOVDB_FORCE_INLINE pnanovdb_coord_t pnanovdb_hdda_pos_to_voxel(PNANOVDB_IN(pnanovdb_vec3_t) pos, int dim) -{ - pnanovdb_coord_t voxel; - voxel.x = pnanovdb_float_to_int32(pnanovdb_floor(PNANOVDB_DEREF(pos).x)) & (~(dim - 1)); - voxel.y = pnanovdb_float_to_int32(pnanovdb_floor(PNANOVDB_DEREF(pos).y)) & (~(dim - 1)); - voxel.z = pnanovdb_float_to_int32(pnanovdb_floor(PNANOVDB_DEREF(pos).z)) & (~(dim - 1)); - return voxel; -} - -PNANOVDB_FORCE_INLINE pnanovdb_vec3_t pnanovdb_hdda_ray_start(PNANOVDB_IN(pnanovdb_vec3_t) origin, float tmin, PNANOVDB_IN(pnanovdb_vec3_t) direction) -{ - pnanovdb_vec3_t pos = pnanovdb_vec3_add( - pnanovdb_vec3_mul(PNANOVDB_DEREF(direction), pnanovdb_vec3_uniform(tmin)), - PNANOVDB_DEREF(origin) - ); - return pos; -} - -PNANOVDB_FORCE_INLINE void pnanovdb_hdda_init(PNANOVDB_INOUT(pnanovdb_hdda_t) hdda, PNANOVDB_IN(pnanovdb_vec3_t) origin, float tmin, PNANOVDB_IN(pnanovdb_vec3_t) direction, float tmax, int dim) -{ - PNANOVDB_DEREF(hdda).dim = dim; - PNANOVDB_DEREF(hdda).tmin = tmin; - PNANOVDB_DEREF(hdda).tmax = tmax; - - pnanovdb_vec3_t pos = pnanovdb_hdda_ray_start(origin, tmin, direction); - pnanovdb_vec3_t dir_inv = pnanovdb_vec3_div(pnanovdb_vec3_uniform(1.f), PNANOVDB_DEREF(direction)); - - PNANOVDB_DEREF(hdda).voxel = pnanovdb_hdda_pos_to_voxel(PNANOVDB_REF(pos), dim); - - // x - if (PNANOVDB_DEREF(direction).x == 0.f) - { - PNANOVDB_DEREF(hdda).next.x = PNANOVDB_HDDA_FLOAT_MAX; - PNANOVDB_DEREF(hdda).step.x = 0; - PNANOVDB_DEREF(hdda).delta.x = 0.f; - } - else if (dir_inv.x > 0.f) - { - PNANOVDB_DEREF(hdda).step.x = 1; - PNANOVDB_DEREF(hdda).next.x = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.x + dim - pos.x) * dir_inv.x; - PNANOVDB_DEREF(hdda).delta.x = dir_inv.x; - } - else - { - PNANOVDB_DEREF(hdda).step.x = -1; - PNANOVDB_DEREF(hdda).next.x = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.x - pos.x) * dir_inv.x; - PNANOVDB_DEREF(hdda).delta.x = -dir_inv.x; - } - - // y - if (PNANOVDB_DEREF(direction).y == 0.f) - { - PNANOVDB_DEREF(hdda).next.y = PNANOVDB_HDDA_FLOAT_MAX; - PNANOVDB_DEREF(hdda).step.y = 0; - PNANOVDB_DEREF(hdda).delta.y = 0.f; - } - else if (dir_inv.y > 0.f) - { - PNANOVDB_DEREF(hdda).step.y = 1; - PNANOVDB_DEREF(hdda).next.y = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.y + dim - pos.y) * dir_inv.y; - PNANOVDB_DEREF(hdda).delta.y = dir_inv.y; - } - else - { - PNANOVDB_DEREF(hdda).step.y = -1; - PNANOVDB_DEREF(hdda).next.y = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.y - pos.y) * dir_inv.y; - PNANOVDB_DEREF(hdda).delta.y = -dir_inv.y; - } - - // z - if (PNANOVDB_DEREF(direction).z == 0.f) - { - PNANOVDB_DEREF(hdda).next.z = PNANOVDB_HDDA_FLOAT_MAX; - PNANOVDB_DEREF(hdda).step.z = 0; - PNANOVDB_DEREF(hdda).delta.z = 0.f; - } - else if (dir_inv.z > 0.f) - { - PNANOVDB_DEREF(hdda).step.z = 1; - PNANOVDB_DEREF(hdda).next.z = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.z + dim - pos.z) * dir_inv.z; - PNANOVDB_DEREF(hdda).delta.z = dir_inv.z; - } - else - { - PNANOVDB_DEREF(hdda).step.z = -1; - PNANOVDB_DEREF(hdda).next.z = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.z - pos.z) * dir_inv.z; - PNANOVDB_DEREF(hdda).delta.z = -dir_inv.z; - } -} - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_hdda_update(PNANOVDB_INOUT(pnanovdb_hdda_t) hdda, PNANOVDB_IN(pnanovdb_vec3_t) origin, PNANOVDB_IN(pnanovdb_vec3_t) direction, int dim) -{ - if (PNANOVDB_DEREF(hdda).dim == dim) - { - return PNANOVDB_FALSE; - } - PNANOVDB_DEREF(hdda).dim = dim; - - pnanovdb_vec3_t pos = pnanovdb_vec3_add( - pnanovdb_vec3_mul(PNANOVDB_DEREF(direction), pnanovdb_vec3_uniform(PNANOVDB_DEREF(hdda).tmin)), - PNANOVDB_DEREF(origin) - ); - pnanovdb_vec3_t dir_inv = pnanovdb_vec3_div(pnanovdb_vec3_uniform(1.f), PNANOVDB_DEREF(direction)); - - PNANOVDB_DEREF(hdda).voxel = pnanovdb_hdda_pos_to_voxel(PNANOVDB_REF(pos), dim); - - if (PNANOVDB_DEREF(hdda).step.x != 0) - { - PNANOVDB_DEREF(hdda).next.x = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.x - pos.x) * dir_inv.x; - if (PNANOVDB_DEREF(hdda).step.x > 0) - { - PNANOVDB_DEREF(hdda).next.x += dim * dir_inv.x; - } - } - if (PNANOVDB_DEREF(hdda).step.y != 0) - { - PNANOVDB_DEREF(hdda).next.y = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.y - pos.y) * dir_inv.y; - if (PNANOVDB_DEREF(hdda).step.y > 0) - { - PNANOVDB_DEREF(hdda).next.y += dim * dir_inv.y; - } - } - if (PNANOVDB_DEREF(hdda).step.z != 0) - { - PNANOVDB_DEREF(hdda).next.z = PNANOVDB_DEREF(hdda).tmin + (PNANOVDB_DEREF(hdda).voxel.z - pos.z) * dir_inv.z; - if (PNANOVDB_DEREF(hdda).step.z > 0) - { - PNANOVDB_DEREF(hdda).next.z += dim * dir_inv.z; - } - } - - return PNANOVDB_TRUE; -} - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_hdda_step(PNANOVDB_INOUT(pnanovdb_hdda_t) hdda) -{ - pnanovdb_bool_t ret; - if (PNANOVDB_DEREF(hdda).next.x < PNANOVDB_DEREF(hdda).next.y && PNANOVDB_DEREF(hdda).next.x < PNANOVDB_DEREF(hdda).next.z) - { -#ifdef PNANOVDB_ENFORCE_FORWARD_STEPPING - if (PNANOVDB_DEREF(hdda).next.x <= PNANOVDB_DEREF(hdda).tmin) - { - PNANOVDB_DEREF(hdda).next.x += PNANOVDB_DEREF(hdda).tmin - 0.999999f * PNANOVDB_DEREF(hdda).next.x + 1.0e-6f; - } -#endif - PNANOVDB_DEREF(hdda).tmin = PNANOVDB_DEREF(hdda).next.x; - PNANOVDB_DEREF(hdda).next.x += PNANOVDB_DEREF(hdda).dim * PNANOVDB_DEREF(hdda).delta.x; - PNANOVDB_DEREF(hdda).voxel.x += PNANOVDB_DEREF(hdda).dim * PNANOVDB_DEREF(hdda).step.x; - ret = PNANOVDB_DEREF(hdda).tmin <= PNANOVDB_DEREF(hdda).tmax; - } - else if (PNANOVDB_DEREF(hdda).next.y < PNANOVDB_DEREF(hdda).next.z) - { -#ifdef PNANOVDB_ENFORCE_FORWARD_STEPPING - if (PNANOVDB_DEREF(hdda).next.y <= PNANOVDB_DEREF(hdda).tmin) - { - PNANOVDB_DEREF(hdda).next.y += PNANOVDB_DEREF(hdda).tmin - 0.999999f * PNANOVDB_DEREF(hdda).next.y + 1.0e-6f; - } -#endif - PNANOVDB_DEREF(hdda).tmin = PNANOVDB_DEREF(hdda).next.y; - PNANOVDB_DEREF(hdda).next.y += PNANOVDB_DEREF(hdda).dim * PNANOVDB_DEREF(hdda).delta.y; - PNANOVDB_DEREF(hdda).voxel.y += PNANOVDB_DEREF(hdda).dim * PNANOVDB_DEREF(hdda).step.y; - ret = PNANOVDB_DEREF(hdda).tmin <= PNANOVDB_DEREF(hdda).tmax; - } - else - { -#ifdef PNANOVDB_ENFORCE_FORWARD_STEPPING - if (PNANOVDB_DEREF(hdda).next.z <= PNANOVDB_DEREF(hdda).tmin) - { - PNANOVDB_DEREF(hdda).next.z += PNANOVDB_DEREF(hdda).tmin - 0.999999f * PNANOVDB_DEREF(hdda).next.z + 1.0e-6f; - } -#endif - PNANOVDB_DEREF(hdda).tmin = PNANOVDB_DEREF(hdda).next.z; - PNANOVDB_DEREF(hdda).next.z += PNANOVDB_DEREF(hdda).dim * PNANOVDB_DEREF(hdda).delta.z; - PNANOVDB_DEREF(hdda).voxel.z += PNANOVDB_DEREF(hdda).dim * PNANOVDB_DEREF(hdda).step.z; - ret = PNANOVDB_DEREF(hdda).tmin <= PNANOVDB_DEREF(hdda).tmax; - } - return ret; -} - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_hdda_ray_clip( - PNANOVDB_IN(pnanovdb_vec3_t) bbox_min, - PNANOVDB_IN(pnanovdb_vec3_t) bbox_max, - PNANOVDB_IN(pnanovdb_vec3_t) origin, PNANOVDB_INOUT(float) tmin, - PNANOVDB_IN(pnanovdb_vec3_t) direction, PNANOVDB_INOUT(float) tmax -) -{ - pnanovdb_vec3_t dir_inv = pnanovdb_vec3_div(pnanovdb_vec3_uniform(1.f), PNANOVDB_DEREF(direction)); - pnanovdb_vec3_t t0 = pnanovdb_vec3_mul(pnanovdb_vec3_sub(PNANOVDB_DEREF(bbox_min), PNANOVDB_DEREF(origin)), dir_inv); - pnanovdb_vec3_t t1 = pnanovdb_vec3_mul(pnanovdb_vec3_sub(PNANOVDB_DEREF(bbox_max), PNANOVDB_DEREF(origin)), dir_inv); - pnanovdb_vec3_t tmin3 = pnanovdb_vec3_min(t0, t1); - pnanovdb_vec3_t tmax3 = pnanovdb_vec3_max(t0, t1); - float tnear = pnanovdb_max(tmin3.x, pnanovdb_max(tmin3.y, tmin3.z)); - float tfar = pnanovdb_min(tmax3.x, pnanovdb_min(tmax3.y, tmax3.z)); - pnanovdb_bool_t hit = tnear <= tfar; - PNANOVDB_DEREF(tmin) = pnanovdb_max(PNANOVDB_DEREF(tmin), tnear); - PNANOVDB_DEREF(tmax) = pnanovdb_min(PNANOVDB_DEREF(tmax), tfar); - return hit; -} - -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_hdda_zero_crossing( - pnanovdb_grid_type_t grid_type, - pnanovdb_buf_t buf, - PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, - PNANOVDB_IN(pnanovdb_vec3_t) origin, float tmin, - PNANOVDB_IN(pnanovdb_vec3_t) direction, float tmax, - PNANOVDB_INOUT(float) thit, - PNANOVDB_INOUT(float) v -) -{ - pnanovdb_coord_t bbox_min = pnanovdb_root_get_bbox_min(buf, PNANOVDB_DEREF(acc).root); - pnanovdb_coord_t bbox_max = pnanovdb_root_get_bbox_max(buf, PNANOVDB_DEREF(acc).root); - pnanovdb_vec3_t bbox_minf = pnanovdb_coord_to_vec3(bbox_min); - pnanovdb_vec3_t bbox_maxf = pnanovdb_coord_to_vec3(pnanovdb_coord_add(bbox_max, pnanovdb_coord_uniform(1))); - - pnanovdb_bool_t hit = pnanovdb_hdda_ray_clip(PNANOVDB_REF(bbox_minf), PNANOVDB_REF(bbox_maxf), origin, PNANOVDB_REF(tmin), direction, PNANOVDB_REF(tmax)); - if (!hit || tmax > 1.0e20f) - { - return PNANOVDB_FALSE; - } - - pnanovdb_vec3_t pos = pnanovdb_hdda_ray_start(origin, tmin, direction); - pnanovdb_coord_t ijk = pnanovdb_hdda_pos_to_ijk(PNANOVDB_REF(pos)); - - pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, PNANOVDB_REF(ijk)); - float v0 = pnanovdb_read_float(buf, address); - - pnanovdb_int32_t dim = pnanovdb_uint32_as_int32(pnanovdb_readaccessor_get_dim(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, PNANOVDB_REF(ijk))); - pnanovdb_hdda_t hdda; - pnanovdb_hdda_init(PNANOVDB_REF(hdda), origin, tmin, direction, tmax, dim); - while (pnanovdb_hdda_step(PNANOVDB_REF(hdda))) - { - pnanovdb_vec3_t pos_start = pnanovdb_hdda_ray_start(origin, hdda.tmin + 1.0001f, direction); - ijk = pnanovdb_hdda_pos_to_ijk(PNANOVDB_REF(pos_start)); - dim = pnanovdb_uint32_as_int32(pnanovdb_readaccessor_get_dim(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, PNANOVDB_REF(ijk))); - pnanovdb_hdda_update(PNANOVDB_REF(hdda), origin, direction, dim); - if (hdda.dim > 1 || !pnanovdb_readaccessor_is_active(grid_type, buf, acc, PNANOVDB_REF(ijk))) - { - continue; - } - while (pnanovdb_hdda_step(PNANOVDB_REF(hdda)) && pnanovdb_readaccessor_is_active(grid_type, buf, acc, PNANOVDB_REF(hdda.voxel))) - { - ijk = hdda.voxel; - pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, PNANOVDB_REF(ijk)); - PNANOVDB_DEREF(v) = pnanovdb_read_float(buf, address); - if (PNANOVDB_DEREF(v) * v0 < 0.f) - { - PNANOVDB_DEREF(thit) = hdda.tmin; - return PNANOVDB_TRUE; - } - } - } - return PNANOVDB_FALSE; -} - -// Copied from Sebastian Gaida https://github.com/AcademySoftwareFoundation/openvdb/pull/1600/commits/d4065e52e5a7baaafc5ae2ad3e5f78f5036c5d5c -PNANOVDB_FORCE_INLINE pnanovdb_bool_t pnanovdb_hdda_tree_marcher( - pnanovdb_grid_type_t grid_type, - pnanovdb_buf_t buf, - PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, - PNANOVDB_IN(pnanovdb_vec3_t) origin, float tmin, - PNANOVDB_IN(pnanovdb_vec3_t) direction, float tmax, - PNANOVDB_INOUT(float) thit, - PNANOVDB_INOUT(float) valueAtHit -) -{ - pnanovdb_coord_t bbox_min = pnanovdb_root_get_bbox_min(buf, PNANOVDB_DEREF(acc).root); - pnanovdb_coord_t bbox_max = pnanovdb_root_get_bbox_max(buf, PNANOVDB_DEREF(acc).root); - pnanovdb_vec3_t bbox_minf = pnanovdb_coord_to_vec3(bbox_min); - pnanovdb_vec3_t bbox_maxf = pnanovdb_coord_to_vec3(pnanovdb_coord_add(bbox_max, pnanovdb_coord_uniform(1))); - - pnanovdb_bool_t hit = pnanovdb_hdda_ray_clip(PNANOVDB_REF(bbox_minf), PNANOVDB_REF(bbox_maxf), origin, PNANOVDB_REF(tmin), direction, PNANOVDB_REF(tmax)); - // Early out if ray does not hit volume - if (!hit || tmax > 1.0e20f) - { - return PNANOVDB_FALSE; - } - - pnanovdb_vec3_t pos = pnanovdb_hdda_ray_start(origin, tmin, direction); - pnanovdb_coord_t ijk = pnanovdb_hdda_pos_to_ijk(PNANOVDB_REF(pos)); - - pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, PNANOVDB_REF(ijk)); - - pnanovdb_int32_t dim = pnanovdb_uint32_as_int32(pnanovdb_readaccessor_get_dim(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, PNANOVDB_REF(ijk))); - pnanovdb_hdda_t hdda; - pnanovdb_hdda_init(PNANOVDB_REF(hdda), origin, tmin, direction, tmax, dim); - while (pnanovdb_hdda_step(PNANOVDB_REF(hdda))) - { - pnanovdb_vec3_t pos_start = pnanovdb_hdda_ray_start(origin, hdda.tmin + 1.0001f, direction); - ijk = pnanovdb_hdda_pos_to_ijk(PNANOVDB_REF(pos_start)); - dim = pnanovdb_uint32_as_int32(pnanovdb_readaccessor_get_dim(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, PNANOVDB_REF(ijk))); - pnanovdb_hdda_update(PNANOVDB_REF(hdda), origin, direction, dim); - // Skip over tile - if (hdda.dim > 1 || !pnanovdb_readaccessor_is_active(grid_type, buf, acc, PNANOVDB_REF(ijk))) - { - continue; - } - // Only check active values - while (pnanovdb_hdda_step(PNANOVDB_REF(hdda)) && pnanovdb_readaccessor_is_active(grid_type, buf, acc, PNANOVDB_REF(hdda.voxel))) - { - ijk = hdda.voxel; - pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, PNANOVDB_REF(ijk)); - PNANOVDB_DEREF(valueAtHit) = pnanovdb_read_float(buf, address); - - if (PNANOVDB_DEREF(valueAtHit) > 0.f) - { - PNANOVDB_DEREF(thit) = hdda.tmin; - return PNANOVDB_TRUE; - } - } - } - return PNANOVDB_FALSE; -} - -PNANOVDB_FORCE_INLINE float pnanovdb_get_value_coord( - pnanovdb_buf_t buf, - PNANOVDB_INOUT(pnanovdb_readaccessor_t) acc, - PNANOVDB_IN(pnanovdb_vec3_t) pos -) -{ - pnanovdb_coord_t ijk = pnanovdb_hdda_pos_to_ijk(PNANOVDB_REF(pos)); - pnanovdb_address_t address = pnanovdb_readaccessor_get_value_address(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, PNANOVDB_REF(ijk)); - return pnanovdb_read_float(buf, address); -} - -#endif - -#endif // end of NANOVDB_PNANOVDB_H_HAS_BEEN_INCLUDED diff --git a/unity/NanoVDB/PNanoVDB.hlsl.meta b/unity/NanoVDB/PNanoVDB.hlsl.meta deleted file mode 100644 index 64db4430..00000000 --- a/unity/NanoVDB/PNanoVDB.hlsl.meta +++ /dev/null @@ -1,46 +0,0 @@ -fileFormatVersion: 2 -guid: 7fabb37c28af77741aff24d4ae1fe924 -PluginImporter: - externalObjects: {} - serializedVersion: 3 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - Any: - enabled: 1 - settings: - Exclude Editor: 0 - Exclude Linux64: 0 - Exclude OSXUniversal: 0 - Exclude Win: 0 - Exclude Win64: 0 - Editor: - enabled: 1 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - Linux64: - enabled: 1 - settings: - CPU: AnyCPU - OSXUniversal: - enabled: 1 - settings: - CPU: AnyCPU - Win: - enabled: 1 - settings: - CPU: AnyCPU - Win64: - enabled: 1 - settings: - CPU: AnyCPU - userData: - assetBundleName: - assetBundleVariant: diff --git a/unity/NanoVDB/PseudoRandom.hlsl b/unity/NanoVDB/PseudoRandom.hlsl deleted file mode 100644 index 3fc6efd2..00000000 --- a/unity/NanoVDB/PseudoRandom.hlsl +++ /dev/null @@ -1,19 +0,0 @@ -// https://www.reedbeta.com/blog/quick-and-easy-gpu-random-numbers-in-d3d11/ - -uint rand_xorshift(uint seed) -{ - // Xorshift algorithm from George Marsaglia's paper - seed ^= (seed << 13); - seed ^= (seed >> 17); - seed ^= (seed << 5); - return seed; -} - -float random_float(float3 view_dir) -{ - uint seed = asuint(view_dir.x + view_dir.y + view_dir.z); - float res = float(rand_xorshift(seed)) * (1.0 / 4294967296.0); - res = float(rand_xorshift(asuint(res))) * (1.0 / 4294967296.0); - res = float(rand_xorshift(asuint(res))) * (1.0 / 4294967296.0); - return res; -} \ No newline at end of file diff --git a/unity/NanoVDB/PseudoRandom.hlsl.meta b/unity/NanoVDB/PseudoRandom.hlsl.meta deleted file mode 100644 index 9721d093..00000000 --- a/unity/NanoVDB/PseudoRandom.hlsl.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 2159eccf73f568d458a47d19c6254765 -ShaderIncludeImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/unity/Plugins/NanoVDBWrapper.cpp b/unity/Plugins/NanoVDBWrapper.cpp deleted file mode 100644 index 69ba4a38..00000000 --- a/unity/Plugins/NanoVDBWrapper.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#define NANOVDB_USE_OPENVDB -#define DLLExport __declspec(dllexport) - -#include -#include - -struct NanoVolume { - uint32_t* buf; - uint64_t byteSize; - uint64_t elementCount; - uint64_t structStride; -} nanoVolumeStruct; - -extern "C" { - typedef void(*DebugLogCallback)(const char*); - - DLLExport void SetDebugLogCallback(DebugLogCallback callback); - DLLExport void LoadNVDB(const char* str, struct NanoVolume** volume); - DLLExport void FreeNVDB(struct NanoVolume* volume); -} - -DebugLogCallback UnityLog = nullptr; -void SetDebugLogCallback(DebugLogCallback callback) { - UnityLog = callback; -} - -nanovdb::GridHandle gridHandle; -void LoadNVDB(const char* path, struct NanoVolume** volume) { - try { - // reads first grid from file - gridHandle = nanovdb::io::readGrid(path); - - // get a (raw) pointer to a NanoVDB grid of value type float - const nanovdb::FloatGrid* buf = gridHandle.grid(); - - if (!buf) { - throw std::runtime_error("File did not contain a grid with value type float"); - } - - *volume = (struct NanoVolume*) malloc(sizeof(struct NanoVolume)); - - if (*volume == nullptr) { - UnityLog("Failed to allocate memory for NanoVolume struct."); - return; - } - - const uint64_t byteSize = gridHandle.buffer().bufferSize(); - const uint64_t elementCount = byteSize / sizeof(float); - const uint64_t structStride = sizeof(float); - - uint32_t* buffer_ptr = (uint32_t*)gridHandle.buffer().data(); - - (*volume)->buf = buffer_ptr; - (*volume)->byteSize = byteSize; - (*volume)->elementCount = elementCount; - (*volume)->structStride = structStride; - } - catch (const std::exception& e) { - UnityLog("An exception occurred:"); - UnityLog(e.what()); - } -} - -void FreeNVDB(struct NanoVolume* volume) { - free(volume); - volume = nullptr; -} diff --git a/unity/Plugins/NanoVDBWrapper.cpp.meta b/unity/Plugins/NanoVDBWrapper.cpp.meta deleted file mode 100644 index 2328f854..00000000 --- a/unity/Plugins/NanoVDBWrapper.cpp.meta +++ /dev/null @@ -1,46 +0,0 @@ -fileFormatVersion: 2 -guid: 44e340e1fd2f2d148a93e969247618ba -PluginImporter: - externalObjects: {} - serializedVersion: 3 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - Any: - enabled: 1 - settings: - Exclude Editor: 0 - Exclude Linux64: 1 - Exclude OSXUniversal: 0 - Exclude Win: 1 - Exclude Win64: 0 - Editor: - enabled: 1 - settings: - CPU: AnyCPU - DefaultValueInitialized: true - OS: AnyOS - Linux64: - enabled: 0 - settings: - CPU: None - OSXUniversal: - enabled: 1 - settings: - CPU: None - Win: - enabled: 0 - settings: - CPU: None - Win64: - enabled: 1 - settings: - CPU: None - userData: - assetBundleName: - assetBundleVariant: diff --git a/unity/Plugins/NanoVDBWrapper.dll b/unity/Plugins/NanoVDBWrapper.dll deleted file mode 100644 index 9850d9402cf2b43e823c8b6cb8b593c9a282b238..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 578560 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 diff --git a/unity/Plugins/NanoVDBWrapper.dll.meta b/unity/Plugins/NanoVDBWrapper.dll.meta deleted file mode 100644 index 10e6b38e..00000000 --- a/unity/Plugins/NanoVDBWrapper.dll.meta +++ /dev/null @@ -1,27 +0,0 @@ -fileFormatVersion: 2 -guid: bb0737f1c8a9f3343b05974ce7647fd8 -PluginImporter: - externalObjects: {} - serializedVersion: 2 - iconMap: {} - executionOrder: {} - defineConstraints: [] - isPreloaded: 0 - isOverridable: 0 - isExplicitlyReferenced: 0 - validateReferences: 1 - platformData: - - first: - Any: - second: - enabled: 1 - settings: {} - - first: - Editor: Editor - second: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/unity/Plugins/README.md b/unity/Plugins/README.md deleted file mode 100644 index 7556f4af..00000000 --- a/unity/Plugins/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# Wrapper for NanoVDB to Unity - -> See [NanoVDBWrapper.cpp](https://github.com/andersblomqvist/unity-nanovdb/blob/main/Assets/Plugins/NanoVDBWrapper.cpp) for source code. - -The NanoVDB library is imported to Unity through a C++ wrapper. This wrapper exposes three functions, which we use in our Unity script [NanoVolumeLoader.cs](https://github.com/andersblomqvist/unity-nanovdb/blob/main/Assets/NanoVDB/NanoVolumeLoader.cs): - -* `void SetDebugLogCallback(DebugLogCallback callback)` -* `void LoadNVDB(const char* str, struct NanoVolume** volume)` -* `void FreeNVDB(struct NanoVolume* volume)` - -The `LoadNVDB` is most important, as it loads a `.nvdb` file from disk and enables Unity to access it through the `NanoVolume` struct. This struct mainly contains a pointer to the VDB grid buffer, which is uploaded to the GPU through the `NanoVolumeLoader.cs` script. That is basically it for the wrapper. - -*Note:* it is not recommended by the author, Ken Museth, to store `.nvdb` files on disk. Instead it is suggested to convert an OpenVDB (`.vdb`) to NanoVDB (`.nvdb`) at runtime, but that requires importing all of OpenVDB. I decided to accept a larger file size on disk instead of bothering to import OpenVDB. - -## Compile to Unity - -The source is compiled to Unity with MSVC and CLR. In Visual Studio, the `Common Language Runtime Support` field is set to `.NET Framework Runtime Support (/clr)`, with the target version of `v4.8`. For Unity to accept version `4.8` we need to go into Unity, Edit, Project Settings, Player, Other Settings, and set `Api Compatibility Level*` to `.NET Framework`. This will make Unity import our DLL when we have a Unity script that uses it. - -## References - -* CLR: https://learn.microsoft.com/en-us/cpp/dotnet/dotnet-programming-with-cpp-cli-visual-cpp -* Logging from DLL in Unity: https://stackoverflow.com/questions/43732825/use-debug-log-from-c -* Unity Managed plugins: https://docs.unity3d.com/6000.0/Documentation/Manual/plug-ins-managed.html -* NanoVDB presentation by Ken Museth under Supplementary Material: https://dl.acm.org/doi/10.1145/3450623.3464653 diff --git a/unity/Plugins/README.md.meta b/unity/Plugins/README.md.meta deleted file mode 100644 index 532785fe..00000000 --- a/unity/Plugins/README.md.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: aab0996318f585d43920e93dc5e3d2e5 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: