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