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