1// Copyright 2020-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#pragma once
5
6// ---------------------------------------------------------------------------
7// Step through a DDA hierarchy.
8//
9// Note: We generate files HDDA_level>.ih from this
10//       template using CMake.
11// ---------------------------------------------------------------------------
12
13#if (@VKL_VDB_NEXT_LEVEL@) < VKL_VDB_NUM_LEVELS
14  #include "HDDA_@VKL_VDB_NEXT_LEVEL@.ih"
15#endif
16
17/*
18 * Step once in the hierarchy.
19 * This potentially steps once on each level.
20 *
21 * Precondition: desc points to a voxel on some level. The goal
22 * of hddaStep is to leave this voxel.
23 */
24#if @VKL_VDB_LEVEL@ == 0
25void hddaStep(const VdbGrid *uniform grid,
26              const VdbVoxelDescriptor &desc,
27              DdaState &dda)
28{
29#else
30bool hddaStep_@VKL_VDB_LEVEL@(const VdbGrid *uniform grid,
31                              const VdbVoxelDescriptor &desc,
32                              DdaState &dda)
33{
34#endif
35
36  // We traverse depth-first to step on the lowest level possible.
37  const bool lowestLevel = (desc.level == @VKL_VDB_LEVEL@);
38  bool stepped = false;
39
40  // First case: we can potentially descend to the next level.
41#if @VKL_VDB_NEXT_LEVEL@ < @VKL_VDB_NUM_LEVELS@
42  const uniform uint32 ox = DDA_STATE_X_OFFSET(@VKL_VDB_LEVEL@);
43  const uniform uint32 oy = DDA_STATE_Y_OFFSET(@VKL_VDB_LEVEL@);
44  const uniform uint32 oz = DDA_STATE_Z_OFFSET(@VKL_VDB_LEVEL@);
45  if (lowestLevel)
46  {
47    const int32 oldx = dda.idx[ox];
48    const int32 oldy = dda.idx[oy];
49    const int32 oldz = dda.idx[oz];
50    ddaStep(dda, @VKL_VDB_LEVEL@);
51    stepped = true;
52
53    if (@VKL_VDB_LEVEL@ < dda.level)
54    {
55      // We are on the same level as the voxel described by desc,
56      // but that is NOT the lowest level dda state.
57      // Reinitialize the lower levels to keep them consistent.
58      // This keeps the dda state consistent towards the leaf level.
59      // If this level moved in x-dimension, then all lower levels
60      // will move by the same amount in x-dimension. y and z must be
61      // recomputed, however, as must tNext for x and y.
62      const int32 dx = dda.idx[ox]-oldx;
63      const int32 dy = dda.idx[oy]-oldy;
64      const int32 dz = dda.idx[oz]-oldz;
65      ddaReinitBelow(dda, @VKL_VDB_LEVEL@, dx, dy, dz);
66    }
67  }
68  else
69  {
70    if (hddaStep_@VKL_VDB_NEXT_LEVEL@(grid, desc, dda))
71    {
72      // We check if the child has left our domain and follow it if it has.
73      // This keeps the dda state consistent towards the root node.
74      const uniform int32 cellRes = VKL_VDB_RES_@VKL_VDB_NEXT_LEVEL@;
75      const uniform uint32 cox = DDA_STATE_X_OFFSET(@VKL_VDB_NEXT_LEVEL@);
76      const uniform uint32 coy = DDA_STATE_Y_OFFSET(@VKL_VDB_NEXT_LEVEL@);
77      const uniform uint32 coz = DDA_STATE_Z_OFFSET(@VKL_VDB_NEXT_LEVEL@);
78      const bool childHasLeftDomain = dda.idx[cox] < dda.idx[ox]
79                                   || dda.idx[coy] < dda.idx[oy]
80                                   || dda.idx[coz] < dda.idx[oz]
81                                   || dda.idx[cox] >= (dda.idx[ox] + cellRes)
82                                   || dda.idx[coy] >= (dda.idx[oy] + cellRes)
83                                   || dda.idx[coz] >= (dda.idx[oz] + cellRes);
84      if (childHasLeftDomain) {
85        ddaStep(dda, @VKL_VDB_LEVEL@);
86        stepped = true;
87      }
88    }
89  }
90
91  // Second case: We cannot descend because there is no next level.
92#else // @VKL_VDB_NEXT_LEVEL@ < @VKL_VDB_NUM_LEVELS@
93  assert(lowestLevel);
94  ddaStep(dda, @VKL_VDB_LEVEL@);
95  stepped = true;
96#endif
97
98#if @VKL_VDB_LEVEL@ > 0
99  return stepped;
100#endif
101}
102