OpenSubdiv: Add API to evaluate face-varying data
authorSergey Sharybin <sergey.vfx@gmail.com>
Tue, 17 Jul 2018 16:06:32 +0000 (18:06 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 18 Jul 2018 13:42:49 +0000 (15:42 +0200)
There are move changes along the line to keep everything
working from from C.

intern/opensubdiv/internal/opensubdiv_converter_factory.cc
intern/opensubdiv/internal/opensubdiv_converter_internal.cc
intern/opensubdiv/internal/opensubdiv_converter_internal.h
intern/opensubdiv/internal/opensubdiv_topology_refiner.cc
intern/opensubdiv/opensubdiv_capi_type.h
intern/opensubdiv/opensubdiv_converter_capi.h
intern/opensubdiv/opensubdiv_topology_refiner_capi.h

index bd6edbb964882fd4c833e225734988ace0aad7c8..48516cc80b7ccc04b1610f5f5c09fe9356286bdb 100644 (file)
@@ -383,6 +383,8 @@ TopologyRefinerFactory<TopologyRefinerData>::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);
index 56b5657121df1365fe62f000fc66c2c298b66de4..32815dc34dcc3c742268cc5f2d4d67cf5f213ffe 100644 (file)
@@ -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) {
index 68518d678845f702a2236fd87336ed18bb90b3ab..c47cdd1004dca066b8dffd25126e42cb82acc853 100644 (file)
@@ -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);
index aa6ba953ef92745b17816bd619a8738241d95391..93f6fdc14a1f5b3d1803673ced44853205f9711d 100644 (file)
@@ -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;
index 04fe2afff53a24a8f8640a1665d4d122dcd756fe..b326e53e168cc8378448c5e361af61b950740016 100644 (file)
@@ -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
index b16d6eb6c8f6d5fad24f1a8fc85d599b7df83575..a939f1117e08f038e00dadc03de8736f354a21e4 100644 (file)
 #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);
index 103ccd2c1f9532b0facd408a1e5e535ceb18e633..fe4db0ca67c9ba190455e98a6b04a4779951a131 100644 (file)
@@ -21,6 +21,8 @@
 
 #include <stdint.h>  // 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
 }