Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2016-07-22 15:46:13 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2016-07-22 15:56:15 +0300
commit48c4b700dce0b326e1b905e133c0db1217a5cae0 (patch)
treed520f9d02eeaa7deb7774ed4dca84bdedd0d7914 /intern/opensubdiv
parent98970f71fe95e6b842582f5b71f3081798a8f54a (diff)
OpenSubdiv: Lay down fundamentals to support multiple UV maps
Diffstat (limited to 'intern/opensubdiv')
-rw-r--r--intern/opensubdiv/opensubdiv_capi.cc78
-rw-r--r--intern/opensubdiv/opensubdiv_capi.h6
-rw-r--r--intern/opensubdiv/opensubdiv_converter.cc8
-rw-r--r--intern/opensubdiv/opensubdiv_gpu_capi.cc72
4 files changed, 101 insertions, 63 deletions
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<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;
- 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<FVarVertex> 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<FVarVertex> 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<FVarVertex *>(&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<FVarVertex *>(&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<FVarVertex *>(&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<FVarVertex *>(&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<float> 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<TopologyRefinerData>::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<TopologyRefinerData>::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<float> 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<size_t> 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);
}