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 <opensubdiv/far/error.h>
32 #include <opensubdiv/far/ptexIndices.h>
33 #include <opensubdiv/osd/cpuEvaluator.h>
34 #include <opensubdiv/osd/cpuGLVertexBuffer.h>
35 #include <opensubdiv/osd/glMesh.h>
36 OpenSubdiv::Osd::GLMeshInterface *g_mesh;
37 
38 #include "../../regression/common/far_utils.h"
39 #include "../../regression/common/arg_utils.h"
40 #include "../common/viewerArgsUtils.h"
41 #include "../common/stopwatch.h"
42 #include "../common/simple_math.h"
43 #include "../common/glHud.h"
44 #include "../common/glShaderCache.h"
45 #include "../common/glUtils.h"
46 
47 #include "init_shapes.h"
48 
49 #include <opensubdiv/osd/glslPatchShaderSource.h>
50 static const char *shaderSource =
51 #include "shader.gen.h"
52 ;
53 static const char *paintShaderSource =
54 #include "paintShader.gen.h"
55 ;
56 
57 #include <cfloat>
58 #include <vector>
59 #include <iostream>
60 #include <fstream>
61 #include <sstream>
62 
63 float g_rotate[2] = {0, 0},
64       g_dolly = 5,
65       g_pan[2] = {0, 0},
66       g_center[3] = {0, 0, 0},
67       g_size = 0;
68 
69 bool  g_yup = false;
70 
71 int   g_prev_x = 0,
72       g_prev_y = 0;
73 
74 int   g_width = 1024,
75       g_height = 1024;
76 
77 GLhud g_hud;
78 
79 int g_level = 2;
80 int g_tessLevel = 6;
81 
82 std::vector<float> g_orgPositions;
83 
84 GLuint g_transformUB = 0,
85        g_transformBinding = 0,
86        g_tessellationUB = 0,
87        g_tessellationBinding = 0,
88        g_lightingUB = 0,
89        g_lightingBinding = 0;
90 
91 struct Transform {
92     float ModelViewMatrix[16];
93     float ProjectionMatrix[16];
94     float ModelViewProjectionMatrix[16];
95     float ModelViewInverseMatrix[16];
96     float ProjectionWithoutPickMatrix[16];
97 } g_transformData;
98 
99 GLuint g_primQuery = 0;
100 GLuint g_vao = 0;
101 
102 GLuint g_paintTexture = 0;
103 
104 GLuint g_depthTexture = 0;
105 
106 int g_running = 1,
107     g_wire = 2,
108     g_displayColor = 1,
109     g_displayDisplacement = 0,
110     g_mbutton[3] = {0, 0, 0};
111 
112 int g_brushSize = 100;
113 int g_frame = 0;
114 
115 GLuint g_ptexPages = 0,
116     g_ptexLayouts = 0,
117     g_ptexTexels = 0;
118 
119 int g_pageSize = 512;
120 
121 int g_currentShape = 0;
122 
123 #define NUM_FPS_TIME_SAMPLES 6
124 float g_fpsTimeSamples[NUM_FPS_TIME_SAMPLES] = {0,0,0,0,0,0};
125 int   g_currentFpsTimeSample = 0;
126 Stopwatch g_fpsTimer;
127 
128 static void
checkGLErrors(std::string const & where="")129 checkGLErrors(std::string const & where = "") {
130 
131     GLuint err;
132     while ((err = glGetError()) != GL_NO_ERROR) {
133         std::cerr << "GL error: "
134                   << (where.empty() ? "" : where + " ")
135                   << err << "\n";
136     }
137 }
138 
139 //------------------------------------------------------------------------------
140 static void
updateGeom()141 updateGeom() {
142 
143     int nverts = (int)g_orgPositions.size() / 3;
144 
145     std::vector<float> vertex;
146     vertex.reserve(nverts*3);
147 
148     const float *p = &g_orgPositions[0];
149 
150     g_frame++;
151 
152 //    float r = sin(frame*0.01f); // * g_moveScale;
153     float r = 0;
154     for (int i = 0; i < nverts; ++i) {
155         //float move = 0.05f*cosf(p[0]*20+g_frame*0.01f);
156         float ct = cos(p[2] * r);
157         float st = sin(p[2] * r);
158         vertex.push_back(p[0]*ct + p[1]*st);
159         vertex.push_back(-p[0]*st + p[1]*ct);
160         vertex.push_back(p[2]);
161         p += 3;
162     }
163 
164     g_mesh->UpdateVertexBuffer(&vertex[0], 0, nverts);
165     g_mesh->Refine();
166     g_mesh->Synchronize();
167 }
168 
169 //------------------------------------------------------------------------------
170 static GLuint
genTextureBuffer(GLenum format,GLsizeiptr size,GLvoid const * data)171 genTextureBuffer(GLenum format, GLsizeiptr size, GLvoid const * data) {
172 
173     GLuint buffer, result;
174     glGenBuffers(1, &buffer);
175     glBindBuffer(GL_TEXTURE_BUFFER, buffer);
176     glBufferData(GL_TEXTURE_BUFFER, size, data, GL_STATIC_DRAW);
177 
178     glGenTextures(1, & result);
179     glBindTexture(GL_TEXTURE_BUFFER, result);
180     glTexBuffer(GL_TEXTURE_BUFFER, format, buffer);
181 
182     // need to reset texture binding before deleting the source buffer.
183     glBindTexture(GL_TEXTURE_BUFFER, 0);
184     glDeleteBuffers(1, &buffer);
185 
186     return result;
187 }
188 
189 static void
createOsdMesh()190 createOsdMesh() {
191 
192     ShapeDesc const & shapeDesc = g_defaultShapes[g_currentShape];
193 
194     Shape * shape = Shape::parseObj(shapeDesc);
195 
196     checkGLErrors("create osd enter");
197 
198     g_orgPositions=shape->verts;
199 
200     // create Far mesh (topology)
201     OpenSubdiv::Sdc::SchemeType sdctype = GetSdcType(*shape);
202     OpenSubdiv::Sdc::Options sdcoptions = GetSdcOptions(*shape);
203 
204     // Recall this application should not accept or include Bilinear shapes
205     assert(sdctype != OpenSubdiv::Sdc::SCHEME_BILINEAR);
206 
207     OpenSubdiv::Far::TopologyRefiner * refiner =
208         OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Create(*shape,
209             OpenSubdiv::Far::TopologyRefinerFactory<Shape>::Options(sdctype, sdcoptions));
210 
211     // count ptex face id
212     OpenSubdiv::Far::PtexIndices ptexIndices(*refiner);
213     int numPtexFaces = ptexIndices.GetNumFaces();
214 
215     delete g_mesh;
216     g_mesh = NULL;
217 
218     bool doAdaptive = true;
219     OpenSubdiv::Osd::MeshBitset bits;
220     bits.set(OpenSubdiv::Osd::MeshAdaptive, doAdaptive);
221     bits.set(OpenSubdiv::Osd::MeshEndCapGregoryBasis, true);
222 
223     g_mesh = new OpenSubdiv::Osd::Mesh<OpenSubdiv::Osd::CpuGLVertexBuffer,
224                                        OpenSubdiv::Far::StencilTable,
225                                        OpenSubdiv::Osd::CpuEvaluator,
226                                        OpenSubdiv::Osd::GLPatchTable>(
227                                            refiner, 3, 0, g_level, bits);
228 
229     // compute model bounding
230     float min[3] = { FLT_MAX,  FLT_MAX,  FLT_MAX};
231     float max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
232     for (size_t i=0; i < g_orgPositions.size()/3; ++i) {
233         for(int j=0; j<3; ++j) {
234             float v = g_orgPositions[i*3+j];
235             min[j] = std::min(min[j], v);
236             max[j] = std::max(max[j], v);
237         }
238     }
239     for (int j=0; j<3; ++j) {
240         g_center[j] = (min[j] + max[j]) * 0.5f;
241         g_size += (max[j]-min[j])*(max[j]-min[j]);
242     }
243     g_size = sqrtf(g_size);
244 
245     updateGeom();
246 
247     // -------- VAO
248     glBindVertexArray(g_vao);
249 
250     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_mesh->GetPatchTable()->GetPatchIndexBuffer());
251     glBindBuffer(GL_ARRAY_BUFFER, g_mesh->BindVertexBuffer());
252 
253     glEnableVertexAttribArray(0);
254     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 3, 0);
255 
256     glBindVertexArray(0);
257 
258     // -------- create ptex
259     if (g_ptexPages) glDeleteTextures(1, &g_ptexPages);
260     if (g_ptexLayouts) glDeleteTextures(1, &g_ptexLayouts);
261     if (g_ptexTexels) glDeleteTextures(1, &g_ptexTexels);
262 
263     std::vector<int> pages;
264     std::vector<float> layouts;
265     for (int i = 0; i < numPtexFaces; ++i) {
266         pages.push_back(i);
267         layouts.push_back(0);
268         layouts.push_back(0);
269         layouts.push_back(1);
270         layouts.push_back(1);
271     }
272     g_ptexPages = genTextureBuffer(GL_R32I,
273                                    numPtexFaces * sizeof(GLint), &pages[0]);
274 
275     g_ptexLayouts = genTextureBuffer(GL_RGBA32F,
276                                      numPtexFaces * 4 * sizeof(GLfloat),
277                                      &layouts[0]);
278 
279     // actual texels texture array
280     glGenTextures(1, &g_ptexTexels);
281     glBindTexture(GL_TEXTURE_2D_ARRAY, g_ptexTexels);
282 
283     glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
284     glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
285     glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
286     glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
287 
288     g_pageSize = std::min(512, (int)sqrt((float)1024*1024*1024/64/numPtexFaces));
289 
290     int pageSize = g_pageSize;
291 
292     std::vector<float> texels;
293     texels.resize(pageSize*pageSize*numPtexFaces);
294     // allocate ptex
295     glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_R32F,
296                  pageSize, pageSize, numPtexFaces, 0, GL_RED, GL_FLOAT, &texels[0]);
297 
298     glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
299 
300     checkGLErrors("create osd exit");
301 }
302 
303 //------------------------------------------------------------------------------
304 static void
fitFrame()305 fitFrame() {
306 
307     g_pan[0] = g_pan[1] = 0;
308     g_dolly = g_size;
309 }
310 
311 //------------------------------------------------------------------------------
312 union Effect {
313     struct {
314         int color:1;
315         int displacement:1;
316         int paint:1;
317         unsigned int wire:2;
318     };
319     int value;
320 
operator <(const Effect & e) const321     bool operator < (const Effect &e) const {
322         return value < e.value;
323     }
324 };
325 
326 struct EffectDesc {
EffectDescEffectDesc327     EffectDesc(OpenSubdiv::Far::PatchDescriptor desc,
328                Effect effect) : desc(desc), effect(effect),
329                                 maxValence(0), numElements(0) { }
330 
331     OpenSubdiv::Far::PatchDescriptor desc;
332     Effect effect;
333     int maxValence;
334     int numElements;
335 
operator <EffectDesc336     bool operator < (const EffectDesc &e) const {
337         return desc < e.desc || (desc == e.desc &&
338               (maxValence < e.maxValence || ((maxValence == e.maxValence) &&
339               (effect < e.effect))));
340     }
341 };
342 
343 // ---------------------------------------------------------------------------
344 
345 class ShaderCache : public GLShaderCache<EffectDesc> {
346 public:
CreateDrawConfig(EffectDesc const & effectDesc)347     virtual GLDrawConfig *CreateDrawConfig(EffectDesc const &effectDesc) {
348 
349         using namespace OpenSubdiv;
350 
351         // compile shader program
352         const char *glslVersion = "#version 420\n";
353         GLDrawConfig *config = new GLDrawConfig(glslVersion);
354 
355         Far::PatchDescriptor::Type type = effectDesc.desc.GetType();
356 
357         std::stringstream ss;
358         if (effectDesc.effect.color) {
359             ss << "#define USE_PTEX_COLOR\n";
360         }
361         if (effectDesc.effect.displacement) {
362             ss << "#define USE_PTEX_DISPLACEMENT\n";
363         }
364         ss << "#define OSD_ENABLE_SCREENSPACE_TESSELLATION\n";
365         if (effectDesc.effect.wire == 0) {
366             ss << "#define GEOMETRY_OUT_WIRE\n";
367         } else if (effectDesc.effect.wire == 1) {
368             ss << "#define GEOMETRY_OUT_FILL\n";
369         } else {
370             ss << "#define GEOMETRY_OUT_LINE\n";
371         }
372 
373         // for legacy gregory
374         ss << "#define OSD_MAX_VALENCE " << effectDesc.maxValence << "\n";
375         ss << "#define OSD_NUM_ELEMENTS " << effectDesc.numElements << "\n";
376 
377         // include osd PatchCommon
378         ss << Osd::GLSLPatchShaderSource::GetCommonShaderSource();
379         std::string common = ss.str();
380         ss.str("");
381 
382         // vertex shader
383         ss << common
384            << (effectDesc.desc.IsAdaptive() ? "" : "#define VERTEX_SHADER\n")
385            << (effectDesc.effect.paint ? paintShaderSource : shaderSource)
386            << Osd::GLSLPatchShaderSource::GetVertexShaderSource(type);
387         config->CompileAndAttachShader(GL_VERTEX_SHADER, ss.str());
388         ss.str("");
389 
390         if (effectDesc.desc.IsAdaptive()) {
391             // tess control shader
392             ss << common
393                << (effectDesc.effect.paint ? paintShaderSource : shaderSource)
394                << Osd::GLSLPatchShaderSource::GetTessControlShaderSource(type);
395             config->CompileAndAttachShader(GL_TESS_CONTROL_SHADER, ss.str());
396             ss.str("");
397 
398             // tess eval shader
399             ss << common
400                << (effectDesc.effect.paint ? paintShaderSource : shaderSource)
401                << Osd::GLSLPatchShaderSource::GetTessEvalShaderSource(type);
402             config->CompileAndAttachShader(GL_TESS_EVALUATION_SHADER, ss.str());
403             ss.str("");
404         }
405 
406         // geometry shader
407         ss << common
408            << "#define GEOMETRY_SHADER\n" // for my shader source
409            << (effectDesc.effect.paint ? paintShaderSource : shaderSource);
410         config->CompileAndAttachShader(GL_GEOMETRY_SHADER, ss.str());
411         ss.str("");
412 
413         // fragment shader
414         ss << common
415            << "#define FRAGMENT_SHADER\n" // for my shader source
416            << (effectDesc.effect.paint ? paintShaderSource : shaderSource);
417         config->CompileAndAttachShader(GL_FRAGMENT_SHADER, ss.str());
418         ss.str("");
419 
420         if (!config->Link()) {
421             delete config;
422             return NULL;
423         }
424 
425         // assign uniform locations
426         GLuint uboIndex;
427         GLuint program = config->GetProgram();
428         g_transformBinding = 0;
429         uboIndex = glGetUniformBlockIndex(program, "Transform");
430         if (uboIndex != GL_INVALID_INDEX)
431             glUniformBlockBinding(program, uboIndex, g_transformBinding);
432 
433         g_tessellationBinding = 1;
434         uboIndex = glGetUniformBlockIndex(program, "Tessellation");
435         if (uboIndex != GL_INVALID_INDEX)
436             glUniformBlockBinding(program, uboIndex, g_tessellationBinding);
437 
438         g_lightingBinding = 2;
439         uboIndex = glGetUniformBlockIndex(program, "Lighting");
440         if (uboIndex != GL_INVALID_INDEX)
441             glUniformBlockBinding(program, uboIndex, g_lightingBinding);
442 
443         // assign texture locations
444         GLint loc;
445         glUseProgram(program);
446 
447         if ((loc = glGetUniformLocation(program, "OsdPatchParamBuffer")) != -1) {
448             glUniform1i(loc, 0); // GL_TEXTURE0
449         }
450 
451         if (effectDesc.effect.paint) {
452             if ((loc = glGetUniformLocation(program, "outTextureImage")) != -1) {
453                 glUniform1i(loc, 0); // image 0
454             }
455             if ((loc = glGetUniformLocation(program, "paintTexture")) != -1) {
456                 glUniform1i(loc, 5); // GL_TEXTURE5
457             }
458             if ((loc = glGetUniformLocation(program, "depthTexture")) != -1) {
459                 glUniform1i(loc, 6); // GL_TEXTURE6
460             }
461         } else {
462             if ((loc = glGetUniformLocation(program, "textureImage_Data")) != -1) {
463                 glUniform1i(loc, 5); // GL_TEXTURE5
464             }
465             if ((loc = glGetUniformLocation(program, "textureImage_Packing")) != -1) {
466                 glUniform1i(loc, 6); // GL_TEXTURE6
467             }
468             if ((loc = glGetUniformLocation(program, "textureImage_Pages")) != -1) {
469                 glUniform1i(loc, 7); // GL_TEXTURE7
470             }
471         }
472 
473         glUseProgram(0);
474         return config;
475     }
476 };
477 
478 ShaderCache g_shaderCache;
479 
480 //------------------------------------------------------------------------------
481 static void
updateUniformBlocks()482 updateUniformBlocks() {
483     if (! g_transformUB) {
484         glGenBuffers(1, &g_transformUB);
485         glBindBuffer(GL_UNIFORM_BUFFER, g_transformUB);
486         glBufferData(GL_UNIFORM_BUFFER,
487                 sizeof(g_transformData), NULL, GL_STATIC_DRAW);
488     };
489     glBindBuffer(GL_UNIFORM_BUFFER, g_transformUB);
490     glBufferSubData(GL_UNIFORM_BUFFER,
491                 0, sizeof(g_transformData), &g_transformData);
492     glBindBuffer(GL_UNIFORM_BUFFER, 0);
493 
494     glBindBufferBase(GL_UNIFORM_BUFFER, g_transformBinding, g_transformUB);
495 
496     // Update and bind tessellation state
497     struct Tessellation {
498         float TessLevel;
499     } tessellationData;
500 
501     tessellationData.TessLevel = static_cast<float>(1 << g_tessLevel);
502 
503     if (! g_tessellationUB) {
504         glGenBuffers(1, &g_tessellationUB);
505         glBindBuffer(GL_UNIFORM_BUFFER, g_tessellationUB);
506         glBufferData(GL_UNIFORM_BUFFER,
507                 sizeof(tessellationData), NULL, GL_STATIC_DRAW);
508     };
509     glBindBuffer(GL_UNIFORM_BUFFER, g_tessellationUB);
510     glBufferSubData(GL_UNIFORM_BUFFER,
511                 0, sizeof(tessellationData), &tessellationData);
512     glBindBuffer(GL_UNIFORM_BUFFER, 0);
513 
514     glBindBufferBase(GL_UNIFORM_BUFFER, g_tessellationBinding, g_tessellationUB);
515 
516     // Update and bind lighting state
517     struct Lighting {
518         struct Light {
519             float position[4];
520             float ambient[4];
521             float diffuse[4];
522             float specular[4];
523         } lightSource[2];
524     } lightingData = {
525        {{  { 0.5,  0.2f, 1.0f, 0.0f },
526            { 0.1f, 0.1f, 0.1f, 1.0f },
527            { 0.7f, 0.7f, 0.7f, 1.0f },
528            { 0.8f, 0.8f, 0.8f, 1.0f } },
529 
530          { { -0.8f, 0.4f, -1.0f, 0.0f },
531            {  0.0f, 0.0f,  0.0f, 1.0f },
532            {  0.5f, 0.5f,  0.5f, 1.0f },
533            {  0.8f, 0.8f,  0.8f, 1.0f } }}
534     };
535     if (! g_lightingUB) {
536         glGenBuffers(1, &g_lightingUB);
537         glBindBuffer(GL_UNIFORM_BUFFER, g_lightingUB);
538         glBufferData(GL_UNIFORM_BUFFER,
539                 sizeof(lightingData), NULL, GL_STATIC_DRAW);
540     };
541     glBindBuffer(GL_UNIFORM_BUFFER, g_lightingUB);
542     glBufferSubData(GL_UNIFORM_BUFFER,
543                 0, sizeof(lightingData), &lightingData);
544     glBindBuffer(GL_UNIFORM_BUFFER, 0);
545 
546     glBindBufferBase(GL_UNIFORM_BUFFER, g_lightingBinding, g_lightingUB);
547 }
548 
bindTextures(Effect effect)549 static void bindTextures(Effect effect) {
550     if (effect.paint) {
551         // set image
552         glBindImageTexture(0, g_ptexTexels, 0, GL_TRUE, 0, GL_READ_WRITE, GL_R32F);
553 
554         glActiveTexture(GL_TEXTURE5);
555         glBindTexture(GL_TEXTURE_2D, g_paintTexture);
556 
557         glActiveTexture(GL_TEXTURE6);
558         glBindTexture(GL_TEXTURE_2D, g_depthTexture);
559 
560         glActiveTexture(GL_TEXTURE0);
561     } else {
562         if (g_mesh->GetPatchTable()->GetPatchParamTextureBuffer()) {
563             glActiveTexture(GL_TEXTURE0);
564             glBindTexture(
565                 GL_TEXTURE_BUFFER,
566                 g_mesh->GetPatchTable()->GetPatchParamTextureBuffer());
567         }
568 
569         // color ptex
570         glActiveTexture(GL_TEXTURE5);
571         glBindTexture(GL_TEXTURE_2D_ARRAY, g_ptexTexels);
572 
573         glActiveTexture(GL_TEXTURE6);
574         glBindTexture(GL_TEXTURE_BUFFER, g_ptexLayouts);
575 
576         glActiveTexture(GL_TEXTURE7);
577         glBindTexture(GL_TEXTURE_BUFFER, g_ptexPages);
578     }
579     glActiveTexture(GL_TEXTURE0);
580 }
581 
582 static GLuint
bindProgram(Effect effect,OpenSubdiv::Osd::PatchArray const & patch)583 bindProgram(Effect effect, OpenSubdiv::Osd::PatchArray const & patch) {
584 
585     EffectDesc effectDesc(patch.GetDescriptor(), effect);
586 
587     // lookup shader cache (compile the shader if needed)
588     GLDrawConfig *config = g_shaderCache.GetDrawConfig(effectDesc);
589     if (!config) return 0;
590 
591     GLuint program = config->GetProgram();
592 
593     glUseProgram(program);
594 
595     GLint uniformImageSize = glGetUniformLocation(program, "imageSize");
596     if (uniformImageSize >= 0)
597         glUniform1i(uniformImageSize, g_pageSize);
598 
599     GLint uniformPrimitiveIdBase =
600         glGetUniformLocation(program, "PrimitiveIdBase");
601     if (uniformPrimitiveIdBase >= 0)
602         glUniform1i(uniformPrimitiveIdBase, patch.GetPrimitiveIdBase());
603 
604 
605     return program;
606 }
607 
608 //------------------------------------------------------------------------------
609 static void
display()610 display() {
611 
612     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
613     glViewport(0, 0, g_width, g_height);
614     g_hud.FillBackground();
615 
616     // primitive counting
617     glBeginQuery(GL_PRIMITIVES_GENERATED, g_primQuery);
618 
619     // prepare view matrix
620     double aspect = g_width/(double)g_height;
621     identity(g_transformData.ModelViewMatrix);
622     translate(g_transformData.ModelViewMatrix, -g_pan[0], -g_pan[1], -g_dolly);
623     rotate(g_transformData.ModelViewMatrix, g_rotate[1], 1, 0, 0);
624     rotate(g_transformData.ModelViewMatrix, g_rotate[0], 0, 1, 0);
625     if (!g_yup) {
626         rotate(g_transformData.ModelViewMatrix, -90, 1, 0, 0);
627     }
628     translate(g_transformData.ModelViewMatrix,
629               -g_center[0], -g_center[1], -g_center[2]);
630     perspective(g_transformData.ProjectionMatrix,
631                 45.0f, (float)aspect, 0.01f, 500.0f);
632     multMatrix(g_transformData.ModelViewProjectionMatrix,
633                g_transformData.ModelViewMatrix,
634                g_transformData.ProjectionMatrix);
635 
636     glEnable(GL_DEPTH_TEST);
637     if (g_wire == 0) {
638         glDisable(GL_CULL_FACE);
639     }
640 
641     updateUniformBlocks();
642 
643     Effect effect;
644     effect.color = g_displayColor;
645     effect.displacement = g_displayDisplacement;
646     effect.wire = g_wire;
647     effect.paint = 0;
648 
649     bindTextures(effect);
650 
651     // make sure that the vertex buffer is interoped back as a GL resource.
652     g_mesh->BindVertexBuffer();
653 
654     glBindVertexArray(g_vao);
655 
656     OpenSubdiv::Osd::PatchArrayVector const & patches =
657         g_mesh->GetPatchTable()->GetPatchArrays();
658 
659     // patch drawing
660     for (int i=0; i<(int)patches.size(); ++i) {
661         OpenSubdiv::Osd::PatchArray const & patch = patches[i];
662         OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor();
663 
664         GLenum primType = GL_PATCHES;
665         glPatchParameteri(GL_PATCH_VERTICES, desc.GetNumControlVertices());
666 
667         GLuint program = bindProgram(effect, patch);
668         GLuint diffuseColor = glGetUniformLocation(program, "diffuseColor");
669         glProgramUniform4f(program, diffuseColor, 1, 1, 1, 1);
670 
671         glDrawElements(primType,
672                        patch.GetNumPatches() * desc.GetNumControlVertices(),
673                        GL_UNSIGNED_INT,
674                        (void *)(patch.GetIndexBase() * sizeof(unsigned int)));
675     }
676 
677     glBindVertexArray(0);
678     glUseProgram(0);
679 
680     glEndQuery(GL_PRIMITIVES_GENERATED);
681 
682     glBindTexture(GL_TEXTURE_2D, g_depthTexture);
683     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, g_width, g_height);
684     glBindTexture(GL_TEXTURE_2D, 0);
685 
686     if (g_wire == 0) {
687         glEnable(GL_CULL_FACE);
688     }
689 
690     GLuint numPrimsGenerated = 0;
691     glGetQueryObjectuiv(g_primQuery, GL_QUERY_RESULT, &numPrimsGenerated);
692 
693     if (g_hud.IsVisible()) {
694         g_fpsTimer.Stop();
695         double fps = 1.0/g_fpsTimer.GetElapsed();
696         g_fpsTimer.Start();
697         // Average fps over a defined number of time samples for
698         // easier reading in the HUD
699         g_fpsTimeSamples[g_currentFpsTimeSample++] = float(fps);
700         if (g_currentFpsTimeSample >= NUM_FPS_TIME_SAMPLES)
701             g_currentFpsTimeSample = 0;
702         double averageFps = 0;
703         for (int i=0; i< NUM_FPS_TIME_SAMPLES; ++i) {
704             averageFps += g_fpsTimeSamples[i]/(float)NUM_FPS_TIME_SAMPLES;
705         }
706 
707         g_hud.DrawString(10, -100, "Tess level (+/-): %d", g_tessLevel);
708         if (numPrimsGenerated > 1000000) {
709             g_hud.DrawString(10, -80, "Primitives      : %3.1f million", (float)numPrimsGenerated/1000000.0);
710         } else if (numPrimsGenerated > 1000) {
711             g_hud.DrawString(10, -80, "Primitives      : %3.1f thousand", (float)numPrimsGenerated/1000.0);
712         } else {
713             g_hud.DrawString(10, -80, "Primitives      : %d", numPrimsGenerated);
714         }
715         g_hud.DrawString(10, -60, "Vertices        : %d", g_mesh->GetNumVertices());
716         g_hud.DrawString(10, -20, "FPS             : %3.1f", averageFps);
717     }
718 
719     g_hud.Flush();
720 
721     glFinish();
722 
723     //checkGLErrors("display leave");
724 
725     glfwSwapBuffers(g_window);
726 }
727 
728 //------------------------------------------------------------------------------
729 void
drawStroke(int x,int y)730 drawStroke(int x, int y) {
731 
732     glViewport(0, 0, g_pageSize, g_pageSize);
733 
734     // prepare view matrix
735     double aspect = g_width/(double)g_height;
736     int viewport[4] = {0, 0, g_width, g_height};
737     float pick[16], pers[16];
738     perspective(pers, 45.0f, (float)aspect, 0.01f, 500.0f);
739     pickMatrix(pick, (float)x, (float)g_height-y, g_brushSize*0.5f, g_brushSize*0.5f, viewport);
740     multMatrix(g_transformData.ProjectionMatrix, pers, pick);
741     multMatrix(g_transformData.ModelViewProjectionMatrix,
742                g_transformData.ModelViewMatrix,
743                g_transformData.ProjectionMatrix);
744     memcpy(g_transformData.ProjectionWithoutPickMatrix, pers, sizeof(float)*16);
745 
746     if (! g_transformUB) {
747         glGenBuffers(1, &g_transformUB);
748         glBindBuffer(GL_UNIFORM_BUFFER, g_transformUB);
749         glBufferData(GL_UNIFORM_BUFFER,
750                 sizeof(g_transformData), NULL, GL_STATIC_DRAW);
751     };
752     glBindBuffer(GL_UNIFORM_BUFFER, g_transformUB);
753     glBufferSubData(GL_UNIFORM_BUFFER,
754                 0, sizeof(g_transformData), &g_transformData);
755     glBindBuffer(GL_UNIFORM_BUFFER, 0);
756 
757     glBindBufferBase(GL_UNIFORM_BUFFER, g_transformBinding, g_transformUB);
758 
759     // Update and bind tessellation state
760     struct Tessellation {
761         float TessLevel;
762     } tessellationData;
763 
764     tessellationData.TessLevel = static_cast<float>(1 << (g_tessLevel>>1));
765 
766     if (! g_tessellationUB) {
767         glGenBuffers(1, &g_tessellationUB);
768         glBindBuffer(GL_UNIFORM_BUFFER, g_tessellationUB);
769         glBufferData(GL_UNIFORM_BUFFER,
770                 sizeof(tessellationData), NULL, GL_STATIC_DRAW);
771     };
772     glBindBuffer(GL_UNIFORM_BUFFER, g_tessellationUB);
773     glBufferSubData(GL_UNIFORM_BUFFER,
774                 0, sizeof(tessellationData), &tessellationData);
775     glBindBuffer(GL_UNIFORM_BUFFER, 0);
776 
777     glBindBufferBase(GL_UNIFORM_BUFFER, g_tessellationBinding, g_tessellationUB);
778 
779     // make sure that the vertex buffer is interoped back as a GL resource.
780     g_mesh->BindVertexBuffer();
781 
782     glBindVertexArray(g_vao);
783 
784     Effect effect;
785     effect.color = 0;
786     effect.displacement = g_displayDisplacement;
787     effect.wire = 1;
788     effect.paint = 1;
789     bindTextures(effect);
790 
791     OpenSubdiv::Osd::PatchArrayVector const & patches =
792         g_mesh->GetPatchTable()->GetPatchArrays();
793 
794     // patch drawing
795     for (int i=0; i<(int)patches.size(); ++i) {
796 
797         OpenSubdiv::Osd::PatchArray const & patch = patches[i];
798         OpenSubdiv::Far::PatchDescriptor desc = patch.GetDescriptor();
799 
800         GLenum primType = GL_PATCHES;
801         glPatchParameteri(GL_PATCH_VERTICES, desc.GetNumControlVertices());
802 
803         bindProgram(effect, patch);
804 
805         glDrawElements(primType,
806                        patch.GetNumPatches() * desc.GetNumControlVertices(),
807                        GL_UNSIGNED_INT,
808                        (void *)(patch.GetIndexBase() * sizeof(unsigned int)));
809     }
810 
811     glBindVertexArray(0);
812     glUseProgram(0);
813 
814     glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT |
815                     GL_TEXTURE_FETCH_BARRIER_BIT);
816 
817     //checkGLErrors("display leave");
818 }
819 
820 //------------------------------------------------------------------------------
821 static void
motion(GLFWwindow * w,double dx,double dy)822 motion(GLFWwindow * w, double dx, double dy) {
823     int x=(int)dx, y=(int)dy;
824 
825     if (glfwGetKey(w,GLFW_KEY_LEFT_ALT)) {
826 
827         if (g_mbutton[0] && !g_mbutton[1] && !g_mbutton[2]) {
828             // orbit
829             g_rotate[0] += x - g_prev_x;
830             g_rotate[1] += y - g_prev_y;
831         } else if (!g_mbutton[0] && !g_mbutton[1] && g_mbutton[2]) {
832             // pan
833             g_pan[0] -= g_dolly*(x - g_prev_x)/g_width;
834             g_pan[1] += g_dolly*(y - g_prev_y)/g_height;
835         } else if ((g_mbutton[0] && !g_mbutton[1] && g_mbutton[2]) ||
836                    (!g_mbutton[0] && g_mbutton[1] && !g_mbutton[2])) {
837             // dolly
838             g_dolly -= g_dolly*0.01f*(x - g_prev_x);
839             if(g_dolly <= 0.01) g_dolly = 0.01f;
840         }
841     } else {
842         if (g_mbutton[0] && !g_mbutton[1] && !g_mbutton[2]) {
843             // paint something into screen
844             drawStroke(x, y);
845         }
846     }
847 
848     g_prev_x = x;
849     g_prev_y = y;
850 }
851 
852 //------------------------------------------------------------------------------
853 static void
mouse(GLFWwindow * w,int button,int state,int)854 mouse(GLFWwindow * w, int button, int state, int /* mods */) {
855 
856     if (button == 0 && state == GLFW_PRESS && g_hud.MouseClick(g_prev_x, g_prev_y))
857         return;
858 
859     if (button < 3) {
860         g_mbutton[button] = (state == GLFW_PRESS);
861     }
862 
863     if (! glfwGetKey(w, GLFW_KEY_LEFT_ALT)) {
864         if (g_mbutton[0] && !g_mbutton[1] && !g_mbutton[2]) {
865             drawStroke(g_prev_x, g_prev_y);
866         }
867     }
868 }
869 
870 //------------------------------------------------------------------------------
871 static void
reshape(GLFWwindow *,int width,int height)872 reshape(GLFWwindow *, int width, int height) {
873 
874     g_width = width;
875     g_height = height;
876 
877     int windowWidth = g_width, windowHeight = g_height;
878 
879     // window size might not match framebuffer size on a high DPI display
880     glfwGetWindowSize(g_window, &windowWidth, &windowHeight);
881 
882     g_hud.Rebuild(windowWidth, windowHeight, width, height);
883 
884     // prepare depth texture
885     if (g_depthTexture == 0) glGenTextures(1, &g_depthTexture);
886     glBindTexture(GL_TEXTURE_2D, g_depthTexture);
887     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
888     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
889     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
890     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
891     glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0,
892                  GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
893     glBindTexture(GL_TEXTURE_2D, 0);
894 
895 }
896 
reshape()897 void reshape() {
898     reshape(g_window, g_width, g_height);
899 }
900 
901 //------------------------------------------------------------------------------
windowClose(GLFWwindow *)902 void windowClose(GLFWwindow*) {
903     g_running = false;
904 }
905 
906 //------------------------------------------------------------------------------
907 static void
toggleFullScreen()908 toggleFullScreen() {
909     // XXXX manuelk : to re-implement from glut
910 }
911 
912 //------------------------------------------------------------------------------
913 static void
keyboard(GLFWwindow *,int key,int,int event,int)914 keyboard(GLFWwindow *, int key, int /* scancode */, int event, int /* mods */) {
915 
916     if (event == GLFW_RELEASE) return;
917     if (g_hud.KeyDown(tolower(key))) return;
918 
919     switch (key) {
920         case 'Q': g_running = 0; break;
921         case 'F': fitFrame(); break;
922         case GLFW_KEY_TAB: toggleFullScreen(); break;
923         case '+':
924         case '=':  g_tessLevel++; break;
925         case '-':  g_tessLevel = std::max(1, g_tessLevel-1); break;
926         case GLFW_KEY_ESCAPE: g_hud.SetVisible(!g_hud.IsVisible()); break;
927     }
928 }
929 
930 //------------------------------------------------------------------------------
931 static void
callbackWireframe(int b)932 callbackWireframe(int b) {
933 
934     g_wire = b;
935 }
936 
937 static void
callbackDisplay(bool,int n)938 callbackDisplay(bool /* checked */, int n) {
939 
940     if (n == 0) g_displayColor = !g_displayColor;
941     else if (n == 1) g_displayDisplacement = !g_displayDisplacement;
942 }
943 
944 static void
callbackLevel(int l)945 callbackLevel(int l) {
946 
947     g_level = l;
948     createOsdMesh();
949 }
950 
951 static void
callbackModel(int m)952 callbackModel(int m) {
953 
954     if (m < 0)
955         m = 0;
956 
957     if (m >= (int)g_defaultShapes.size())
958         m = (int)g_defaultShapes.size() - 1;
959 
960     g_currentShape = m;
961     createOsdMesh();
962 }
963 
964 static void
callbackBrushSize(float value,int)965 callbackBrushSize(float value, int /* data */) {
966 
967     g_brushSize = (int)value;
968 }
969 
970 //------------------------------------------------------------------------------
971 static void
initHUD()972 initHUD() {
973 
974     int windowWidth = g_width, windowHeight = g_height,
975         frameBufferWidth = g_width, frameBufferHeight = g_height;
976 
977     // window size might not match framebuffer size on a high DPI display
978     glfwGetWindowSize(g_window, &windowWidth, &windowHeight);
979     glfwGetFramebufferSize(g_window, &frameBufferWidth, &frameBufferHeight);
980 
981     g_hud.Init(windowWidth, windowHeight, frameBufferWidth, frameBufferHeight);
982 
983     g_hud.AddCheckBox("Color (C)",  g_displayColor != 0, 10, 10, callbackDisplay, 0, 'c');
984     g_hud.AddCheckBox("Displacement (D)",  g_displayDisplacement != 0, 10, 30, callbackDisplay, 1, 'd');
985 
986     int shading_pulldown = g_hud.AddPullDown("Shading (W)", 200, 10, 250, callbackWireframe, 'w');
987     g_hud.AddPullDownButton(shading_pulldown, "Wire", 0, g_wire==0);
988     g_hud.AddPullDownButton(shading_pulldown, "Shaded", 1, g_wire==1);
989     g_hud.AddPullDownButton(shading_pulldown, "Wire+Shaded", 2, g_wire==2);
990 
991     g_hud.AddSlider("Brush size", 10.0f, 500.0f, (float)g_brushSize,
992                      350, -60, 40, true, callbackBrushSize, 0);
993 
994     for (int i = 1; i < 11; ++i) {
995         char level[16];
996         sprintf(level, "Lv. %d", i);
997         g_hud.AddRadioButton(3, level, i==g_level, 10, 170+i*20, callbackLevel, i, '0'+(i%10));
998     }
999 
1000     int pulldown_handle = g_hud.AddPullDown("Shape (N)", -300, 10, 300, callbackModel, 'n');
1001     for (int i = 0; i < (int)g_defaultShapes.size(); ++i) {
1002         g_hud.AddPullDownButton(pulldown_handle, g_defaultShapes[i].name.c_str(),i);
1003     }
1004 
1005     g_hud.Rebuild(g_width, g_height, frameBufferWidth, frameBufferHeight);
1006 }
1007 
1008 //------------------------------------------------------------------------------
1009 static void
initGL()1010 initGL() {
1011 
1012     glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
1013     glEnable(GL_DEPTH_TEST);
1014     glDepthFunc(GL_LEQUAL);
1015     glCullFace(GL_BACK);
1016     glEnable(GL_CULL_FACE);
1017 
1018     glGenVertexArrays(1, &g_vao);
1019     glGenTextures(1, &g_paintTexture);
1020 
1021     static const GLfloat border[] = { 0.0, 0.0, 0.0, 0.0 };
1022 
1023     // create brush-size buffer
1024     glBindTexture(GL_TEXTURE_2D, g_paintTexture);
1025     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1026     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1027     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
1028     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
1029     glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
1030 
1031     int reso = 64;
1032 
1033     std::vector<float> values;
1034     for(int yy = 0; yy < reso; ++yy) {
1035         for (int xx = 0; xx < reso; ++xx) {
1036             float r = sqrtf((xx-reso*0.5f)*(xx-reso*0.5f)+
1037                             (yy-reso*0.5f)*(yy-reso*0.5f))/(reso*0.5f);
1038             float v = 0.5f*std::max(0.0f, expf(-r*r)-0.4f);
1039             values.push_back(v);
1040             values.push_back(v);
1041             values.push_back(v);
1042         }
1043     }
1044 
1045     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, reso, reso, 0, GL_RGB, GL_FLOAT, &values[0]);
1046     glBindTexture(GL_TEXTURE_2D, 0);
1047 
1048     glGenQueries(1, &g_primQuery);
1049 }
1050 
1051 //------------------------------------------------------------------------------
1052 static void
uninitGL()1053 uninitGL() {
1054 
1055     if (g_vao) glDeleteVertexArrays(1, &g_vao);
1056     if (g_paintTexture) glDeleteTextures(1, &g_paintTexture);
1057     if (g_depthTexture) glDeleteTextures(1, &g_depthTexture);
1058     if (g_primQuery) glDeleteQueries(1, &g_primQuery);
1059     if (g_ptexPages) glDeleteTextures(1, &g_ptexPages);
1060     if (g_ptexLayouts) glDeleteTextures(1, &g_ptexLayouts);
1061     if (g_ptexTexels) glDeleteTextures(1, &g_ptexTexels);
1062 
1063     if (g_mesh)
1064         delete g_mesh;
1065 }
1066 
1067 //------------------------------------------------------------------------------
1068 static void
idle()1069 idle() {
1070     updateGeom();
1071 }
1072 
1073 //------------------------------------------------------------------------------
1074 static void
callbackError(OpenSubdiv::Far::ErrorType err,const char * message)1075 callbackError(OpenSubdiv::Far::ErrorType err, const char *message) {
1076     printf("OpenSubdiv Error: %d\n", err);
1077     printf("    %s\n", message);
1078 }
1079 
1080 //------------------------------------------------------------------------------
1081 static void
callbackErrorGLFW(int error,const char * description)1082 callbackErrorGLFW(int error, const char* description) {
1083     fprintf(stderr, "GLFW Error (%d) : %s\n", error, description);
1084 }
1085 
1086 //------------------------------------------------------------------------------
1087 
main(int argc,char ** argv)1088 int main(int argc, char ** argv) {
1089 
1090     ArgOptions args;
1091 
1092     args.Parse(argc, argv);
1093     args.PrintUnrecognizedArgsWarnings();
1094 
1095     g_yup = args.GetYUp();
1096     g_level = args.GetLevel();
1097 
1098     ViewerArgsUtils::PopulateShapes(args, &g_defaultShapes);
1099 
1100     initShapes();
1101 
1102     OpenSubdiv::Far::SetErrorCallback(callbackError);
1103 
1104     glfwSetErrorCallback(callbackErrorGLFW);
1105     if (! glfwInit()) {
1106         printf("Failed to initialize GLFW\n");
1107         return 1;
1108     }
1109 
1110     static const char windowTitle[] = "OpenSubdiv glPaintTest " OPENSUBDIV_VERSION_STRING;
1111 
1112     GLUtils::SetMinimumGLVersion();
1113 
1114     if (args.GetFullScreen()) {
1115 
1116         g_primary = glfwGetPrimaryMonitor();
1117 
1118         // apparently glfwGetPrimaryMonitor fails under linux : if no primary,
1119         // settle for the first one in the list
1120         if (! g_primary) {
1121             int count=0;
1122             GLFWmonitor ** monitors = glfwGetMonitors(&count);
1123 
1124             if (count)
1125                 g_primary = monitors[0];
1126         }
1127 
1128         if (g_primary) {
1129             GLFWvidmode const * vidmode = glfwGetVideoMode(g_primary);
1130             g_width = vidmode->width;
1131             g_height = vidmode->height;
1132         }
1133     }
1134 
1135     if (! (g_window=glfwCreateWindow(g_width, g_height, windowTitle,
1136            args.GetFullScreen() && g_primary ? g_primary : NULL, NULL))) {
1137         printf("Failed to open window.\n");
1138         glfwTerminate();
1139         return 1;
1140     }
1141 
1142     glfwMakeContextCurrent(g_window);
1143 
1144     GLUtils::InitializeGL();
1145     GLUtils::PrintGLVersion();
1146 
1147     glfwSetKeyCallback(g_window, keyboard);
1148     glfwSetCursorPosCallback(g_window, motion);
1149     glfwSetMouseButtonCallback(g_window, mouse);
1150     glfwSetWindowCloseCallback(g_window, windowClose);
1151 
1152     initGL();
1153 
1154     // accommodate high DPI displays (e.g. mac retina displays)
1155     glfwGetFramebufferSize(g_window, &g_width, &g_height);
1156     glfwSetFramebufferSizeCallback(g_window, reshape);
1157 
1158     // as of GLFW 3.0.1 this callback is not implicit
1159     reshape();
1160 
1161     glfwSwapInterval(0);
1162 
1163     initHUD();
1164     callbackModel(g_currentShape);
1165 
1166     while (g_running) {
1167         idle();
1168         display();
1169 
1170         glfwPollEvents();
1171     }
1172 
1173     uninitGL();
1174     glfwTerminate();
1175 }
1176 
1177 //------------------------------------------------------------------------------
1178