From c64262a05ab0e9a7c5b69fc83ea53fb5825f442c Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 17 Jul 2018 18:06:32 +0200 Subject: OpenSubdiv: Add API to evaluate face-varying data There are move changes along the line to keep everything working from from C. --- .../internal/opensubdiv_converter_factory.cc | 2 + .../internal/opensubdiv_converter_internal.cc | 26 ++++++++++ .../internal/opensubdiv_converter_internal.h | 5 ++ .../internal/opensubdiv_topology_refiner.cc | 60 ++++++++++++++++++++-- intern/opensubdiv/opensubdiv_capi_type.h | 15 ++++++ intern/opensubdiv/opensubdiv_converter_capi.h | 15 +----- .../opensubdiv/opensubdiv_topology_refiner_capi.h | 43 +++++++++++++++- 7 files changed, 148 insertions(+), 18 deletions(-) (limited to 'intern') diff --git a/intern/opensubdiv/internal/opensubdiv_converter_factory.cc b/intern/opensubdiv/internal/opensubdiv_converter_factory.cc index bd6edbb9648..48516cc80b7 100644 --- a/intern/opensubdiv/internal/opensubdiv_converter_factory.cc +++ b/intern/opensubdiv/internal/opensubdiv_converter_factory.cc @@ -383,6 +383,8 @@ TopologyRefinerFactory::assignFaceVaryingTopology( const int num_uvs = converter->getNumUVCoordinates(converter); // Fill in per-corner index of the UV. const int channel = createBaseFVarChannel(refiner, num_uvs); + // TODO(sergey): Need to check whether converter changed the winding of + // face to match OpenSubdiv's expectations. for (int face_index = 0; face_index < num_faces; ++face_index) { Far::IndexArray dst_face_uvs = getBaseFaceFVarValues(refiner, face_index, channel); diff --git a/intern/opensubdiv/internal/opensubdiv_converter_internal.cc b/intern/opensubdiv/internal/opensubdiv_converter_internal.cc index 56b5657121d..32815dc34dc 100644 --- a/intern/opensubdiv/internal/opensubdiv_converter_internal.cc +++ b/intern/opensubdiv/internal/opensubdiv_converter_internal.cc @@ -49,6 +49,10 @@ getFVarLinearInterpolationFromCAPI( return Options::FVAR_LINEAR_NONE; case OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY: return Options::FVAR_LINEAR_CORNERS_ONLY; + case OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS1: + return Options::FVAR_LINEAR_CORNERS_PLUS1; + case OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS2: + return Options::FVAR_LINEAR_CORNERS_PLUS2; case OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES: return Options::FVAR_LINEAR_BOUNDARIES; case OSD_FVAR_LINEAR_INTERPOLATION_ALL: @@ -58,6 +62,28 @@ getFVarLinearInterpolationFromCAPI( return Options::FVAR_LINEAR_NONE; } +OpenSubdiv_FVarLinearInterpolation +getCAPIFVarLinearInterpolationFromOSD( + OpenSubdiv::Sdc::Options::FVarLinearInterpolation linear_interpolation) { + typedef OpenSubdiv::Sdc::Options Options; + switch (linear_interpolation) { + case Options::FVAR_LINEAR_NONE: + return OSD_FVAR_LINEAR_INTERPOLATION_NONE; + case Options::FVAR_LINEAR_CORNERS_ONLY: + return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY; + case Options::FVAR_LINEAR_CORNERS_PLUS1: + return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS1; + case Options::FVAR_LINEAR_CORNERS_PLUS2: + return OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS2; + case Options::FVAR_LINEAR_BOUNDARIES: + return OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES; + case Options::FVAR_LINEAR_ALL: + return OSD_FVAR_LINEAR_INTERPOLATION_ALL; + } + assert(!"Unknown fvar linear interpolation passed via C-API"); + return OSD_FVAR_LINEAR_INTERPOLATION_NONE; +} + float getCompatibleEdgeSharpness(const OpenSubdiv_Converter* converter, int edge_index) { if (converter->getNumEdgeFaces(converter, edge_index) == 2) { diff --git a/intern/opensubdiv/internal/opensubdiv_converter_internal.h b/intern/opensubdiv/internal/opensubdiv_converter_internal.h index 68518d67884..c47cdd1004d 100644 --- a/intern/opensubdiv/internal/opensubdiv_converter_internal.h +++ b/intern/opensubdiv/internal/opensubdiv_converter_internal.h @@ -41,6 +41,11 @@ OpenSubdiv::Sdc::Options::FVarLinearInterpolation getFVarLinearInterpolationFromCAPI( OpenSubdiv_FVarLinearInterpolation linear_interpolation); +// Similar to above, just other way around. +OpenSubdiv_FVarLinearInterpolation +getCAPIFVarLinearInterpolationFromOSD( + OpenSubdiv::Sdc::Options::FVarLinearInterpolation linear_interpolation); + // Get edge sharpness in a way which makes OpenSubdiv happy. float getCompatibleEdgeSharpness(const OpenSubdiv_Converter* converter, int edge_index); diff --git a/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc b/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc index aa6ba953ef9..93f6fdc14a1 100644 --- a/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc +++ b/intern/opensubdiv/internal/opensubdiv_topology_refiner.cc @@ -46,6 +46,9 @@ bool getIsAdaptive(const OpenSubdiv_TopologyRefiner* topology_refiner) { return topology_refiner->internal->settings.is_adaptive; } +//////////////////////////////////////////////////////////////////////////////// +// Query basic topology information from base level. + int getNumVertices(const OpenSubdiv_TopologyRefiner* topology_refiner) { return getOSDTopologyBaseLevel(topology_refiner)->GetNumVertices(); } @@ -58,6 +61,9 @@ int getNumFaces(const OpenSubdiv_TopologyRefiner* topology_refiner) { return getOSDTopologyBaseLevel(topology_refiner)->GetNumFaces(); } +//////////////////////////////////////////////////////////////////////////////// +// PTex face geometry queries. + int getNumFaceVertices(const OpenSubdiv_TopologyRefiner* topology_refiner, const int face_index) { const OpenSubdiv::Far::TopologyLevel* base_level = @@ -97,18 +103,59 @@ void fillFacePtexIndexOffset(const OpenSubdiv_TopologyRefiner* topology_refiner, } } +////////////////////////////////////////////////////////////////////////////// +// Face-varying data. + +int getNumFVarChannels( + const struct OpenSubdiv_TopologyRefiner* topology_refiner) { + const OpenSubdiv::Far::TopologyLevel* base_level = + getOSDTopologyBaseLevel(topology_refiner); + return base_level->GetNumFVarChannels(); +} + +OpenSubdiv_FVarLinearInterpolation getFVarLinearInterpolation( + const struct OpenSubdiv_TopologyRefiner* topology_refiner) { + return opensubdiv_capi::getCAPIFVarLinearInterpolationFromOSD( + getOSDTopologyRefiner(topology_refiner)->GetFVarLinearInterpolation()); +} + +int getNumFVarValues( + const struct OpenSubdiv_TopologyRefiner* topology_refiner, + const int channel) { + const OpenSubdiv::Far::TopologyLevel* base_level = + getOSDTopologyBaseLevel(topology_refiner); + return base_level->GetNumFVarValues(channel); +} + +const int* getFaceFVarValueIndices( + const struct OpenSubdiv_TopologyRefiner* topology_refiner, + const int face_index, + const int channel) { + const OpenSubdiv::Far::TopologyLevel* base_level = + getOSDTopologyBaseLevel(topology_refiner); + return &base_level->GetFaceFVarValues(face_index, channel)[0]; +} + +////////////////////////////////////////////////////////////////////////////// +// Internal helpers. + void assignFunctionPointers(OpenSubdiv_TopologyRefiner* topology_refiner) { topology_refiner->getSubdivisionLevel = getSubdivisionLevel; topology_refiner->getIsAdaptive = getIsAdaptive; - + // Basic topology information. topology_refiner->getNumVertices = getNumVertices; topology_refiner->getNumEdges = getNumEdges; topology_refiner->getNumFaces = getNumFaces; topology_refiner->getNumFaceVertices = getNumFaceVertices; - + // PTex face geometry. topology_refiner->getNumFacePtexFaces = getNumFacePtexFaces; topology_refiner->getNumPtexFaces = getNumPtexFaces; topology_refiner->fillFacePtexIndexOffset = fillFacePtexIndexOffset; + // Face-varying data. + topology_refiner->getNumFVarChannels = getNumFVarChannels; + topology_refiner->getFVarLinearInterpolation = getFVarLinearInterpolation; + topology_refiner->getNumFVarValues = getNumFVarValues; + topology_refiner->getFaceFVarValueIndices = getFaceFVarValueIndices; } OpenSubdiv_TopologyRefiner* allocateTopologyRefiner() { @@ -125,9 +172,14 @@ OpenSubdiv_TopologyRefiner* allocateTopologyRefiner() { OpenSubdiv_TopologyRefiner* openSubdiv_createTopologyRefinerFromConverter( OpenSubdiv_Converter* converter, const OpenSubdiv_TopologyRefinerSettings* settings) { - OpenSubdiv_TopologyRefiner* topology_refiner = allocateTopologyRefiner(); - topology_refiner->internal->osd_topology_refiner = + OpenSubdiv::Far::TopologyRefiner* osd_topology_refiner = opensubdiv_capi::createOSDTopologyRefinerFromConverter(converter); + if (osd_topology_refiner == NULL) { + // Happens on empty or bad topology. + return NULL; + } + OpenSubdiv_TopologyRefiner* topology_refiner = allocateTopologyRefiner(); + topology_refiner->internal->osd_topology_refiner = osd_topology_refiner; // Store setting which we want to keep track of and which can not be stored // in OpenSubdiv's descriptor yet. topology_refiner->internal->settings = *settings; diff --git a/intern/opensubdiv/opensubdiv_capi_type.h b/intern/opensubdiv/opensubdiv_capi_type.h index 04fe2afff53..b326e53e168 100644 --- a/intern/opensubdiv/opensubdiv_capi_type.h +++ b/intern/opensubdiv/opensubdiv_capi_type.h @@ -34,6 +34,21 @@ typedef enum eOpenSubdivEvaluator { OPENSUBDIV_EVALUATOR_GLSL_COMPUTE = (1 << 5), } eOpenSubdivEvaluator; +typedef enum OpenSubdiv_SchemeType { + OSD_SCHEME_BILINEAR, + OSD_SCHEME_CATMARK, + OSD_SCHEME_LOOP, +} OpenSubdiv_SchemeType; + +typedef enum OpenSubdiv_FVarLinearInterpolation { + OSD_FVAR_LINEAR_INTERPOLATION_NONE, + OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY, + OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS1, + OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS2, + OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES, + OSD_FVAR_LINEAR_INTERPOLATION_ALL, +} OpenSubdiv_FVarLinearInterpolation; + #ifdef __cplusplus } #endif diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h index b16d6eb6c8f..a939f1117e0 100644 --- a/intern/opensubdiv/opensubdiv_converter_capi.h +++ b/intern/opensubdiv/opensubdiv_converter_capi.h @@ -19,23 +19,12 @@ #ifndef OPENSUBDIV_CONVERTER_CAPI_H_ #define OPENSUBDIV_CONVERTER_CAPI_H_ +#include "opensubdiv_capi_type.h" + #ifdef __cplusplus extern "C" { #endif -typedef enum OpenSubdiv_SchemeType { - OSD_SCHEME_BILINEAR, - OSD_SCHEME_CATMARK, - OSD_SCHEME_LOOP, -} OpenSubdiv_SchemeType; - -typedef enum OpenSubdiv_FVarLinearInterpolation { - OSD_FVAR_LINEAR_INTERPOLATION_NONE, - OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY, - OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES, - OSD_FVAR_LINEAR_INTERPOLATION_ALL, -} OpenSubdiv_FVarLinearInterpolation; - typedef struct OpenSubdiv_Converter { OpenSubdiv_SchemeType (*getSchemeType)( const struct OpenSubdiv_Converter* converter); diff --git a/intern/opensubdiv/opensubdiv_topology_refiner_capi.h b/intern/opensubdiv/opensubdiv_topology_refiner_capi.h index 103ccd2c1f9..fe4db0ca67c 100644 --- a/intern/opensubdiv/opensubdiv_topology_refiner_capi.h +++ b/intern/opensubdiv/opensubdiv_topology_refiner_capi.h @@ -21,6 +21,8 @@ #include // for bool +#include "opensubdiv_capi_type.h" + #ifdef __cplusplus extern "C" { #endif @@ -45,7 +47,16 @@ typedef struct OpenSubdiv_TopologyRefiner { bool (*getIsAdaptive)( const struct OpenSubdiv_TopologyRefiner* topology_refiner); + // NOTE: All queries are querying base level. + // + // TODO(sergey): Consider making it more obvious in function naming, + // but since it's unlikely (or at least, will be uncommon use) for API + // which queries final geometry, we should be fine with this name for + // now. + + ////////////////////////////////////////////////////////////////////////////// // Query basic topology information from base level. + int (*getNumVertices)( const struct OpenSubdiv_TopologyRefiner* topology_refiner); int (*getNumEdges)( @@ -56,6 +67,9 @@ typedef struct OpenSubdiv_TopologyRefiner { const struct OpenSubdiv_TopologyRefiner* topology_refiner, const int face_index); + ////////////////////////////////////////////////////////////////////////////// + // PTex face geometry queries. + // Ptex face corresponds to OpenSubdiv's internal "patch" and to Blender's // subdivision grid. The rule commes as: // - Triangle face consist of 3 ptex faces, ordered in the order of @@ -79,6 +93,31 @@ typedef struct OpenSubdiv_TopologyRefiner { const struct OpenSubdiv_TopologyRefiner* topology_refiner, int* face_ptex_index_offset); + ////////////////////////////////////////////////////////////////////////////// + // Face-varying data. + + // Number of face-varying channels (or how they are called in Blender layers). + int (*getNumFVarChannels)( + const struct OpenSubdiv_TopologyRefiner* topology_refiner); + // Get face-varying interpolation type. + OpenSubdiv_FVarLinearInterpolation (*getFVarLinearInterpolation)( + const struct OpenSubdiv_TopologyRefiner* topology_refiner); + // Get total number of face-varying values in a particular channel. + int (*getNumFVarValues)( + const struct OpenSubdiv_TopologyRefiner* topology_refiner, + const int channel); + // Get face-varying value indices associated with a particular face. + // + // This is an array of indices inside of face-varying array, array elements + // are aligned with face corners (or loops in Blender terminology). + const int* (*getFaceFVarValueIndices)( + const struct OpenSubdiv_TopologyRefiner* topology_refiner, + const int face_index, + const int channel); + + ////////////////////////////////////////////////////////////////////////////// + // Internal use. + // Internal storage for the use in this module only. // // Tease: Contains actual OpenSubdiv's refiner and (optionally) some other @@ -86,6 +125,8 @@ typedef struct OpenSubdiv_TopologyRefiner { struct OpenSubdiv_TopologyRefinerInternal* internal; } OpenSubdiv_TopologyRefiner; +// NOTE: Will return NULL in cases of bad topology. +// NOTE: Mesh without faces is considered a bad topology. OpenSubdiv_TopologyRefiner* openSubdiv_createTopologyRefinerFromConverter( struct OpenSubdiv_Converter* converter, const OpenSubdiv_TopologyRefinerSettings* settings); @@ -101,7 +142,7 @@ void openSubdiv_deleteTopologyRefiner( // complicated parts of subdivision process. bool openSubdiv_topologyRefinerCompareWithConverter( const OpenSubdiv_TopologyRefiner* topology_refiner, - const OpenSubdiv_Converter* converter); + const struct OpenSubdiv_Converter* converter); #ifdef __cplusplus } -- cgit v1.2.3