1 /*
2 Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al.
3 All Rights Reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 * Redistributions of source code must retain the above copyright
9   notice, this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11   notice, this list of conditions and the following disclaimer in the
12   documentation and/or other materials provided with the distribution.
13 * Neither the name of Sony Pictures Imageworks nor the names of its
14   contributors may be used to endorse or promote products derived from
15   this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 
30 #include <cstdlib>
31 #include <cmath>
32 #include <cstdio>
33 #include <cstring>
34 #include <iostream>
35 #include <fstream>
36 #include <sstream>
37 #include <vector>
38 
39 #include <OpenColorIO/OpenColorIO.h>
40 namespace OCIO = OCIO_NAMESPACE;
41 
42 #include <OpenImageIO/imageio.h>
43 #include <OpenImageIO/typedesc.h>
44 
45 #if OIIO_VERSION >= 10903 && __cplusplus < 201103
46 #error While not officially supported, compile with C++11 (or higher) to use OIIO versions 1.9.3 or newer
47 #endif
48 
49 #ifdef __APPLE__
50 #include <OpenGL/gl.h>
51 #include <OpenGL/glext.h>
52 #include <GLUT/glut.h>
53 #elif _WIN32
54 #include <GL/glew.h>
55 #include <GL/glut.h>
56 #else
57 #include <GL/glew.h>
58 #include <GL/gl.h>
59 #include <GL/glext.h>
60 #include <GL/glut.h>
61 #endif
62 
63 
64 bool g_verbose = false;
65 std::string g_filename;
66 
67 
68 GLint g_win = 0;
69 int g_winWidth = 0;
70 int g_winHeight = 0;
71 
72 GLuint g_fragShader = 0;
73 GLuint g_program = 0;
74 
75 GLuint g_imageTexID;
76 float g_imageAspect;
77 
78 GLuint g_lut3dTexID;
79 const int LUT3D_EDGE_SIZE = 32;
80 std::vector<float> g_lut3d;
81 std::string g_lut3dcacheid;
82 std::string g_shadercacheid;
83 
84 std::string g_inputColorSpace;
85 std::string g_display;
86 std::string g_transformName;
87 std::string g_look;
88 
89 float g_exposure_fstop = 0.0f;
90 float g_display_gamma = 1.0f;
91 int g_channelHot[4] = { 1, 1, 1, 1 };  // show rgb
92 
93 
94 void UpdateOCIOGLState();
95 
InitImageTexture(const char * filename)96 static void InitImageTexture(const char * filename)
97 {
98     glGenTextures(1, &g_imageTexID);
99 
100     std::vector<float> img;
101     int texWidth = 512;
102     int texHeight = 512;
103     int components = 4;
104 
105     if(filename && *filename)
106     {
107         std::cout << "loading: " << filename << std::endl;
108         try
109         {
110 #if OIIO_VERSION < 10903
111             OIIO::ImageInput* f = OIIO::ImageInput::create(filename);
112 #else
113             auto f = OIIO::ImageInput::create(filename);
114 #endif
115             if(!f)
116             {
117                 std::cerr << "Could not create image input." << std::endl;
118                 exit(1);
119             }
120 
121             OIIO::ImageSpec spec;
122             f->open(filename, spec);
123 
124             std::string error = f->geterror();
125             if(!error.empty())
126             {
127                 std::cerr << "Error loading image " << error << std::endl;
128                 exit(1);
129             }
130 
131             texWidth = spec.width;
132             texHeight = spec.height;
133             components = spec.nchannels;
134 
135             img.resize(texWidth*texHeight*components);
136             memset(&img[0], 0, texWidth*texHeight*components*sizeof(float));
137 
138             f->read_image(
139 #if (OIIO_VERSION >= 10800)
140                 OIIO::TypeFloat,
141 #else
142                 OIIO::TypeDesc::TypeFloat,
143 #endif
144                 &img[0]);
145 #if OIIO_VERSION < 10903
146             OIIO::ImageInput::destroy(f);
147 #endif
148         }
149         catch(...)
150         {
151             std::cerr << "Error loading file.";
152             exit(1);
153         }
154     }
155     // If no file is provided, use a default gradient texture
156     else
157     {
158         std::cout << "No image specified, loading gradient." << std::endl;
159 
160         img.resize(texWidth*texHeight*components);
161         memset(&img[0], 0, texWidth*texHeight*components*sizeof(float));
162 
163         for(int y=0; y<texHeight; ++y)
164         {
165             for(int x=0; x<texWidth; ++x)
166             {
167                 float c = (float)x/((float)texWidth-1.0f);
168                 img[components*(texWidth*y+x) + 0] = c;
169                 img[components*(texWidth*y+x) + 1] = c;
170                 img[components*(texWidth*y+x) + 2] = c;
171                 img[components*(texWidth*y+x) + 3] = 1.0f;
172             }
173         }
174     }
175 
176 
177     GLenum format = 0;
178     if(components == 4) format = GL_RGBA;
179     else if(components == 3) format = GL_RGB;
180     else
181     {
182         std::cerr << "Cannot load image with " << components << " components." << std::endl;
183         exit(1);
184     }
185 
186     g_imageAspect = 1.0;
187     if(texHeight!=0)
188     {
189         g_imageAspect = (float) texWidth / (float) texHeight;
190     }
191 
192     glActiveTexture(GL_TEXTURE1);
193     glBindTexture(GL_TEXTURE_2D, g_imageTexID);
194     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, texWidth, texHeight, 0,
195         format, GL_FLOAT, &img[0]);
196     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
197     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
198     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
199     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
200 }
201 
InitOCIO(const char * filename)202 void InitOCIO(const char * filename)
203 {
204     OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
205     g_display = config->getDefaultDisplay();
206     g_transformName = config->getDefaultView(g_display.c_str());
207     g_look = config->getDisplayLooks(g_display.c_str(), g_transformName.c_str());
208 
209     g_inputColorSpace = OCIO::ROLE_SCENE_LINEAR;
210     if(filename && *filename)
211     {
212         std::string cs = config->parseColorSpaceFromString(filename);
213         if(!cs.empty())
214         {
215             g_inputColorSpace = cs;
216             std::cout << "colorspace: " << cs << std::endl;
217         }
218         else
219         {
220             std::cout << "colorspace: " << g_inputColorSpace
221                 << " \t(could not determine from filename, using default)" << std::endl;
222         }
223     }
224 }
225 
AllocateLut3D()226 static void AllocateLut3D()
227 {
228     glGenTextures(1, &g_lut3dTexID);
229 
230     int num3Dentries = 3*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE*LUT3D_EDGE_SIZE;
231     g_lut3d.resize(num3Dentries);
232     memset(&g_lut3d[0], 0, sizeof(float)*num3Dentries);
233 
234     glActiveTexture(GL_TEXTURE2);
235 
236     glBindTexture(GL_TEXTURE_3D, g_lut3dTexID);
237     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
238     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
239     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
240     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
241     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
242     glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16F_ARB,
243                  LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
244                  0, GL_RGB,GL_FLOAT, &g_lut3d[0]);
245 }
246 
247 /*
248 static void
249 Idle(void)
250 {
251    // + Do Work
252    glutPostRedisplay();
253 }
254 */
255 
Redisplay(void)256 void Redisplay(void)
257 {
258     float windowAspect = 1.0;
259     if(g_winHeight != 0)
260     {
261         windowAspect = (float)g_winWidth/(float)g_winHeight;
262     }
263 
264     float pts[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; // x0,y0,x1,y1
265     if(windowAspect>g_imageAspect)
266     {
267         float imgWidthScreenSpace = g_imageAspect * (float)g_winHeight;
268         pts[0] = (float)g_winWidth * 0.5f - (float)imgWidthScreenSpace * 0.5f;
269         pts[2] = (float)g_winWidth * 0.5f + (float)imgWidthScreenSpace * 0.5f;
270         pts[1] = 0.0f;
271         pts[3] = (float)g_winHeight;
272     }
273     else
274     {
275         float imgHeightScreenSpace = (float)g_winWidth / g_imageAspect;
276         pts[0] = 0.0f;
277         pts[2] = (float)g_winWidth;
278         pts[1] = (float)g_winHeight * 0.5f - imgHeightScreenSpace * 0.5f;
279         pts[3] = (float)g_winHeight * 0.5f + imgHeightScreenSpace * 0.5f;
280     }
281 
282     glEnable(GL_TEXTURE_2D);
283     glClearColor(0.1f, 0.1f, 0.1f, 0.0f);
284     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
285     glColor3f(1, 1, 1);
286 
287     glPushMatrix();
288     glBegin(GL_QUADS);
289     glTexCoord2f(0.0f, 1.0f);
290     glVertex2f(pts[0], pts[1]);
291 
292     glTexCoord2f(0.0f, 0.0f);
293     glVertex2f(pts[0], pts[3]);
294 
295     glTexCoord2f(1.0f, 0.0f);
296     glVertex2f(pts[2], pts[3]);
297 
298     glTexCoord2f(1.0f, 1.0f);
299     glVertex2f(pts[2], pts[1]);
300 
301     glEnd();
302     glPopMatrix();
303 
304     glDisable(GL_TEXTURE_2D);
305 
306     glutSwapBuffers();
307 }
308 
309 
Reshape(int width,int height)310 static void Reshape(int width, int height)
311 {
312     g_winWidth = width;
313     g_winHeight = height;
314 
315     glViewport(0, 0, width, height);
316     glMatrixMode(GL_PROJECTION);
317     glLoadIdentity();
318     glOrtho(0.0, g_winWidth, 0.0, g_winHeight, -100.0, 100.0);
319     glMatrixMode(GL_MODELVIEW);
320     glLoadIdentity();
321 }
322 
323 
CleanUp(void)324 static void CleanUp(void)
325 {
326     glDeleteShader(g_fragShader);
327     glDeleteProgram(g_program);
328     glutDestroyWindow(g_win);
329 }
330 
331 
Key(unsigned char key,int,int)332 static void Key(unsigned char key, int /*x*/, int /*y*/)
333 {
334     if(key == 'c' || key == 'C')
335     {
336         g_channelHot[0] = 1;
337         g_channelHot[1] = 1;
338         g_channelHot[2] = 1;
339         g_channelHot[3] = 1;
340     }
341     else if(key == 'r' || key == 'R')
342     {
343         g_channelHot[0] = 1;
344         g_channelHot[1] = 0;
345         g_channelHot[2] = 0;
346         g_channelHot[3] = 0;
347     }
348     else if(key == 'g' || key == 'G')
349     {
350         g_channelHot[0] = 0;
351         g_channelHot[1] = 1;
352         g_channelHot[2] = 0;
353         g_channelHot[3] = 0;
354     }
355     else if(key == 'b' || key == 'B')
356     {
357         g_channelHot[0] = 0;
358         g_channelHot[1] = 0;
359         g_channelHot[2] = 1;
360         g_channelHot[3] = 0;
361     }
362     else if(key == 'a' || key == 'A')
363     {
364         g_channelHot[0] = 0;
365         g_channelHot[1] = 0;
366         g_channelHot[2] = 0;
367         g_channelHot[3] = 1;
368     }
369     else if(key == 'l' || key == 'L')
370     {
371         g_channelHot[0] = 1;
372         g_channelHot[1] = 1;
373         g_channelHot[2] = 1;
374         g_channelHot[3] = 0;
375     }
376     else if(key == 27)
377     {
378         CleanUp();
379         exit(0);
380     }
381 
382     UpdateOCIOGLState();
383     glutPostRedisplay();
384 }
385 
386 
SpecialKey(int key,int x,int y)387 static void SpecialKey(int key, int x, int y)
388 {
389     (void) x;
390     (void) y;
391 
392     int mod = glutGetModifiers();
393 
394     if(key == GLUT_KEY_UP && (mod & GLUT_ACTIVE_CTRL))
395     {
396         g_exposure_fstop += 0.25f;
397     }
398     else if(key == GLUT_KEY_DOWN && (mod & GLUT_ACTIVE_CTRL))
399     {
400         g_exposure_fstop -= 0.25f;
401     }
402     else if(key == GLUT_KEY_HOME && (mod & GLUT_ACTIVE_CTRL))
403     {
404         g_exposure_fstop = 0.0f;
405         g_display_gamma = 1.0f;
406     }
407 
408     else if(key == GLUT_KEY_UP && (mod & GLUT_ACTIVE_ALT))
409     {
410         g_display_gamma *= 1.1f;
411     }
412     else if(key == GLUT_KEY_DOWN && (mod & GLUT_ACTIVE_ALT))
413     {
414         g_display_gamma /= 1.1f;
415     }
416     else if(key == GLUT_KEY_HOME && (mod & GLUT_ACTIVE_ALT))
417     {
418         g_exposure_fstop = 0.0f;
419         g_display_gamma = 1.0f;
420     }
421 
422     UpdateOCIOGLState();
423 
424     glutPostRedisplay();
425 }
426 
427 GLuint
CompileShaderText(GLenum shaderType,const char * text)428 CompileShaderText(GLenum shaderType, const char *text)
429 {
430     GLuint shader;
431     GLint stat;
432 
433     shader = glCreateShader(shaderType);
434     glShaderSource(shader, 1, (const GLchar **) &text, NULL);
435     glCompileShader(shader);
436     glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
437 
438     if (!stat)
439     {
440         GLchar log[1000];
441         GLsizei len;
442         glGetShaderInfoLog(shader, 1000, &len, log);
443         fprintf(stderr, "Error: problem compiling shader: %s\n", log);
444         return 0;
445     }
446 
447     return shader;
448 }
449 
450 GLuint
LinkShaders(GLuint fragShader)451 LinkShaders(GLuint fragShader)
452 {
453     if (!fragShader) return 0;
454 
455     GLuint program = glCreateProgram();
456 
457     if (fragShader)
458         glAttachShader(program, fragShader);
459 
460     glLinkProgram(program);
461 
462     /* check link */
463     {
464         GLint stat;
465         glGetProgramiv(program, GL_LINK_STATUS, &stat);
466         if (!stat) {
467             GLchar log[1000];
468             GLsizei len;
469             glGetProgramInfoLog(program, 1000, &len, log);
470             fprintf(stderr, "Shader link error:\n%s\n", log);
471             return 0;
472         }
473     }
474 
475     return program;
476 }
477 
478 const char * g_fragShaderText = ""
479 "\n"
480 "uniform sampler2D tex1;\n"
481 "uniform sampler3D tex2;\n"
482 "\n"
483 "void main()\n"
484 "{\n"
485 "    vec4 col = texture2D(tex1, gl_TexCoord[0].st);\n"
486 "    gl_FragColor = OCIODisplay(col, tex2);\n"
487 "}\n";
488 
489 
UpdateOCIOGLState()490 void UpdateOCIOGLState()
491 {
492     // Step 0: Get the processor using any of the pipelines mentioned above.
493     OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
494 
495     OCIO::DisplayTransformRcPtr transform = OCIO::DisplayTransform::Create();
496     transform->setInputColorSpaceName( g_inputColorSpace.c_str() );
497     transform->setDisplay( g_display.c_str() );
498     transform->setView( g_transformName.c_str() );
499     transform->setLooksOverride( g_look.c_str() );
500 
501     if(g_verbose)
502     {
503         std::cout << std::endl;
504         std::cout << "Color transformation composed of:" << std::endl;
505         std::cout << "      Image ColorSpace is:\t" << g_inputColorSpace << std::endl;
506         std::cout << "      Transform is:\t\t" << g_transformName << std::endl;
507         std::cout << "      Device is:\t\t" << g_display << std::endl;
508         std::cout << "      Looks Override is:\t'" << g_look << "'" << std::endl;
509         std::cout << "  with:" << std::endl;
510         std::cout << "    exposure_fstop = " << g_exposure_fstop << std::endl;
511         std::cout << "    display_gamma  = " << g_display_gamma << std::endl;
512         std::cout << "    channels       = "
513                   << (g_channelHot[0] ? "R" : "")
514                   << (g_channelHot[1] ? "G" : "")
515                   << (g_channelHot[2] ? "B" : "")
516                   << (g_channelHot[3] ? "A" : "") << std::endl;
517 
518     }
519 
520     // Add optional transforms to create a full-featured, "canonical" display pipeline
521     // Fstop exposure control (in SCENE_LINEAR)
522     {
523         float gain = powf(2.0f, g_exposure_fstop);
524         const float slope4f[] = { gain, gain, gain, gain };
525         float m44[16];
526         float offset4[4];
527         OCIO::MatrixTransform::Scale(m44, offset4, slope4f);
528         OCIO::MatrixTransformRcPtr mtx =  OCIO::MatrixTransform::Create();
529         mtx->setValue(m44, offset4);
530         transform->setLinearCC(mtx);
531     }
532 
533     // Channel swizzling
534     {
535         float lumacoef[3];
536         config->getDefaultLumaCoefs(lumacoef);
537         float m44[16];
538         float offset[4];
539         OCIO::MatrixTransform::View(m44, offset, g_channelHot, lumacoef);
540         OCIO::MatrixTransformRcPtr swizzle = OCIO::MatrixTransform::Create();
541         swizzle->setValue(m44, offset);
542         transform->setChannelView(swizzle);
543     }
544 
545     // Post-display transform gamma
546     {
547         float exponent = 1.0f/std::max(1e-6f, static_cast<float>(g_display_gamma));
548         const float exponent4f[] = { exponent, exponent, exponent, exponent };
549         OCIO::ExponentTransformRcPtr expTransform =  OCIO::ExponentTransform::Create();
550         expTransform->setValue(exponent4f);
551         transform->setDisplayCC(expTransform);
552     }
553 
554     OCIO::ConstProcessorRcPtr processor;
555     try
556     {
557         processor = config->getProcessor(transform);
558     }
559     catch(OCIO::Exception & e)
560     {
561         std::cerr << e.what() << std::endl;
562         return;
563     }
564     catch(...)
565     {
566         return;
567     }
568 
569     // Step 1: Create a GPU Shader Description
570     OCIO::GpuShaderDesc shaderDesc;
571     shaderDesc.setLanguage(OCIO::GPU_LANGUAGE_GLSL_1_0);
572     shaderDesc.setFunctionName("OCIODisplay");
573     shaderDesc.setLut3DEdgeLen(LUT3D_EDGE_SIZE);
574 
575     // Step 2: Compute the 3D LUT
576     std::string lut3dCacheID = processor->getGpuLut3DCacheID(shaderDesc);
577     if(lut3dCacheID != g_lut3dcacheid)
578     {
579         //std::cerr << "Computing 3DLut " << g_lut3dcacheid << std::endl;
580 
581         g_lut3dcacheid = lut3dCacheID;
582         processor->getGpuLut3D(&g_lut3d[0], shaderDesc);
583 
584         glBindTexture(GL_TEXTURE_3D, g_lut3dTexID);
585         glTexSubImage3D(GL_TEXTURE_3D, 0,
586                         0, 0, 0,
587                         LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE, LUT3D_EDGE_SIZE,
588                         GL_RGB,GL_FLOAT, &g_lut3d[0]);
589     }
590 
591     // Step 3: Compute the Shader
592     std::string shaderCacheID = processor->getGpuShaderTextCacheID(shaderDesc);
593     if(g_program == 0 || shaderCacheID != g_shadercacheid)
594     {
595         //std::cerr << "Computing Shader " << g_shadercacheid << std::endl;
596 
597         g_shadercacheid = shaderCacheID;
598 
599         std::ostringstream os;
600         os << processor->getGpuShaderText(shaderDesc) << "\n";
601         os << g_fragShaderText;
602         //std::cerr << os.str() << std::endl;
603 
604         if(g_fragShader) glDeleteShader(g_fragShader);
605         g_fragShader = CompileShaderText(GL_FRAGMENT_SHADER, os.str().c_str());
606         if(g_program) glDeleteProgram(g_program);
607         g_program = LinkShaders(g_fragShader);
608     }
609 
610     glUseProgram(g_program);
611     glUniform1i(glGetUniformLocation(g_program, "tex1"), 1);
612     glUniform1i(glGetUniformLocation(g_program, "tex2"), 2);
613 }
614 
menuCallback(int)615 void menuCallback(int /*id*/)
616 {
617     glutPostRedisplay();
618 }
619 
imageColorSpace_CB(int id)620 void imageColorSpace_CB(int id)
621 {
622     OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
623     const char * name = config->getColorSpaceNameByIndex(id);
624     if(!name) return;
625 
626     g_inputColorSpace = name;
627 
628     UpdateOCIOGLState();
629     glutPostRedisplay();
630 }
631 
displayDevice_CB(int id)632 void displayDevice_CB(int id)
633 {
634     OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
635     const char * display = config->getDisplay(id);
636     if(!display) return;
637 
638     g_display = display;
639 
640     const char * csname = config->getDisplayColorSpaceName(g_display.c_str(), g_transformName.c_str());
641     if(!csname)
642     {
643         g_transformName = config->getDefaultView(g_display.c_str());
644     }
645 
646     g_look = config->getDisplayLooks(g_display.c_str(), g_transformName.c_str());
647 
648     UpdateOCIOGLState();
649     glutPostRedisplay();
650 }
651 
transform_CB(int id)652 void transform_CB(int id)
653 {
654     OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
655 
656     const char * transform = config->getView(g_display.c_str(), id);
657     if(!transform) return;
658 
659     g_transformName = transform;
660 
661     g_look = config->getDisplayLooks(g_display.c_str(), g_transformName.c_str());
662 
663     UpdateOCIOGLState();
664     glutPostRedisplay();
665 }
666 
look_CB(int id)667 void look_CB(int id)
668 {
669     OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
670 
671     const char * look = config->getLookNameByIndex(id);
672     if(!look || !*look) return;
673 
674     g_look = look;
675 
676     UpdateOCIOGLState();
677     glutPostRedisplay();
678 }
679 
PopulateOCIOMenus()680 static void PopulateOCIOMenus()
681 {
682     OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
683 
684     int csMenuID = glutCreateMenu(imageColorSpace_CB);
685 
686     std::map<std::string, int> families;
687     for(int i=0; i<config->getNumColorSpaces(); ++i)
688     {
689         const char * csName = config->getColorSpaceNameByIndex(i);
690         if(csName && *csName)
691         {
692             OCIO::ConstColorSpaceRcPtr cs = config->getColorSpace(csName);
693             if(cs)
694             {
695                 const char * family = cs->getFamily();
696                 if(family && *family)
697                 {
698                     if(families.find(family)==families.end())
699                     {
700                         families[family] = glutCreateMenu(imageColorSpace_CB);
701                         glutAddMenuEntry(csName, i);
702 
703                         glutSetMenu(csMenuID);
704                         glutAddSubMenu(family, families[family]);
705                     }
706                     else
707                     {
708                         glutSetMenu(families[family]);
709                         glutAddMenuEntry(csName, i);
710                     }
711                 }
712                 else
713                 {
714                     glutSetMenu(csMenuID);
715                     glutAddMenuEntry(csName, i);
716                 }
717             }
718         }
719     }
720 
721     int deviceMenuID = glutCreateMenu(displayDevice_CB);
722     for(int i=0; i<config->getNumDisplays(); ++i)
723     {
724         glutAddMenuEntry(config->getDisplay(i), i);
725     }
726 
727     int transformMenuID = glutCreateMenu(transform_CB);
728     const char * defaultDisplay = config->getDefaultDisplay();
729     for(int i=0; i<config->getNumViews(defaultDisplay); ++i)
730     {
731         glutAddMenuEntry(config->getView(defaultDisplay, i), i);
732     }
733 
734     int lookMenuID = glutCreateMenu(look_CB);
735     for(int i=0; i<config->getNumLooks(); ++i)
736     {
737         glutAddMenuEntry(config->getLookNameByIndex(i), i);
738     }
739 
740     glutCreateMenu(menuCallback);
741     glutAddSubMenu("Image ColorSpace", csMenuID);
742     glutAddSubMenu("Transform", transformMenuID);
743     glutAddSubMenu("Device", deviceMenuID);
744     glutAddSubMenu("Looks Override", lookMenuID);
745 
746     glutAttachMenu(GLUT_RIGHT_BUTTON);
747 }
748 
749 const char * USAGE_TEXT = "\n"
750 "Keys:\n"
751 "\tCtrl+Up:   Exposure +1/4 stop (in scene linear)\n"
752 "\tCtrl+Down: Exposure -1/4 stop (in scene linear)\n"
753 "\tCtrl+Home: Reset Exposure + Gamma\n"
754 "\n"
755 "\tAlt+Up:    Gamma up (post display transform)\n"
756 "\tAlt+Down:  Gamma down (post display transform)\n"
757 "\tAlt+Home:  Reset Exposure + Gamma\n"
758 "\n"
759 "\tC:   View Color\n"
760 "\tR:   View Red  \n"
761 "\tG:   View Green\n"
762 "\tB:   View Blue\n"
763 "\tA:   View Alpha\n"
764 "\tL:   View Luma\n"
765 "\n"
766 "\tRight-Mouse Button:   Configure Display / Transform / ColorSpace / Looks\n"
767 "\n"
768 "\tEsc: Quit\n";
769 
parseArguments(int argc,char ** argv)770 void parseArguments(int argc, char **argv)
771 {
772     for(int i=1; i<argc; ++i)
773     {
774         if(0==strcmp(argv[i], "-v"))
775         {
776             g_verbose = true;
777         }
778         else if(0==strcmp(argv[i], "-h"))
779         {
780             std::cout << std::endl;
781             std::cout << "help:" << std::endl;
782             std::cout << "  ociodisplay [OPTIONS] [image]  where" << std::endl;
783             std::cout << std::endl;
784             std::cout << "  OPTIONS:" << std::endl;
785             std::cout << "     -h :  displays the help and exit" << std::endl;
786             std::cout << "     -v :  displays the color space information" << std::endl;
787             std::cout << std::endl;
788             exit(0);
789         }
790         else
791         {
792             g_filename = argv[i];
793         }
794     }
795 
796     if(g_verbose)
797     {
798         std::cout << std::endl;
799         if(!g_filename.empty())
800         {
801             std::cout << "Image:" << std::endl
802                       << "\t" << g_filename << std::endl;
803         }
804         std::cout << std::endl;
805         std::cout << "OIIO: " << std::endl
806                   << "\tversion       = " << OIIO_VERSION_STRING << std::endl;
807         std::cout << std::endl;
808         std::cout << "OCIO: " << std::endl
809                   << "\tversion       = " << OCIO::GetVersion() << std::endl;
810         if(getenv("OCIO"))
811         {
812             std::cout << "\tconfiguration = " << getenv("OCIO") << std::endl;
813             OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig();
814             std::cout << "\tsearch_path   = " << config->getSearchPath() << std::endl;
815         }
816     }
817 }
818 
main(int argc,char ** argv)819 int main(int argc, char **argv)
820 {
821     glutInit(&argc, argv);
822 
823     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
824     glutInitWindowSize(512, 512);
825     glutInitWindowPosition (100, 100);
826 
827     parseArguments(argc, argv);
828 
829     g_win = glutCreateWindow(argv[0]);
830 
831 #ifndef __APPLE__
832     glewInit();
833     if (!glewIsSupported("GL_VERSION_2_0"))
834     {
835         printf("OpenGL 2.0 not supported\n");
836         exit(1);
837     }
838 #endif
839 
840     glutReshapeFunc(Reshape);
841     glutKeyboardFunc(Key);
842     glutSpecialFunc(SpecialKey);
843     glutDisplayFunc(Redisplay);
844 
845     std::cout << USAGE_TEXT << std::endl;
846 
847     // TODO: switch profiles based on shading language
848     std::cout << "GL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
849     std::cout << std::endl;
850 
851     AllocateLut3D();
852 
853     InitImageTexture(g_filename.c_str());
854     try
855     {
856         InitOCIO(g_filename.c_str());
857     }
858     catch(OCIO::Exception & e)
859     {
860         std::cerr << e.what() << std::endl;
861         exit(1);
862     }
863 
864     PopulateOCIOMenus();
865 
866     Reshape(1024, 512);
867 
868     UpdateOCIOGLState();
869 
870     Redisplay();
871 
872     /*
873     if (Anim)
874     {
875         glutIdleFunc(Idle);
876     }
877     */
878 
879     glutMainLoop();
880 
881     return 0;
882 }
883