OpenSubdiv: Initial work to support UV maps in textured OSD viewport
authorSergey Sharybin <sergey.vfx@gmail.com>
Tue, 19 Jul 2016 07:28:54 +0000 (09:28 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 20 Jul 2016 12:16:38 +0000 (14:16 +0200)
A bit work in progress, currently the following limitations:

- Texture shading only, Material shading will come later

- No UVs subdivision yet

- Always uses active UV and currently changing active UV will
  not properly update the viewport.

Well, need to start somewhere :)

12 files changed:
intern/opensubdiv/opensubdiv_capi.cc
intern/opensubdiv/opensubdiv_capi.h
intern/opensubdiv/opensubdiv_converter.cc
intern/opensubdiv/opensubdiv_converter_capi.h
intern/opensubdiv/opensubdiv_gpu_capi.cc
intern/opensubdiv/opensubdiv_topology_refiner.h
source/blender/blenkernel/intern/CCGSubSurf.c
source/blender/blenkernel/intern/CCGSubSurf_intern.h
source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/gpu/intern/gpu_codegen.c

index 0463982fdf6ce1d28dd52afa376d0485d81ca529..e04b23725b1485f20f304c8216caead76bb3f46c 100644 (file)
@@ -67,6 +67,7 @@
 
 #include <opensubdiv/osd/glPatchTable.h>
 #include <opensubdiv/far/stencilTable.h>
+#include <opensubdiv/far/primvarRefiner.h>
 
 #include "opensubdiv_intern.h"
 #include "opensubdiv_topology_refiner.h"
@@ -143,11 +144,69 @@ typedef Mesh<GLVertexBuffer,
              GLPatchTable> OsdGLSLComputeMesh;
 #endif
 
+namespace {
+
+struct FVarVertex {
+       float u, v;
+       void Clear() {
+               u = v = 0.0f;
+       }
+       void AddWithWeight(FVarVertex const & src, float weight) {
+               u += weight * src.u;
+               v += weight * src.v;
+       }
+};
+
+static void interpolate_fvar_data(OpenSubdiv::Far::TopologyRefiner& refiner,
+                                  const std::vector<float> uvs,
+                                  std::vector<float> &fvar_data) {
+       /* TODO(sergey): Support all FVar channels. */
+       const int channel = 0;
+       /* TODO(sergey): Make it somehow more generic way. */
+       const int fvar_width = 2;
+
+       int max_level = refiner.GetMaxLevel(),
+           num_values_max = refiner.GetLevel(max_level).GetNumFVarValues(channel),
+           num_values_total = refiner.GetNumFVarValuesTotal(channel);
+       if (num_values_total <= 0) {
+               return;
+       }
+       OpenSubdiv::Far::PrimvarRefiner primvarRefiner(refiner);
+       if (refiner.IsUniform()) {
+               /* For uniform we only keep the highest level of refinement. */
+               fvar_data.resize(num_values_max * fvar_width);
+               std::vector<FVarVertex> buffer(num_values_total - num_values_max);
+               FVarVertex *src = &buffer[0];
+               memcpy(src, &uvs[0], uvs.size() * sizeof(float));
+               /* Defer the last level to treat separately with its alternate
+                * destination.
+                */
+               for (int level = 1; level < max_level; ++level) {
+                       FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
+                       primvarRefiner.InterpolateFaceVarying(level, src, dst, channel);
+                       src = dst;
+               }
+               FVarVertex *dst = reinterpret_cast<FVarVertex *>(&fvar_data[0]);
+               primvarRefiner.InterpolateFaceVarying(max_level, src, dst, channel);
+       } else {
+               /* For adaptive we keep all levels. */
+               fvar_data.resize(num_values_total * fvar_width);
+               FVarVertex *src = reinterpret_cast<FVarVertex *>(&fvar_data[0]);
+               memcpy(src, &uvs[0], uvs.size() * sizeof(float));
+               for (int level = 1; level <= max_level; ++level) {
+                       FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel);
+                       primvarRefiner.InterpolateFaceVarying(level, src, dst, channel);
+                       src = dst;
+        }
+    }
+}
+
+}  // namespace
+
 struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
         OpenSubdiv_TopologyRefinerDescr *topology_refiner,
         int evaluator_type,
-        int level,
-        int /*subdivide_uvs*/)
+        int level)
 {
        using OpenSubdiv::Far::TopologyRefiner;
 
@@ -213,11 +272,21 @@ struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
        gl_mesh->descriptor = (OpenSubdiv_GLMeshDescr *) mesh;
        gl_mesh->topology_refiner = topology_refiner;
 
+       if (refiner->GetNumFVarChannels() > 0) {
+               std::vector<float> fvar_data;
+               interpolate_fvar_data(*refiner, topology_refiner->uvs, fvar_data);
+               openSubdiv_osdGLAllocFVar(gl_mesh, &fvar_data[0]);
+       }
+       else {
+               gl_mesh->fvar_data = NULL;
+       }
+
        return gl_mesh;
 }
 
 void openSubdiv_deleteOsdGLMesh(struct OpenSubdiv_GLMesh *gl_mesh)
 {
+       openSubdiv_osdGLDestroyFVar(gl_mesh);
        switch (gl_mesh->evaluator_type) {
 #define CHECK_EVALUATOR_TYPE(type, class) \
                case OPENSUBDIV_EVALUATOR_ ## type: \
index b40505b197d074326432f2ef42a85f383f93ff50..0410083304e81443857adc70a8cb4cf9d1ee79ee 100644 (file)
@@ -32,16 +32,19 @@ extern "C" {
 
 // Types declaration.
 struct OpenSubdiv_GLMesh;
+struct OpenSubdiv_GLMeshFVarData;
 struct OpenSubdiv_TopologyRefinerDescr;
 
 typedef struct OpenSubdiv_GLMesh OpenSubdiv_GLMesh;
 
 #ifdef __cplusplus
 struct OpenSubdiv_GLMeshDescr;
+
 typedef struct OpenSubdiv_GLMesh {
        int evaluator_type;
        OpenSubdiv_GLMeshDescr *descriptor;
        OpenSubdiv_TopologyRefinerDescr *topology_refiner;
+       OpenSubdiv_GLMeshFVarData *fvar_data;
 } OpenSubdiv_GLMesh;
 #endif
 
@@ -66,8 +69,7 @@ enum {
 OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner(
         struct OpenSubdiv_TopologyRefinerDescr *topology_refiner,
         int evaluator_type,
-        int level,
-        int subdivide_uvs);
+        int level);
 
 void openSubdiv_deleteOsdGLMesh(OpenSubdiv_GLMesh *gl_mesh);
 unsigned int openSubdiv_getOsdGLMeshPatchIndexBuffer(
@@ -129,8 +131,7 @@ void openSubdiv_evaluateVarying(OpenSubdiv_EvaluatorDescr *evaluator_descr,
  *
  * TODO(sergey): Some of the stuff could be initialized once for all meshes.
  */
-void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
-                                        int active_uv_index);
+void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl);
 
 /* Draw specified patches. */
 void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
@@ -138,6 +139,10 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
                                  int start_patch,
                                  int num_patches);
 
+void openSubdiv_osdGLAllocFVar(OpenSubdiv_GLMesh *gl_mesh,
+                               const float *fvar_data);
+void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh);
+
 /* ** Utility functions ** */
 int openSubdiv_supportGPUDisplay(void);
 int openSubdiv_getAvailableEvaluators(void);
index e718d6b4dc86581d14facea59d4b00e3617c87dc..e6c8985e9472a1e65b0c0f8fcc709fbcdd7632fc 100644 (file)
@@ -488,6 +488,39 @@ inline void TopologyRefinerFactory<OpenSubdiv_Converter>::reportInvalidTopology(
        printf("OpenSubdiv Error: %s\n", msg);
 }
 
+template <>
+inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignFaceVaryingTopology(
+        TopologyRefiner& refiner,
+        const OpenSubdiv_Converter& conv)
+{
+       if (conv.get_num_uv_layers(&conv) <= 0) {
+               /* No UV maps, we can skip any face-varying data. */
+               return true;
+       }
+       /* Count overall number of UV data.
+        * NOTE: We only do single UV layer here, and we don't "merge" loops
+        * together as it is done in OpenSubdiv examples.x
+        */
+       const int num_faces = getNumBaseFaces(refiner);
+       int num_uvs = 0;
+       for (int face = 0; face < num_faces; ++face) {
+               IndexArray face_verts = getBaseFaceVertices(refiner, face);
+               num_uvs += face_verts.size();
+       }
+       /* Fill in actual UV offsets. */
+       const int channel = createBaseFVarChannel(refiner, num_uvs);
+       for (int face = 0, offset = 0; face < num_faces; ++face) {
+               Far::IndexArray dst_face_uvs = getBaseFaceFVarValues(refiner,
+                                                                    face,
+                                                                    channel);
+               for (int corner = 0; corner < dst_face_uvs.size(); ++corner) {
+                       dst_face_uvs[corner] = offset;
+                       ++offset;
+               }
+       }
+       return true;
+}
+
 }  /* namespace Far */
 }  /* namespace OPENSUBDIV_VERSION */
 }  /* namespace OpenSubdiv */
@@ -508,6 +541,33 @@ OpenSubdiv::Sdc::SchemeType get_capi_scheme_type(OpenSubdiv_SchemeType type)
        return OpenSubdiv::Sdc::SCHEME_CATMARK;
 }
 
+static void import_fvar_data(OpenSubdiv_TopologyRefinerDescr *result,
+                             const OpenSubdiv_Converter& conv)
+{
+       const int num_layers = conv.get_num_uv_layers(&conv),
+                 num_faces = conv.get_num_faces(&conv);
+       /* Pre-allocate values in one go. */
+       int num_fvar_values = 0;
+       for (int layer = 0; layer < num_layers; ++layer) {
+               num_fvar_values = result->osd_refiner->GetNumFVarValuesTotal();
+       }
+       result->uvs.resize(num_fvar_values * 2);
+       /* Fill in all channels. */
+       for (int layer = 0, offset = 0; layer < num_layers; ++layer) {
+               for (int face = 0; face < num_faces; ++face) {
+                       const int num_verts = conv.get_num_face_verts(&conv, face);
+                       for (int vert = 0; vert < num_verts; ++vert) {
+                               float uv[2];
+                               conv.get_face_corner_uv(&conv, face, vert, uv);
+                               result->uvs[offset++] = uv[0];
+                               result->uvs[offset++] = uv[1];
+                       }
+               }
+               /* TODO(sergey): Currently we only support first layer only. */
+               break;
+       }
+}
+
 }  /* namespace */
 
 struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr(
@@ -536,6 +596,18 @@ struct OpenSubdiv_TopologyRefinerDescr *openSubdiv_createTopologyRefinerDescr(
                TopologyRefinerFactory<OpenSubdiv_Converter>::Create(
                        *converter,
                        topology_options);
+
+       if (result->osd_refiner->GetNumFVarChannels() > 0) {
+               /* Import face varrying data now since later we wouldn't have
+                * access to the converter.
+                *
+                * TODO(sergey): This is so-called "for now", for until we'll
+                * find better way to plug OSD to Blender or for until something
+                * happens inside of OSD API.
+                */
+               import_fvar_data(result, *converter);
+       }
+
        return result;
 }
 
index 1f09fa074d862e3cb0f349e0a6b181a0baced18a..47c8dab49de8fe51583cf349de1890896964c29e 100644 (file)
@@ -83,6 +83,14 @@ typedef struct OpenSubdiv_Converter {
                               int vert,
                               int *vert_faces);
 
+       /* Face-varying data. */
+
+       int (*get_num_uv_layers)(const OpenSubdiv_Converter *converter);
+       void (*get_face_corner_uv)(const OpenSubdiv_Converter *converter,
+                                  int face,
+                                  int corner,
+                                  float r_uv[2]);
+
        void (*free_user_data)(const OpenSubdiv_Converter *converter);
        void *user_data;
 } OpenSubdiv_Converter;
index 63cf390276f378208ed24f25984ac19488d60713..84984e8bd7ecacc20e3e0d6d449d14c5c672cc49 100644 (file)
 #include <opensubdiv/osd/cpuGLVertexBuffer.h>
 #include <opensubdiv/osd/cpuEvaluator.h>
 
+#include "MEM_guardedalloc.h"
+
+#include "opensubdiv_capi.h"
+
 using OpenSubdiv::Osd::GLMeshInterface;
 
 extern "C" char datatoc_gpu_shader_opensubd_display_glsl[];
@@ -78,7 +82,6 @@ typedef struct Transform {
 } Transform;
 
 static bool g_use_osd_glsl = false;
-static int g_active_uv_index = -1;
 
 static GLuint g_flat_fill_solid_program = 0;
 static GLuint g_flat_fill_texture2d_program = 0;
@@ -90,6 +93,59 @@ static GLuint g_lighting_ub = 0;
 static Lighting g_lighting_data;
 static Transform g_transform;
 
+struct OpenSubdiv_GLMeshFVarData
+{
+       OpenSubdiv_GLMeshFVarData() :
+               texture_buffer(0) {
+       }
+
+       ~OpenSubdiv_GLMeshFVarData()
+       {
+               Release();
+       }
+
+       void Release()
+       {
+               if (texture_buffer) {
+                       glDeleteTextures(1, &texture_buffer);
+               }
+               texture_buffer = 0;
+       }
+
+       void Create(const OpenSubdiv::Far::PatchTable *patch_table,
+                   int fvarWidth,
+                   const float *fvar_src_data)
+       {
+               Release();
+               OpenSubdiv::Far::ConstIndexArray indices = patch_table->GetFVarValues();
+
+               // expand fvardata to per-patch array
+               std::vector<float> data;
+               data.reserve(indices.size() * fvarWidth);
+
+               for (int fvert = 0; fvert < (int)indices.size(); ++fvert) {
+                       int index = indices[fvert] * fvarWidth;
+                       for (int i = 0; i < fvarWidth; ++i) {
+                               data.push_back(fvar_src_data[index++]);
+                       }
+               }
+               GLuint buffer;
+               glGenBuffers(1, &buffer);
+               glBindBuffer(GL_ARRAY_BUFFER, buffer);
+               glBufferData(GL_ARRAY_BUFFER, data.size()*sizeof(float),
+                            &data[0], GL_STATIC_DRAW);
+
+               glGenTextures(1, &texture_buffer);
+               glBindTexture(GL_TEXTURE_BUFFER, texture_buffer);
+               glTexBuffer(GL_TEXTURE_BUFFER, GL_R32F, buffer);
+               glBindTexture(GL_TEXTURE_BUFFER, 0);
+               glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+               glDeleteBuffers(1, &buffer);
+       }
+       GLuint texture_buffer;
+};
+
 /* TODO(sergey): This is actually duplicated code from BLI. */
 namespace {
 void copy_m3_m3(float m1[3][3], float m2[3][3])
@@ -307,8 +363,7 @@ GLuint linkProgram(const char *version, const char *define)
        return program;
 }
 
-void bindProgram(GLMeshInterface * /*mesh*/,
-                 int program)
+void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program)
 {
        glUseProgram(program);
 
@@ -352,23 +407,16 @@ void bindProgram(GLMeshInterface * /*mesh*/,
                glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color);
        }
 
-       /* TODO(sergey): Bring face varying back. */
-#if 0
        /* Face-vertex data */
-       if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) {
+       if (gl_mesh->fvar_data != NULL && gl_mesh->fvar_data->texture_buffer) {
                glActiveTexture(GL_TEXTURE31);
-               glBindTexture(GL_TEXTURE_BUFFER,
-                             mesh->GetDrawContext()->GetFvarDataTextureBuffer());
+               glBindTexture(GL_TEXTURE_BUFFER, gl_mesh->fvar_data->texture_buffer);
                glActiveTexture(GL_TEXTURE0);
        }
-#endif
-
-       /* TODO(sergey): Bring face varying back. */
-       glUniform1i(glGetUniformLocation(program, "osd_fvar_count"),
-                   0/* * mesh->GetFVarCount()*/);
 
-       glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"),
-                   g_active_uv_index * 2);
+       /* See notes below about why we use such values. */
+       glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 2);
+       glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0);
 }
 
 }  /* namespace */
@@ -455,11 +503,9 @@ void openSubdiv_osdGLDisplayDeinit(void)
        }
 }
 
-void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
-                                        int active_uv_index)
+void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl)
 {
        g_use_osd_glsl = use_osd_glsl != 0;
-       g_active_uv_index = active_uv_index;
 
        /* Update transformation matrices. */
        glGetFloatv(GL_PROJECTION_MATRIX, g_transform.projection_matrix);
@@ -516,7 +562,7 @@ void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
        }
 }
 
-static GLuint prepare_patchDraw(GLMeshInterface *mesh,
+static GLuint prepare_patchDraw(OpenSubdiv_GLMesh *gl_mesh,
                                 bool fill_quads)
 {
        GLint program = 0;
@@ -531,28 +577,31 @@ static GLuint prepare_patchDraw(GLMeshInterface *mesh,
                                glUniform1i(location, model == GL_FLAT);
                        }
 
-                       /* TODO(sergey): Bring this back. */
-#if 0
                        /* Face-vertex data */
-                       if (mesh->GetDrawContext()->GetFvarDataTextureBuffer()) {
+                       if (gl_mesh->fvar_data != NULL &&
+                           gl_mesh->fvar_data->texture_buffer)
+                       {
                                glActiveTexture(GL_TEXTURE31);
                                glBindTexture(GL_TEXTURE_BUFFER,
-                                             mesh->GetDrawContext()->GetFvarDataTextureBuffer());
+                                             gl_mesh->fvar_data->texture_buffer);
                                glActiveTexture(GL_TEXTURE0);
 
                                GLint location = glGetUniformLocation(program, "osd_fvar_count");
                                if (location != -1) {
-                                       glUniform1i(location, mesh->GetFVarCount());
+                                       /* TODO(sergey): This is width of FVar data, which happened to be 2. */
+                                       glUniform1i(location, 2);
                                }
 
                                location = glGetUniformLocation(program, "osd_active_uv_offset");
                                if (location != -1) {
-                                       glUniform1i(location,
-                                                   g_active_uv_index * 2);
+                                       /* TODO(sergey): Since we only store single UV channel
+                                        * we can always suuppose offset is 0.
+                                        *
+                                        * Ideally it should be active UV index times 2.
+                                        */
+                                       glUniform1i(location, 0);
                                }
                        }
-#endif
-
                }
                return program;
        }
@@ -584,7 +633,7 @@ static GLuint prepare_patchDraw(GLMeshInterface *mesh,
                program = g_wireframe_program;
        }
 
-       bindProgram(mesh, program);
+       bindProgram(gl_mesh, program);
 
        return program;
 }
@@ -645,7 +694,7 @@ static void draw_partition_patches_range(GLMeshInterface *mesh,
                                const int num_draw_patches = std::min(num_remained_patches,
                                                                      num_block_patches - start_draw_patch);
                                perform_drawElements(program,
-                                                    i,
+                                                    i + start_draw_patch,
                                                     num_draw_patches * num_control_verts,
                                                     patch.GetIndexBase() + start_draw_patch * num_control_verts);
                                num_remained_patches -= num_draw_patches;
@@ -691,7 +740,7 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
        }
 
        /* Setup GLSL/OpenGL to draw patches in current context. */
-       GLuint program = prepare_patchDraw(mesh, fill_quads != 0);
+       GLuint program = prepare_patchDraw(gl_mesh, fill_quads != 0);
 
        if (start_patch != -1) {
                draw_partition_patches_range(mesh,
@@ -706,3 +755,21 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
        /* Finish patch drawing by restoring all changes to the OpenGL context. */
        finish_patchDraw(fill_quads != 0);
 }
+
+void openSubdiv_osdGLAllocFVar(OpenSubdiv_GLMesh *gl_mesh,
+                               const float *fvar_data)
+{
+       GLMeshInterface *mesh =
+               (GLMeshInterface *)(gl_mesh->descriptor);
+       gl_mesh->fvar_data = OBJECT_GUARDED_NEW(OpenSubdiv_GLMeshFVarData);
+       gl_mesh->fvar_data->Create(mesh->GetFarPatchTable(),
+                                  2,
+                                  fvar_data);
+}
+
+void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh)
+{
+       if (gl_mesh->fvar_data != NULL) {
+               OBJECT_GUARDED_DELETE(gl_mesh->fvar_data, OpenSubdiv_GLMeshFVarData);
+       }
+}
index 5c299ac5df58efe14f0f5bb86039bc58503816e7..b00f6a542015fae32bbaa2b25077d569023df57e 100644 (file)
 
 typedef struct OpenSubdiv_TopologyRefinerDescr {
        OpenSubdiv::Far::TopologyRefiner *osd_refiner;
+
+       /* TODO(sergey): For now only, need to find better place
+        * after revisiting whole OSD drawing pipeline and Blender
+        * integration.
+        */
+       std::vector<float> uvs;
 } OpenSubdiv_TopologyRefinerDescr;
 
 #endif  /* __OPENSUBDIV_TOPOLOGY_REFINER_H__ */
index 828a6bb16ac66d95ca43ef464cdce22f836451e6..c4886a2174039a6baae6df70dc85a5ad71e5f7a2 100644 (file)
@@ -313,9 +313,6 @@ CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, int subdivLevels, CCGAllocatorIFC *a
                ss->osd_vao = 0;
                ss->skip_grids = false;
                ss->osd_compute = 0;
-               ss->osd_uvs_invalid = true;
-               ss->osd_subsurf_uv = 0;
-               ss->osd_uv_index = -1;
                ss->osd_next_face_ptex_index = 0;
                ss->osd_coarse_coords = NULL;
                ss->osd_num_coarse_coords = 0;
index 0cdf3acf075955c3963884e15d9591d1e2906901..7e8059e62fc0bfc615409ca64efb42939eb42e8e 100644 (file)
@@ -254,11 +254,6 @@ struct CCGSubSurf {
         * to fill in PTex index of CCGFace.
         */
        int osd_next_face_ptex_index;
-
-       /* ** Needs review.  ** */
-       bool osd_subsurf_uv;
-       int osd_uv_index;
-       bool osd_uvs_invalid;
 #endif
 };
 
index 2bb55c2d1ed36b3360ed54eb24b000512b88fa56..c715c1fa1eead7b2ff0e19302a916677231e33a2 100644 (file)
@@ -190,7 +190,6 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, DerivedMesh *dm)
                /* ** Make sure both GPU and CPU backends are properly reset. ** */
 
                ss->osd_coarse_coords_invalid = true;
-               ss->osd_uvs_invalid = true;
 
                /* Reset GPU part. */
                ss->osd_mesh_invalid = true;
@@ -256,8 +255,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl)
                ss->osd_mesh = openSubdiv_createOsdGLMeshFromTopologyRefiner(
                        ss->osd_topology_refiner,
                        compute_type,
-                       ss->subdivLevels,
-                       ss->osd_subsurf_uv);
+                       ss->subdivLevels);
                ss->osd_topology_refiner = NULL;
 
                if (UNLIKELY(ss->osd_mesh == NULL)) {
@@ -290,7 +288,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl)
                ss->osd_coarse_coords_invalid = false;
        }
 
-       openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl, ss->osd_uv_index);
+       openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl);
 
        return true;
 }
index c4317f4d7409c9a5fd903ae082c88efabfbb3e73..72e5f9f13465c886458e9bfec43fa366a864a6aa 100644 (file)
@@ -62,6 +62,11 @@ typedef struct ConvDMStorage {
            *vert_poly_mem,
            *edge_poly_mem;
 #endif
+
+       MEdge *medge;
+       MLoop *mloop;
+       MPoly *mpoly;
+       MLoopUV *mloopuv;
 } ConvDMStorage;
 
 static OpenSubdiv_SchemeType conv_dm_get_type(
@@ -99,9 +104,7 @@ static int conv_dm_get_num_face_verts(const OpenSubdiv_Converter *converter,
                                       int face)
 {
        ConvDMStorage *storage = converter->user_data;
-       DerivedMesh *dm = storage->dm;
-       const MPoly *mp = dm->getPolyArray(dm);
-       const MPoly *mpoly = &mp[face];
+       const MPoly *mpoly = &storage->mpoly[face];
        return mpoly->totloop;
 }
 
@@ -110,13 +113,10 @@ static void conv_dm_get_face_verts(const OpenSubdiv_Converter *converter,
                                    int *face_verts)
 {
        ConvDMStorage *storage = converter->user_data;
-       DerivedMesh *dm = storage->dm;
-       const MLoop *ml = dm->getLoopArray(dm);
-       const MPoly *mp = dm->getPolyArray(dm);
-       const MPoly *mpoly = &mp[face];
+       const MPoly *mpoly = &storage->mpoly[face];
        int loop;
        for (loop = 0; loop < mpoly->totloop; loop++) {
-               face_verts[loop] = ml[mpoly->loopstart + loop].v;
+               face_verts[loop] = storage->mloop[mpoly->loopstart + loop].v;
        }
 }
 
@@ -125,13 +125,10 @@ static void conv_dm_get_face_edges(const OpenSubdiv_Converter *converter,
                                    int *face_edges)
 {
        ConvDMStorage *storage = converter->user_data;
-       DerivedMesh *dm = storage->dm;
-       const MLoop *ml = dm->getLoopArray(dm);
-       const MPoly *mp = dm->getPolyArray(dm);
-       const MPoly *mpoly = &mp[face];
+       const MPoly *mpoly = &storage->mpoly[face];
        int loop;
        for (loop = 0; loop < mpoly->totloop; loop++) {
-               face_edges[loop] = ml[mpoly->loopstart + loop].e;
+               face_edges[loop] = storage->mloop[mpoly->loopstart + loop].e;
        }
 }
 
@@ -140,9 +137,7 @@ static void conv_dm_get_edge_verts(const OpenSubdiv_Converter *converter,
                                    int *edge_verts)
 {
        ConvDMStorage *storage = converter->user_data;
-       DerivedMesh *dm = storage->dm;
-       const MEdge *me = dm->getEdgeArray(dm);
-       const MEdge *medge = &me[edge];
+       const MEdge *medge = &storage->medge[edge];
        edge_verts[0] = medge->v1;
        edge_verts[1] = medge->v2;
 }
@@ -153,14 +148,12 @@ static int conv_dm_get_num_edge_faces(const OpenSubdiv_Converter *converter,
        ConvDMStorage *storage = converter->user_data;
 #ifndef USE_MESH_ELEMENT_MAPPING
        DerivedMesh *dm = storage->dm;
-       const MLoop *ml = dm->getLoopArray(dm);
-       const MPoly *mp = dm->getPolyArray(dm);
        int num = 0, poly;
        for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
-               const MPoly *mpoly = &mp[poly];
+               const MPoly *mpoly = &user_data->mpoly[poly];
                int loop;
                for (loop = 0; loop < mpoly->totloop; loop++) {
-                       const MLoop *mloop = &ml[mpoly->loopstart + loop];
+                       const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
                        if (mloop->e == edge) {
                                ++num;
                                break;
@@ -180,14 +173,12 @@ static void conv_dm_get_edge_faces(const OpenSubdiv_Converter *converter,
        ConvDMStorage *storage = converter->user_data;
 #ifndef USE_MESH_ELEMENT_MAPPING
        DerivedMesh *dm = storage->dm;
-       const MLoop *ml = dm->getLoopArray(dm);
-       const MPoly *mp = dm->getPolyArray(dm);
        int num = 0, poly;
        for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
-               const MPoly *mpoly = &mp[poly];
+               const MPoly *mpoly = &user_data->mpoly[poly];
                int loop;
                for (loop = 0; loop < mpoly->totloop; loop++) {
-                       const MLoop *mloop = &ml[mpoly->loopstart + loop];
+                       const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
                        if (mloop->e == edge) {
                                edge_faces[num++] = poly;
                                break;
@@ -205,9 +196,8 @@ static float conv_dm_get_edge_sharpness(const OpenSubdiv_Converter *converter,
                                         int edge)
 {
        ConvDMStorage *storage = converter->user_data;
-       DerivedMesh *dm = storage->dm;
        CCGSubSurf *ss = storage->ss;
-       const MEdge *medge = dm->getEdgeArray(dm);
+       const MEdge *medge = storage->medge;
        return (float)medge[edge].crease / 255.0f * ss->subdivLevels;
 }
 
@@ -217,10 +207,9 @@ static int conv_dm_get_num_vert_edges(const OpenSubdiv_Converter *converter,
        ConvDMStorage *storage = converter->user_data;
 #ifndef USE_MESH_ELEMENT_MAPPING
        DerivedMesh *dm = storage->dm;
-       const MEdge *me = dm->getEdgeArray(dm);
        int num = 0, edge;
        for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
-               const MEdge *medge = &me[edge];
+               const MEdge *medge = &user_data->medge[edge];
                if (medge->v1 == vert || medge->v2 == vert) {
                        ++num;
                }
@@ -238,10 +227,9 @@ static void conv_dm_get_vert_edges(const OpenSubdiv_Converter *converter,
        ConvDMStorage *storage = converter->user_data;
 #ifndef USE_MESH_ELEMENT_MAPPING
        DerivedMesh *dm = storage->dm;
-       const MEdge *me = dm->getEdgeArray(dm);
        int num = 0, edge;
        for (edge = 0; edge < dm->getNumEdges(dm); edge++) {
-               const MEdge *medge = &me[edge];
+               const MEdge *medge = &user_data->medge[edge];
                if (medge->v1 == vert || medge->v2 == vert) {
                        vert_edges[num++] = edge;
                }
@@ -259,14 +247,12 @@ static int conv_dm_get_num_vert_faces(const OpenSubdiv_Converter *converter,
        ConvDMStorage *storage = converter->user_data;
 #ifndef USE_MESH_ELEMENT_MAPPING
        DerivedMesh *dm = storage->dm;
-       const MLoop *ml = dm->getLoopArray(dm);
-       const MPoly *mp = dm->getPolyArray(dm);
        int num = 0, poly;
        for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
-               const MPoly *mpoly = &mp[poly];
+               const MPoly *mpoly = &user_data->mpoly[poly];
                int loop;
                for (loop = 0; loop < mpoly->totloop; loop++) {
-                       const MLoop *mloop = &ml[mpoly->loopstart + loop];
+                       const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
                        if (mloop->v == vert) {
                                ++num;
                                break;
@@ -286,14 +272,12 @@ static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter,
        ConvDMStorage *storage = converter->user_data;
 #ifndef USE_MESH_ELEMENT_MAPPING
        DerivedMesh *dm = storage->dm;
-       const MLoop *ml = dm->getLoopArray(dm);
-       const MPoly *mp = dm->getPolyArray(dm);
        int num = 0, poly;
        for (poly = 0; poly < dm->getNumPolys(dm); poly++) {
-               const MPoly *mpoly = &mp[poly];
+               const MPoly *mpoly = &storage->mpoly[poly];
                int loop;
                for (loop = 0; loop < mpoly->totloop; loop++) {
-                       const MLoop *mloop = &ml[mpoly->loopstart + loop];
+                       const MLoop *mloop = &storage->mloop[mpoly->loopstart + loop];
                        if (mloop->v == vert) {
                                vert_faces[num++] = poly;
                                break;
@@ -307,6 +291,24 @@ static void conv_dm_get_vert_faces(const OpenSubdiv_Converter *converter,
 #endif
 }
 
+static int conv_dm_get_num_uv_layers(const OpenSubdiv_Converter *converter)
+{
+       ConvDMStorage *storage = converter->user_data;
+       DerivedMesh *dm = storage->dm;
+       return CustomData_number_of_layers(&dm->loopData, CD_MLOOPUV);
+}
+
+static void conv_dm_get_face_corner_uv(const OpenSubdiv_Converter *converter,
+                                       int face,
+                                       int corner,
+                                       float r_uv[2])
+{
+       ConvDMStorage *storage = converter->user_data;
+       MPoly *mpoly = &storage->mpoly[face];
+       MLoopUV *mloopuv = &storage->mloopuv[mpoly->loopstart + corner];
+       copy_v2_v2(r_uv, mloopuv->uv);
+}
+
 static void conv_dm_free_user_data(const OpenSubdiv_Converter *converter)
 {
        ConvDMStorage *user_data = converter->user_data;
@@ -348,9 +350,18 @@ void ccgSubSurf_converter_setup_from_derivedmesh(
        converter->get_num_vert_faces = conv_dm_get_num_vert_faces;
        converter->get_vert_faces = conv_dm_get_vert_faces;
 
+       converter->get_num_uv_layers = conv_dm_get_num_uv_layers;
+       converter->get_face_corner_uv = conv_dm_get_face_corner_uv;
+
        user_data = MEM_mallocN(sizeof(ConvDMStorage), __func__);
        user_data->ss = ss;
        user_data->dm = dm;
+
+       user_data->medge = dm->getEdgeArray(dm);
+       user_data->mloop = dm->getLoopArray(dm);
+       user_data->mpoly = dm->getPolyArray(dm);
+       user_data->mloopuv = DM_get_loop_data_layer(dm, CD_MLOOPUV);
+
        converter->free_user_data = conv_dm_free_user_data;
        converter->user_data = user_data;
 
@@ -548,6 +559,19 @@ static void conv_ccg_get_vert_faces(const OpenSubdiv_Converter *converter,
        }
 }
 
+static int conv_ccg_get_num_uv_layers(const OpenSubdiv_Converter *UNUSED(converter))
+{
+       return 0;
+}
+
+static void conv_ccg_get_face_corner_uv(const OpenSubdiv_Converter * UNUSED(converter),
+                                        int UNUSED(face),
+                                        int UNUSED(corner),
+                                        float r_uv[2])
+{
+       zero_v2(r_uv);
+}
+
 void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss,
                                          OpenSubdiv_Converter *converter)
 {
@@ -571,6 +595,9 @@ void ccgSubSurf_converter_setup_from_ccg(CCGSubSurf *ss,
        converter->get_num_vert_faces = conv_ccg_get_num_vert_faces;
        converter->get_vert_faces = conv_ccg_get_vert_faces;
 
+       converter->get_num_uv_layers = conv_ccg_get_num_uv_layers;
+       converter->get_face_corner_uv = conv_ccg_get_face_corner_uv;
+
        converter->free_user_data = NULL;
        converter->user_data = ss;
 }
index f73dbd8078faa1b7ab369fd9340cbb15e9564fec..b9efe23a4b3d650a731875f4a745c644be4a92be 100644 (file)
@@ -3386,19 +3386,6 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
        int mat_index;
        int tot_element, start_element, tot_drawn;
 
-#ifdef WITH_OPENSUBDIV
-       if (ccgdm->useGpuBackend) {
-               if (ccgSubSurf_prepareGLMesh(ss, true) == false) {
-                       return;
-               }
-               ccgSubSurf_drawGLMesh(ss, true, -1, -1);
-               return;
-       }
-#endif
-
-       CCG_key_top_level(&key, ss);
-       ccgdm_pbvh_update(ccgdm);
-
        if (use_colors) {
                colType = CD_TEXTURE_MLOOPCOL;
                mloopcol = dm->getLoopDataArray(dm, colType);
@@ -3412,6 +3399,77 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
                }
        }
 
+#ifdef WITH_OPENSUBDIV
+       if (ccgdm->useGpuBackend) {
+               if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true) == false)) {
+                       return;
+               }
+               if (drawParams == NULL) {
+                       ccgSubSurf_drawGLMesh(ss, true, -1, -1);
+                       return;
+               }
+               const int level = ccgSubSurf_getSubdivisionLevels(ss);
+               const int face_side = 1 << level;
+               const int grid_side = 1 << (level - 1);
+               const int face_patches = face_side * face_side;
+               const int grid_patches = grid_side * grid_side;
+               const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
+               int current_patch = 0;
+               int mat_nr = -1;
+               int start_draw_patch = 0, num_draw_patches = 0;
+               for (i = 0; i < num_base_faces; ++i) {
+                       const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
+                       const int num_patches = (num_face_verts == 4) ? face_patches
+                                                                     : num_face_verts * grid_patches;
+                       if (faceFlags) {
+                               mat_nr = faceFlags[i].mat_nr + 1;
+                       }
+                       else {
+                               mat_nr = 0;
+                       }
+
+                       if (drawParams != NULL) {
+                               MTexPoly *tp = (use_tface && mtexpoly) ? &mtexpoly[i] : NULL;
+                               draw_option = drawParams(tp, (mloopcol != NULL), mat_nr);
+                       }
+                       else {
+                               draw_option = (drawParamsMapped)
+                                                 ? drawParamsMapped(userData, i, mat_nr)
+                                                 : DM_DRAW_OPTION_NORMAL;
+                       }
+
+                       flush = (draw_option == DM_DRAW_OPTION_SKIP) || (i == num_base_faces - 1);
+
+                       if (!flush && compareDrawOptions) {
+                               flush |= compareDrawOptions(userData, i, min_ii(i + 1, num_base_faces - 1)) == 0;
+                       }
+
+                       current_patch += num_patches;
+
+                       if (flush) {
+                               if (draw_option != DM_DRAW_OPTION_SKIP) {
+                                       num_draw_patches += num_patches;
+                               }
+                               if (num_draw_patches != 0) {
+                                       ccgSubSurf_drawGLMesh(ss,
+                                                             true,
+                                                             start_draw_patch,
+                                                             num_draw_patches);
+                               }
+                               start_draw_patch = current_patch;
+                               num_draw_patches = 0;
+                       }
+                       else {
+                               num_draw_patches += num_patches;
+                       }
+               }
+               return;
+       }
+#endif
+
+       CCG_key_top_level(&key, ss);
+       ccgdm_pbvh_update(ccgdm);
+
        GPU_vertex_setup(dm);
        GPU_normal_setup(dm);
        GPU_triangle_setup(dm);
index 3c028ff080533d70b2faef899b3905e32f6b0e22..8ec932f4184b9f793fb5a7c505f8e007614355e8 100644 (file)
@@ -868,14 +868,12 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
                BLI_dynstr_append(ds, datatoc_gpu_shader_geometry_glsl);
 
                /* Generate varying assignments. */
-               /* TODO(sergey): Disabled for now, needs revisit. */
-#if 0
                for (node = nodes->first; node; node = node->next) {
                        for (input = node->inputs.first; input; input = input->next) {
                                if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) {
                                        if (input->attribtype == CD_MTFACE) {
                                                BLI_dynstr_appendf(ds,
-                                                                  "\tINTERP_FACE_VARYING_2(var%d, "
+                                                                  "\t// INTERP_FACE_VARYING_2(var%d, "
                                                                       "fvar%d_offset, st);\n",
                                                                   input->attribid,
                                                                   input->attribid);
@@ -883,7 +881,6 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
                                }
                        }
                }
-#endif
 
                BLI_dynstr_append(ds, "}\n");
                code = BLI_dynstr_get_cstring(ds);