ClangFormat: apply to source, most of intern
[blender.git] / intern / opensubdiv / internal / opensubdiv_gl_mesh_draw.cc
1 // Copyright 2013 Blender Foundation. All rights reserved.
2 //
3 // This program is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU General Public License
5 // as published by the Free Software Foundation; either version 2
6 // of the License, or (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software Foundation,
15 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 //
17 // Author: Sergey Sharybin
18
19 #include "internal/opensubdiv_gl_mesh_draw.h"
20
21 #ifdef _MSC_VER
22 #  include <iso646.h>
23 #endif
24
25 #include <GL/glew.h>
26 #include <cmath>
27 #include <cstdio>
28
29 #include <opensubdiv/osd/glMesh.h>
30
31 #ifdef OPENSUBDIV_HAS_CUDA
32 #  include <opensubdiv/osd/cudaGLVertexBuffer.h>
33 #endif  // OPENSUBDIV_HAS_CUDA
34
35 #include <opensubdiv/osd/cpuEvaluator.h>
36 #include <opensubdiv/osd/cpuGLVertexBuffer.h>
37
38 #include "internal/opensubdiv_gl_mesh_fvar.h"
39 #include "internal/opensubdiv_gl_mesh_internal.h"
40 #include "internal/opensubdiv_util.h"
41 #include "opensubdiv_capi.h"
42 #include "opensubdiv_gl_mesh_capi.h"
43
44 using OpenSubdiv::Osd::GLMeshInterface;
45
46 extern "C" char datatoc_gpu_shader_opensubdiv_vertex_glsl[];
47 extern "C" char datatoc_gpu_shader_opensubdiv_geometry_glsl[];
48 extern "C" char datatoc_gpu_shader_opensubdiv_fragment_glsl[];
49
50 // TODO(sergey): Those are a bit of bad level calls :S
51 extern "C" {
52 void copy_m3_m3(float m1[3][3], float m2[3][3]);
53 void copy_m3_m4(float m1[3][3], float m2[4][4]);
54 void adjoint_m3_m3(float m1[3][3], float m[3][3]);
55 float determinant_m3_array(float m[3][3]);
56 bool invert_m3_m3(float m1[3][3], float m2[3][3]);
57 bool invert_m3(float m[3][3]);
58 void transpose_m3(float mat[3][3]);
59 }
60
61 #define MAX_LIGHTS 8
62 #define SUPPORT_COLOR_MATERIAL
63
64 typedef struct Light {
65   float position[4];
66   float ambient[4];
67   float diffuse[4];
68   float specular[4];
69   float spot_direction[4];
70 #ifdef SUPPORT_COLOR_MATERIAL
71   float constant_attenuation;
72   float linear_attenuation;
73   float quadratic_attenuation;
74   float spot_cutoff;
75   float spot_exponent;
76   float spot_cos_cutoff;
77   float pad, pad2;
78 #endif
79 } Light;
80
81 typedef struct Lighting {
82   Light lights[MAX_LIGHTS];
83   int num_enabled;
84 } Lighting;
85
86 typedef struct Transform {
87   float projection_matrix[16];
88   float model_view_matrix[16];
89   float normal_matrix[9];
90 } Transform;
91
92 static bool g_use_osd_glsl = false;
93 static int g_active_uv_index = 0;
94
95 static GLuint g_flat_fill_solid_program = 0;
96 static GLuint g_flat_fill_texture2d_program = 0;
97 static GLuint g_smooth_fill_solid_program = 0;
98 static GLuint g_smooth_fill_texture2d_program = 0;
99
100 static GLuint g_flat_fill_solid_shadeless_program = 0;
101 static GLuint g_flat_fill_texture2d_shadeless_program = 0;
102 static GLuint g_smooth_fill_solid_shadeless_program = 0;
103 static GLuint g_smooth_fill_texture2d_shadeless_program = 0;
104
105 static GLuint g_wireframe_program = 0;
106
107 static GLuint g_lighting_ub = 0;
108 static Lighting g_lighting_data;
109 static Transform g_transform;
110
111 namespace {
112
113 GLuint compileShader(GLenum shaderType,
114                      const char *version,
115                      const char *define,
116                      const char *source)
117 {
118   const char *sources[] = {
119       version,
120       define,
121 #ifdef SUPPORT_COLOR_MATERIAL
122       "#define SUPPORT_COLOR_MATERIAL\n",
123 #else
124       "",
125 #endif
126       source,
127   };
128
129   GLuint shader = glCreateShader(shaderType);
130   glShaderSource(shader, 4, sources, NULL);
131   glCompileShader(shader);
132
133   GLint status;
134   glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
135   if (status == GL_FALSE) {
136     GLchar emsg[1024];
137     glGetShaderInfoLog(shader, sizeof(emsg), 0, emsg);
138     fprintf(stderr, "Error compiling GLSL: %s\n", emsg);
139     fprintf(stderr, "Version: %s\n", version);
140     fprintf(stderr, "Defines: %s\n", define);
141     fprintf(stderr, "Source: %s\n", source);
142     return 0;
143   }
144
145   return shader;
146 }
147
148 GLuint linkProgram(const char *version, const char *define)
149 {
150   GLuint vertexShader = compileShader(
151       GL_VERTEX_SHADER, version, define, datatoc_gpu_shader_opensubdiv_vertex_glsl);
152   if (vertexShader == 0) {
153     return 0;
154   }
155   GLuint geometryShader = compileShader(
156       GL_GEOMETRY_SHADER, version, define, datatoc_gpu_shader_opensubdiv_geometry_glsl);
157   if (geometryShader == 0) {
158     return 0;
159   }
160   GLuint fragmentShader = compileShader(
161       GL_FRAGMENT_SHADER, version, define, datatoc_gpu_shader_opensubdiv_fragment_glsl);
162   if (fragmentShader == 0) {
163     return 0;
164   }
165
166   GLuint program = glCreateProgram();
167
168   glAttachShader(program, vertexShader);
169   glAttachShader(program, geometryShader);
170   glAttachShader(program, fragmentShader);
171
172   glBindAttribLocation(program, 0, "position");
173   glBindAttribLocation(program, 1, "normal");
174
175   glLinkProgram(program);
176
177   glDeleteShader(vertexShader);
178   glDeleteShader(geometryShader);
179   glDeleteShader(fragmentShader);
180
181   GLint status;
182   glGetProgramiv(program, GL_LINK_STATUS, &status);
183   if (status == GL_FALSE) {
184     GLchar emsg[1024];
185     glGetProgramInfoLog(program, sizeof(emsg), 0, emsg);
186     fprintf(stderr, "Error linking GLSL program : %s\n", emsg);
187     fprintf(stderr, "Defines: %s\n", define);
188     glDeleteProgram(program);
189     return 0;
190   }
191
192   glUniformBlockBinding(program, glGetUniformBlockIndex(program, "Lighting"), 0);
193
194   if (GLEW_VERSION_4_1) {
195     glProgramUniform1i(program, glGetUniformLocation(program, "texture_buffer"), 0);
196     glProgramUniform1i(program, glGetUniformLocation(program, "FVarDataOffsetBuffer"), 30);
197     glProgramUniform1i(program, glGetUniformLocation(program, "FVarDataBuffer"), 31);
198   }
199   else {
200     glUseProgram(program);
201     glUniform1i(glGetUniformLocation(program, "texture_buffer"), 0);
202     glUniform1i(glGetUniformLocation(program, "FVarDataOffsetBuffer"), 30);
203     glUniform1i(glGetUniformLocation(program, "FVarDataBuffer"), 31);
204     glUseProgram(0);
205   }
206
207   return program;
208 }
209
210 void bindProgram(OpenSubdiv_GLMesh *gl_mesh, int program)
211 {
212   glUseProgram(program);
213   // Matrices
214   glUniformMatrix4fv(
215       glGetUniformLocation(program, "modelViewMatrix"), 1, false, g_transform.model_view_matrix);
216   glUniformMatrix4fv(
217       glGetUniformLocation(program, "projectionMatrix"), 1, false, g_transform.projection_matrix);
218   glUniformMatrix3fv(
219       glGetUniformLocation(program, "normalMatrix"), 1, false, g_transform.normal_matrix);
220   // Lighting.
221   glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub);
222   glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(g_lighting_data), &g_lighting_data);
223   glBindBuffer(GL_UNIFORM_BUFFER, 0);
224   glBindBufferBase(GL_UNIFORM_BUFFER, 0, g_lighting_ub);
225   // Color.
226   {
227     // TODO(sergey): Stop using glGetMaterial.
228     float color[4];
229     glGetMaterialfv(GL_FRONT, GL_DIFFUSE, color);
230     glUniform4fv(glGetUniformLocation(program, "diffuse"), 1, color);
231     glGetMaterialfv(GL_FRONT, GL_SPECULAR, color);
232     glUniform4fv(glGetUniformLocation(program, "specular"), 1, color);
233     glGetMaterialfv(GL_FRONT, GL_SHININESS, color);
234     glUniform1f(glGetUniformLocation(program, "shininess"), color[0]);
235   }
236   // Face-vertex data.
237   opensubdiv_capi::GLMeshFVarData *fvar_data = gl_mesh->internal->fvar_data;
238   if (fvar_data != NULL) {
239     if (fvar_data->texture_buffer) {
240       glActiveTexture(GL_TEXTURE31);
241       glBindTexture(GL_TEXTURE_BUFFER, fvar_data->texture_buffer);
242       glActiveTexture(GL_TEXTURE0);
243     }
244     if (fvar_data->offset_buffer) {
245       glActiveTexture(GL_TEXTURE30);
246       glBindTexture(GL_TEXTURE_BUFFER, fvar_data->offset_buffer);
247       glActiveTexture(GL_TEXTURE0);
248     }
249     glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), fvar_data->fvar_width);
250     if (fvar_data->channel_offsets.size() > 0 && g_active_uv_index >= 0) {
251       glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"),
252                   fvar_data->channel_offsets[g_active_uv_index]);
253     }
254     else {
255       glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0);
256     }
257   }
258   else {
259     glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0);
260     glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0);
261   }
262 }
263
264 }  // namespace
265
266 bool openSubdiv_initGLMeshDrawingResources(void)
267 {
268   static bool need_init = true;
269   static bool init_success = false;
270   if (!need_init) {
271     return init_success;
272   }
273   // TODO(sergey): Update OSD drawing to OpenGL 3.3 core,
274   // then remove following line.
275   return false;
276   const char *version = "";
277   if (GLEW_VERSION_3_2) {
278     version = "#version 150 compatibility\n";
279   }
280   else if (GLEW_VERSION_3_1) {
281     version =
282         "#version 140\n"
283         "#extension GL_ARB_compatibility: enable\n";
284   }
285   else {
286     version = "#version 130\n";
287     // Minimum supported for OpenSubdiv.
288   }
289   g_flat_fill_solid_program = linkProgram(version,
290                                           "#define USE_COLOR_MATERIAL\n"
291                                           "#define USE_LIGHTING\n"
292                                           "#define FLAT_SHADING\n");
293   g_flat_fill_texture2d_program = linkProgram(version,
294                                               "#define USE_COLOR_MATERIAL\n"
295                                               "#define USE_LIGHTING\n"
296                                               "#define USE_TEXTURE_2D\n"
297                                               "#define FLAT_SHADING\n");
298   g_smooth_fill_solid_program = linkProgram(version,
299                                             "#define USE_COLOR_MATERIAL\n"
300                                             "#define USE_LIGHTING\n"
301                                             "#define SMOOTH_SHADING\n");
302   g_smooth_fill_texture2d_program = linkProgram(version,
303                                                 "#define USE_COLOR_MATERIAL\n"
304                                                 "#define USE_LIGHTING\n"
305                                                 "#define USE_TEXTURE_2D\n"
306                                                 "#define SMOOTH_SHADING\n");
307
308   g_flat_fill_solid_shadeless_program = linkProgram(version,
309                                                     "#define USE_COLOR_MATERIAL\n"
310                                                     "#define FLAT_SHADING\n");
311   g_flat_fill_texture2d_shadeless_program = linkProgram(version,
312                                                         "#define USE_COLOR_MATERIAL\n"
313                                                         "#define USE_TEXTURE_2D\n"
314                                                         "#define FLAT_SHADING\n");
315   g_smooth_fill_solid_shadeless_program = linkProgram(version,
316                                                       "#define USE_COLOR_MATERIAL\n"
317                                                       "#define SMOOTH_SHADING\n");
318   g_smooth_fill_texture2d_shadeless_program = linkProgram(version,
319                                                           "#define USE_COLOR_MATERIAL\n"
320                                                           "#define USE_TEXTURE_2D\n"
321                                                           "#define SMOOTH_SHADING\n");
322   g_wireframe_program = linkProgram(version, "#define WIREFRAME\n");
323
324   glGenBuffers(1, &g_lighting_ub);
325   glBindBuffer(GL_UNIFORM_BUFFER, g_lighting_ub);
326   glBufferData(GL_UNIFORM_BUFFER, sizeof(g_lighting_data), NULL, GL_STATIC_DRAW);
327   need_init = false;
328   init_success = g_flat_fill_solid_program != 0 && g_flat_fill_texture2d_program != 0 &&
329                  g_smooth_fill_solid_program != 0 && g_smooth_fill_texture2d_program != 0 &&
330                  g_wireframe_program;
331   return init_success;
332 }
333
334 void openSubdiv_deinitGLMeshDrawingResources(void)
335 {
336   if (g_lighting_ub != 0) {
337     glDeleteBuffers(1, &g_lighting_ub);
338   }
339 #define SAFE_DELETE_PROGRAM(program) \
340   do { \
341     if (program) { \
342       glDeleteProgram(program); \
343     } \
344   } while (false)
345
346   SAFE_DELETE_PROGRAM(g_flat_fill_solid_program);
347   SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_program);
348   SAFE_DELETE_PROGRAM(g_smooth_fill_solid_program);
349   SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_program);
350   SAFE_DELETE_PROGRAM(g_flat_fill_solid_shadeless_program);
351   SAFE_DELETE_PROGRAM(g_flat_fill_texture2d_shadeless_program);
352   SAFE_DELETE_PROGRAM(g_smooth_fill_solid_shadeless_program);
353   SAFE_DELETE_PROGRAM(g_smooth_fill_texture2d_shadeless_program);
354   SAFE_DELETE_PROGRAM(g_wireframe_program);
355
356 #undef SAFE_DELETE_PROGRAM
357 }
358
359 namespace opensubdiv_capi {
360
361 namespace {
362
363 GLuint prepare_patchDraw(OpenSubdiv_GLMesh *gl_mesh, bool fill_quads)
364 {
365   GLint program = 0;
366   if (!g_use_osd_glsl) {
367     glGetIntegerv(GL_CURRENT_PROGRAM, &program);
368     if (program) {
369       GLint model;
370       glGetIntegerv(GL_SHADE_MODEL, &model);
371       GLint location = glGetUniformLocation(program, "osd_flat_shading");
372       if (location != -1) {
373         glUniform1i(location, model == GL_FLAT);
374       }
375       // Face-vertex data.
376       opensubdiv_capi::GLMeshFVarData *fvar_data = gl_mesh->internal->fvar_data;
377       if (fvar_data != NULL) {
378         if (fvar_data->texture_buffer) {
379           glActiveTexture(GL_TEXTURE31);
380           glBindTexture(GL_TEXTURE_BUFFER, fvar_data->texture_buffer);
381           glActiveTexture(GL_TEXTURE0);
382         }
383         if (fvar_data->offset_buffer) {
384           glActiveTexture(GL_TEXTURE30);
385           glBindTexture(GL_TEXTURE_BUFFER, fvar_data->offset_buffer);
386           glActiveTexture(GL_TEXTURE0);
387         }
388         GLint location = glGetUniformLocation(program, "osd_fvar_count");
389         if (location != -1) {
390           glUniform1i(location, fvar_data->fvar_width);
391         }
392         location = glGetUniformLocation(program, "osd_active_uv_offset");
393         if (location != -1) {
394           if (fvar_data->channel_offsets.size() > 0 && g_active_uv_index >= 0) {
395             glUniform1i(location, fvar_data->channel_offsets[g_active_uv_index]);
396           }
397           else {
398             glUniform1i(location, 0);
399           }
400         }
401       }
402       else {
403         glUniform1i(glGetUniformLocation(program, "osd_fvar_count"), 0);
404         glUniform1i(glGetUniformLocation(program, "osd_active_uv_offset"), 0);
405       }
406     }
407     return program;
408   }
409   if (fill_quads) {
410     int model;
411     GLboolean use_texture_2d;
412     glGetIntegerv(GL_SHADE_MODEL, &model);
413     glGetBooleanv(GL_TEXTURE_2D, &use_texture_2d);
414     if (model == GL_FLAT) {
415       if (use_texture_2d) {
416         program = g_flat_fill_texture2d_program;
417       }
418       else {
419         program = g_flat_fill_solid_program;
420       }
421     }
422     else {
423       if (use_texture_2d) {
424         program = g_smooth_fill_texture2d_program;
425       }
426       else {
427         program = g_smooth_fill_solid_program;
428       }
429     }
430   }
431   else {
432     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
433     program = g_wireframe_program;
434   }
435   bindProgram(gl_mesh, program);
436   return program;
437 }
438
439 void perform_drawElements(GLuint program, int patch_index, int num_elements, int start_element)
440 {
441   if (program) {
442     glUniform1i(glGetUniformLocation(program, "PrimitiveIdBase"), patch_index);
443   }
444   glDrawElements(GL_LINES_ADJACENCY,
445                  num_elements,
446                  GL_UNSIGNED_INT,
447                  reinterpret_cast<void *>(start_element * sizeof(unsigned int)));
448 }
449
450 void finishPatchDraw(bool fill_quads)
451 {
452   // TODO(sergey): Some of the stuff could be done once after the whole
453   // mesh is displayed.
454   /// Restore state.
455   if (!fill_quads) {
456     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
457   }
458   glBindVertexArray(0);
459   if (g_use_osd_glsl) {
460     // TODO(sergey): Store previously used program and roll back to it?
461     glUseProgram(0);
462   }
463 }
464
465 void drawPartitionPatchesRange(GLMeshInterface *mesh,
466                                GLuint program,
467                                int start_patch,
468                                int num_patches)
469 {
470   int traversed_patches = 0, num_remained_patches = num_patches;
471   const OpenSubdiv::Osd::PatchArrayVector &patches = mesh->GetPatchTable()->GetPatchArrays();
472   for (int i = 0; i < patches.size(); ++i) {
473     const OpenSubdiv::Osd::PatchArray &patch = patches[i];
474     OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor();
475     OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType();
476     if (patchType == OpenSubdiv::Far::PatchDescriptor::QUADS) {
477       const int num_block_patches = patch.GetNumPatches();
478       if (start_patch >= traversed_patches &&
479           start_patch < traversed_patches + num_block_patches) {
480         const int num_control_verts = desc.GetNumControlVertices();
481         const int start_draw_patch = start_patch - traversed_patches;
482         const int num_draw_patches = min(num_remained_patches,
483                                          num_block_patches - start_draw_patch);
484         perform_drawElements(program,
485                              i + start_draw_patch,
486                              num_draw_patches * num_control_verts,
487                              patch.GetIndexBase() + start_draw_patch * num_control_verts);
488         num_remained_patches -= num_draw_patches;
489       }
490       if (num_remained_patches == 0) {
491         break;
492       }
493       traversed_patches += num_block_patches;
494     }
495   }
496 }
497
498 static void drawAllPatches(GLMeshInterface *mesh, GLuint program)
499 {
500   const OpenSubdiv::Osd::PatchArrayVector &patches = mesh->GetPatchTable()->GetPatchArrays();
501   for (int i = 0; i < patches.size(); ++i) {
502     const OpenSubdiv::Osd::PatchArray &patch = patches[i];
503     OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor();
504     OpenSubdiv::Far::PatchDescriptor::Type patchType = desc.GetType();
505
506     if (patchType == OpenSubdiv::Far::PatchDescriptor::QUADS) {
507       perform_drawElements(
508           program, i, patch.GetNumPatches() * desc.GetNumControlVertices(), patch.GetIndexBase());
509     }
510   }
511 }
512
513 }  // namespace
514
515 void GLMeshDisplayPrepare(struct OpenSubdiv_GLMesh * /*gl_mesh*/,
516                           const bool use_osd_glsl,
517                           const int active_uv_index)
518 {
519   g_active_uv_index = active_uv_index;
520   g_use_osd_glsl = (use_osd_glsl != 0);
521   // Update transformation matrices.
522   glGetFloatv(GL_PROJECTION_MATRIX, g_transform.projection_matrix);
523   glGetFloatv(GL_MODELVIEW_MATRIX, g_transform.model_view_matrix);
524   copy_m3_m4((float(*)[3])g_transform.normal_matrix, (float(*)[4])g_transform.model_view_matrix);
525   invert_m3((float(*)[3])g_transform.normal_matrix);
526   transpose_m3((float(*)[3])g_transform.normal_matrix);
527   // Update OpenGL lights positions, colors etc.
528   g_lighting_data.num_enabled = 0;
529   for (int i = 0; i < MAX_LIGHTS; ++i) {
530     GLboolean enabled;
531     glGetBooleanv(GL_LIGHT0 + i, &enabled);
532     if (enabled) {
533       g_lighting_data.num_enabled++;
534     }
535     // TODO(sergey): Stop using glGetLight.
536     glGetLightfv(GL_LIGHT0 + i, GL_POSITION, g_lighting_data.lights[i].position);
537     glGetLightfv(GL_LIGHT0 + i, GL_AMBIENT, g_lighting_data.lights[i].ambient);
538     glGetLightfv(GL_LIGHT0 + i, GL_DIFFUSE, g_lighting_data.lights[i].diffuse);
539     glGetLightfv(GL_LIGHT0 + i, GL_SPECULAR, g_lighting_data.lights[i].specular);
540     glGetLightfv(GL_LIGHT0 + i, GL_SPOT_DIRECTION, g_lighting_data.lights[i].spot_direction);
541 #ifdef SUPPORT_COLOR_MATERIAL
542     glGetLightfv(
543         GL_LIGHT0 + i, GL_CONSTANT_ATTENUATION, &g_lighting_data.lights[i].constant_attenuation);
544     glGetLightfv(
545         GL_LIGHT0 + i, GL_LINEAR_ATTENUATION, &g_lighting_data.lights[i].linear_attenuation);
546     glGetLightfv(
547         GL_LIGHT0 + i, GL_QUADRATIC_ATTENUATION, &g_lighting_data.lights[i].quadratic_attenuation);
548     glGetLightfv(GL_LIGHT0 + i, GL_SPOT_CUTOFF, &g_lighting_data.lights[i].spot_cutoff);
549     glGetLightfv(GL_LIGHT0 + i, GL_SPOT_EXPONENT, &g_lighting_data.lights[i].spot_exponent);
550     g_lighting_data.lights[i].spot_cos_cutoff = cos(g_lighting_data.lights[i].spot_cutoff);
551 #endif
552   }
553 }
554
555 void GLMeshDisplayDrawPatches(OpenSubdiv_GLMesh *gl_mesh,
556                               const bool fill_quads,
557                               const int start_patch,
558                               const int num_patches)
559 {
560   GLMeshInterface *mesh = gl_mesh->internal->mesh_interface;
561   // Make sure all global invariants are initialized.
562   if (!openSubdiv_initGLMeshDrawingResources()) {
563     return;
564   }
565   /// Setup GLSL/OpenGL to draw patches in current context.
566   GLuint program = prepare_patchDraw(gl_mesh, fill_quads != 0);
567   if (start_patch != -1) {
568     drawPartitionPatchesRange(mesh, program, start_patch, num_patches);
569   }
570   else {
571     drawAllPatches(mesh, program);
572   }
573   // Finish patch drawing by restoring all changes to the OpenGL context.
574   finishPatchDraw(fill_quads != 0);
575 }
576
577 }  // namespace opensubdiv_capi