OpenSubdiv: Lay down fundamentals to support multiple UV maps
This commit is contained in:
parent
98970f71fe
commit
48c4b700dc
|
@ -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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
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);
|
||||
|
||||
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++]);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue