From 48c4b700dce0b326e1b905e133c0db1217a5cae0 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 22 Jul 2016 14:46:13 +0200 Subject: OpenSubdiv: Lay down fundamentals to support multiple UV maps --- intern/opensubdiv/opensubdiv_capi.cc | 78 ++++++++++++++++--------------- intern/opensubdiv/opensubdiv_capi.h | 6 ++- intern/opensubdiv/opensubdiv_converter.cc | 8 ++-- intern/opensubdiv/opensubdiv_gpu_capi.cc | 72 ++++++++++++++++++++-------- 4 files changed, 101 insertions(+), 63 deletions(-) (limited to 'intern/opensubdiv') diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc index 9093fd87a44..ab904953c70 100644 --- a/intern/opensubdiv/opensubdiv_capi.cc +++ b/intern/opensubdiv/opensubdiv_capi.cc @@ -160,45 +160,49 @@ struct FVarVertex { 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; - const int num_uvs = refiner.GetLevel(0).GetNumFVarValues(0) * 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 primvar_refiner(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], num_uvs * 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); - primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); - src = dst; + const int max_level = refiner.GetMaxLevel(); + size_t fvar_data_offset = 0, values_offset = 0; + for (int channel = 0; channel < refiner.GetNumFVarChannels(); ++channel) { + const int num_values = refiner.GetLevel(0).GetNumFVarValues(0) * 2, + num_values_max = refiner.GetLevel(max_level).GetNumFVarValues(channel), + num_values_total = refiner.GetNumFVarValuesTotal(channel); + if (num_values_total <= 0) { + continue; + } + OpenSubdiv::Far::PrimvarRefiner primvar_refiner(refiner); + if (refiner.IsUniform()) { + /* For uniform we only keep the highest level of refinement. */ + fvar_data.resize(fvar_data.size() + num_values_max * fvar_width); + std::vector buffer(num_values_total - num_values_max); + FVarVertex *src = &buffer[0]; + memcpy(src, &uvs[values_offset], num_values * 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); + primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); + src = dst; + } + FVarVertex *dst = reinterpret_cast(&fvar_data[fvar_data_offset]); + primvar_refiner.InterpolateFaceVarying(max_level, src, dst, channel); + fvar_data_offset += num_values_max * fvar_width; + } else { + /* For adaptive we keep all levels. */ + fvar_data.resize(fvar_data.size() + num_values_total * fvar_width); + FVarVertex *src = reinterpret_cast(&fvar_data[fvar_data_offset]); + memcpy(src, &uvs[values_offset], num_values * sizeof(float)); + for (int level = 1; level <= max_level; ++level) { + FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel); + primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); + src = dst; + } + fvar_data_offset += num_values_total * fvar_width; } - FVarVertex *dst = reinterpret_cast(&fvar_data[0]); - primvar_refiner.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], num_uvs * sizeof(float)); - for (int level = 1; level <= max_level; ++level) { - FVarVertex *dst = src + refiner.GetLevel(level-1).GetNumFVarValues(channel); - primvar_refiner.InterpolateFaceVarying(level, src, dst, channel); - src = dst; - } - } + values_offset += num_values; + } } } // namespace @@ -275,7 +279,7 @@ struct OpenSubdiv_GLMesh *openSubdiv_createOsdGLMeshFromTopologyRefiner( if (refiner->GetNumFVarChannels() > 0) { std::vector fvar_data; interpolate_fvar_data(*refiner, topology_refiner->uvs, fvar_data); - openSubdiv_osdGLAllocFVar(gl_mesh, &fvar_data[0]); + openSubdiv_osdGLAllocFVar(topology_refiner, gl_mesh, &fvar_data[0]); } else { gl_mesh->fvar_data = NULL; diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h index 0410083304e..c3a194813e6 100644 --- a/intern/opensubdiv/opensubdiv_capi.h +++ b/intern/opensubdiv/opensubdiv_capi.h @@ -131,7 +131,8 @@ 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); +void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl, + int active_uv_index); /* Draw specified patches. */ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh, @@ -139,7 +140,8 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh, int start_patch, int num_patches); -void openSubdiv_osdGLAllocFVar(OpenSubdiv_GLMesh *gl_mesh, +void openSubdiv_osdGLAllocFVar(struct OpenSubdiv_TopologyRefinerDescr *topology_refiner, + OpenSubdiv_GLMesh *gl_mesh, const float *fvar_data); void openSubdiv_osdGLDestroyFVar(OpenSubdiv_GLMesh *gl_mesh); diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc index f637f514bf4..9b2fb19808c 100644 --- a/intern/opensubdiv/opensubdiv_converter.cc +++ b/intern/opensubdiv/opensubdiv_converter.cc @@ -508,12 +508,14 @@ inline bool TopologyRefinerFactory::assignFaceVaryingTopolo return true; } const int num_faces = getNumBaseFaces(refiner); + size_t uvs_offset = 0; for (int layer = 0; layer < num_layers; ++layer) { conv.precalc_uv_layer(&conv, layer); const int num_uvs = conv.get_num_uvs(&conv); /* Fill in UV coordinates. */ - cb_data.uvs->resize(num_uvs * 2); - conv.get_uvs(&conv, &cb_data.uvs->at(0)); + cb_data.uvs->resize(cb_data.uvs->size() + num_uvs * 2); + conv.get_uvs(&conv, &cb_data.uvs->at(uvs_offset)); + uvs_offset += num_uvs * 2; /* Fill in per-corner index of the UV. */ const int channel = createBaseFVarChannel(refiner, num_uvs); for (int face = 0; face < num_faces; ++face) { @@ -528,8 +530,6 @@ inline bool TopologyRefinerFactory::assignFaceVaryingTopolo } } conv.finish_uv_layer(&conv); - /* TODO(sergey): Single layer only for now. */ - break; } return true; } diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc index 8329062c452..a7c42aea07f 100644 --- a/intern/opensubdiv/opensubdiv_gpu_capi.cc +++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc @@ -45,6 +45,7 @@ #include "MEM_guardedalloc.h" #include "opensubdiv_capi.h" +#include "opensubdiv_topology_refiner.h" using OpenSubdiv::Osd::GLMeshInterface; @@ -82,6 +83,7 @@ typedef struct Transform { } Transform; static bool g_use_osd_glsl = false; +static int g_active_uv_index = 0; static GLuint g_flat_fill_solid_program = 0; static GLuint g_flat_fill_texture2d_program = 0; @@ -110,25 +112,44 @@ struct OpenSubdiv_GLMeshFVarData glDeleteTextures(1, &texture_buffer); } texture_buffer = 0; + channel_offsets.clear(); } - void Create(const OpenSubdiv::Far::PatchTable *patch_table, + void Create(const OpenSubdiv::Far::TopologyRefiner *refiner, + const OpenSubdiv::Far::PatchTable *patch_table, int fvar_width, const float *fvar_src_data) { Release(); - OpenSubdiv::Far::ConstIndexArray indices = patch_table->GetFVarValues(); - // expand fvardata to per-patch array + /* Expand fvar data to per-patch array */ + const int max_level = refiner->GetMaxLevel(); + const int num_channels = patch_table->GetNumFVarChannels(); std::vector data; - data.reserve(indices.size() * fvar_width); - - for (int fvert = 0; fvert < (int)indices.size(); ++fvert) { - int index = indices[fvert] * fvar_width; - for (int i = 0; i < fvar_width; ++i) { - data.push_back(fvar_src_data[index++]); + size_t fvar_data_offset = 0; + channel_offsets.resize(num_channels); + for (int channel = 0; channel < num_channels; ++channel) { + OpenSubdiv::Far::ConstIndexArray indices = + patch_table->GetFVarValues(channel); + + channel_offsets[channel] = data.size(); + data.reserve(data.size() + indices.size() * fvar_width); + + for (int fvert = 0; fvert < (int)indices.size(); ++fvert) { + int index = indices[fvert] * fvar_width; + for (int i = 0; i < fvar_width; ++i) { + data.push_back(fvar_src_data[fvar_data_offset + index++]); + } + } + if (refiner->IsUniform()) { + const int num_values_max = refiner->GetLevel(max_level).GetNumFVarValues(channel); + fvar_data_offset += num_values_max * fvar_width; + } else { + const int num_values_total = refiner->GetNumFVarValuesTotal(channel); + fvar_data_offset += num_values_total * fvar_width; } } + GLuint buffer; glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); @@ -144,6 +165,7 @@ struct OpenSubdiv_GLMeshFVarData glDeleteBuffers(1, &buffer); } GLuint texture_buffer; + std::vector channel_offsets; }; /* TODO(sergey): This is actually duplicated code from BLI. */ @@ -415,8 +437,14 @@ void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program) } /* See notes below about why we use such values. */ + /* TOO(sergey): Get proper value for FVar width. */ glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 2); - glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); + if (gl_mesh->fvar_data->channel_offsets.size() > 0 && g_active_uv_index >= 0) { + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), + gl_mesh->fvar_data->channel_offsets[g_active_uv_index]); + } else { + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); + } } } /* namespace */ @@ -503,9 +531,11 @@ void openSubdiv_osdGLDisplayDeinit(void) } } -void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl) +void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl, + int active_uv_index) { - g_use_osd_glsl = use_osd_glsl != 0; + g_active_uv_index = active_uv_index; + g_use_osd_glsl = (use_osd_glsl != 0); /* Update transformation matrices. */ glGetFloatv(GL_PROJECTION_MATRIX, g_transform.projection_matrix); @@ -594,12 +624,12 @@ static GLuint prepare_patchDraw(OpenSubdiv_GLMesh *gl_mesh, location = glGetUniformLocation(program, "osd_active_uv_offset"); if (location != -1) { - /* 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); + if (gl_mesh->fvar_data->channel_offsets.size() > 0 && g_active_uv_index >= 0) { + glUniform1i(location, + gl_mesh->fvar_data->channel_offsets[g_active_uv_index]); + } else { + glUniform1i(location, 0); + } } } } @@ -756,13 +786,15 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh, finish_patchDraw(fill_quads != 0); } -void openSubdiv_osdGLAllocFVar(OpenSubdiv_GLMesh *gl_mesh, +void openSubdiv_osdGLAllocFVar(OpenSubdiv_TopologyRefinerDescr *topology_refiner, + 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(), + gl_mesh->fvar_data->Create(topology_refiner->osd_refiner, + mesh->GetFarPatchTable(), 2, fvar_data); } -- cgit v1.2.3