diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc index 0463982fdf6..e04b23725b1 100644 --- a/intern/opensubdiv/opensubdiv_capi.cc +++ b/intern/opensubdiv/opensubdiv_capi.cc @@ -67,6 +67,7 @@ #include #include +#include #include "opensubdiv_intern.h" #include "opensubdiv_topology_refiner.h" @@ -143,11 +144,69 @@ typedef Mesh 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 uvs, + std::vector &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 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(&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(&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 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: \ diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h index b40505b197d..0410083304e 100644 --- a/intern/opensubdiv/opensubdiv_capi.h +++ b/intern/opensubdiv/opensubdiv_capi.h @@ -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); diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc index e718d6b4dc8..e6c8985e947 100644 --- a/intern/opensubdiv/opensubdiv_converter.cc +++ b/intern/opensubdiv/opensubdiv_converter.cc @@ -488,6 +488,39 @@ inline void TopologyRefinerFactory::reportInvalidTopology( printf("OpenSubdiv Error: %s\n", msg); } +template <> +inline bool TopologyRefinerFactory::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::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; } diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h index 1f09fa074d8..47c8dab49de 100644 --- a/intern/opensubdiv/opensubdiv_converter_capi.h +++ b/intern/opensubdiv/opensubdiv_converter_capi.h @@ -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; diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc index 63cf390276f..84984e8bd7e 100644 --- a/intern/opensubdiv/opensubdiv_gpu_capi.cc +++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc @@ -42,6 +42,10 @@ #include #include +#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 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); + } +} diff --git a/intern/opensubdiv/opensubdiv_topology_refiner.h b/intern/opensubdiv/opensubdiv_topology_refiner.h index 5c299ac5df5..b00f6a54201 100644 --- a/intern/opensubdiv/opensubdiv_topology_refiner.h +++ b/intern/opensubdiv/opensubdiv_topology_refiner.h @@ -30,6 +30,12 @@ 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 uvs; } OpenSubdiv_TopologyRefinerDescr; #endif /* __OPENSUBDIV_TOPOLOGY_REFINER_H__ */ diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index 828a6bb16ac..c4886a21740 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -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; diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h index 0cdf3acf075..7e8059e62fc 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h +++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h @@ -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 }; diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c index 2bb55c2d1ed..c715c1fa1ee 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c @@ -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; } diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c index c4317f4d740..72e5f9f1346 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv_converter.c @@ -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; } diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index f73dbd8078f..b9efe23a4b3 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -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); diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 3c028ff0805..8ec932f4184 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -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);