diff options
Diffstat (limited to 'intern/opensubdiv/internal/opensubdiv_gpu.cc')
-rw-r--r-- | intern/opensubdiv/internal/opensubdiv_gpu.cc | 788 |
1 files changed, 788 insertions, 0 deletions
diff --git a/intern/opensubdiv/internal/opensubdiv_gpu.cc b/intern/opensubdiv/internal/opensubdiv_gpu.cc new file mode 100644 index 00000000000..d28b48ddd18 --- /dev/null +++ b/intern/opensubdiv/internal/opensubdiv_gpu.cc @@ -0,0 +1,788 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Sergey Sharybin + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "opensubdiv_capi.h" + +#ifdef _MSC_VER +# include "iso646.h" +#endif + +#include <cstdio> +#include <cmath> +#include <GL/glew.h> + +#include <opensubdiv/osd/glMesh.h> + +#ifdef OPENSUBDIV_HAS_CUDA +# include <opensubdiv/osd/cudaGLVertexBuffer.h> +#endif /* OPENSUBDIV_HAS_CUDA */ + +#include <opensubdiv/osd/cpuGLVertexBuffer.h> +#include <opensubdiv/osd/cpuEvaluator.h> + +#include "MEM_guardedalloc.h" + +#include "opensubdiv_capi.h" +#include "opensubdiv_gl_mesh.h" +#include "opensubdiv_topology_refiner.h" + +using OpenSubdiv::Osd::GLMeshInterface; + +extern "C" char datatoc_gpu_shader_opensubdiv_vertex_glsl[]; +extern "C" char datatoc_gpu_shader_opensubdiv_geometry_glsl[]; +extern "C" char datatoc_gpu_shader_opensubdiv_fragment_glsl[]; + +/* TODO(sergey): This is bit of bad level calls :S */ +extern "C" { +void copy_m3_m3(float m1[3][3], float m2[3][3]); +void copy_m3_m4(float m1[3][3], float m2[4][4]); +void adjoint_m3_m3(float m1[3][3], float m[3][3]); +float determinant_m3_array(float m[3][3]); +bool invert_m3_m3(float m1[3][3], float m2[3][3]); +bool invert_m3(float m[3][3]); +void transpose_m3(float mat[3][3]); +} + +#define MAX_LIGHTS 8 +#define SUPPORT_COLOR_MATERIAL + +typedef struct Light { + float position[4]; + float ambient[4]; + float diffuse[4]; + float specular[4]; + float spot_direction[4]; +#ifdef SUPPORT_COLOR_MATERIAL + float constant_attenuation; + float linear_attenuation; + float quadratic_attenuation; + float spot_cutoff; + float spot_exponent; + float spot_cos_cutoff; + float pad, pad2; +#endif +} Light; + +typedef struct Lighting { + Light lights[MAX_LIGHTS]; + int num_enabled; +} Lighting; + +typedef struct Transform { + float projection_matrix[16]; + float model_view_matrix[16]; + float normal_matrix[9]; +} 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; +static GLuint g_smooth_fill_solid_program = 0; +static GLuint g_smooth_fill_texture2d_program = 0; + +static GLuint g_flat_fill_solid_shadeless_program = 0; +static GLuint g_flat_fill_texture2d_shadeless_program = 0; +static GLuint g_smooth_fill_solid_shadeless_program = 0; +static GLuint g_smooth_fill_texture2d_shadeless_program = 0; + +static GLuint g_wireframe_program = 0; + +static GLuint g_lighting_ub = 0; +static Lighting g_lighting_data; +static Transform g_transform; + +struct OpenSubdiv_GLMeshFVarData +{ + OpenSubdiv_GLMeshFVarData() : + texture_buffer(0), offset_buffer(0) { + } + + ~OpenSubdiv_GLMeshFVarData() + { + Release(); + } + + void Release() + { + if (texture_buffer) { + glDeleteTextures(1, &texture_buffer); + } + if (offset_buffer) { + glDeleteTextures(1, &offset_buffer); + } + texture_buffer = 0; + offset_buffer = 0; + fvar_width = 0; + channel_offsets.clear(); + } + + void Create(const OpenSubdiv::Far::TopologyRefiner *refiner, + const OpenSubdiv::Far::PatchTable *patch_table, + int fvar_width, + const float *fvar_src_data) + { + Release(); + + this->fvar_width = fvar_width; + + /* Expand fvar data to per-patch array */ + const int max_level = refiner->GetMaxLevel(); + const int num_channels = patch_table->GetNumFVarChannels(); + std::vector<float> data; + int 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); + 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); + + glDeleteBuffers(1, &buffer); + + glGenBuffers(1, &buffer); + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, channel_offsets.size()*sizeof(int), + &channel_offsets[0], GL_STATIC_DRAW); + + glGenTextures(1, &offset_buffer); + glBindTexture(GL_TEXTURE_BUFFER, offset_buffer); + glTexBuffer(GL_TEXTURE_BUFFER, GL_R32I, buffer); + glBindTexture(GL_TEXTURE_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + GLuint texture_buffer; + GLuint offset_buffer; + std::vector<int> channel_offsets; + int fvar_width; +}; + +namespace { + +GLuint compileShader(GLenum shaderType, + const char *version, + const char *define, + const char *source) +{ + const char *sources[] = { + version, + define, +#ifdef SUPPORT_COLOR_MATERIAL + "#define SUPPORT_COLOR_MATERIAL\n", +#else + "", +#endif + source, + }; + + GLuint shader = glCreateShader(shaderType); + glShaderSource(shader, 4, sources, NULL); + glCompileShader(shader); + + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) { + GLchar emsg[1024]; + glGetShaderInfoLog(shader, sizeof(emsg), 0, emsg); + fprintf(stderr, "Error compiling GLSL: %s\n", emsg); + fprintf(stderr, "Version: %s\n", version); + fprintf(stderr, "Defines: %s\n", define); + fprintf(stderr, "Source: %s\n", source); + return 0; + } + + return shader; +} + +GLuint linkProgram(const char *version, const char *define) +{ + GLuint vertexShader = compileShader(GL_VERTEX_SHADER, + version, + define, + datatoc_gpu_shader_opensubdiv_vertex_glsl); + if (vertexShader == 0) { + return 0; + } + GLuint geometryShader = compileShader(GL_GEOMETRY_SHADER, + version, + define, + datatoc_gpu_shader_opensubdiv_geometry_glsl); + if (geometryShader == 0) { + return 0; + } + GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, + version, + define, + datatoc_gpu_shader_opensubdiv_fragment_glsl ); + if (fragmentShader == 0) { + return 0; + } + + GLuint program = glCreateProgram(); + + glAttachShader(program, vertexShader); + glAttachShader(program, geometryShader); + glAttachShader(program, fragmentShader); + + glBindAttribLocation(program, 0, "position"); + glBindAttribLocation(program, 1, "normal"); + + glLinkProgram(program); + + glDeleteShader(vertexShader); + glDeleteShader(geometryShader); + glDeleteShader(fragmentShader); + + GLint status; + glGetProgramiv(program, GL_LINK_STATUS, &status); + if (status == GL_FALSE) { + GLchar emsg[1024]; + glGetProgramInfoLog(program, sizeof(emsg), 0, emsg); + fprintf(stderr, "Error linking GLSL program : %s\n", emsg); + fprintf(stderr, "Defines: %s\n", define); + glDeleteProgram(program); + return 0; + } + + glUniformBlockBinding(program, + glGetUniformBlockIndex(program, "Lighting"), + 0); + + if (GLEW_VERSION_4_1) { + glProgramUniform1i(program, + glGetUniformLocation(program, "texture_buffer"), + 0); /* GL_TEXTURE0 */ + + glProgramUniform1i(program, + glGetUniformLocation(program, "FVarDataOffsetBuffer"), + 30); /* GL_TEXTURE30 */ + + glProgramUniform1i(program, + glGetUniformLocation(program, "FVarDataBuffer"), + 31); /* GL_TEXTURE31 */ + } + else { + glUseProgram(program); + glUniform1i(glGetUniformLocation(program, "texture_buffer"), 0); /* GL_TEXTURE0 */ + glUniform1i(glGetUniformLocation(program, "FVarDataOffsetBuffer"), 30); /* GL_TEXTURE30 */ + glUniform1i(glGetUniformLocation(program, "FVarDataBuffer"), 31); /* GL_TEXTURE31 */ + glUseProgram(0); + } + + return program; +} + +void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program) +{ + glUseProgram(program); + + /* Matrices */ + glUniformMatrix4fv(glGetUniformLocation(program, "modelViewMatrix"), + 1, false, + g_transform.model_view_matrix); + glUniformMatrix4fv(glGetUniformLocation(program, "projectionMatrix"), + 1, false, + g_transform.projection_matrix); + glUniformMatrix3fv(glGetUniformLocation(program, "normalMatrix"), + 1, false, + g_transform.normal_matrix); + + /* Lighting */ + glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub); + glBufferSubData(GL_UNIFORM_BUFFER, + 0, sizeof(g_lighting_data), &g_lighting_data); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + glBindBufferBase(GL_UNIFORM_BUFFER, 0, g_lighting_ub); + + /* Color */ + { + /* TODO: stop using glGetMaterial */ + float color[4]; + glGetMaterialfv(GL_FRONT, GL_DIFFUSE, color); + glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color); + + glGetMaterialfv(GL_FRONT, GL_SPECULAR, color); + glUniform4fv(glGetUniformLocation(program, "specular"), 1, color); + + glGetMaterialfv(GL_FRONT, GL_SHININESS, color); + glUniform1f(glGetUniformLocation(program, "shininess"), color[0]); + } + + /* Face-vertex data */ + if (gl_mesh->fvar_data != NULL) { + if (gl_mesh->fvar_data->texture_buffer) { + glActiveTexture(GL_TEXTURE31); + glBindTexture(GL_TEXTURE_BUFFER, gl_mesh->fvar_data->texture_buffer); + glActiveTexture(GL_TEXTURE0); + } + + if (gl_mesh->fvar_data->offset_buffer) { + glActiveTexture(GL_TEXTURE30); + glBindTexture(GL_TEXTURE_BUFFER, gl_mesh->fvar_data->offset_buffer); + glActiveTexture(GL_TEXTURE0); + } + + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), + gl_mesh->fvar_data->fvar_width); + 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); + } + } else { + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0); + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); + } +} + +} /* namespace */ + +bool openSubdiv_osdGLDisplayInit(void) +{ + static bool need_init = true; + static bool init_success = false; + + if (need_init) { + /* TODO: update OSD drawing to OpenGL 3.3 core, then remove following line */ + return false; + + const char *version = ""; + if (GLEW_VERSION_3_2) { + version = "#version 150 compatibility\n"; + } + else if (GLEW_VERSION_3_1) { + version = "#version 140\n" + "#extension GL_ARB_compatibility: enable\n"; + } + else { + version = "#version 130\n"; + /* minimum supported for OpenSubdiv */ + } + + g_flat_fill_solid_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define FLAT_SHADING\n"); + g_flat_fill_texture2d_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define USE_TEXTURE_2D\n" + "#define FLAT_SHADING\n"); + g_smooth_fill_solid_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define SMOOTH_SHADING\n"); + g_smooth_fill_texture2d_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_LIGHTING\n" + "#define USE_TEXTURE_2D\n" + "#define SMOOTH_SHADING\n"); + + g_flat_fill_solid_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define FLAT_SHADING\n"); + g_flat_fill_texture2d_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_TEXTURE_2D\n" + "#define FLAT_SHADING\n"); + g_smooth_fill_solid_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define SMOOTH_SHADING\n"); + g_smooth_fill_texture2d_shadeless_program = linkProgram( + version, + "#define USE_COLOR_MATERIAL\n" + "#define USE_TEXTURE_2D\n" + "#define SMOOTH_SHADING\n"); + + g_wireframe_program = linkProgram( + version, + "#define WIREFRAME\n"); + + glGenBuffers(1, &g_lighting_ub); + glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub); + glBufferData(GL_UNIFORM_BUFFER, + sizeof(g_lighting_data), NULL, GL_STATIC_DRAW); + + need_init = false; + init_success = g_flat_fill_solid_program != 0 && + g_flat_fill_texture2d_program != 0 && + g_smooth_fill_solid_program != 0 && + g_smooth_fill_texture2d_program != 0 && + g_wireframe_program; + } + return init_success; +} + +void openSubdiv_osdGLDisplayDeinit(void) +{ + if (g_lighting_ub != 0) { + glDeleteBuffers(1, &g_lighting_ub); + } +#define SAFE_DELETE_PROGRAM(program) \ + do { \ + if (program) { \ + glDeleteProgram(program); \ + } \ + } while (false) + + SAFE_DELETE_PROGRAM(g_flat_fill_solid_program); + SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_solid_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_program); + SAFE_DELETE_PROGRAM(g_flat_fill_solid_shadeless_program); + SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_shadeless_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_solid_shadeless_program); + SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_shadeless_program); + SAFE_DELETE_PROGRAM(g_wireframe_program); + +#undef SAFE_DELETE_PROGRAM +} + +void openSubdiv_osdGLMeshDisplayPrepare(int use_osd_glsl, + int active_uv_index) +{ + 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); + glGetFloatv(GL_MODELVIEW_MATRIX, g_transform.model_view_matrix); + + copy_m3_m4((float (*)[3])g_transform.normal_matrix, + (float (*)[4])g_transform.model_view_matrix); + invert_m3((float (*)[3])g_transform.normal_matrix); + transpose_m3((float (*)[3])g_transform.normal_matrix); + + /* Update OpenGL lights positions, colors etc. */ + g_lighting_data.num_enabled = 0; + for (int i = 0; i < MAX_LIGHTS; ++i) { + GLboolean enabled; + glGetBooleanv(GL_LIGHT0 + i, &enabled); + if (enabled) { + g_lighting_data.num_enabled++; + } + + /* TODO: stop using glGetLight */ + glGetLightfv(GL_LIGHT0 + i, + GL_POSITION, + g_lighting_data.lights[i].position); + glGetLightfv(GL_LIGHT0 + i, + GL_AMBIENT, + g_lighting_data.lights[i].ambient); + glGetLightfv(GL_LIGHT0 + i, + GL_DIFFUSE, + g_lighting_data.lights[i].diffuse); + glGetLightfv(GL_LIGHT0 + i, + GL_SPECULAR, + g_lighting_data.lights[i].specular); + glGetLightfv(GL_LIGHT0 + i, + GL_SPOT_DIRECTION, + g_lighting_data.lights[i].spot_direction); +#ifdef SUPPORT_COLOR_MATERIAL + glGetLightfv(GL_LIGHT0 + i, + GL_CONSTANT_ATTENUATION, + &g_lighting_data.lights[i].constant_attenuation); + glGetLightfv(GL_LIGHT0 + i, + GL_LINEAR_ATTENUATION, + &g_lighting_data.lights[i].linear_attenuation); + glGetLightfv(GL_LIGHT0 + i, + GL_QUADRATIC_ATTENUATION, + &g_lighting_data.lights[i].quadratic_attenuation); + glGetLightfv(GL_LIGHT0 + i, + GL_SPOT_CUTOFF, + &g_lighting_data.lights[i].spot_cutoff); + glGetLightfv(GL_LIGHT0 + i, + GL_SPOT_EXPONENT, + &g_lighting_data.lights[i].spot_exponent); + g_lighting_data.lights[i].spot_cos_cutoff = + cos(g_lighting_data.lights[i].spot_cutoff); +#endif + } +} + +static GLuint prepare_patchDraw(OpenSubdiv_GLMesh *gl_mesh, + bool fill_quads) +{ + GLint program = 0; + if (!g_use_osd_glsl) { + glGetIntegerv(GL_CURRENT_PROGRAM, &program); + if (program) { + GLint model; + glGetIntegerv(GL_SHADE_MODEL, &model); + + GLint location = glGetUniformLocation(program, "osd_flat_shading"); + if (location != -1) { + glUniform1i(location, model == GL_FLAT); + } + + /* Face-vertex data */ + if (gl_mesh->fvar_data != NULL) { + if (gl_mesh->fvar_data->texture_buffer) { + glActiveTexture(GL_TEXTURE31); + glBindTexture(GL_TEXTURE_BUFFER, + gl_mesh->fvar_data->texture_buffer); + glActiveTexture(GL_TEXTURE0); + } + + if (gl_mesh->fvar_data->offset_buffer) { + glActiveTexture(GL_TEXTURE30); + glBindTexture(GL_TEXTURE_BUFFER, + gl_mesh->fvar_data->offset_buffer); + glActiveTexture(GL_TEXTURE0); + } + + GLint location = glGetUniformLocation(program, "osd_fvar_count"); + if (location != -1) { + glUniform1i(location, gl_mesh->fvar_data->fvar_width); + } + + location = glGetUniformLocation(program, "osd_active_uv_offset"); + if (location != -1) { + 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); + } + } + } else { + glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0); + glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0); + } + } + return program; + } + + if (fill_quads) { + int model; + GLboolean use_texture_2d; + glGetIntegerv(GL_SHADE_MODEL, &model); + glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d); + + if (model == GL_FLAT) { + if (use_texture_2d) { + program = g_flat_fill_texture2d_program; + } + else { + program = g_flat_fill_solid_program; + } + } + else { + if (use_texture_2d) { + program = g_smooth_fill_texture2d_program; + } + else { + program = g_smooth_fill_solid_program; + } + } + + } + else { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + program = g_wireframe_program; + } + + bindProgram(gl_mesh, program); + + return program; +} + +static void perform_drawElements(GLuint program, + int patch_index, + int num_elements, + int start_element) +{ + if (program) { + glUniform1i(glGetUniformLocation(program, "PrimitiveIdBase"), + patch_index); + } + glDrawElements(GL_LINES_ADJACENCY, + num_elements, + GL_UNSIGNED_INT, + (void *)(start_element * sizeof(unsigned int))); +} + +static void finish_patchDraw(bool fill_quads) +{ + /* TODO(sergey): Some of the stuff could be done once after the whole + * mesh is displayed. + */ + + /* Restore state. */ + if (!fill_quads) { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + glBindVertexArray(0); + + if (g_use_osd_glsl) { + /* TODO(sergey): Store previously used program and roll back to it? */ + glUseProgram(0); + } +} + +static void draw_partition_patches_range(GLMeshInterface *mesh, + GLuint program, + int start_patch, + int num_patches) +{ + int traversed_patches = 0, num_remained_patches = num_patches; + const OpenSubdiv::Osd::PatchArrayVector& patches = + mesh->GetPatchTable()->GetPatchArrays(); + for (int i = 0; i < (int)patches.size(); ++i) { + const OpenSubdiv::Osd::PatchArray& patch = patches[i]; + OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor(); + OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType(); + + if (patchType == OpenSubdiv::Far::PatchDescriptor::QUADS) { + const int num_block_patches = patch.GetNumPatches(); + if (start_patch >= traversed_patches && + start_patch < traversed_patches + num_block_patches) + { + const int num_control_verts = desc.GetNumControlVertices(); + const int start_draw_patch = start_patch - traversed_patches; + const int num_draw_patches = std::min(num_remained_patches, + num_block_patches - start_draw_patch); + perform_drawElements(program, + i + start_draw_patch, + num_draw_patches * num_control_verts, + patch.GetIndexBase() + start_draw_patch * num_control_verts); + num_remained_patches -= num_draw_patches; + } + if (num_remained_patches == 0) { + break; + } + traversed_patches += num_block_patches; + } + } +} + +static void draw_all_patches(GLMeshInterface *mesh, + GLuint program) +{ + const OpenSubdiv::Osd::PatchArrayVector& patches = + mesh->GetPatchTable()->GetPatchArrays(); + for (int i = 0; i < (int)patches.size(); ++i) { + const OpenSubdiv::Osd::PatchArray& patch = patches[i]; + OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor(); + OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType(); + + if (patchType == OpenSubdiv::Far::PatchDescriptor::QUADS) { + perform_drawElements(program, + i, + patch.GetNumPatches() * desc.GetNumControlVertices(), + patch.GetIndexBase()); + } + } +} + +void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh, + int fill_quads, + int start_patch, + int num_patches) +{ + GLMeshInterface *mesh = + (GLMeshInterface *)(gl_mesh->descriptor); + + /* Make sure all global invariants are initialized. */ + if (!openSubdiv_osdGLDisplayInit()) { + return; + } + + /* Setup GLSL/OpenGL to draw patches in current context. */ + GLuint program = prepare_patchDraw(gl_mesh, fill_quads != 0); + + if (start_patch != -1) { + draw_partition_patches_range(mesh, + program, + start_patch, + num_patches); + } + else { + draw_all_patches(mesh, program); + } + + /* Finish patch drawing by restoring all changes to the OpenGL context. */ + finish_patchDraw(fill_quads != 0); +} + +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(topology_refiner->osd_refiner, + 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); + } +} |