OpenSubdiv: Support for multiple materials in solid shading mode
authorSergey Sharybin <sergey.vfx@gmail.com>
Tue, 25 Aug 2015 13:05:28 +0000 (15:05 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Tue, 25 Aug 2015 13:11:56 +0000 (15:11 +0200)
Implementation is less optimal compared to non-opensubdiv drawing but
it is now as good as we can do it without affecting on how patches are
being created by OpenSubdiv.

intern/opensubdiv/opensubdiv_capi.h
intern/opensubdiv/opensubdiv_converter.cc
intern/opensubdiv/opensubdiv_converter_capi.h
intern/opensubdiv/opensubdiv_gpu_capi.cc
source/blender/blenkernel/intern/CCGSubSurf.h
source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
source/blender/blenkernel/intern/subsurf_ccg.c

index c86e739f12b54c6c33bfdb5456f5a9e3b117eb91..c09d03262649b5d1a326e513b5ee436ba2baf6c8 100644 (file)
@@ -135,8 +135,8 @@ void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl,
 /* Draw patches which corresponds to a given partition. */
 void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
                                  int fill_quads,
-                                 int start_partition,
-                                 int num_partitions);
+                                 int start_patch,
+                                 int num_patches);
 
 /* ** Utility functions ** */
 int openSubdiv_supportGPUDisplay(void);
index 098807428959963dcf540baefef73d84e63a90b4..5d43cafd1f353f349e1b07bf82c47d14fba030e5 100644 (file)
@@ -574,6 +574,17 @@ int openSubdiv_topologyRefinerGetNumFaces(
        return base_level.GetNumFaces();
 }
 
+int openSubdiv_topologyRefinerGetNumFaceVerts(
+        const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
+        int face)
+{
+       using OpenSubdiv::Far::TopologyLevel;
+       using OpenSubdiv::Far::TopologyRefiner;
+       const TopologyRefiner *refiner = (const TopologyRefiner *)topology_refiner;
+       const TopologyLevel &base_level = refiner->GetLevel(0);
+       return base_level.GetFaceVertices(face).size();
+}
+
 int openSubdiv_topologyRefnerCompareConverter(
         const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
         OpenSubdiv_Converter *converter)
index 7c96d3d8b966c0935327b3134a459a386f8e52d5..ac1e8301a4295b166de95a65d8df46e7a6e5044e 100644 (file)
@@ -94,7 +94,7 @@ void openSubdiv_deleteTopologyRefinerDescr(
         OpenSubdiv_TopologyRefinerDescr *topology_refiner);
 
 /* TODO(sergey): Those calls are not strictly related on conversion.
- * needs some dedicated fiel perhaps.
+ * needs some dedicated file perhaps.
  */
 
 int openSubdiv_topologyRefinerGetSubdivLevel(
@@ -109,6 +109,10 @@ int openSubdiv_topologyRefinerGetNumEdges(
 int openSubdiv_topologyRefinerGetNumFaces(
         const OpenSubdiv_TopologyRefinerDescr *topology_refiner);
 
+int openSubdiv_topologyRefinerGetNumFaceVerts(
+        const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
+        int face);
+
 int openSubdiv_topologyRefnerCompareConverter(
         const OpenSubdiv_TopologyRefinerDescr *topology_refiner,
         OpenSubdiv_Converter *converter);
index 9498f936b6b9be99be84f8a3e599c1a72b2ff08c..803265dbe28d77fd7421627e41d15961a985235a 100644 (file)
@@ -575,46 +575,41 @@ static void finish_patchDraw(bool fill_quads)
        }
 }
 
-#if 0
 static void draw_partition_patches_range(PartitionedGLMeshInterface *mesh,
                                          GLuint program,
-                                         int start_partition,
-                                         int num_partitions)
+                                         int start_patch,
+                                         int num_patches)
 {
-       /* Glue patches from all partitions in the range together. */
-       int patch_index = -1, start_element = -1, num_elements = 0;
-       for (int partition = start_partition;
-            partition < start_partition + num_partitions;
-            ++partition)
-       {
-               OsdDrawContext::PatchArrayVector const &patches =
-                       mesh->GetPatchArrays(partition);
-               for (int i = 0; i < (int)patches.size(); ++i) {
-                       OsdDrawContext::PatchArray const &patch = patches[i];
-                       OsdDrawContext::PatchDescriptor desc = patch.GetDescriptor();
-                       OpenSubdiv::FarPatchTables::Type patchType = desc.GetType();
-                       if (patchType == OpenSubdiv::FarPatchTables::QUADS) {
-                               if (start_element == -1) {
-                                       patch_index = patch.GetPatchIndex();
-                                       start_element = patch.GetVertIndex();
-                               }
+       int traversed_patches = 0, num_remained_patches = num_patches;
+       const OpenSubdiv::Osd::PatchArrayVector& patches =
+               mesh->GetPatchTable()->GetPatchArrays();
+       for (int i = 0; i < (int)patches.size(); ++i) {
+               const OpenSubdiv::Osd::PatchArray& patch = patches[i];
+               OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor();
+               OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType();
 
-                               assert(patch.GetVertIndex() == start_element + num_elements);
-                               num_elements += patch.GetNumIndices();
+               if (patchType == OpenSubdiv::Far::PatchDescriptor::QUADS) {
+                       const int num_block_patches = patch.GetNumPatches();
+                       if (start_patch >= traversed_patches &&
+                           start_patch < traversed_patches + num_block_patches)
+                       {
+                               const int num_control_verts = desc.GetNumControlVertices();
+                               const int start_draw_patch = start_patch - traversed_patches;
+                               const int num_draw_patches = std::min(num_remained_patches,
+                                                                     num_block_patches - start_draw_patch);
+                               perform_drawElements(program,
+                                                    i,
+                                                    num_draw_patches * num_control_verts,
+                                                    patch.GetIndexBase() + start_draw_patch * num_control_verts);
+                               num_remained_patches -= num_draw_patches;
                        }
-                       else {
-                               assert(!"Discontinuitied are not supported yet.");
+                       if (num_remained_patches == 0) {
+                               break;
                        }
+                       traversed_patches += num_block_patches;
                }
-       }
-
-       /* Perform actual draw. */
-       perform_drawElements(program,
-                            patch_index,
-                            num_elements,
-                            start_element);
+    }
 }
-#endif
 
 static void draw_all_patches(PartitionedGLMeshInterface *mesh,
                              GLuint program)
@@ -637,8 +632,8 @@ static void draw_all_patches(PartitionedGLMeshInterface *mesh,
 
 void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
                                  int fill_quads,
-                                 int start_partition,
-                                 int num_partitions)
+                                 int start_patch,
+                                 int num_patches)
 {
        PartitionedGLMeshInterface *mesh =
                (PartitionedGLMeshInterface *)(gl_mesh->descriptor);
@@ -649,18 +644,11 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
        /* Setup GLSL/OpenGL to draw patches in current context. */
        GLuint program = preapre_patchDraw(mesh, fill_quads != 0);
 
-       if (start_partition != -1) {
-#if 0
+       if (start_patch != -1) {
                draw_partition_patches_range(mesh,
                                             program,
-                                            start_partition,
-                                            num_partitions);
-#else
-               (void)num_partitions;
-               if(start_partition == 0) {
-                       draw_all_patches(mesh, program);
-               }
-#endif
+                                            start_patch,
+                                            num_patches);
        }
        else {
                draw_all_patches(mesh, program);
index e9ad4c52531bea229613f46c136159f8dfab0267..a825cffe7a07c31e7138c66eff32e32d0c3ba616 100644 (file)
@@ -215,6 +215,12 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl);
 void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads,
                            int start_partition, int num_partitions);
 
+/* Get number of base faces in a particular GL mesh. */
+int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss);
+
+/* Get number of vertices in base faces in a particular GL mesh. */
+int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face);
+
 /* Controls whether CCG are needed (Cmeaning CPU evaluation) or fully GPU compute
  * and draw is allowed.
  */
index eb7c3bf6ffdef76c87dc2e600168520204aa8c4f..fcc46308efaa892352bde77942499ba1d8f21855 100644 (file)
@@ -308,6 +308,31 @@ void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads,
        }
 }
 
+int ccgSubSurf_getNumGLMeshBaseFaces(CCGSubSurf *ss)
+{
+       const OpenSubdiv_TopologyRefinerDescr *topology_refiner;
+       if (ss->osd_topology_refiner != NULL) {
+               topology_refiner = ss->osd_topology_refiner;
+       }
+       else {
+               topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
+       }
+       return openSubdiv_topologyRefinerGetNumFaces(topology_refiner);
+}
+
+/* Get number of vertices in base faces in a particular GL mesh. */
+int ccgSubSurf_getNumGLMeshBaseFaceVerts(CCGSubSurf *ss, int face)
+{
+       const OpenSubdiv_TopologyRefinerDescr *topology_refiner;
+       if (ss->osd_topology_refiner != NULL) {
+               topology_refiner = ss->osd_topology_refiner;
+       }
+       else {
+               topology_refiner = openSubdiv_getGLMeshTopologyRefiner(ss->osd_mesh);
+       }
+       return openSubdiv_topologyRefinerGetNumFaceVerts(topology_refiner, face);
+}
+
 void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids)
 {
        ss->skip_grids = skip_grids;
index e38d62cd9bca1afa275ba20b4605a94f8a5e559f..867065b060d6584b83235afdc7b0aae41c4777d7 100644 (file)
@@ -2622,24 +2622,72 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
 #ifdef WITH_OPENSUBDIV
        if (ccgdm->useGpuBackend) {
                CCGSubSurf *ss = ccgdm->ss;
-               DMFlagMat *faceFlags = ccgdm->faceFlags;
-               int new_matnr;
-               bool draw_smooth;
+               const DMFlagMat *faceFlags = ccgdm->faceFlags;
+               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 i, current_patch = 0;
+               int mat_nr = -1;
+               bool draw_smooth = false;
+               int start_draw_patch = -1, num_draw_patches = 0;
                if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL) == false)) {
                        return;
                }
-               /* TODO(sergey): Single matierial currently. */
-               if (faceFlags) {
-                       draw_smooth = (faceFlags[0].flag & ME_SMOOTH);
-                       new_matnr = (faceFlags[0].mat_nr + 1);
-               }
-               else {
-                       draw_smooth = true;
-                       new_matnr = 1;
+               if (setMaterial == NULL) {
+                       ccgSubSurf_drawGLMesh(ss,
+                                             true,
+                                             -1,
+                                             -1);
+                       return;
                }
-               if (setMaterial && setMaterial(new_matnr, NULL)) {
-                       glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
-                       ccgSubSurf_drawGLMesh(ss, true, -1, -1);
+               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;
+                       int new_matnr;
+                       bool new_draw_smooth;
+                       if (faceFlags) {
+                               new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
+                               new_matnr = (faceFlags[i].mat_nr + 1);
+                       }
+                       else {
+                               new_draw_smooth = true;
+                               new_matnr = 1;
+                       }
+                       if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
+                               if (num_draw_patches != 0) {
+                                       bool do_draw = setMaterial == NULL ||
+                                                      setMaterial(mat_nr, NULL);
+                                       if (do_draw) {
+                                               glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
+                                               ccgSubSurf_drawGLMesh(ss,
+                                                                     true,
+                                                                     start_draw_patch,
+                                                                     num_draw_patches);
+                                       }
+                               }
+                               start_draw_patch = current_patch;
+                               num_draw_patches = num_patches;
+                               mat_nr = new_matnr;
+                               draw_smooth = new_draw_smooth;
+                       }
+                       else {
+                               num_draw_patches += num_patches;
+                       }
+                       current_patch += num_patches;
+               }
+               if (num_draw_patches != 0) {
+                       bool do_draw = setMaterial(mat_nr, NULL);
+                       if (do_draw) {
+                               glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
+                               ccgSubSurf_drawGLMesh(ss,
+                                                     true,
+                                                     start_draw_patch,
+                                                     num_draw_patches);
+                       }
                }
                return;
        }
@@ -4528,8 +4576,7 @@ static void set_ccgdm_gpu_geometry(CCGDerivedMesh *ccgdm, DerivedMesh *dm)
 
        for (index = 0; index < totface; index++) {
                faceFlags->flag = mpoly ?  mpoly[index].flag : 0;
-               /* faceFlags->mat_nr = mpoly ? mpoly[index].mat_nr : 0; */
-               faceFlags->mat_nr = 0;
+               faceFlags->mat_nr = mpoly ? mpoly[index].mat_nr : 0;
                faceFlags++;
        }