/**

@page api_0_98_0 Porting to OpenVDB 0.98.0

Starting in OpenVDB 0.98.0, @vdblink::tree::Tree Tree@endlink and
@vdblink::math::Transform Transform@endlink objects (and
@vdblink::Grid Grid@endlink objects in the context of Houdini SOPs)
are passed and accessed primarily by reference
rather than by shared pointer.
(This is partly for performance reasons; the overhead of copying shared
pointers, especially in a threaded environment, can be significant.)
Furthermore, those objects now exhibit copy-on-write semantics, so that
in most cases it is no longer necessary to make explicit deep copies.
These changes were, for the most part, requested and implemented by
Side&nbsp;Effects.

Accessor methods like @vdblink::Grid::tree() Grid::tree@endlink,
@vdblink::Grid::transform() Grid::transform@endlink and
@c GEO_PrimVDB::getGrid that used to return shared pointers now return const
references.
Variants like @c Grid::constTree, which returned const shared
pointers, have been removed, and new read/write accessors have been added.
The latter, including @c Grid::treeRW(), @c Grid::transformRW() and
@c GEO_PrimVDB::getGridRW, return non-const references, but they also ensure
that ownership of the returned object is exclusive to the container
(that is, they ensure that the grid has exclusive ownership of the tree or
transform and that the primitive has exclusive ownership of the grid).
The logic is as follows: if a grid, for example, has sole ownership of a
tree, then @c Grid::treeRW() returns a non-const reference to that tree;
but if the tree is shared (with other grids, perhaps), then
@c Grid::treeRW() assigns the grid a new, deep copy of the tree
and returns a non-const reference to the new tree.

Shared pointers to @c Tree, @c Transform and @c Grid objects can still be
requested from their respective containers via @c Grid::sharedTree(),
@c Grid::sharedTransform() and @c GEO_PrimVDB::getSharedGrid,
but their use is now discouraged.

For Houdini SOPs, there are additional changes.  First, VDB primitives are
now normally processed in-place.  That is, rather than extract a
primitive's grid, make a deep copy of it and construct a new primitive to
hold the copy, one now requests read/write access to a primitive's grid and
then modifies the resulting grid.  (SOPs that generate primitives or that
replace grids of one type with another type can still do so using the old
approach, however.)

Second, grid metadata such as a grid's class (level set, fog volume, etc.),
value type (@c float, @c vec3s, etc.), background value and so on (the full
list is hardcoded into @c GEO_PrimVDB) is now exposed via "intrinsic"
attributes of grid primitives, rather than via primitive attributes as before.
As a result, this information no longer appears in a SOP's geometry
spreadsheet, nor does any extra metadata that a SOP might add to a grid during
processing.  The metadata is still preserved in the @c Grid objects, though.

Third, @c openvdb_houdini::processTypedGrid, which passes a shared grid
pointer to a functor that also takes a shared pointer, is now deprecated in
favor of @c openvdb_houdini::UTvdbProcessTypedGrid, which accepts shared
pointers, raw pointers or references to grids (provided that the functor
accepts an argument of the same kind).  Below is a comparison of the old
and new usage in the typical case of a SOP that processes input grids:


<b>Old API</b> (0.97.0 and earlier)

@code
    struct MyGridProcessor
    {
        template<typename GridT>
        void operator()(typename GridT::Ptr grid) const
        {
            // Process the grid's tree.
(1)         grid->tree()->pruneInactive();
        }
    };

    SOP_OpenVDB_Example::cookMySop(OP_Context& context)
    {
        ...
        duplicateSource(0, context);

        // Process each VDB primitive that belongs to the selected group.
        for (openvdb_houdini::VdbPrimIterator it(gdp, group); it; ++it) {

            openvdb_houdini::GU_PrimVDB* vdbPrim = *it;

            // Deep copy the primitive's grid if it is going to be modified.
            openvdb_houdini::GridPtr grid = vdbPrim->getGrid()->deepCopyGrid();
            // Otherwise, retrieve a read-only grid pointer.
            //openvdb_houdini::GridCPtr grid = vdbPrim->getGrid();

            // Process the grid.
            MyGridProcessor proc;
(2)         openvdb_houdini::processTypedGrid(grid, proc);

            // Create a new VDB primitive that contains the modified grid,
            // and in the output detail replace the original primitive with
            // the new one.
(3)         openvdb_houdini::replaceVdbPrimitive(*gdp, grid, *vdbPrim);
        }
    }
@endcode


<b>New API</b> (0.98.0 and later)

@code
    struct MyGridProcessor {
        template<typename GridT>
        void operator()(GridT& grid) const
        {
            // Request write access to the grid's tree, then process the tree.
(1)         grid.treeRW().pruneInactive();
        }
    };

    SOP_OpenVDB_Example::cookMySop(OP_Context& context)
    {
        ...
        duplicateSource(0, context);

        // Process each VDB primitive that belongs to the selected group.
        for (openvdb_houdini::VdbPrimIterator it(gdp, group); it; ++it) {

            openvdb_houdini::GU_PrimVDB* vdbPrim = *it;

            // Get write access to the grid associated with the primitive.
            // If the grid is shared with other primitives, this will
            // make a deep copy of it.
            openvdb_houdini::Grid& grid = vdbPrim->getGridRW();

            // If the grid is not going to be modified, get read-only access.
            //const openvdb_houdini::Grid& grid = vdbPrim->getGrid();

            // Process the grid.
            MyGridProcessor proc;
(2)         openvdb_houdini::UTvdbProcessTypedGrid(
(4)             vdbPrim->getStorageType(), grid, proc);
        }
    }
@endcode


@b Notes
<ol>
<li>
In the old API, @vdblink::Grid::tree() Grid::tree@endlink returned either
a shared, non-const pointer to a tree or a shared const pointer, depending
on whether the grid itself was non-const or const.  In the new API,
@vdblink::Grid::tree() Grid::tree@endlink always returns a const reference,
and @c Grid::treeRW() always returns a non-const reference.

<li>
@c openvdb_houdini::processTypedGrid (old API) accepts only shared pointers
to grids (or shared pointers to const grids), together with functors that
accept shared pointers to grids.  @c openvdb_houdini::UTvdbProcessTypedGrid
(new API) accepts const and non-const references, shared pointers and raw
pointers, together with matching functors.  That is, all of the following
are valid pairs of grid and functor arguments to @c UTvdbProcessTypedGrid():
@code
openvdb_houdini::Grid& grid = vdbPrim->getGridRW();
struct MyProc { template<class GridT> operator()(GridT&) {...} };

const openvdb_houdini::Grid& grid = vdbPrim->getGrid();
struct MyProc { template<class GridT> operator()(const GridT&) {...} };

openvdb_houdini::GridPtr grid = vdbPrim->getSharedGrid();
struct MyProc { template<class GridT> operator()(typename GridT::Ptr) {...} };

openvdb_houdini::GridCPtr grid = vdbPrim->getSharedConstGrid();
struct MyProc { template<class GridT> operator()(typename GridT::ConstPtr) {...} };

openvdb_houdini::Grid* grid = &vdbPrim->getGridRW();
struct MyProc { template<class GridT> operator()(GridT*) {...} };

const openvdb_houdini::Grid* grid = &vdbPrim->getGrid();
struct MyProc { template<class GridT> operator()(const GridT*) {...} };
@endcode

<li>
In the old API, input grid primitives were (usually) deleted after
processing, and a new primitive was created for each output grid.
@c openvdb_houdini::replaceVdbPrimitive() did both operations in one step
and had the side effect of transferring the output grid's metadata to
primitive attributes.  In the new API, @c replaceVdbPrimitive() is rarely
needed, because input grids can usually be processed in-place, and
most commonly-used metadata is exposed via intrinsic attributes, which
don't need to be manually updated.

<li>
The first argument to @c openvdb_houdini::UTvdbProcessTypedGrid() is the
grid's storage type, which can be retrieved either by passing the grid
to @c openvdb_houdini::UTvdbGetGridType() or by calling
@c GEO_PrimVDB::getStorageType() on the primitive.
</ol>

*/
