OpenSubdiv: Initial work to support UV maps in textured OSD viewport

A bit work in progress, currently the following limitations:

- Texture shading only, Material shading will come later

- No UVs subdivision yet

- Always uses active UV and currently changing active UV will
  not properly update the viewport.

Well, need to start somewhere :)
This commit is contained in:
Sergey Sharybin 2016-07-19 09:28:54 +02:00
parent 9a0634a253
commit f0f60d775d
12 changed files with 403 additions and 104 deletions

@ -67,6 +67,7 @@
#include <opensubdiv/osd/glPatchTable.h>
#include <opensubdiv/far/stencilTable.h>
#include <opensubdiv/far/primvarRefiner.h>
#include "opensubdiv_intern.h"
#include "opensubdiv_topology_refiner.h"
@ -143,11 +144,69 @@ typedef Mesh<GLVertexBuffer,
GLPatchTable> 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<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;
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<FVarVertex> 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<FVarVertex *>(&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<FVarVertex *>(&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<float> 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: \

@ -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);

@ -488,6 +488,39 @@ inline void TopologyRefinerFactory<OpenSubdiv_Converter>::reportInvalidTopology(
printf("OpenSubdiv Error: %s\n", msg);
}
template <>
inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::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<OpenSubdiv_Converter>::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;
}

@ -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;

@ -42,6 +42,10 @@
#include <opensubdiv/osd/cpuGLVertexBuffer.h>
#include <opensubdiv/osd/cpuEvaluator.h>
#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<float> 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);
}
}

@ -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<float> uvs;
} OpenSubdiv_TopologyRefinerDescr;
#endif /* __OPENSUBDIV_TOPOLOGY_REFINER_H__ */

@ -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;

@ -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
};

@ -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;
}

@ -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;
}

@ -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);

@ -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);