1 //
2 //   Copyright 2013 Pixar
3 //
4 //   Licensed under the Apache License, Version 2.0 (the "Apache License")
5 //   with the following modification; you may not use this file except in
6 //   compliance with the Apache License and the following modification to it:
7 //   Section 6. Trademarks. is deleted and replaced with:
8 //
9 //   6. Trademarks. This License does not grant permission to use the trade
10 //      names, trademarks, service marks, or product names of the Licensor
11 //      and its affiliates, except as required to comply with Section 4(c) of
12 //      the License and to reproduce the content of the NOTICE file.
13 //
14 //   You may obtain a copy of the Apache License at
15 //
16 //       http://www.apache.org/licenses/LICENSE-2.0
17 //
18 //   Unless required by applicable law or agreed to in writing, software
19 //   distributed under the Apache License with the above modification is
20 //   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 //   KIND, either express or implied. See the Apache License for the specific
22 //   language governing permissions and limitations under the Apache License.
23 //
24 
25 #include "glLoader.h"
26 
27 #include <GLFW/glfw3.h>
28 GLFWwindow* g_window = 0;
29 GLFWmonitor* g_primary = 0;
30 
31 #include <vector>
32 #include <sstream>
33 #include <iostream>
34 #include <fstream>
35 #include <string>
36 #include <utility>
37 #include <algorithm>
38 #include <opensubdiv/far/error.h>
39 
40 #include <opensubdiv/osd/cpuEvaluator.h>
41 #include <opensubdiv/osd/cpuGLVertexBuffer.h>
42 
43 #ifdef OPENSUBDIV_HAS_OPENMP
44     #include <opensubdiv/osd/ompEvaluator.h>
45 #endif
46 
47 #ifdef OPENSUBDIV_HAS_TBB
48     #include <opensubdiv/osd/tbbEvaluator.h>
49 #endif
50 
51 #ifdef OPENSUBDIV_HAS_OPENCL
52     #include <opensubdiv/osd/clEvaluator.h>
53     #include <opensubdiv/osd/clGLVertexBuffer.h>
54     #include "../common/clDeviceContext.h"
55     CLDeviceContext g_clDeviceContext;
56 #endif
57 
58 #ifdef OPENSUBDIV_HAS_CUDA
59     #include <opensubdiv/osd/cudaEvaluator.h>
60     #include <opensubdiv/osd/cudaGLVertexBuffer.h>
61     #include "../common/cudaDeviceContext.h"
62     CudaDeviceContext g_cudaDeviceContext;
63 #endif
64 
65 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
66     #include <opensubdiv/osd/glXFBEvaluator.h>
67     #include <opensubdiv/osd/glVertexBuffer.h>
68 #endif
69 
70 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
71     #include <opensubdiv/osd/glComputeEvaluator.h>
72     #include <opensubdiv/osd/glVertexBuffer.h>
73 #endif
74 
75 #include <opensubdiv/osd/glMesh.h>
76 OpenSubdiv::Osd::GLMeshInterface *g_mesh;
77 
78 #include "Ptexture.h"
79 #include "PtexUtils.h"
80 
81 #include "../../regression/common/far_utils.h"
82 #include "../../regression/common/arg_utils.h"
83 #include "../common/objAnim.h"
84 #include "../common/stopwatch.h"
85 #include "../common/simple_math.h"
86 #include "../common/glControlMeshDisplay.h"
87 #include "../common/glHud.h"
88 #include "../common/hdr_reader.h"
89 #include "../common/glPtexMipmapTexture.h"
90 #include "../common/glShaderCache.h"
91 #include "../common/glUtils.h"
92 
93 #include <opensubdiv/osd/glslPatchShaderSource.h>
94 static const char *g_defaultShaderSource =
95 #if defined(GL_ARB_tessellation_shader) || defined(GL_VERSION_4_0)
96     #include "shader.gen.h"
97 #else
98     #include "shader_gl3.gen.h"
99 #endif
100 ;
101 static const char *g_skyShaderSource =
102 #include "skyshader.gen.h"
103 ;
104 static std::string g_shaderSource;
105 static const char *g_shaderFilename = NULL;
106 
107 enum KernelType { kCPU = 0,
108                   kOPENMP = 1,
109                   kTBB = 2,
110                   kCUDA = 3,
111                   kCL = 4,
112                   kGLSL = 5,
113                   kGLSLCompute = 6 };
114 
115 enum HudCheckBox { HUD_CB_ADAPTIVE,
116                    HUD_CB_DISPLAY_OCCLUSION,
117                    HUD_CB_DISPLAY_NORMALMAP,
118                    HUD_CB_DISPLAY_SPECULAR,
119                    HUD_CB_CONTROL_MESH_EDGES,
120                    HUD_CB_ANIMATE_VERTICES,
121                    HUD_CB_VIEW_LOD,
122                    HUD_CB_FRACTIONAL_SPACING,
123                    HUD_CB_PATCH_CULL,
124                    HUD_CB_IBL,
125                    HUD_CB_BLOOM,
126                    HUD_CB_SEAMLESS_MIPMAP,
127                    HUD_CB_FREEZE };
128 
129 enum HudRadioGroup { HUD_RB_KERNEL,
130                      HUD_RB_LEVEL,
131                      HUD_RB_SCHEME,
132                      HUD_RB_WIRE,
133                      HUD_RB_COLOR,
134                      HUD_RB_DISPLACEMENT,
135                      HUD_RB_NORMAL };
136 
137 enum DisplayType { DISPLAY_WIRE,
138                    DISPLAY_SHADED,
139                    DISPLAY_WIRE_ON_SHADED };
140 
141 enum ColorType { COLOR_NONE,
142                  COLOR_PTEX_NEAREST,
143                  COLOR_PTEX_HW_BILINEAR,
144                  COLOR_PTEX_BILINEAR,
145                  COLOR_PTEX_BIQUADRATIC,
146                  COLOR_PATCHTYPE,
147                  COLOR_PATCHCOORD,
148                  COLOR_NORMAL };
149 
150 enum DisplacementType { DISPLACEMENT_NONE,
151                         DISPLACEMENT_HW_BILINEAR,
152                         DISPLACEMENT_BILINEAR,
153                         DISPLACEMENT_BIQUADRATIC };
154 
155 enum NormalType { NORMAL_SURFACE,
156                   NORMAL_FACET,
157                   NORMAL_HW_SCREENSPACE,
158                   NORMAL_SCREENSPACE,
159                   NORMAL_BIQUADRATIC,
160                   NORMAL_BIQUADRATIC_WG };
161 
162 //-----------------------------------------------------------------------------
163 int   g_frame = 0,
164       g_repeatCount = 0;
165 
166 // GUI variables
167 int   g_fullscreen = 0,
168       g_wire = DISPLAY_SHADED,
169       g_drawNormals = 0,
170       g_mbutton[3] = {0, 0, 0},
171       g_level = 2,
172       g_tessLevel = 2,
173       g_kernel = kCPU,
174       g_scheme = 0,
175       g_running = 1,
176       g_maxMipmapLevels = 10,
177       g_color = COLOR_PTEX_BILINEAR,
178       g_displacement = DISPLACEMENT_NONE,
179       g_normal = NORMAL_SURFACE;
180 
181 
182 float g_moveScale = 0.0f,
183       g_displacementScale = 1.0f,
184       g_mipmapBias = 0.0;
185 
186 bool  g_adaptive = true,
187       g_yup = false,
188       g_patchCull = true,
189       g_screenSpaceTess = true,
190       g_fractionalSpacing = true,
191       g_ibl = false,
192       g_bloom = false,
193       g_freeze = false;
194 
195 GLuint g_constantUB = 0,
196        g_constantBinding = 0;
197 
198 // ptex switch
199 bool  g_occlusion = false,
200       g_specular = false;
201 
202 bool g_seamless = true;
203 
204 // camera
205 float g_rotate[2] = {0, 0},
206       g_dolly = 5,
207       g_pan[2] = {0, 0},
208       g_center[3] = {0, 0, 0},
209       g_size = 0;
210 float g_modelViewProjection[16];
211 
212 int   g_prev_x = 0,
213       g_prev_y = 0;
214 
215 // viewport
216 int   g_width = 1024,
217       g_height = 1024;
218 
219 GLhud g_hud;
220 GLControlMeshDisplay g_controlMeshDisplay;
221 
222 // performance
223 float g_cpuTime = 0;
224 float g_gpuTime = 0;
225 #define NUM_FPS_TIME_SAMPLES 6
226 float g_fpsTimeSamples[NUM_FPS_TIME_SAMPLES] = {0, 0, 0, 0, 0, 0};
227 int   g_currentFpsTimeSample = 0;
228 Stopwatch g_fpsTimer;
229 float g_animTime = 0;
230 
231 // geometry
232 std::vector<float> g_positions,
233                    g_normals;
234 
235 ObjAnim const * g_objAnim = 0;
236 
237 GLuint g_queries[2] = {0, 0};
238 GLuint g_vao = 0;
239 GLuint g_skyVAO = 0;
240 GLuint g_edgeIndexBuffer = 0;
241 
242 GLuint g_diffuseEnvironmentMap = 0;
243 GLuint g_specularEnvironmentMap = 0;
244 
245 //------------------------------------------------------------------------------
246 
247 struct Sky {
248     int numIndices;
249     GLuint vertexBuffer;
250     GLuint elementBuffer;
251     GLuint mvpMatrix;
252     GLDrawConfig *drawConfig;
253 
SkySky254     Sky() : numIndices(0), vertexBuffer(0), elementBuffer(0), mvpMatrix(0),
255             drawConfig(NULL) {}
~SkySky256     ~Sky() {
257         delete drawConfig;
258     }
259 
BuildProgramSky260     bool BuildProgram(const char *source) {
261         if (drawConfig) delete drawConfig;
262 
263         drawConfig = new GLDrawConfig("#version 410\n");
264 
265         drawConfig->CompileAndAttachShader(GL_VERTEX_SHADER,
266                                            "#define SKY_VERTEX_SHADER\n" +
267                                            std::string(source));
268         drawConfig->CompileAndAttachShader(GL_FRAGMENT_SHADER,
269                                            "#define SKY_FRAGMENT_SHADER\n" +
270                                            std::string(source));
271         if (drawConfig->Link() == false) {
272             delete drawConfig;
273             drawConfig = NULL;
274             return false;
275         }
276         return true;
277     }
278 
GetProgramSky279     int GetProgram() const {
280         if (drawConfig) return drawConfig->GetProgram();
281         return 0;
282     }
283 
284 } g_sky;
285 
286 //------------------------------------------------------------------------------
287 
288 GLPtexMipmapTexture * g_osdPTexImage = 0;
289 GLPtexMipmapTexture * g_osdPTexDisplacement = 0;
290 GLPtexMipmapTexture * g_osdPTexOcclusion = 0;
291 GLPtexMipmapTexture * g_osdPTexSpecular = 0;
292 const char * g_ptexColorFilename;
293 size_t g_ptexMemoryUsage = 0;
294 
295 
296 //------------------------------------------------------------------------------
297 static void
calcNormals(OpenSubdiv::Far::TopologyRefiner * refiner,std::vector<float> const & pos,std::vector<float> & result)298 calcNormals(OpenSubdiv::Far::TopologyRefiner * refiner,
299     std::vector<float> const & pos, std::vector<float> & result ) {
300 
301     typedef OpenSubdiv::Far::ConstIndexArray IndexArray;
302 
303     OpenSubdiv::Far::TopologyLevel const & refBaseLevel = refiner->GetLevel(0);
304 
305     // calc normal vectors
306     int nverts = refBaseLevel.GetNumVertices(),
307         nfaces = refBaseLevel.GetNumFaces();
308 
309     for (int face = 0; face < nfaces; ++face) {
310 
311         IndexArray fverts = refBaseLevel.GetFaceVertices(face);
312 
313         float const * p0 = &pos[fverts[0]*3],
314                     * p1 = &pos[fverts[1]*3],
315                     * p2 = &pos[fverts[2]*3];
316 
317         float n[3];
318         cross(n, p0, p1, p2);
319 
320         for (int vert = 0; vert < fverts.size(); ++vert) {
321             int idx = fverts[vert] * 3;
322             result[idx  ] += n[0];
323             result[idx+1] += n[1];
324             result[idx+2] += n[2];
325         }
326     }
327     for (int i = 0; i < nverts; ++i)
328         normalize(&result[i*3]);
329 }
330 
331 //------------------------------------------------------------------------------
332 void
updateGeom()333 updateGeom() {
334 
335     int nverts = (int)g_positions.size() / 3;
336 
337     if (g_moveScale && g_adaptive && g_objAnim) {
338 
339         std::vector<float> vertex;
340         vertex.resize(nverts*3);
341 
342         g_objAnim->InterpolatePositions(g_animTime, &vertex[0], 3);
343 
344         g_mesh->UpdateVertexBuffer(&vertex[0], 0, nverts);
345 
346     } else {
347         std::vector<float> vertex;
348         vertex.reserve(nverts*6);
349 
350         const float *p = &g_positions[0];
351         const float *n = &g_normals[0];
352 
353         for (int i = 0; i < nverts; ++i) {
354             float move = g_size*0.005f*cosf(p[0]*100/g_size+g_frame*0.01f);
355             vertex.push_back(p[0]);
356             vertex.push_back(p[1]+g_moveScale*move);
357             vertex.push_back(p[2]);
358             p += 3;
359             if (g_adaptive == false) {
360                 vertex.push_back(n[0]);
361                 vertex.push_back(n[1]);
362                 vertex.push_back(n[2]);
363                 n += 3;
364             }
365         }
366 
367         g_mesh->UpdateVertexBuffer(&vertex[0], 0, nverts);
368     }
369 
370     Stopwatch s;
371     s.Start();
372 
373     g_mesh->Refine();
374 
375     s.Stop();
376     g_cpuTime = float(s.GetElapsed() * 1000.0f);
377     s.Start();
378 
379     g_mesh->Synchronize();
380 
381     s.Stop();
382     g_gpuTime = float(s.GetElapsed() * 1000.0f);
383 }
384 
385 //-------------------------------------------------------------------------------
386 void
fitFrame()387 fitFrame() {
388     g_pan[0] = g_pan[1] = 0;
389     g_dolly = g_size;
390 }
391 
392 //-------------------------------------------------------------------------------
393 Shape *
createPTexGeo(PtexTexture * r)394 createPTexGeo(PtexTexture * r) {
395 
396     PtexMetaData* meta = r->getMetaData();
397 
398     if (meta->numKeys() < 3) {
399         return NULL;
400     }
401 
402     float const * vp;
403     int const *vi, *vc;
404     int nvp, nvi, nvc;
405 
406     meta->getValue("PtexFaceVertCounts", vc, nvc);
407     if (nvc == 0) {
408         return NULL;
409     }
410     meta->getValue("PtexVertPositions", vp, nvp);
411     if (nvp == 0) {
412         return NULL;
413     }
414     meta->getValue("PtexFaceVertIndices", vi, nvi);
415     if (nvi == 0) {
416         return NULL;
417     }
418 
419     Shape * shape = new Shape;
420 
421     shape->scheme = kCatmark;
422     assert(r->meshType() == Ptex::mt_quad);
423 
424     shape->verts.resize(nvp);
425     for (int i=0; i<nvp; ++i) {
426         shape->verts[i] = vp[i];
427     }
428 
429     shape->nvertsPerFace.resize(nvc);
430     for (int i=0; i<nvc; ++i) {
431         shape->nvertsPerFace[i] = vc[i];
432     }
433 
434     shape->faceverts.resize(nvi);
435     for (int i=0; i<nvi; ++i) {
436         shape->faceverts[i] = vi[i];
437     }
438 
439     // compute model bounding
440     float min[3] = {vp[0], vp[1], vp[2]};
441     float max[3] = {vp[0], vp[1], vp[2]};
442     for (int i = 0; i < nvp/3; ++i) {
443         for (int j = 0; j < 3; ++j) {
444             float v = vp[i*3+j];
445             min[j] = std::min(min[j], v);
446             max[j] = std::max(max[j], v);
447         }
448     }
449 
450     for (int j = 0; j < 3; ++j) {
451         g_center[j] = (min[j] + max[j]) * 0.5f;
452         g_size += (max[j]-min[j])*(max[j]-min[j]);
453     }
454     g_size = sqrtf(g_size);
455 
456     return shape;
457 }
458 
459 //------------------------------------------------------------------------------
460 
461 void
reshape(GLFWwindow *,int width,int height)462 reshape(GLFWwindow *, int width, int height) {
463 
464     g_width = width;
465     g_height = height;
466 
467     int windowWidth = g_width, windowHeight = g_height;
468 
469     // window size might not match framebuffer size on a high DPI display
470     glfwGetWindowSize(g_window, &windowWidth, &windowHeight);
471 
472     g_hud.Rebuild(windowWidth, windowHeight, width, height);
473 
474     glBindTexture(GL_TEXTURE_2D, 0);
475 
476     GLUtils::CheckGLErrors("Reshape");
477 }
478 
reshape()479 void reshape() {
480     reshape(g_window, g_width, g_height);
481 }
482 
windowClose(GLFWwindow *)483 void windowClose(GLFWwindow*) {
484     g_running = false;
485 }
486 
487 //------------------------------------------------------------------------------
getKernelName(int kernel)488 const char *getKernelName(int kernel) {
489 
490          if (kernel == kCPU)
491         return "CPU";
492     else if (kernel == kOPENMP)
493         return "OpenMP";
494     else if (kernel == kCUDA)
495         return "Cuda";
496     else if (kernel == kGLSL)
497         return "GLSL";
498     else if (kernel == kCL)
499         return "OpenCL";
500     return "Unknown";
501 }
502 
503 //------------------------------------------------------------------------------
504 
505 union Effect {
506     struct {
507         unsigned int wire:2;
508         unsigned int color:3;
509         unsigned int displacement:2;
510         unsigned int normal:3;
511         int occlusion:1;
512         int specular:1;
513         int patchCull:1;
514         int screenSpaceTess:1;
515         int fractionalSpacing:1;
516         int ibl:1;
517         int seamless:1;
518     };
519     int value;
520 
operator <(const Effect & e) const521     bool operator < (const Effect &e) const {
522         return value < e.value;
523     }
524 };
525 
526 struct EffectDesc {
EffectDescEffectDesc527     EffectDesc(OpenSubdiv::Far::PatchDescriptor desc,
528                Effect effect) : desc(desc), effect(effect),
529                                 maxValence(0), numElements(0) { }
530 
531     OpenSubdiv::Far::PatchDescriptor desc;
532     Effect effect;
533     int maxValence;
534     int numElements;
535 
operator <EffectDesc536     bool operator < (const EffectDesc &e) const {
537         return desc < e.desc || (desc == e.desc &&
538               (maxValence < e.maxValence || ((maxValence == e.maxValence) &&
539               (effect < e.effect))));
540     }
541 };
542 
543 //------------------------------------------------------------------------------
544 class ShaderCache : public GLShaderCache<EffectDesc> {
545 public:
CreateDrawConfig(EffectDesc const & effectDesc)546     virtual GLDrawConfig *CreateDrawConfig(EffectDesc const &effectDesc) {
547 
548         using namespace OpenSubdiv;
549 
550         // compile shader program
551 #if defined(GL_ARB_tessellation_shader) || defined(GL_VERSION_4_0)
552         const char *glslVersion = "#version 400\n";
553 #else
554         const char *glslVersion = "#version 330\n";
555 #endif
556         GLDrawConfig *config = new GLDrawConfig(glslVersion);
557 
558         Far::PatchDescriptor::Type type = effectDesc.desc.GetType();
559 
560         // common defines
561         std::stringstream ss;
562 
563         if (type == Far::PatchDescriptor::QUADS) {
564             ss << "#define PRIM_QUAD\n";
565         } else if (type == Far::PatchDescriptor::LINES) {
566             ss << "#define PRIM_LINE\n";
567         } else {
568             ss << "#define PRIM_TRI\n";
569         }
570 
571         // OSD tessellation controls
572         if (effectDesc.effect.screenSpaceTess) {
573             ss << "#define OSD_ENABLE_SCREENSPACE_TESSELLATION\n";
574         }
575         if (effectDesc.effect.fractionalSpacing) {
576             ss << "#define OSD_FRACTIONAL_ODD_SPACING\n";
577         }
578         if (effectDesc.effect.patchCull) {
579             ss << "#define OSD_ENABLE_PATCH_CULL\n";
580         }
581 
582         // for legacy gregory
583         ss << "#define OSD_MAX_VALENCE " << effectDesc.maxValence << "\n";
584         ss << "#define OSD_NUM_ELEMENTS " << effectDesc.numElements << "\n";
585 
586         // add ptex functions
587         ss << GLPtexMipmapTexture::GetShaderSource();
588 
589         // -------------------------------------------------------------
590         // display styles
591         // -------------------------------------------------------------
592 
593         // mipmap
594         if (effectDesc.effect.seamless) {
595             ss << "#define SEAMLESS_MIPMAP\n";
596         }
597 
598         //  wire
599         if (effectDesc.effect.wire == 0) {
600             ss << "#define GEOMETRY_OUT_WIRE\n";
601         } else if (effectDesc.effect.wire == 1) {
602             ss << "#define GEOMETRY_OUT_FILL\n";
603         } else if (effectDesc.effect.wire == 2) {
604             ss << "#define GEOMETRY_OUT_LINE\n";
605         }
606 
607         //  color
608         switch(effectDesc.effect.color) {
609         case COLOR_NONE:
610             break;
611         case COLOR_PTEX_NEAREST:
612             ss << "#define COLOR_PTEX_NEAREST\n";
613             break;
614         case COLOR_PTEX_HW_BILINEAR:
615             ss << "#define COLOR_PTEX_HW_BILINEAR\n";
616             break;
617         case COLOR_PTEX_BILINEAR:
618             ss << "#define COLOR_PTEX_BILINEAR\n";
619             break;
620         case COLOR_PTEX_BIQUADRATIC:
621             ss << "#define COLOR_PTEX_BIQUADRATIC\n";
622             break;
623         case COLOR_PATCHTYPE:
624             ss << "#define COLOR_PATCHTYPE\n";
625             break;
626         case COLOR_PATCHCOORD:
627             ss << "#define COLOR_PATCHCOORD\n";
628             break;
629         case COLOR_NORMAL:
630             ss << "#define COLOR_NORMAL\n";
631             break;
632         }
633 
634         // displacement
635         switch (effectDesc.effect.displacement) {
636         case DISPLACEMENT_NONE:
637             break;
638         case DISPLACEMENT_HW_BILINEAR:
639             ss << "#define DISPLACEMENT_HW_BILINEAR\n";
640             break;
641         case DISPLACEMENT_BILINEAR:
642             ss << "#define DISPLACEMENT_BILINEAR\n";
643             break;
644         case DISPLACEMENT_BIQUADRATIC:
645             ss << "#define DISPLACEMENT_BIQUADRATIC\n";
646             break;
647         }
648 
649         // normal
650         switch (effectDesc.effect.normal) {
651         case NORMAL_FACET:
652             ss << "#define NORMAL_FACET\n";
653             break;
654         case NORMAL_HW_SCREENSPACE:
655             ss << "#define NORMAL_HW_SCREENSPACE\n";
656             break;
657         case NORMAL_SCREENSPACE:
658             ss << "#define NORMAL_SCREENSPACE\n";
659             break;
660         case NORMAL_BIQUADRATIC:
661             ss << "#define NORMAL_BIQUADRATIC\n";
662             break;
663         case NORMAL_BIQUADRATIC_WG:
664             ss << "#define OSD_COMPUTE_NORMAL_DERIVATIVES\n";
665             ss << "#define NORMAL_BIQUADRATIC_WG\n";
666             break;
667         }
668 
669         // occlusion
670         if (effectDesc.effect.occlusion)
671             ss << "#define USE_PTEX_OCCLUSION\n";
672 
673         // specular
674         if (effectDesc.effect.specular)
675             ss << "#define USE_PTEX_SPECULAR\n";
676 
677         // IBL
678         if (effectDesc.effect.ibl)
679             ss << "#define USE_IBL\n";
680 
681         // need for patch color-coding : we need these defines in the fragment shader
682         if (type == Far::PatchDescriptor::GREGORY) {
683             ss << "#define OSD_PATCH_GREGORY\n";
684         } else if (type == Far::PatchDescriptor::GREGORY_BOUNDARY) {
685             ss << "#define OSD_PATCH_GREGORY_BOUNDARY\n";
686         } else if (type == Far::PatchDescriptor::GREGORY_BASIS) {
687             ss << "#define OSD_PATCH_GREGORY_BASIS\n";
688         } else if (type == Far::PatchDescriptor::LOOP) {
689             ss << "#define OSD_PATCH_LOOP\n";
690         } else if (type == Far::PatchDescriptor::GREGORY_TRIANGLE) {
691             ss << "#define OSD_PATCH_GREGORY_TRIANGLE\n";
692         }
693 
694         // include osd PatchCommon
695         ss << Osd::GLSLPatchShaderSource::GetCommonShaderSource();
696         std::string common = ss.str();
697         ss.str("");
698 
699         // vertex shader
700         ss << common
701             // enable local vertex shader
702            << (effectDesc.desc.IsAdaptive() ? "" : "#define VERTEX_SHADER\n")
703            << g_shaderSource
704            << Osd::GLSLPatchShaderSource::GetVertexShaderSource(type);
705         config->CompileAndAttachShader(GL_VERTEX_SHADER, ss.str());
706         ss.str("");
707 
708         if (effectDesc.desc.IsAdaptive()) {
709             // tess control shader
710             ss << common
711                << g_shaderSource
712                << Osd::GLSLPatchShaderSource::GetTessControlShaderSource(type);
713             config->CompileAndAttachShader(GL_TESS_CONTROL_SHADER, ss.str());
714             ss.str("");
715 
716             // tess eval shader
717             ss << common
718                << g_shaderSource
719                << Osd::GLSLPatchShaderSource::GetTessEvalShaderSource(type);
720             config->CompileAndAttachShader(GL_TESS_EVALUATION_SHADER, ss.str());
721             ss.str("");
722         }
723 
724         // geometry shader
725         ss << common
726            << "#define GEOMETRY_SHADER\n" // enable local geometry shader
727            << g_shaderSource;
728         config->CompileAndAttachShader(GL_GEOMETRY_SHADER, ss.str());
729         ss.str("");
730 
731         // fragment shader
732         ss << common
733            << "#define FRAGMENT_SHADER\n" // enable local fragment shader
734            << g_shaderSource;
735         config->CompileAndAttachShader(GL_FRAGMENT_SHADER, ss.str());
736         ss.str("");
737 
738         if (!config->Link()) {
739             delete config;
740             return NULL;
741         }
742 
743         // assign uniform locations
744         GLuint program = config->GetProgram();
745         GLuint uboIndex = glGetUniformBlockIndex(program, "Constant");
746         if (uboIndex != GL_INVALID_INDEX)
747             glUniformBlockBinding(program, uboIndex, g_constantBinding);
748 
749         // assign texture locations
750         GLint loc;
751         // patch textures
752         glUseProgram(program);
753         if ((loc = glGetUniformLocation(program, "OsdPatchParamBuffer")) != -1) {
754             glUniform1i(loc, 0); // GL_TEXTURE0
755         }
756 
757         // environment textures
758         if ((loc = glGetUniformLocation(program, "diffuseEnvironmentMap")) != -1) {
759             glUniform1i(loc, 5);
760         }
761         if ((loc = glGetUniformLocation(program, "specularEnvironmentMap")) != -1) {
762             glUniform1i(loc, 6);
763         }
764 
765         // ptex textures
766         if ((loc = glGetUniformLocation(program, "textureImage_Data")) != -1) {
767             glUniform1i(loc, 7);
768         }
769         if ((loc = glGetUniformLocation(program, "textureImage_Packing")) != -1) {
770             glUniform1i(loc, 8);
771         }
772         if ((loc = glGetUniformLocation(program, "textureDisplace_Data")) != -1) {
773             glUniform1i(loc, 9);
774         }
775         if ((loc = glGetUniformLocation(program, "textureDisplace_Packing")) != -1) {
776             glUniform1i(loc, 10);
777         }
778         if ((loc = glGetUniformLocation(program, "textureOcclusion_Data")) != -1) {
779             glUniform1i(loc, 11);
780         }
781         if ((loc = glGetUniformLocation(program, "textureOcclusion_Packing")) != -1) {
782             glUniform1i(loc, 12);
783         }
784         if ((loc = glGetUniformLocation(program, "textureSpecular_Data")) != -1) {
785             glUniform1i(loc, 13);
786         }
787         if ((loc = glGetUniformLocation(program, "textureSpecular_Packing")) != -1) {
788             glUniform1i(loc, 14);
789         }
790 
791         glUseProgram(0);
792 
793         return config;
794     }
795 };
796 
797 ShaderCache g_shaderCache;
798 
799 //------------------------------------------------------------------------------
800 GLPtexMipmapTexture *
createPtex(const char * filename,int memLimit)801 createPtex(const char *filename, int memLimit) {
802 
803     Ptex::String ptexError;
804     printf("Loading ptex : %s\n", filename);
805 
806 #define USE_PTEX_CACHE
807 #define PTEX_CACHE_SIZE (512*1024*1024)
808 
809 #ifdef USE_PTEX_CACHE
810     PtexCache *cache = PtexCache::create(1, PTEX_CACHE_SIZE);
811     PtexTexture *ptex = cache->get(filename, ptexError);
812 #else
813     PtexTexture *ptex = PtexTexture::open(filename, ptexError, true);
814 #endif
815 
816     if (ptex == NULL) {
817         printf("Error in reading %s\n", filename);
818         exit(1);
819     }
820     if (ptex->meshType() == Ptex::mt_triangle) {
821         printf("Error in %s:  triangular Ptex not yet supported\n", filename);
822         exit(1);
823     }
824 
825     size_t targetMemory = memLimit * 1024 * 1024; // MB
826 
827     GLPtexMipmapTexture *osdPtex = GLPtexMipmapTexture::Create(
828         ptex, g_maxMipmapLevels, targetMemory);
829 
830     GLuint texture = osdPtex->GetTexelsTexture();
831     glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
832     GLint w, h, d;
833     glGetTexLevelParameteriv(GL_TEXTURE_2D_ARRAY, 0, GL_TEXTURE_WIDTH, &w);
834     glGetTexLevelParameteriv(GL_TEXTURE_2D_ARRAY, 0, GL_TEXTURE_HEIGHT, &h);
835     glGetTexLevelParameteriv(GL_TEXTURE_2D_ARRAY, 0, GL_TEXTURE_DEPTH, &d);
836     printf("PageSize = %d x %d x %d\n", w, h, d);
837     glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
838 
839     ptex->release();
840 
841 #ifdef USE_PTEX_CACHE
842     cache->release();
843 #endif
844 
845     return osdPtex;
846 }
847 
848 //------------------------------------------------------------------------------
849 
850 void
createOsdMesh(int level,int kernel)851 createOsdMesh(int level, int kernel) {
852 
853     GLUtils::CheckGLErrors("createOsdMesh");
854 
855     Ptex::String ptexError;
856     PtexTexture *ptexColor = PtexTexture::open(g_ptexColorFilename, ptexError, true);
857     if (ptexColor == NULL) {
858         printf("Error in reading %s\n", g_ptexColorFilename);
859         exit(1);
860     }
861     if (ptexColor->meshType() == Ptex::mt_triangle) {
862         printf("Error in %s:  triangular Ptex not yet supported\n", g_ptexColorFilename);
863         exit(1);
864     }
865 
866     // generate Shape representation from ptex
867     Shape * shape = createPTexGeo(ptexColor);
868     if (!shape) {
869         return;
870     }
871 
872     g_positions=shape->verts;
873 
874     // create Far mesh (topology)
875     OpenSubdiv::Sdc::SchemeType sdctype = GetSdcType(*shape);
876     OpenSubdiv::Sdc::Options sdcoptions = GetSdcOptions(*shape);
877 
878     OpenSubdiv::Far::TopologyRefiner * refiner =
879         OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Create(*shape,
880             OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions));
881 
882     // save coarse topology (used for coarse mesh drawing)
883     g_controlMeshDisplay.SetTopology(refiner->GetLevel(0));
884 
885     delete shape;
886 
887     g_normals.resize(g_positions.size(), 0.0f);
888     calcNormals(refiner, g_positions, g_normals);
889 
890     delete g_mesh;
891     g_mesh = NULL;
892 
893     OpenSubdiv::Osd::MeshBitset bits;
894     bits.set(OpenSubdiv::Osd::MeshAdaptive, g_adaptive);
895     bits.set(OpenSubdiv::Osd::MeshEndCapGregoryBasis, true);
896 
897     int numVertexElements = g_adaptive ? 3 : 6;
898     int numVaryingElements = 0;
899 
900     if (kernel == kCPU) {
901         g_mesh = new OpenSubdiv::Osd::Mesh<OpenSubdiv::Osd::CpuGLVertexBuffer,
902                                            OpenSubdiv::Far::StencilTable,
903                                            OpenSubdiv::Osd::CpuEvaluator,
904                                            OpenSubdiv::Osd::GLPatchTable>(
905                                                 refiner,
906                                                 numVertexElements,
907                                                 numVaryingElements,
908                                                 level, bits);
909 #ifdef OPENSUBDIV_HAS_OPENMP
910     } else if (kernel == kOPENMP) {
911         g_mesh = new OpenSubdiv::Osd::Mesh<OpenSubdiv::Osd::CpuGLVertexBuffer,
912                                            OpenSubdiv::Far::StencilTable,
913                                            OpenSubdiv::Osd::OmpEvaluator,
914                                            OpenSubdiv::Osd::GLPatchTable>(
915                                                 refiner,
916                                                 numVertexElements,
917                                                 numVaryingElements,
918                                                 level, bits);
919 #endif
920 #ifdef OPENSUBDIV_HAS_TBB
921     } else if (kernel == kTBB) {
922         g_mesh = new OpenSubdiv::Osd::Mesh<OpenSubdiv::Osd::CpuGLVertexBuffer,
923                                            OpenSubdiv::Far::StencilTable,
924                                            OpenSubdiv::Osd::TbbEvaluator,
925                                            OpenSubdiv::Osd::GLPatchTable>(
926                                                 refiner,
927                                                 numVertexElements,
928                                                 numVaryingElements,
929                                                 level, bits);
930 #endif
931 #ifdef OPENSUBDIV_HAS_OPENCL
932     } else if (kernel == kCL) {
933         static OpenSubdiv::Osd::EvaluatorCacheT<OpenSubdiv::Osd::CLEvaluator> clEvaluatorCache;
934         g_mesh = new OpenSubdiv::Osd::Mesh<OpenSubdiv::Osd::CLGLVertexBuffer,
935                                            OpenSubdiv::Osd::CLStencilTable,
936                                            OpenSubdiv::Osd::CLEvaluator,
937                                            OpenSubdiv::Osd::GLPatchTable,
938                                            CLDeviceContext>(
939                                                 refiner,
940                                                 numVertexElements,
941                                                 numVaryingElements,
942                                                 level, bits,
943                                                 &clEvaluatorCache,
944                                                 &g_clDeviceContext);
945 #endif
946 #ifdef OPENSUBDIV_HAS_CUDA
947     } else if (kernel == kCUDA) {
948         g_mesh = new OpenSubdiv::Osd::Mesh<OpenSubdiv::Osd::CudaGLVertexBuffer,
949                                            OpenSubdiv::Osd::CudaStencilTable,
950                                            OpenSubdiv::Osd::CudaEvaluator,
951                                            OpenSubdiv::Osd::GLPatchTable>(
952                                                 refiner,
953                                                 numVertexElements,
954                                                 numVaryingElements,
955                                                 level, bits);
956 #endif
957 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
958     } else if (kernel == kGLSL) {
959         static OpenSubdiv::Osd::EvaluatorCacheT<OpenSubdiv::Osd::GLXFBEvaluator> glXFBEvaluatorCache;
960         g_mesh = new OpenSubdiv::Osd::Mesh<OpenSubdiv::Osd::GLVertexBuffer,
961                                            OpenSubdiv::Osd::GLStencilTableTBO,
962                                            OpenSubdiv::Osd::GLXFBEvaluator,
963                                            OpenSubdiv::Osd::GLPatchTable>(
964                                                refiner,
965                                                numVertexElements,
966                                                numVaryingElements,
967                                                level, bits,
968                                                &glXFBEvaluatorCache);
969 #endif
970 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
971     } else if (kernel == kGLSLCompute) {
972         static OpenSubdiv::Osd::EvaluatorCacheT<OpenSubdiv::Osd::GLComputeEvaluator> glComputeEvaluatorCache;
973         g_mesh = new OpenSubdiv::Osd::Mesh<OpenSubdiv::Osd::GLVertexBuffer,
974                                            OpenSubdiv::Osd::GLStencilTableSSBO,
975                                            OpenSubdiv::Osd::GLComputeEvaluator,
976                                            OpenSubdiv::Osd::GLPatchTable>(
977                                                 refiner,
978                                                 numVertexElements,
979                                                 numVaryingElements,
980                                                 level, bits,
981                                                &glComputeEvaluatorCache);
982 #endif
983     } else {
984         printf("Unsupported kernel %s\n", getKernelName(kernel));
985     }
986 
987     if (glGetError() != GL_NO_ERROR) {
988         printf("GLERROR\n");
989     }
990 
991     updateGeom();
992 
993     // ------ VAO
994     glBindVertexArray(g_vao);
995 
996     glBindBuffer(GL_ARRAY_BUFFER, g_mesh->BindVertexBuffer());
997 
998     if (g_adaptive) {
999         glEnableVertexAttribArray(0);
1000         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
1001     } else {
1002         glEnableVertexAttribArray(0);
1003         glEnableVertexAttribArray(1);
1004         glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, 0);
1005         glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 6, (float*)12);
1006     }
1007     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_mesh->GetPatchTable()->GetPatchIndexBuffer());
1008 
1009     glBindVertexArray(0);
1010 }
1011 
1012 //------------------------------------------------------------------------------
1013 
1014 void
createSky()1015 createSky() {
1016 
1017     const int U_DIV = 20;
1018     const int V_DIV = 20;
1019 
1020     std::vector<float> vbo;
1021     std::vector<int> indices;
1022     for (int u = 0; u <= U_DIV; ++u) {
1023         for (int v = 0; v < V_DIV; ++v) {
1024             float s = float(2*M_PI*float(u)/U_DIV);
1025             float t = float(M_PI*float(v)/(V_DIV-1));
1026             vbo.push_back(-sin(t)*sin(s));
1027             vbo.push_back(cos(t));
1028             vbo.push_back(-sin(t)*cos(s));
1029             vbo.push_back(u/float(U_DIV));
1030             vbo.push_back(v/float(V_DIV));
1031 
1032             if (v > 0 && u > 0) {
1033                 indices.push_back((u-1)*V_DIV+v-1);
1034                 indices.push_back(u*V_DIV+v-1);
1035                 indices.push_back((u-1)*V_DIV+v);
1036                 indices.push_back((u-1)*V_DIV+v);
1037                 indices.push_back(u*V_DIV+v-1);
1038                 indices.push_back(u*V_DIV+v);
1039             }
1040         }
1041     }
1042 
1043     glGenBuffers(1, &g_sky.vertexBuffer);
1044     glBindBuffer(GL_ARRAY_BUFFER, g_sky.vertexBuffer);
1045     glBufferData(GL_ARRAY_BUFFER, sizeof(float)*vbo.size(), &vbo[0], GL_STATIC_DRAW);
1046     glBindBuffer(GL_ARRAY_BUFFER, 0);
1047 
1048     glGenBuffers(1, &g_sky.elementBuffer);
1049     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_sky.elementBuffer);
1050     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*indices.size(), &indices[0], GL_STATIC_DRAW);
1051 
1052     g_sky.numIndices = (int)indices.size();
1053 
1054     g_sky.BuildProgram(g_skyShaderSource);
1055 
1056     GLint environmentMap = glGetUniformLocation(g_sky.GetProgram(), "environmentMap");
1057     glUseProgram(g_sky.GetProgram());
1058     if (g_specularEnvironmentMap)
1059         glUniform1i(environmentMap, 6);
1060     else
1061         glUniform1i(environmentMap, 5);
1062     glUseProgram(0);
1063 
1064     g_sky.mvpMatrix = glGetUniformLocation(g_sky.GetProgram(), "ModelViewProjectionMatrix");
1065 }
1066 
1067 //------------------------------------------------------------------------------
1068 
1069 static void
updateConstantUniformBlock()1070 updateConstantUniformBlock() {
1071     struct Constant {
1072         float ModelViewMatrix[16];
1073         float ProjectionMatrix[16];
1074         float ModelViewProjectionMatrix[16];
1075         float ModelViewInverseMatrix[16];
1076         struct Light {
1077             float position[4];
1078             float ambient[4];
1079             float diffuse[4];
1080             float specular[4];
1081         } lightSource[2];
1082         float TessLevel;
1083         float displacementScale;
1084         float mipmapBias;
1085     } constantData;
1086 
1087     // transforms
1088     double aspect = g_width/(double)g_height;
1089     identity(constantData.ModelViewMatrix);
1090     translate(constantData.ModelViewMatrix, -g_pan[0], -g_pan[1], -g_dolly);
1091     rotate(constantData.ModelViewMatrix, g_rotate[1], 1, 0, 0);
1092     rotate(constantData.ModelViewMatrix, g_rotate[0], 0, 1, 0);
1093     if (!g_yup) {
1094         rotate(constantData.ModelViewMatrix, -90, 1, 0, 0);
1095     }
1096     translate(constantData.ModelViewMatrix, -g_center[0], -g_center[1], -g_center[2]);
1097     perspective(constantData.ProjectionMatrix, 45.0f, (float)aspect, g_size*0.001f,
1098                 g_size+g_dolly);
1099     multMatrix(constantData.ModelViewProjectionMatrix,
1100                constantData.ModelViewMatrix,
1101                constantData.ProjectionMatrix);
1102     inverseMatrix(constantData.ModelViewInverseMatrix,
1103                   constantData.ModelViewMatrix);
1104     // save mvp for the control mesh drawing
1105     memcpy(g_modelViewProjection, constantData.ModelViewProjectionMatrix,
1106            16*sizeof(float));
1107 
1108     // lights
1109     Constant::Light light0 = {  { 0.6f, 1.0f, 0.6f, 0.0f },
1110                                 { 0.1f, 0.1f, 0.1f, 1.0f },
1111                                 { 1.7f, 1.3f, 1.1f, 1.0f },
1112                                 { 1.0f, 1.0f, 1.0f, 1.0f } };
1113     Constant::Light light1 = {  { -0.8f, 0.6f, -0.7f, 0.0f },
1114                                 {  0.0f, 0.0f,  0.0f, 1.0f },
1115                                 {  0.8f, 0.8f,  1.5f, 1.0f },
1116                                 {  0.4f, 0.4f,  0.4f, 1.0f } };
1117     constantData.lightSource[0] = light0;
1118     constantData.lightSource[1] = light1;
1119 
1120     // other
1121     constantData.TessLevel = static_cast<float>(1 << g_tessLevel);
1122     constantData.displacementScale = g_displacementScale;
1123     constantData.mipmapBias = g_mipmapBias;
1124 
1125     // update GPU buffer
1126     if (g_constantUB == 0) {
1127         glGenBuffers(1, &g_constantUB);
1128         glBindBuffer(GL_UNIFORM_BUFFER, g_constantUB);
1129         glBufferData(GL_UNIFORM_BUFFER,
1130                      sizeof(constantData), NULL, GL_STATIC_DRAW);
1131     };
1132     glBindBuffer(GL_UNIFORM_BUFFER, g_constantUB);
1133     glBufferSubData(GL_UNIFORM_BUFFER,
1134                 0, sizeof(constantData), &constantData);
1135     glBindBuffer(GL_UNIFORM_BUFFER, 0);
1136 
1137     glBindBufferBase(GL_UNIFORM_BUFFER, g_constantBinding, g_constantUB);
1138 
1139 }
1140 
1141 static void
bindTextures()1142 bindTextures() {
1143     if (g_mesh->GetPatchTable()->GetPatchParamTextureBuffer()) {
1144         glActiveTexture(GL_TEXTURE0);
1145         glBindTexture(GL_TEXTURE_BUFFER,
1146                       g_mesh->GetPatchTable()->GetPatchParamTextureBuffer());
1147     }
1148 
1149     // other textures
1150     if (g_ibl) {
1151         if (g_diffuseEnvironmentMap) {
1152             glActiveTexture(GL_TEXTURE5);
1153             glBindTexture(GL_TEXTURE_2D, g_diffuseEnvironmentMap);
1154         }
1155         if (g_specularEnvironmentMap) {
1156             glActiveTexture(GL_TEXTURE6);
1157             glBindTexture(GL_TEXTURE_2D, g_specularEnvironmentMap);
1158         }
1159         glActiveTexture(GL_TEXTURE0);
1160     }
1161 
1162     // color ptex
1163     glActiveTexture(GL_TEXTURE7);
1164     glBindTexture(GL_TEXTURE_2D_ARRAY, g_osdPTexImage->GetTexelsTexture());
1165     glActiveTexture(GL_TEXTURE8);
1166     glBindTexture(GL_TEXTURE_BUFFER, g_osdPTexImage->GetLayoutTextureBuffer());
1167 
1168     // displacement ptex
1169     if (g_displacement != DISPLACEMENT_NONE || g_normal) {
1170         glActiveTexture(GL_TEXTURE9);
1171         glBindTexture(GL_TEXTURE_2D_ARRAY, g_osdPTexDisplacement->GetTexelsTexture());
1172         glActiveTexture(GL_TEXTURE10);
1173         glBindTexture(GL_TEXTURE_BUFFER, g_osdPTexDisplacement->GetLayoutTextureBuffer());
1174     }
1175 
1176     // occlusion ptex
1177     if (g_occlusion) {
1178         glActiveTexture(GL_TEXTURE11);
1179         glBindTexture(GL_TEXTURE_2D_ARRAY, g_osdPTexOcclusion->GetTexelsTexture());
1180         glActiveTexture(GL_TEXTURE12);
1181         glBindTexture(GL_TEXTURE_BUFFER, g_osdPTexOcclusion->GetLayoutTextureBuffer());
1182     }
1183 
1184     // specular ptex
1185     if (g_specular) {
1186         glActiveTexture(GL_TEXTURE13);
1187         glBindTexture(GL_TEXTURE_2D_ARRAY, g_osdPTexSpecular->GetTexelsTexture());
1188         glActiveTexture(GL_TEXTURE14);
1189         glBindTexture(GL_TEXTURE_BUFFER, g_osdPTexSpecular->GetLayoutTextureBuffer());
1190     }
1191 
1192     glActiveTexture(GL_TEXTURE0);
1193 }
1194 
1195 //------------------------------------------------------------------------------
1196 static GLenum
bindProgram(Effect effect,OpenSubdiv::Osd::PatchArray const & patch)1197 bindProgram(Effect effect,
1198             OpenSubdiv::Osd::PatchArray const & patch) {
1199     EffectDesc effectDesc(patch.GetDescriptor(), effect);
1200 
1201     GLDrawConfig *config = g_shaderCache.GetDrawConfig(effectDesc);
1202     if (!config) return 0;
1203 
1204     GLuint program = config->GetProgram();
1205 
1206     glUseProgram(program);
1207 
1208     // bind standalone uniforms
1209     GLint uniformPrimitiveIdBase =
1210         glGetUniformLocation(program, "PrimitiveIdBase");
1211     if (uniformPrimitiveIdBase >= 0)
1212         glUniform1i(uniformPrimitiveIdBase, patch.GetPrimitiveIdBase());
1213 
1214     GLenum primType;
1215     switch(effectDesc.desc.GetType()) {
1216     case OpenSubdiv::Far::PatchDescriptor::QUADS:
1217         primType = GL_LINES_ADJACENCY;
1218         break;
1219     case OpenSubdiv::Far::PatchDescriptor::TRIANGLES:
1220         primType = GL_TRIANGLES;
1221         break;
1222     default:
1223 #if defined(GL_ARB_tessellation_shader) || defined(GL_VERSION_4_0)
1224         primType = GL_PATCHES;
1225         glPatchParameteri(GL_PATCH_VERTICES, effectDesc.desc.GetNumControlVertices());
1226 #else
1227         primType = GL_POINTS;
1228 #endif
1229     }
1230 
1231     return primType;
1232 }
1233 
1234 //------------------------------------------------------------------------------
1235 void
drawModel()1236 drawModel() {
1237     g_mesh->BindVertexBuffer();
1238 
1239     // bind patch related textures and PtexTexture
1240     bindTextures();
1241 
1242     glBindVertexArray(g_vao);
1243 
1244     // patch drawing
1245     OpenSubdiv::Osd::PatchArrayVector const & patches =
1246         g_mesh->GetPatchTable()->GetPatchArrays();
1247     for (int i = 0; i < (int)patches.size(); ++i) {
1248         OpenSubdiv::Osd::PatchArray const & patch = patches[i];
1249 
1250         Effect effect;
1251         effect.value = 0;
1252 
1253         effect.color = g_color;
1254         effect.displacement = g_displacement;
1255         effect.occlusion = g_occlusion;
1256         effect.normal = g_normal;
1257         effect.specular = g_specular;
1258         effect.patchCull = g_patchCull;
1259         effect.screenSpaceTess = g_screenSpaceTess;
1260         effect.fractionalSpacing = g_fractionalSpacing;
1261         effect.ibl = g_ibl;
1262         effect.wire = g_wire;
1263         effect.seamless = g_seamless;
1264 
1265         GLenum primType = bindProgram(effect, patch);
1266 
1267         glDrawElements(primType,
1268                        patch.GetNumPatches() * patch.GetDescriptor().GetNumControlVertices(),
1269                        GL_UNSIGNED_INT,
1270                        (void *)(patch.GetIndexBase() * sizeof(unsigned int)));
1271     }
1272 
1273     glBindVertexArray(0);
1274 }
1275 
1276 //------------------------------------------------------------------------------
1277 
1278 void
drawSky()1279 drawSky() {
1280     glUseProgram(g_sky.GetProgram());
1281 
1282     glDisable(GL_DEPTH_TEST);
1283     glDepthMask(GL_FALSE);
1284 
1285     float modelView[16], projection[16], mvp[16];
1286     double aspect = g_width/(double)g_height;
1287 
1288     identity(modelView);
1289     rotate(modelView, g_rotate[1], 1, 0, 0);
1290     rotate(modelView, g_rotate[0], 0, 1, 0);
1291     perspective(projection, 45.0f, (float)aspect, g_size*0.001f, g_size+g_dolly);
1292     multMatrix(mvp, modelView, projection);
1293     glUniformMatrix4fv(g_sky.mvpMatrix, 1, GL_FALSE, mvp);
1294 
1295     glBindVertexArray(g_skyVAO);
1296 
1297     glEnableVertexAttribArray(0);
1298     glEnableVertexAttribArray(1);
1299 
1300     glBindBuffer(GL_ARRAY_BUFFER, g_sky.vertexBuffer);
1301     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, 0);
1302     glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5,
1303                           (void*)(sizeof(GLfloat)*3));
1304 
1305     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_sky.elementBuffer);
1306     glDrawElements(GL_TRIANGLES, g_sky.numIndices, GL_UNSIGNED_INT, 0);
1307 
1308     glDisableVertexAttribArray(0);
1309     glDisableVertexAttribArray(1);
1310 
1311     glBindVertexArray(0);
1312 
1313     glEnable(GL_DEPTH_TEST);
1314     glDepthMask(GL_TRUE);
1315 
1316     GLUtils::CheckGLErrors("draw model");
1317 }
1318 
1319 //------------------------------------------------------------------------------
1320 
1321 void
display()1322 display() {
1323 
1324     Stopwatch s;
1325     s.Start();
1326 
1327     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1328     glViewport(0, 0, g_width, g_height);
1329     g_hud.FillBackground();
1330 
1331     if (g_ibl) {
1332         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1333         drawSky();
1334     }
1335 
1336     // update transform and light
1337     updateConstantUniformBlock();
1338 
1339     glEnable(GL_DEPTH_TEST);
1340     if (g_wire == DISPLAY_WIRE) {
1341         glDisable(GL_CULL_FACE);
1342     }
1343 
1344     // primitive counting
1345     glBeginQuery(GL_PRIMITIVES_GENERATED, g_queries[0]);
1346 #if defined(GL_VERSION_3_3)
1347     glBeginQuery(GL_TIME_ELAPSED, g_queries[1]);
1348 #endif
1349 
1350     drawModel();
1351 
1352     glEndQuery(GL_PRIMITIVES_GENERATED);
1353 #if defined(GL_VERSION_3_3)
1354     glEndQuery(GL_TIME_ELAPSED);
1355 #endif
1356 
1357     // draw the control mesh
1358     {
1359         GLuint vbo = g_mesh->BindVertexBuffer();
1360         int stride = g_adaptive ? 3 : 6;
1361         g_controlMeshDisplay.Draw(vbo, stride*sizeof(float),
1362                                   g_modelViewProjection);
1363     }
1364 
1365     if (g_wire == DISPLAY_WIRE) {
1366         glEnable(GL_CULL_FACE);
1367     }
1368     glDisable(GL_DEPTH_TEST);
1369 
1370     glUseProgram(0);
1371 
1372     s.Stop();
1373     float drawCpuTime = float(s.GetElapsed() * 1000.0f);
1374 
1375     GLuint numPrimsGenerated = 0;
1376     GLuint timeElapsed = 0;
1377     glGetQueryObjectuiv(g_queries[0], GL_QUERY_RESULT, &numPrimsGenerated);
1378 #if defined(GL_VERSION_3_3)
1379     glGetQueryObjectuiv(g_queries[1], GL_QUERY_RESULT, &timeElapsed);
1380 #endif
1381     float drawGpuTime = timeElapsed / 1000.0f / 1000.0f;
1382 
1383     g_fpsTimer.Stop();
1384     float elapsed = (float)g_fpsTimer.GetElapsed();
1385     if (!g_freeze)
1386         g_animTime += elapsed;
1387     g_fpsTimer.Start();
1388 
1389     if (g_hud.IsVisible()) {
1390         double fps = 1.0/elapsed;
1391 
1392         // Average fps over a defined number of time samples for
1393         // easier reading in the HUD
1394         g_fpsTimeSamples[g_currentFpsTimeSample++] = float(fps);
1395         if (g_currentFpsTimeSample >= NUM_FPS_TIME_SAMPLES)
1396             g_currentFpsTimeSample = 0;
1397         double averageFps = 0;
1398         for (int i = 0; i < NUM_FPS_TIME_SAMPLES; ++i) {
1399             averageFps += g_fpsTimeSamples[i]/(float)NUM_FPS_TIME_SAMPLES;
1400         }
1401 
1402         g_hud.DrawString(10, -220, "Ptex memory use : %.1f mb", g_ptexMemoryUsage/1024.0/1024.0);
1403         g_hud.DrawString(10, -180, "Tess level (+/-): %d", g_tessLevel);
1404         if (numPrimsGenerated > 1000000) {
1405             g_hud.DrawString(10, -160, "Primitives      : %3.1f million",
1406                              (float)numPrimsGenerated/1000000.0);
1407         } else if (numPrimsGenerated > 1000) {
1408             g_hud.DrawString(10, -160, "Primitives      : %3.1f thousand",
1409                              (float)numPrimsGenerated/1000.0);
1410         } else {
1411             g_hud.DrawString(10, -160, "Primitives      : %d", numPrimsGenerated);
1412         }
1413         g_hud.DrawString(10, -140, "Vertices        : %d", g_mesh->GetNumVertices());
1414         g_hud.DrawString(10, -120, "Scheme          : %s", g_scheme == 0 ? "CATMARK" : "BILINEAR");
1415         g_hud.DrawString(10, -100, "GPU Kernel      : %.3f ms", g_gpuTime);
1416         g_hud.DrawString(10, -80,  "CPU Kernel      : %.3f ms", g_cpuTime);
1417         g_hud.DrawString(10, -60,  "GPU Draw        : %.3f ms", drawGpuTime);
1418         g_hud.DrawString(10, -40,  "CPU Draw        : %.3f ms", drawCpuTime);
1419         g_hud.DrawString(10, -20,  "FPS             : %3.1f", averageFps);
1420 
1421         g_hud.Flush();
1422     }
1423 
1424     glFinish();
1425 
1426     GLUtils::CheckGLErrors("draw end");
1427 }
1428 
1429 //------------------------------------------------------------------------------
1430 static void
mouse(GLFWwindow *,int button,int state,int)1431 mouse(GLFWwindow *, int button, int state, int /* mods */) {
1432 
1433     if (state == GLFW_RELEASE)
1434         g_hud.MouseRelease();
1435 
1436     if (button == 0 && state == GLFW_PRESS && g_hud.MouseClick(g_prev_x, g_prev_y))
1437         return;
1438     g_mbutton[button] = (state == GLFW_PRESS);
1439 }
1440 
1441 //------------------------------------------------------------------------------
1442 static void
motion(GLFWwindow *,double dx,double dy)1443 motion(GLFWwindow *, double dx, double dy) {
1444     int x = (int)dx, y = (int)dy;
1445 
1446     if (g_hud.MouseCapture()) {
1447         // check gui
1448         g_hud.MouseMotion(x, y);
1449     } else if (g_mbutton[0] && !g_mbutton[1] && !g_mbutton[2]) {
1450         // orbit
1451         g_rotate[0] += x - g_prev_x;
1452         g_rotate[1] += y - g_prev_y;
1453     } else if (!g_mbutton[0] && !g_mbutton[1] && g_mbutton[2]) {
1454         // pan
1455         g_pan[0] -= g_dolly*(x - g_prev_x)/g_width;
1456         g_pan[1] += g_dolly*(y - g_prev_y)/g_height;
1457     } else if ((g_mbutton[0] && !g_mbutton[1] && g_mbutton[2]) ||
1458                (!g_mbutton[0] && g_mbutton[1] && !g_mbutton[2])) {
1459         // dolly
1460         g_dolly -= g_dolly*0.01f*(x - g_prev_x);
1461         if (g_dolly <= 0.01) g_dolly = 0.01f;
1462     }
1463 
1464     g_prev_x = x;
1465     g_prev_y = y;
1466 }
1467 
1468 //------------------------------------------------------------------------------
uninitGL()1469 void uninitGL() {
1470     if (g_osdPTexImage) delete g_osdPTexImage;
1471     if (g_osdPTexDisplacement) delete g_osdPTexDisplacement;
1472     if (g_osdPTexOcclusion) delete g_osdPTexOcclusion;
1473     if (g_osdPTexSpecular) delete g_osdPTexSpecular;
1474 
1475     glDeleteQueries(2, g_queries);
1476     glDeleteVertexArrays(1, &g_vao);
1477     glDeleteVertexArrays(1, &g_skyVAO);
1478 
1479     if (g_mesh)
1480         delete g_mesh;
1481 
1482     if (g_diffuseEnvironmentMap)
1483         glDeleteTextures(1, &g_diffuseEnvironmentMap);
1484     if (g_specularEnvironmentMap)
1485         glDeleteTextures(1, &g_specularEnvironmentMap);
1486 
1487     if (g_sky.vertexBuffer) glDeleteBuffers(1, &g_sky.vertexBuffer);
1488     if (g_sky.elementBuffer) glDeleteBuffers(1, &g_sky.elementBuffer);
1489 }
1490 
1491 //------------------------------------------------------------------------------
1492 static void
callbackWireframe(int b)1493 callbackWireframe(int b) {
1494     g_wire = b;
1495 }
1496 static void
callbackKernel(int k)1497 callbackKernel(int k) {
1498     g_kernel = k;
1499 
1500 #ifdef OPENSUBDIV_HAS_OPENCL
1501     if (g_kernel == kCL && (!g_clDeviceContext.IsInitialized())) {
1502         // Initialize OpenCL
1503         if (g_clDeviceContext.Initialize() == false) {
1504             printf("Error in initializing OpenCL\n");
1505             exit(1);
1506         }
1507     }
1508 #endif
1509 #ifdef OPENSUBDIV_HAS_CUDA
1510     if (g_kernel == kCUDA && (!g_cudaDeviceContext.IsInitialized())) {
1511         if (g_cudaDeviceContext.Initialize() == false) {
1512             printf("Error in initializing Cuda\n");
1513             exit(1);
1514         }
1515     }
1516 #endif
1517     createOsdMesh(g_level, g_kernel);
1518 }
1519 
1520 static void
callbackScheme(int s)1521 callbackScheme(int s) {
1522     g_scheme = s;
1523     createOsdMesh(g_level, g_kernel);
1524 }
1525 static void
callbackLevel(int l)1526 callbackLevel(int l) {
1527     g_level = l;
1528     createOsdMesh(g_level, g_kernel);
1529 }
1530 static void
callbackColor(int c)1531 callbackColor(int c) {
1532     g_color = c;
1533 }
1534 static void
callbackDisplacement(int d)1535 callbackDisplacement(int d) {
1536     g_displacement = d;
1537 }
1538 static void
callbackNormal(int n)1539 callbackNormal(int n) {
1540     g_normal = n;
1541 }
1542 static void
callbackCheckBox(bool checked,int button)1543 callbackCheckBox(bool checked, int button) {
1544     bool rebuild = false;
1545 
1546     switch (button) {
1547     case HUD_CB_ADAPTIVE:
1548         if (GLUtils::SupportsAdaptiveTessellation()) {
1549             g_adaptive = checked;
1550             rebuild = true;
1551         }
1552         break;
1553     case HUD_CB_DISPLAY_OCCLUSION:
1554         g_occlusion = checked;
1555         break;
1556     case HUD_CB_DISPLAY_SPECULAR:
1557         g_specular = checked;
1558         break;
1559     case HUD_CB_CONTROL_MESH_EDGES:
1560         g_controlMeshDisplay.SetEdgesDisplay(checked);
1561         break;
1562     case HUD_CB_ANIMATE_VERTICES:
1563         g_moveScale = checked ? 1.0f : 0.0f;
1564         g_animTime = 0;
1565         break;
1566     case HUD_CB_VIEW_LOD:
1567         g_screenSpaceTess = checked;
1568         break;
1569     case HUD_CB_FRACTIONAL_SPACING:
1570         g_fractionalSpacing = checked;
1571         break;
1572     case HUD_CB_PATCH_CULL:
1573         g_patchCull = checked;
1574         break;
1575     case HUD_CB_IBL:
1576         g_ibl = checked;
1577         break;
1578     case HUD_CB_BLOOM:
1579         g_bloom = checked;
1580         break;
1581     case HUD_CB_SEAMLESS_MIPMAP:
1582         g_seamless = checked;
1583         break;
1584     case HUD_CB_FREEZE:
1585         g_freeze = checked;
1586         break;
1587     }
1588 
1589     if (rebuild)
1590         createOsdMesh(g_level, g_kernel);
1591 }
1592 
1593 static void
callbackSlider(float value,int data)1594 callbackSlider(float value, int data) {
1595     switch (data) {
1596     case 0:
1597         g_mipmapBias = value;
1598         break;
1599     case 1:
1600         g_displacementScale = value;
1601         break;
1602     }
1603 }
1604 //-------------------------------------------------------------------------------
1605 void
reloadShaderFile()1606 reloadShaderFile() {
1607     if (!g_shaderFilename) return;
1608 
1609     std::ifstream ifs(g_shaderFilename);
1610     if (!ifs) return;
1611     printf("Load shader %s\n", g_shaderFilename);
1612 
1613     std::stringstream ss;
1614     ss << ifs.rdbuf();
1615     ifs.close();
1616 
1617     g_shaderSource = ss.str();
1618 
1619     g_shaderCache.Reset();
1620 }
1621 
1622 //------------------------------------------------------------------------------
1623 static void
toggleFullScreen()1624 toggleFullScreen() {
1625     // XXXX manuelk : to re-implement from glut
1626 }
1627 
1628 //------------------------------------------------------------------------------
1629 void
keyboard(GLFWwindow *,int key,int,int event,int)1630 keyboard(GLFWwindow *, int key, int /* scancode */, int event, int /* mods */) {
1631 
1632     if (event == GLFW_RELEASE) return;
1633     if (g_hud.KeyDown(tolower(key))) return;
1634 
1635     switch (key) {
1636         case 'Q': g_running = 0; break;
1637         case 'E': g_drawNormals = (g_drawNormals+1)%2; break;
1638         case 'F': fitFrame(); break;
1639         case GLFW_KEY_TAB: toggleFullScreen(); break;
1640         case 'R': reloadShaderFile(); createOsdMesh(g_level, g_kernel); break;
1641         case '+':
1642         case '=': g_tessLevel++; break;
1643         case '-': g_tessLevel = std::max(1, g_tessLevel-1); break;
1644         case GLFW_KEY_ESCAPE: g_hud.SetVisible(!g_hud.IsVisible()); break;
1645         case 'X': GLUtils::WriteScreenshot(g_width, g_height); break;
1646     }
1647 }
1648 
1649 //------------------------------------------------------------------------------
1650 void
idle()1651 idle() {
1652     if (!g_freeze)
1653         g_frame++;
1654 
1655     updateGeom();
1656 
1657     if (g_repeatCount != 0 && g_frame >= g_repeatCount)
1658         g_running = 0;
1659 }
1660 
1661 //------------------------------------------------------------------------------
1662 void
initGL()1663 initGL() {
1664     glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
1665     glEnable(GL_DEPTH_TEST);
1666     glDepthFunc(GL_LEQUAL);
1667     glEnable(GL_CULL_FACE);
1668 
1669     glGenQueries(2, g_queries);
1670     glGenVertexArrays(1, &g_vao);
1671     glGenVertexArrays(1, &g_skyVAO);
1672 
1673     glBindTexture(GL_TEXTURE_2D, 0);
1674 }
1675 
1676 //------------------------------------------------------------------------------
usage(const char * program)1677 void usage(const char *program) {
1678     printf("Usage: %s [options] <color.ptx> [<displacement.ptx>] [occlusion.ptx>] "
1679            "[specular.ptx] [pose.obj]...\n", program);
1680     printf("Options:  -l level                : subdivision level\n");
1681     printf("          -c count                : frame count until exit (for profiler)\n");
1682     printf("          -d <diffseEnvMap.hdr>   : diffuse environment map for IBL\n");
1683     printf("          -e <specularEnvMap.hdr> : specular environment map for IBL\n");
1684     printf("          -s <shaderfile.glsl>    : custom shader file\n");
1685     printf("          -yup                    : Y-up model\n");
1686     printf("          -m level                : max mipmap level (default=10)\n");
1687     printf("          -x <ptex limit MB>      : ptex target memory size\n");
1688     printf("          --disp <scale>          : Displacement scale\n");
1689 }
1690 
1691 //------------------------------------------------------------------------------
1692 static void
callbackError(OpenSubdiv::Far::ErrorType err,const char * message)1693 callbackError(OpenSubdiv::Far::ErrorType err, const char *message) {
1694     printf("OpenSubdiv Error: %d\n", err);
1695     printf("    %s\n", message);
1696 }
1697 
1698 //------------------------------------------------------------------------------
1699 static void
callbackErrorGLFW(int error,const char * description)1700 callbackErrorGLFW(int error, const char* description) {
1701     fprintf(stderr, "GLFW Error (%d) : %s\n", error, description);
1702 }
1703 
1704 //------------------------------------------------------------------------------
main(int argc,char ** argv)1705 int main(int argc, char ** argv) {
1706 
1707     ArgOptions args;
1708     args.Parse(argc, argv);
1709 
1710     const std::vector<const char *> &animobjs = args.GetObjFiles();
1711     bool fullscreen = args.GetFullScreen();
1712 
1713     g_yup = args.GetYUp();
1714     g_adaptive = args.GetAdaptive();
1715     g_level = args.GetLevel();
1716     g_repeatCount = args.GetRepeatCount();
1717 
1718     //  Retrieve and parse remaining args:
1719     const std::vector<const char *> &argvRem = args.GetRemainingArgs();
1720 
1721     const char *diffuseEnvironmentMap = NULL, *specularEnvironmentMap = NULL;
1722     const char *colorFilename = NULL, *displacementFilename = NULL,
1723         *occlusionFilename = NULL, *specularFilename = NULL;
1724     int memLimit = 0, colorMem = 0, displacementMem = 0,
1725         occlusionMem = 0, specularMem = 0;
1726 
1727     for (size_t i = 0; i < argvRem.size(); ++i) {
1728         if (!strcmp(argvRem[i], "-d"))
1729             diffuseEnvironmentMap = argvRem[++i];
1730         else if (!strcmp(argvRem[i], "-e"))
1731             specularEnvironmentMap = argvRem[++i];
1732         else if (!strcmp(argvRem[i], "-s"))
1733             g_shaderFilename = argvRem[++i];
1734         else if (!strcmp(argvRem[i], "-m"))
1735             g_maxMipmapLevels = atoi(argvRem[++i]);
1736         else if (!strcmp(argvRem[i], "-x"))
1737             memLimit = atoi(argvRem[++i]);
1738         else if (!strcmp(argvRem[i], "--disp"))
1739             g_displacementScale = (float)atof(argvRem[++i]);
1740         else if (colorFilename == NULL) {
1741             colorFilename = argvRem[i];
1742             colorMem = memLimit;
1743         } else if (displacementFilename == NULL) {
1744             displacementFilename = argvRem[i];
1745             displacementMem = memLimit;
1746             g_displacement = DISPLACEMENT_BILINEAR;
1747             g_normal = NORMAL_BIQUADRATIC;
1748         } else if (occlusionFilename == NULL) {
1749             occlusionFilename = argvRem[i];
1750             occlusionMem = memLimit;
1751             g_occlusion = 1;
1752         } else if (specularFilename == NULL) {
1753             specularFilename = argvRem[i];
1754             specularMem = memLimit;
1755             g_specular = 1;
1756         }
1757     }
1758 
1759     OpenSubdiv::Far::SetErrorCallback(callbackError);
1760 
1761     g_shaderSource = g_defaultShaderSource;
1762     reloadShaderFile();
1763 
1764     g_ptexColorFilename = colorFilename;
1765     if (g_ptexColorFilename == NULL) {
1766         usage(argv[0]);
1767         return 1;
1768     }
1769 
1770     glfwSetErrorCallback(callbackErrorGLFW);
1771     if (!glfwInit()) {
1772         printf("Failed to initialize GLFW\n");
1773         return 1;
1774     }
1775 
1776     static const char windowTitle[] = "OpenSubdiv glPtexViewer" OPENSUBDIV_VERSION_STRING;
1777 
1778     GLUtils::SetMinimumGLVersion();
1779 
1780     if (fullscreen) {
1781         g_primary = glfwGetPrimaryMonitor();
1782 
1783         // apparently glfwGetPrimaryMonitor fails under linux : if no primary,
1784         // settle for the first one in the list
1785         if (!g_primary) {
1786             int count = 0;
1787             GLFWmonitor ** monitors = glfwGetMonitors(&count);
1788 
1789             if (count)
1790                 g_primary = monitors[0];
1791         }
1792 
1793         if (g_primary) {
1794             GLFWvidmode const * vidmode = glfwGetVideoMode(g_primary);
1795             g_width = vidmode->width;
1796             g_height = vidmode->height;
1797         }
1798     }
1799 
1800     if (!(g_window=glfwCreateWindow(g_width, g_height, windowTitle,
1801                                fullscreen && g_primary ? g_primary : NULL, NULL))) {
1802         std::cerr << "Failed to create OpenGL context.\n";
1803         glfwTerminate();
1804         return 1;
1805     }
1806 
1807     glfwMakeContextCurrent(g_window);
1808 
1809     GLUtils::InitializeGL();
1810     GLUtils::PrintGLVersion();
1811 
1812     glfwSetKeyCallback(g_window, keyboard);
1813     glfwSetCursorPosCallback(g_window, motion);
1814     glfwSetMouseButtonCallback(g_window, mouse);
1815 
1816     initGL();
1817 
1818     // accommodate high DPI displays (e.g. mac retina displays)
1819     glfwGetFramebufferSize(g_window, &g_width, &g_height);
1820     glfwSetFramebufferSizeCallback(g_window, reshape);
1821 
1822     glfwSetWindowCloseCallback(g_window, windowClose);
1823     // as of GLFW 3.0.1 this callback is not implicit
1824     reshape();
1825 
1826     // activate feature adaptive tessellation if OSD supports it
1827     g_adaptive = g_adaptive && GLUtils::SupportsAdaptiveTessellation();
1828 
1829     int windowWidth = g_width, windowHeight = g_height;
1830 
1831     // window size might not match framebuffer size on a high DPI display
1832     glfwGetWindowSize(g_window, &windowWidth, &windowHeight);
1833 
1834     g_hud.Init(windowWidth, windowHeight, g_width, g_height);
1835 
1836     g_controlMeshDisplay.SetEdgesDisplay(false);
1837 
1838     if (occlusionFilename != NULL) {
1839         g_hud.AddCheckBox("Ambient Occlusion (A)", g_occlusion,
1840                           -200, 570, callbackCheckBox, HUD_CB_DISPLAY_OCCLUSION, 'a');
1841     }
1842     if (specularFilename != NULL)
1843         g_hud.AddCheckBox("Specular (S)", g_specular,
1844                           -200, 590, callbackCheckBox, HUD_CB_DISPLAY_SPECULAR, 's');
1845 
1846     if (diffuseEnvironmentMap || specularEnvironmentMap) {
1847         g_hud.AddCheckBox("IBL (I)", g_ibl,
1848                           -200, 610, callbackCheckBox, HUD_CB_IBL, 'i');
1849     }
1850 
1851     g_hud.AddCheckBox("Control edges (H)",
1852                       g_controlMeshDisplay.GetEdgesDisplay(),
1853                       10, 10, callbackCheckBox,
1854                       HUD_CB_CONTROL_MESH_EDGES, 'h');
1855     g_hud.AddCheckBox("Animate vertices (M)", g_moveScale != 0.0,
1856                       10, 30, callbackCheckBox, HUD_CB_ANIMATE_VERTICES, 'm');
1857     g_hud.AddCheckBox("Screen space LOD (V)",  g_screenSpaceTess,
1858                       10, 50, callbackCheckBox, HUD_CB_VIEW_LOD, 'v');
1859     g_hud.AddCheckBox("Fractional spacing (T)",  g_fractionalSpacing,
1860                       10, 70, callbackCheckBox, HUD_CB_FRACTIONAL_SPACING, 't');
1861     g_hud.AddCheckBox("Frustum Patch Culling (B)",  g_patchCull,
1862                       10, 90, callbackCheckBox, HUD_CB_PATCH_CULL, 'b');
1863     g_hud.AddCheckBox("Bloom (Y)", g_bloom,
1864                       10, 110, callbackCheckBox, HUD_CB_BLOOM, 'y');
1865     g_hud.AddCheckBox("Freeze (spc)", g_freeze,
1866                       10, 130, callbackCheckBox, HUD_CB_FREEZE, ' ');
1867 
1868     g_hud.AddRadioButton(HUD_RB_SCHEME, "CATMARK", true, 10, 190, callbackScheme, 0);
1869     g_hud.AddRadioButton(HUD_RB_SCHEME, "BILINEAR", false, 10, 210, callbackScheme, 1);
1870 
1871     if (GLUtils::SupportsAdaptiveTessellation())
1872         g_hud.AddCheckBox("Adaptive (`)", g_adaptive,
1873                           10, 300, callbackCheckBox, HUD_CB_ADAPTIVE, '`');
1874 
1875     for (int i = 1; i < 8; ++i) {
1876         char level[16];
1877         sprintf(level, "Lv. %d", i);
1878         g_hud.AddRadioButton(HUD_RB_LEVEL, level, i == g_level,
1879                              10, 320+i*20, callbackLevel, i, '0'+i);
1880     }
1881 
1882     int compute_pulldown = g_hud.AddPullDown("Compute (K)", 475, 10, 300, callbackKernel, 'k');
1883     g_hud.AddPullDownButton(compute_pulldown, "CPU", kCPU);
1884 #ifdef OPENSUBDIV_HAS_OPENMP
1885     g_hud.AddPullDownButton(compute_pulldown, "OpenMP", kOPENMP);
1886 #endif
1887 #ifdef OPENSUBDIV_HAS_TBB
1888     g_hud.AddPullDownButton(compute_pulldown, "TBB", kTBB);
1889 #endif
1890 #ifdef OPENSUBDIV_HAS_CUDA
1891     g_hud.AddPullDownButton(compute_pulldown, "CUDA", kCUDA);
1892 #endif
1893 #ifdef OPENSUBDIV_HAS_OPENCL
1894     if (CLDeviceContext::HAS_CL_VERSION_1_1()) {
1895         g_hud.AddPullDownButton(compute_pulldown, "OpenCL", kCL);
1896     }
1897 #endif
1898 #ifdef OPENSUBDIV_HAS_GLSL_TRANSFORM_FEEDBACK
1899     g_hud.AddPullDownButton(compute_pulldown, "GLSL TransformFeedback", kGLSL);
1900 #endif
1901 #ifdef OPENSUBDIV_HAS_GLSL_COMPUTE
1902     if (GLUtils::GL_ARBComputeShaderOrGL_VERSION_4_3()) {
1903         g_hud.AddPullDownButton(compute_pulldown, "GLSL Compute", kGLSLCompute);
1904     }
1905 #endif
1906 
1907     int shading_pulldown = g_hud.AddPullDown("Shading (W)", 250, 10, 250, callbackWireframe, 'w');
1908     g_hud.AddPullDownButton(shading_pulldown, "Wire", DISPLAY_WIRE, g_wire==DISPLAY_WIRE);
1909     g_hud.AddPullDownButton(shading_pulldown, "Shaded", DISPLAY_SHADED, g_wire==DISPLAY_SHADED);
1910     g_hud.AddPullDownButton(shading_pulldown, "Wire+Shaded", DISPLAY_WIRE_ON_SHADED, g_wire==DISPLAY_WIRE_ON_SHADED);
1911 
1912     g_hud.AddLabel("Color (C)", -200, 10);
1913     g_hud.AddRadioButton(HUD_RB_COLOR, "None", (g_color == COLOR_NONE),
1914                          -200, 30, callbackColor, COLOR_NONE, 'c');
1915     g_hud.AddRadioButton(HUD_RB_COLOR, "Ptex Nearest", (g_color == COLOR_PTEX_NEAREST),
1916                          -200, 50, callbackColor, COLOR_PTEX_NEAREST, 'c');
1917     g_hud.AddRadioButton(HUD_RB_COLOR, "Ptex HW bilinear", (g_color == COLOR_PTEX_HW_BILINEAR),
1918                          -200, 70, callbackColor, COLOR_PTEX_HW_BILINEAR, 'c');
1919     g_hud.AddRadioButton(HUD_RB_COLOR, "Ptex bilinear", (g_color == COLOR_PTEX_BILINEAR),
1920                          -200, 90, callbackColor, COLOR_PTEX_BILINEAR, 'c');
1921     g_hud.AddRadioButton(HUD_RB_COLOR, "Ptex biquadratic", (g_color == COLOR_PTEX_BIQUADRATIC),
1922                          -200, 110, callbackColor, COLOR_PTEX_BIQUADRATIC, 'c');
1923     g_hud.AddRadioButton(HUD_RB_COLOR, "Patch type", (g_color == COLOR_PATCHTYPE),
1924                          -200, 130, callbackColor, COLOR_PATCHTYPE, 'c');
1925     g_hud.AddRadioButton(HUD_RB_COLOR, "Patch coord", (g_color == COLOR_PATCHCOORD),
1926                          -200, 150, callbackColor, COLOR_PATCHCOORD, 'c');
1927     g_hud.AddRadioButton(HUD_RB_COLOR, "Normal", (g_color == COLOR_NORMAL),
1928                          -200, 170, callbackColor, COLOR_NORMAL, 'c');
1929 
1930     if (displacementFilename != NULL) {
1931         g_hud.AddLabel("Displacement (D)", -200, 200);
1932         g_hud.AddRadioButton(HUD_RB_DISPLACEMENT, "None",
1933                              (g_displacement == DISPLACEMENT_NONE),
1934                              -200, 220, callbackDisplacement, DISPLACEMENT_NONE, 'd');
1935         g_hud.AddRadioButton(HUD_RB_DISPLACEMENT, "HW bilinear",
1936                              (g_displacement == DISPLACEMENT_HW_BILINEAR),
1937                              -200, 240, callbackDisplacement, DISPLACEMENT_HW_BILINEAR, 'd');
1938         g_hud.AddRadioButton(HUD_RB_DISPLACEMENT, "Bilinear",
1939                              (g_displacement == DISPLACEMENT_BILINEAR),
1940                              -200, 260, callbackDisplacement, DISPLACEMENT_BILINEAR, 'd');
1941         g_hud.AddRadioButton(HUD_RB_DISPLACEMENT, "Biquadratic",
1942                              (g_displacement == DISPLACEMENT_BIQUADRATIC),
1943                              -200, 280, callbackDisplacement, DISPLACEMENT_BIQUADRATIC, 'd');
1944 
1945         g_hud.AddLabel("Normal (N)", -200, 310);
1946         g_hud.AddRadioButton(HUD_RB_NORMAL, "Surface",
1947                              (g_normal == NORMAL_SURFACE),
1948                              -200, 330, callbackNormal, NORMAL_SURFACE, 'n');
1949         g_hud.AddRadioButton(HUD_RB_NORMAL, "Facet",
1950                              (g_normal == NORMAL_FACET),
1951                              -200, 350, callbackNormal, NORMAL_FACET, 'n');
1952         g_hud.AddRadioButton(HUD_RB_NORMAL, "HW Screen space",
1953                              (g_normal == NORMAL_HW_SCREENSPACE),
1954                              -200, 370, callbackNormal, NORMAL_HW_SCREENSPACE, 'n');
1955         g_hud.AddRadioButton(HUD_RB_NORMAL, "Screen space",
1956                              (g_normal == NORMAL_SCREENSPACE),
1957                              -200, 390, callbackNormal, NORMAL_SCREENSPACE, 'n');
1958         g_hud.AddRadioButton(HUD_RB_NORMAL, "Biquadratic",
1959                              (g_normal == NORMAL_BIQUADRATIC),
1960                              -200, 410, callbackNormal, NORMAL_BIQUADRATIC, 'n');
1961         g_hud.AddRadioButton(HUD_RB_NORMAL, "Biquadratic WG",
1962                              (g_normal == NORMAL_BIQUADRATIC_WG),
1963                              -200, 430, callbackNormal, NORMAL_BIQUADRATIC_WG, 'n');
1964     }
1965 
1966     g_hud.AddSlider("Mipmap Bias", 0, 5, 0,
1967                     -200, 450, 20, false, callbackSlider, 0);
1968     g_hud.AddSlider("Displacement", 0, 5, 1,
1969                     -200, 490, 20, false, callbackSlider, 1);
1970     g_hud.AddCheckBox("Seamless Mipmap", g_seamless,
1971                       -200, 530, callbackCheckBox, HUD_CB_SEAMLESS_MIPMAP, 'j');
1972 
1973     g_hud.Rebuild(windowWidth, windowHeight, g_width, g_height);
1974 
1975     // create mesh from ptex metadata
1976     createOsdMesh(g_level, g_kernel);
1977 
1978     // load ptex files
1979     if (colorFilename)
1980         g_osdPTexImage = createPtex(colorFilename, colorMem);
1981     if (displacementFilename)
1982         g_osdPTexDisplacement = createPtex(displacementFilename, displacementMem);
1983     if (occlusionFilename)
1984         g_osdPTexOcclusion = createPtex(occlusionFilename, occlusionMem);
1985     if (specularFilename)
1986         g_osdPTexSpecular = createPtex(specularFilename, specularMem);
1987 
1988     g_ptexMemoryUsage =
1989         (g_osdPTexImage ? g_osdPTexImage->GetMemoryUsage() : 0)
1990         + (g_osdPTexDisplacement ? g_osdPTexDisplacement->GetMemoryUsage() : 0)
1991         + (g_osdPTexOcclusion ? g_osdPTexOcclusion->GetMemoryUsage() : 0)
1992         + (g_osdPTexSpecular ? g_osdPTexSpecular->GetMemoryUsage() : 0);
1993 
1994     // load animation obj sequences (optional)
1995     if (!animobjs.empty()) {
1996         //  The Scheme passed here should ideally match the Ptex geometry (not the
1997         //  defaults from the command line), but only the vertex positions of the
1998         //  ObjAnim are used, so it is effectively ignored
1999         g_objAnim = ObjAnim::Create(animobjs, kCatmark);
2000         if (g_objAnim == 0) {
2001             printf("Error in reading animation Obj file sequence\n");
2002             goto error;
2003         }
2004 
2005         const Shape *animShape = g_objAnim->GetShape();
2006         if (animShape->verts.size() != g_positions.size()) {
2007             printf("Error in animation sequence, does not match ptex vertex count\n");
2008             goto error;
2009         }
2010 
2011         glBindBuffer(GL_ARRAY_BUFFER, 0);
2012     }
2013 
2014     if (diffuseEnvironmentMap) {
2015         HdrInfo info;
2016         unsigned char * image = loadHdr(diffuseEnvironmentMap, &info, /*convertToFloat=*/true);
2017         if (image) {
2018             glGenTextures(1, &g_diffuseEnvironmentMap);
2019             glBindTexture(GL_TEXTURE_2D, g_diffuseEnvironmentMap);
2020             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, info.width, info.height,
2021                          0, GL_RGBA, GL_FLOAT, image);
2022             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
2023             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2024             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2025             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2026             glBindTexture(GL_TEXTURE_2D, 0);
2027             free(image);
2028         }
2029     }
2030     if (specularEnvironmentMap) {
2031         HdrInfo info;
2032         unsigned char * image = loadHdr(specularEnvironmentMap, &info, /*convertToFloat=*/true);
2033         if (image) {
2034             glGenTextures(1, &g_specularEnvironmentMap);
2035             glBindTexture(GL_TEXTURE_2D, g_specularEnvironmentMap);
2036             // glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);  // deprecated
2037             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, info.width, info.height,
2038                          0, GL_RGBA, GL_FLOAT, image);
2039             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
2040             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2041             // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
2042             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2043             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
2044             glBindTexture(GL_TEXTURE_2D, 0);
2045             free(image);
2046         }
2047     }
2048     if (diffuseEnvironmentMap || specularEnvironmentMap) {
2049         createSky();
2050     }
2051 
2052     fitFrame();
2053 
2054     while (g_running) {
2055         idle();
2056         display();
2057 
2058         glfwPollEvents();
2059         glfwSwapBuffers(g_window);
2060 
2061         glFinish();
2062     }
2063   error:
2064     uninitGL();
2065     glfwTerminate();
2066 }
2067