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