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
path: root/intern
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2016-07-19 10:28:54 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2016-07-20 15:16:38 +0300
commitf0f60d775def20ff3a3699704b33c66712d50c6a (patch)
treec9c4ec927a9eb447e1a0f9753a74eb99c470d5b5 /intern
parent9a0634a253421c02dbb6d2864db49e4d382ea2a3 (diff)
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 :)
Diffstat (limited to 'intern')
-rw-r--r--intern/opensubdiv/opensubdiv_capi.cc73
-rw-r--r--intern/opensubdiv/opensubdiv_capi.h13
-rw-r--r--intern/opensubdiv/opensubdiv_converter.cc72
-rw-r--r--intern/opensubdiv/opensubdiv_converter_capi.h8
-rw-r--r--intern/opensubdiv/opensubdiv_gpu_capi.cc129
-rw-r--r--intern/opensubdiv/opensubdiv_topology_refiner.h6
6 files changed, 264 insertions, 37 deletions
diff --git a/intern/opensubdiv/opensubdiv_capi.cc b/intern/opensubdiv/opensubdiv_capi.cc
index 0463982fdf6..e04b23725b1 100644
--- a/intern/opensubdiv/opensubdiv_capi.cc
+++ b/intern/opensubdiv/opensubdiv_capi.cc
@@ -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: \
diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h
index b40505b197d..0410083304e 100644
--- a/intern/opensubdiv/opensubdiv_capi.h
+++ b/intern/opensubdiv/opensubdiv_capi.h
@@ -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);
diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc
index e718d6b4dc8..e6c8985e947 100644
--- a/intern/opensubdiv/opensubdiv_converter.cc
+++ b/intern/opensubdiv/opensubdiv_converter.cc
@@ -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;
}
diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h
index 1f09fa074d8..47c8dab49de 100644
--- a/intern/opensubdiv/opensubdiv_converter_capi.h
+++ b/intern/opensubdiv/opensubdiv_converter_capi.h
@@ -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;
diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc
index 63cf390276f..84984e8bd7e 100644
--- a/intern/opensubdiv/opensubdiv_gpu_capi.cc
+++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc
@@ -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);
+ }
+}
diff --git a/intern/opensubdiv/opensubdiv_topology_refiner.h b/intern/opensubdiv/opensubdiv_topology_refiner.h
index 5c299ac5df5..b00f6a54201 100644
--- a/intern/opensubdiv/opensubdiv_topology_refiner.h
+++ b/intern/opensubdiv/opensubdiv_topology_refiner.h
@@ -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__ */