// // Copyright 2021 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // #ifndef OPENSUBDIV3_BFR_SURFACE_H #define OPENSUBDIV3_BFR_SURFACE_H #include "../version.h" #include "../bfr/surfaceData.h" #include "../bfr/parameterization.h" #include "../vtr/array.h" namespace OpenSubdiv { namespace OPENSUBDIV_VERSION { namespace Bfr { /// /// @brief Encapsulates the limit surface for a face of a mesh /// /// The Surface class encapsulates the limit surface for a face of a mesh /// for any data interpolation type (vertex, varying and face-varying) and /// provides the public interface for its evaluation. Surface is a class /// template parameterized to support evaluation in single or double /// precision. /// /// @tparam REAL Floating point precision (float or double only) /// /// Instances of Surface are created or initialized by a subclass of the /// SurfaceFactory. Since existing instances can be re-initialized, they /// should be tested for validity after such re-initialization. /// /// All Surfaces are assigned a Parameterization based on the subdivision /// scheme and the size of the face, which can then be used for evaluation /// and tessellation of the surface. /// template class Surface { public: /// @brief Simple struct defining the size and stride of points in /// arrays. struct PointDescriptor { PointDescriptor() : size(0), stride(0) { } PointDescriptor(int n) : size(n), stride(n) { } PointDescriptor(int n, int m) : size(n), stride(m) { } int size, stride; }; /// @brief Integer type representing a mesh index typedef int Index; public: //@{ /// @name Construction and initialization /// /// Instances of Surface may be explicitly constructed, but are /// initialized by SurfaceFactory and so only default construction /// is provided. An instance will be invalid (and so unusable) if /// default constructed, or if the factory that initialized it /// determined that the face associated with it has no limit surface. /// /// @brief Return true if successfully initialized bool IsValid() const { return _data.isValid(); } /// @brief Clear a previously initialized Surface void Clear() { _data.reinitialize(); } /// @brief Default construction produces an invalid instance Surface(); Surface(Surface const & src) = default; Surface& operator=(Surface const & src) = default; ~Surface() = default; //@} //@{ /// @name Simple queries /// /// Simple queries of valid Surface. /// /// @brief Return the Parameterization Parameterization GetParameterization() const { return _data.getParam(); } /// @brief Return the size of the face int GetFaceSize() const { return GetParameterization().GetFaceSize(); } /// @brief Return if the Surface is a single regular patch bool IsRegular() const { return _data.isRegular(); } /// @brief Return if the Surface is linear bool IsLinear() const { return _data.isLinear(); } //@} //@{ /// @name Methods to manage control points /// /// Control points are the subset of points in the mesh that influence /// a Surface. They can be identified as part of the mesh data by their /// indices, or gathered into an array for other purposes. /// /// It is not necessary to deal directly with control points for /// evaluation, but they are useful with limit stencils and other /// purposes, e.g. computing a bounding box of the control hull of /// the Surface. /// /// Note that methods that access control points from the array of /// mesh data require that the array be contiguous. If a large data /// set is fragmented into blocks or pages, these methods cannot be /// used and control points will need to be gathered explicitly. /// /// @brief Return the number of control points affecting the Surface int GetNumControlPoints() const { return _data.getNumCVs(); } /// @brief Identify indices of control points in the mesh int GetControlPointIndices(Index meshPointIndices[]) const; /// @brief Gather control points in a local array /// /// @tparam REAL_MESH Floating point precision of mesh points /// /// @param meshPoints Input array of mesh point data /// @param meshPointDesc The size and stride of mesh point data /// @param controlPoints Output array of control point data /// @param controlPointDesc The size and stride of control point data /// template void GatherControlPoints(REAL_MESH const meshPoints[], PointDescriptor const & meshPointDesc, REAL controlPoints[], PointDescriptor const & controlPointDesc) const; /// @brief Compute bounds of control points from a local array void BoundControlPoints(REAL const controlPoints[], PointDescriptor const & controlPointDesc, REAL minExtent[], REAL maxExtent[]) const; /// @brief Compute bounds of control points from the mesh data void BoundControlPointsFromMesh(REAL const meshPoints[], PointDescriptor const & meshPointDesc, REAL minExtent[], REAL maxExtent[]) const; //@} //@{ /// @name Methods to manage patch points /// /// Patch points are derived from the control points and are used to /// evaluate the Surface. The patch points always include the control /// points as a subset. /// /// @brief Return the number of patch points representing the Surface int GetNumPatchPoints() const; /// /// @brief Prepare patch points in a local array for evaluation /// /// The patch points consist of the control points plus any additional /// points derived from them that may be required to represent the /// limit surface as one or more parametric patches. /// /// @param meshPoints Input array of mesh point data /// @param meshPointDesc The size and stride of mesh point data /// @param patchPoints Output array of patch point data /// @param patchPointDesc The size and stride of patch point data /// /// Note that this method requires the mesh data be in a contiguous /// array. If a large data set is fragmented into blocks or pages, this /// method cannot be used. The control points will need to be gathered /// explicitly as the subset of patch points, after which the method to /// compute the remaining patch points can be used. /// void PreparePatchPoints(REAL const meshPoints[], PointDescriptor const & meshPointDesc, REAL patchPoints[], PointDescriptor const & patchPointDesc) const; /// @brief Compute all patch points following the control points /// /// For cases where the control points have already been gathered into /// an array allocated for the patch points, the remaining patch points /// will be computed. /// /// @param patchPoints Array of patch point data to be modified /// @param patchPointDesc The size and stride of patch point data /// void ComputePatchPoints(REAL patchPoints[], PointDescriptor const & patchPointDesc) const; //@} //@{ /// @name Evaluation of positions and derivatives /// /// Evaluation methods use the patch points to compute position, 1st and /// 2nd derivatives of the Surface at a given (u,v) coordinate within /// the domain of the Surface's Parameterization. All parameters of the /// different overloads are required. /// /// @brief Evaluation of position void Evaluate(REAL const uv[2], REAL const patchPoints[], PointDescriptor const & pointDesc, REAL P[]) const; /// @brief Overload of evaluation for 1st derivatives void Evaluate(REAL const uv[2], REAL const patchPoints[], PointDescriptor const & pointDesc, REAL P[], REAL Du[], REAL Dv[]) const; /// @brief Overload of evaluation for 2nd derivatives void Evaluate(REAL const uv[2], REAL const patchPoints[], PointDescriptor const & pointDesc, REAL P[], REAL Du[], REAL Dv[], REAL Duu[], REAL Duv[], REAL Dvv[]) const; //@} //@{ /// @name Evaluation and application of limit stencils /// /// Limit stencils are sets of coefficients that express an evaluation /// as a linear combination of the control points. As with the direct /// evaluation methods, they are overloaded to optionally provide /// evaluation for 1st and 2nd derivatives. /// /// In addition to methods to provide limit stencils, methods are also /// provided to apply them to the control points. Since application of /// stencils is identical for each (i.e. the same for position and any /// derivative) no overloads are provided for derivatives. /// /// @brief Evaluation of the limit stencil for position int EvaluateStencil(REAL const uv[2], REAL sP[]) const; /// @brief Overload of limit stencil evaluation for 1st derivatives int EvaluateStencil(REAL const uv[2], REAL sP[], REAL sDu[], REAL sDv[]) const; /// @brief Overload of limit stencil evaluation for 2nd derivatives int EvaluateStencil(REAL const uv[2], REAL sP[], REAL sDu[], REAL sDv[], REAL sDuu[], REAL sDuv[], REAL sDvv[]) const; /// @brief Apply a single stencil to control points from a local array void ApplyStencil(REAL const stencil[], REAL const controlPoints[], PointDescriptor const &, REAL result[]) const; /// @brief Apply a single stencil to control points from the mesh data void ApplyStencilFromMesh(REAL const stencil[], REAL const meshPoints[], PointDescriptor const &, REAL result[]) const; //@} private: // Internal methods for evaluating derivatives, basis weights and // stencils for regular, irregular and irregular linear patches: typedef Vtr::ConstArray IndexArray; void evaluateDerivs(REAL const uv[2], REAL const patchPoints[], PointDescriptor const &, REAL * derivs[]) const; void evalRegularDerivs(REAL const uv[2], REAL const patchPoints[], PointDescriptor const &, REAL * derivs[]) const; void evalIrregularDerivs(REAL const uv[2], REAL const patchPoints[], PointDescriptor const &, REAL * derivs[]) const; void evalMultiLinearDerivs(REAL const uv[2], REAL const patchPoints[], PointDescriptor const &, REAL * derivs[]) const; void evalRegularBasis(REAL const uv[2], REAL * wDeriv[]) const; IndexArray evalIrregularBasis(REAL const uv[2], REAL * wDeriv[]) const; int evalMultiLinearBasis(REAL const uv[2], REAL * wDeriv[]) const; int evaluateStencils(REAL const uv[2], REAL * sDeriv[]) const; int evalRegularStencils(REAL const uv[2], REAL * sDeriv[]) const; int evalIrregularStencils(REAL const uv[2], REAL * sDeriv[]) const; int evalMultiLinearStencils(REAL const uv[2], REAL * sDeriv[]) const; // Internal methods to compute patch points: void computeLinearPatchPoints(REAL p[], PointDescriptor const &) const; void computeIrregularPatchPoints(REAL p[], PointDescriptor const &) const; // Internal methods specific to regular or irregular patches: unsigned char getRegPatchType() const { return _data.getRegPatchType(); } unsigned char getRegPatchMask() const { return _data.getRegPatchMask(); } internal::IrregularPatchType const & getIrregPatch() const; private: // Access to the set of member variables - provided to the Factory: friend class SurfaceFactory; internal::SurfaceData & getSurfaceData() { return _data; } internal::SurfaceData const & getSurfaceData() const { return _data; } private: // All member variables encapsulated in a single class: internal::SurfaceData _data; }; // // Simple inline methods composed of other methods: // template inline void Surface::ComputePatchPoints(REAL points[], PointDescriptor const & pointDesc) const { if (!IsRegular()) { if (IsLinear()) { computeLinearPatchPoints(points, pointDesc); } else { computeIrregularPatchPoints(points, pointDesc); } } } template inline void Surface::PreparePatchPoints( REAL const meshPoints[], PointDescriptor const & meshPointDesc, REAL patchPoints[], PointDescriptor const & patchPointDesc) const { GatherControlPoints(meshPoints, meshPointDesc, patchPoints, patchPointDesc); ComputePatchPoints(patchPoints, patchPointDesc); } // // Inline invocations of more general methods for derivative overloads: // template inline void Surface::evaluateDerivs(REAL const uv[2], REAL const patchPoints[], PointDescriptor const & pointDesc, REAL * derivatives[]) const { if (IsRegular()) { evalRegularDerivs(uv, patchPoints, pointDesc, derivatives); } else if (IsLinear()) { evalMultiLinearDerivs(uv, patchPoints, pointDesc, derivatives); } else { evalIrregularDerivs(uv, patchPoints, pointDesc, derivatives); } } template inline void Surface::Evaluate(REAL const uv[2], REAL const patchPoints[], PointDescriptor const & pointDesc, REAL P[]) const { REAL * derivatives[6] = { P, 0, 0, 0, 0, 0 }; evaluateDerivs(uv, patchPoints, pointDesc, derivatives); } template inline void Surface::Evaluate(REAL const uv[2], REAL const patchPoints[], PointDescriptor const & pointDesc, REAL P[], REAL Du[], REAL Dv[]) const { REAL * derivatives[6] = { P, Du, Dv, 0, 0, 0 }; evaluateDerivs(uv, patchPoints, pointDesc, derivatives); } template inline void Surface::Evaluate(REAL const uv[2], REAL const patchPoints[], PointDescriptor const & pointDesc, REAL P[], REAL Du[], REAL Dv[], REAL Duu[], REAL Duv[], REAL Dvv[]) const { REAL * derivatives[6] = { P, Du, Dv, Duu, Duv, Dvv }; evaluateDerivs(uv, patchPoints, pointDesc, derivatives); } template inline int Surface::evaluateStencils(REAL const uv[2], REAL * sDeriv[]) const { if (IsRegular()) { return evalRegularStencils(uv, sDeriv); } else if (IsLinear()) { return evalMultiLinearStencils(uv, sDeriv); } else { return evalIrregularStencils(uv, sDeriv); } } template inline int Surface::EvaluateStencil(REAL const uv[2], REAL sP[]) const { REAL * derivativeStencils[6] = { sP, 0, 0, 0, 0, 0 }; return evaluateStencils(uv, derivativeStencils); } template inline int Surface::EvaluateStencil(REAL const uv[2], REAL sP[], REAL sDu[], REAL sDv[]) const { REAL * derivativeStencils[6] = { sP, sDu, sDv, 0, 0, 0 }; return evaluateStencils(uv, derivativeStencils); } template inline int Surface::EvaluateStencil(REAL const uv[2], REAL sP[], REAL sDu[], REAL sDv[], REAL sDuu[], REAL sDuv[], REAL sDvv[]) const { REAL * derivativeStencils[6] = { sP, sDu, sDv, sDuu, sDuv, sDvv }; return evaluateStencils(uv, derivativeStencils); } } // end namespace Bfr } // end namespace OPENSUBDIV_VERSION using namespace OPENSUBDIV_VERSION; } // end namespace OpenSubdiv #endif /* OPENSUBDIV3_BFR_SURFACE */