From f1e68474e051667b85ac804bded8fa2c8e0ff374 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 25 Aug 2015 15:05:28 +0200 Subject: OpenSubdiv: Support for multiple materials in solid shading mode 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 | 4 +- intern/opensubdiv/opensubdiv_converter.cc | 11 +++ intern/opensubdiv/opensubdiv_converter_capi.h | 6 +- intern/opensubdiv/opensubdiv_gpu_capi.cc | 76 +++++++++------------ source/blender/blenkernel/intern/CCGSubSurf.h | 6 ++ .../blenkernel/intern/CCGSubSurf_opensubdiv.c | 25 +++++++ source/blender/blenkernel/intern/subsurf_ccg.c | 79 +++++++++++++++++----- 7 files changed, 144 insertions(+), 63 deletions(-) diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h index c86e739f12b..c09d0326264 100644 --- a/intern/opensubdiv/opensubdiv_capi.h +++ b/intern/opensubdiv/opensubdiv_capi.h @@ -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); diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc index 09880742895..5d43cafd1f3 100644 --- a/intern/opensubdiv/opensubdiv_converter.cc +++ b/intern/opensubdiv/opensubdiv_converter.cc @@ -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) diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h index 7c96d3d8b96..ac1e8301a42 100644 --- a/intern/opensubdiv/opensubdiv_converter_capi.h +++ b/intern/opensubdiv/opensubdiv_converter_capi.h @@ -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); diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc index 9498f936b6b..803265dbe28 100644 --- a/intern/opensubdiv/opensubdiv_gpu_capi.cc +++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc @@ -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); diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h index e9ad4c52531..a825cffe7a0 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.h +++ b/source/blender/blenkernel/intern/CCGSubSurf.h @@ -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. */ diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c index eb7c3bf6ffd..fcc46308efa 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c @@ -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; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index e38d62cd9bc..867065b060d 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -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++; } -- cgit v1.2.3