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
parent98970f71fe95e6b842582f5b71f3081798a8f54a (diff)
OpenSubdiv: Lay down fundamentals to support multiple UV maps
-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
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.h2
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c6
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c14
7 files changed, 113 insertions, 73 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);
}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
index a825cffe7a0..72f386bf246 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -205,7 +205,7 @@ void ccgSubSurf_checkTopologyChanged(CCGSubSurf *ss, struct DerivedMesh *dm);
void ccgSubSurf_prepareTopologyRefiner(CCGSubSurf *ss, struct DerivedMesh *dm);
/* Make sure GL mesh exists, up to date and ready to draw. */
-bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl);
+bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl, int active_uv_index);
/* Draw given partitions of the GL mesh.
*
diff --git a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
index c715c1fa1ee..9dc1a71adab 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf_opensubdiv.c
@@ -215,7 +215,9 @@ static void ccgSubSurf__updateGLMeshCoords(CCGSubSurf *ss)
ss->osd_num_coarse_coords);
}
-bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl)
+bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss,
+ bool use_osd_glsl,
+ int active_uv_index)
{
int compute_type;
@@ -288,7 +290,7 @@ bool ccgSubSurf_prepareGLMesh(CCGSubSurf *ss, bool use_osd_glsl)
ss->osd_coarse_coords_invalid = false;
}
- openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl);
+ openSubdiv_osdGLMeshDisplayPrepare(use_osd_glsl, active_uv_index);
return true;
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index b9efe23a4b3..c6e20b995ba 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -1801,7 +1801,7 @@ static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEd
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
/* TODO(sergey): We currently only support all edges drawing. */
- if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true)) {
+ if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
}
return;
@@ -2638,7 +2638,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
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)) {
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, setMaterial != NULL, -1) == false)) {
return;
}
if (setMaterial == NULL) {
@@ -2750,7 +2750,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
bool draw_smooth = false;
int start_draw_patch = -1, num_draw_patches = 0;
GPU_draw_update_fvar_offset(dm);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false) == false)) {
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, false, -1) == false)) {
return;
}
for (i = 0; i < num_base_faces; ++i) {
@@ -3193,7 +3193,7 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
int new_matnr;
bool draw_smooth;
GPU_draw_update_fvar_offset(dm);
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true) == false)) {
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
return;
}
/* TODO(sergey): Single matierial currently. */
@@ -3401,7 +3401,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true) == false)) {
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
return;
}
if (drawParams == NULL) {
@@ -3639,7 +3639,7 @@ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
*/
glColor3f(0.8f, 0.8f, 0.8f);
}
- if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true) == false)) {
+ if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
return;
}
if (faceFlags) {
@@ -3838,7 +3838,7 @@ static void ccgDM_drawMappedEdges(DerivedMesh *dm,
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
/* TODO(sergey): Only draw edges from base mesh. */
- if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true)) {
+ if (ccgSubSurf_prepareGLMesh(ccgdm->ss, true, -1)) {
if (!setDrawOptions || (setDrawOptions(userData, 0) != DM_DRAW_OPTION_SKIP)) {
ccgSubSurf_drawGLMesh(ccgdm->ss, false, -1, -1);
}