diff options
Diffstat (limited to 'graphics/asymptote/tinyexr/examples/exrview/main.cc')
-rw-r--r-- | graphics/asymptote/tinyexr/examples/exrview/main.cc | 541 |
1 files changed, 541 insertions, 0 deletions
diff --git a/graphics/asymptote/tinyexr/examples/exrview/main.cc b/graphics/asymptote/tinyexr/examples/exrview/main.cc new file mode 100644 index 0000000000..2254fe7078 --- /dev/null +++ b/graphics/asymptote/tinyexr/examples/exrview/main.cc @@ -0,0 +1,541 @@ +#define USE_OPENGL2 +#include "OpenGLWindow/OpenGLInclude.h" +#ifdef _WIN32 +#include "OpenGLWindow/Win32OpenGLWindow.h" +#elif defined __APPLE__ +#include "OpenGLWindow/MacOpenGLWindow.h" +#else +// assume linux +#include "OpenGLWindow/X11OpenGLWindow.h" +#endif + +#ifdef _WIN32 +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#else +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#endif + +#include <cstdio> +#include <cstdlib> +#include <string> +#include <cstring> + +#ifdef USE_NATIVEFILEDIALOG +#include <nfd.h> +#endif + +#define NK_INCLUDE_FIXED_TYPES +#define NK_INCLUDE_STANDARD_IO +#define NK_INCLUDE_DEFAULT_ALLOCATOR +#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT +#define NK_INCLUDE_FONT_BAKING +#define NK_INCLUDE_DEFAULT_FONT +#define NK_IMPLEMENTATION +#define NK_BTGUI_GL2_IMPLEMENTATION +#include "nuklear.h" +#include "nuklear_btgui_gl2.h" + +#include "exr-io.h" + +b3gDefaultOpenGLWindow* window = 0; +int gWidth = 512; +int gHeight = 512; +GLuint gTexId; +float gIntensityScale = 1.0; +float gGamma = 1.0; +int gExrWidth, gExrHeight; +float* gExrRGBA; +int gMousePosX, gMousePosY; + +struct nk_context* ctx; + +#define MAX_VERTEX_BUFFER 512 * 1024 +#define MAX_ELEMENT_BUFFER 128 * 1024 + +void checkErrors(std::string desc) { + GLenum e = glGetError(); + if (e != GL_NO_ERROR) { + fprintf(stderr, "OpenGL error in \"%s\": %d (%d)\n", desc.c_str(), e, e); + exit(20); + } +} + +void keyboardCallback(int keycode, int state) { + // printf("hello key %d, state %d\n", keycode, state); + if (keycode == 27) { + if (window) window->setRequestExit(); + } +} + +void mouseMoveCallback(float x, float y) { + // printf("Mouse Move: %f, %f\n", x, y); + + gMousePosX = (int)x; + gMousePosY = (int)y; + + // @todo { move to nuklear_btgui_gl2.h } + nk_btgui_update_mouse_pos((int)x, (int)y); +} +void mouseButtonCallback(int button, int state, float x, float y) { + nk_btgui_update_mouse_state((button == 0) && (state == 1), 0, 0); +} + +void resizeCallback(float width, float height) { + GLfloat h = (GLfloat)height / (GLfloat)width; + GLfloat xmax, znear, zfar; + + znear = 1.0f; + zfar = 1000.0f; + xmax = znear * 0.5f; + + gWidth = width; + gHeight = height; +} + +GLuint GenTexture(int w, int h, const float* rgba) +{ + // Create floating point RGBA texture + GLuint texHandle; + glGenTextures(1, &texHandle); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texHandle); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // @todo { Use GL_RGBA32F for internal texture format. } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_FLOAT, rgba); + checkErrors("GenTexture"); + + return texHandle; +} + + +bool +LoadShader( + GLenum shaderType, // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER(or maybe GL_COMPUTE_SHADER) + GLuint& shader, + const char* shaderSourceFilename) +{ + GLint val = 0; + + // free old shader/program + if (shader != 0) glDeleteShader(shader); + + static GLchar srcbuf[16384]; + FILE *fp = fopen(shaderSourceFilename, "rb"); + if (!fp) { + fprintf(stderr, "failed to load shader: %s\n", shaderSourceFilename); + return false; + } + fseek(fp, 0, SEEK_END); + size_t len = ftell(fp); + rewind(fp); + len = fread(srcbuf, 1, len, fp); + srcbuf[len] = 0; + fclose(fp); + + static const GLchar *src = srcbuf; + + shader = glCreateShader(shaderType); + glShaderSource(shader, 1, &src, NULL); + glCompileShader(shader); + glGetShaderiv(shader, GL_COMPILE_STATUS, &val); + if (val != GL_TRUE) { + char log[4096]; + GLsizei msglen; + glGetShaderInfoLog(shader, 4096, &msglen, log); + printf("%s\n", log); + assert(val == GL_TRUE && "failed to compile shader"); + } + + printf("Load shader [ %s ] OK\n", shaderSourceFilename); + return true; +} + +bool +LinkShader( + GLuint& prog, + GLuint& vertShader, + GLuint& fragShader) +{ + GLint val = 0; + + if (prog != 0) { + glDeleteProgram(prog); + } + + prog = glCreateProgram(); + + glAttachShader(prog, vertShader); + glAttachShader(prog, fragShader); + glLinkProgram(prog); + + glGetProgramiv(prog, GL_LINK_STATUS, &val); + assert(val == GL_TRUE && "failed to link shader"); + + printf("Link shader OK\n"); + + return true; +} + +void +Render(GLuint prog_id, int w, int h) +{ + glDisable(GL_DEPTH_TEST); + + glUseProgram(prog_id); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, gTexId); + + glEnable(GL_TEXTURE_2D); + GLint texLoc = glGetUniformLocation(prog_id, "tex"); + assert(texLoc >= 0); + glUniform1i(texLoc, 0); // TEXTURE0 + + GLint intensityScaleLoc = glGetUniformLocation(prog_id, "intensity_scale"); + if (intensityScaleLoc >= 0) { + glUniform1f(intensityScaleLoc, gIntensityScale); + } + + GLint gammaLoc = glGetUniformLocation(prog_id, "gamma"); + if (gammaLoc >= 0) { + glUniform1f(gammaLoc, gGamma); + } + + GLint pos_id = glGetAttribLocation(prog_id, "in_position"); + assert(pos_id >= 0); + GLint texcoord_id = glGetAttribLocation(prog_id, "in_texcoord"); + assert(texcoord_id >= 0); + + const float vertices[] = {-1, -1, -1, 1, 1, 1, 1, -1}; + const float texcoords[] = {0, 1, 0, 0, 1, 0, 1, 1}; + + glVertexAttribPointer(pos_id, 2, GL_FLOAT, GL_FALSE, 0, (const void*)(vertices)); + glVertexAttribPointer(texcoord_id, 2, GL_FLOAT, GL_FALSE, 0, (const void*)(texcoords)); + + glEnableVertexAttribArray(pos_id); + glEnableVertexAttribArray(texcoord_id); + + glDrawArrays(GL_QUADS, 0, 4); + + glDisableVertexAttribArray(pos_id); + glDisableVertexAttribArray(texcoord_id); + + checkErrors("render"); + + glUseProgram(0); + checkErrors("UseProgram(0)"); + + glEnable(GL_DEPTH_TEST); + glDisable(GL_TEXTURE_2D); +} + +void InspectPixel(float rgba[4], int x, int y) { + if (x < 0) x = 0; + if (x > (gExrWidth-1)) x = gExrWidth - 1; + + if (y < 0) y = 0; + if (y > (gExrHeight-1)) y = gExrHeight - 1; + + rgba[0] = gExrRGBA[4 * (y * gExrWidth + x) + 0]; + rgba[1] = gExrRGBA[4 * (y * gExrWidth + x) + 1]; + rgba[2] = gExrRGBA[4 * (y * gExrWidth + x) + 2]; + rgba[3] = gExrRGBA[4 * (y * gExrWidth + x) + 3]; +} + +int main(int argc, char** argv) { + + const char *filename = NULL; + const char *layername = NULL; + +#ifdef USE_NATIVEFILEDIALOG + if (argc < 2) { + nfdchar_t *outPath = NULL; + nfdresult_t result = NFD_OpenDialog( "exr", NULL, &outPath ); + if ( result == NFD_OKAY ) + { + puts("Success!"); + filename = strdup(outPath); + } + else if ( result == NFD_CANCEL ) + { + puts("User pressed cancel."); + exit(-1); + } + else + { + printf("Error: %s\n", NFD_GetError() ); + exit(-1); + } + } else { + filename = argv[1]; + if (argc > 2) { + layername = argv[2]; + } + } +#else + if (argc < 2) { + printf("Usage: exrview input.exr [layer name]\n"); + exit(-1); + } + filename = argv[1]; + if (argc > 2) { + layername = argv[2]; + } +#endif + + { + bool ret = exrio::GetEXRLayers(filename); + if (!ret) { + exit(-1); + } + } + + { + bool ret = exrio::LoadEXRRGBA(&gExrRGBA, &gExrWidth, &gExrHeight, filename, layername); + if (!ret) { + exit(-1); + } + } + + window = new b3gDefaultOpenGLWindow; + b3gWindowConstructionInfo ci; +#ifdef USE_OPENGL2 + ci.m_openglVersion = 2; +#endif + ci.m_width = gExrWidth; + ci.m_height = gExrHeight; + window->createWindow(ci); + + char title[1024]; + sprintf(title, "%s (%d x %d)", filename, gExrWidth, gExrHeight); + window->setWindowTitle(title); + +#ifndef __APPLE__ +#ifndef _WIN32 + //some Linux implementations need the 'glewExperimental' to be true + glewExperimental = GL_TRUE; +#endif + if (glewInit() != GLEW_OK) { + fprintf(stderr, "Failed to initialize GLEW\n"); + exit(-1); + } + + if (!GLEW_VERSION_2_1) { + fprintf(stderr, "OpenGL 2.1 is not available\n"); + exit(-1); + } +#endif + + + checkErrors("init"); + + window->setMouseButtonCallback(mouseButtonCallback); + window->setMouseMoveCallback(mouseMoveCallback); + checkErrors("mouse"); + window->setKeyboardCallback(keyboardCallback); + checkErrors("keyboard"); + window->setResizeCallback(resizeCallback); + checkErrors("resize"); + + struct nk_color background; + background = nk_rgb(28,48,62); + + + { + // Upload EXR image to OpenGL texture. + gTexId = GenTexture(gExrWidth, gExrHeight, gExrRGBA); + if (gTexId == 0) { + fprintf(stderr, "OpenGL texture error\n"); + exit(-1); + } + } + + + /* GUI */ + ctx = nk_btgui_init(window, NK_BTGUI3_DEFAULT); + /* Load Fonts: if none of these are loaded a default font will be used */ + { + struct nk_font_atlas* atlas; + nk_btgui_font_stash_begin(&atlas); + /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, + * "../../../extra_font/DroidSans.ttf", 14, 0);*/ + /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, + * "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/ + /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, + * "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/ + /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, + * "../../../extra_font/ProggyClean.ttf", 12, 0);*/ + /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, + * "../../../extra_font/ProggyTiny.ttf", 10, 0);*/ + /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, + * "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/ + struct nk_font *droid = nk_font_atlas_add_from_file(atlas, + "./DroidSans.ttf", 14, 0); + nk_btgui_font_stash_end(); + if (droid) { + nk_style_set_font(ctx, &droid->handle); + } + + // Color + struct nk_color table[NK_COLOR_COUNT]; + table[NK_COLOR_TEXT] = nk_rgba(210, 210, 210, 255); + table[NK_COLOR_WINDOW] = nk_rgba(57, 67, 71, 245); + table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 230); + table[NK_COLOR_BORDER] = nk_rgba(46, 46, 46, 255); + table[NK_COLOR_BUTTON] = nk_rgba(48, 48, 48, 255); + table[NK_COLOR_BUTTON_HOVER] = nk_rgba(58, 93, 121, 255); + table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(63, 98, 126, 255); + table[NK_COLOR_TOGGLE] = nk_rgba(50, 58, 61, 255); + table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 53, 56, 255); + table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(48, 83, 111, 255); + table[NK_COLOR_SELECT] = nk_rgba(57, 67, 61, 255); + table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(48, 83, 111, 255); + table[NK_COLOR_SLIDER] = nk_rgba(50, 58, 61, 255); + table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(48, 83, 111, 245); + table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255); + table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255); + table[NK_COLOR_PROPERTY] = nk_rgba(50, 58, 61, 255); + table[NK_COLOR_EDIT] = nk_rgba(50, 58, 61, 225); + table[NK_COLOR_EDIT_CURSOR] = nk_rgba(210, 210, 210, 255); + table[NK_COLOR_COMBO] = nk_rgba(50, 58, 61, 255); + table[NK_COLOR_CHART] = nk_rgba(50, 58, 61, 255); + table[NK_COLOR_CHART_COLOR] = nk_rgba(48, 83, 111, 255); + table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255); + table[NK_COLOR_SCROLLBAR] = nk_rgba(50, 58, 61, 255); + table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(48, 83, 111, 255); + table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255); + table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255); + table[NK_COLOR_TAB_HEADER] = nk_rgba(48, 83, 111, 255); + nk_style_from_table(ctx, table); + } + + checkErrors("start"); + + GLuint vert_id = 0, frag_id = 0, prog_id = 0; + { + bool ret = LoadShader(GL_VERTEX_SHADER, vert_id, "shader.vert"); + if (!ret) { + fprintf(stderr, "Failed to compile vertex shader.\n"); + exit(-1); + } + } + checkErrors("vertex shader load"); + + { + bool ret = LoadShader(GL_FRAGMENT_SHADER, frag_id, "shader.frag"); + if (!ret) { + fprintf(stderr, "Failed to compile fragment shader.\n"); + exit(-1); + } + } + checkErrors("fragment shader load"); + + { + bool ret = LinkShader(prog_id, vert_id, frag_id); + if (!ret) { + fprintf(stderr, "Failed to link shader.\n"); + exit(-1); + } + } + checkErrors("link shader"); + + + while (!window->requestedExit()) { + window->startRendering(); + + glClear(GL_COLOR_BUFFER_BIT); + + checkErrors("begin frame"); + nk_btgui_new_frame(); + + float pixel[4]; + InspectPixel(pixel, gMousePosX, gMousePosY); + + /* GUI */ + { + //struct nk_panel layout; + if (nk_begin(ctx, "UI", nk_rect(50, 50, 350, 250), + NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE | + NK_WINDOW_MINIMIZABLE | NK_WINDOW_TITLE)) { + nk_layout_row_static(ctx, 30, 300, 1); + //if (nk_button_label(ctx, "button", NK_BUTTON_DEFAULT)) + // fprintf(stdout, "button pressed\n"); + + nk_label(ctx, "Intensity", NK_TEXT_LEFT); + if (nk_slider_float(ctx, 0, &gIntensityScale, 10.0, 0.1f)) { + fprintf(stdout, "Intensity: %f\n", gIntensityScale); + } + nk_label(ctx, "Display gamma", NK_TEXT_LEFT); + if (nk_slider_float(ctx, 0, &gGamma, 10.0, 0.01f)) { + fprintf(stdout, "Gamma: %f\n", gGamma); + } + + nk_label(ctx, "RAW pixel value", NK_TEXT_LEFT); + char txt[1024]; + sprintf(txt, "(%d, %d) = %f, %f, %f, %f", gMousePosX, gMousePosY, pixel[0], pixel[1], pixel[2], pixel[3]); + nk_text(ctx, txt, strlen(txt), NK_TEXT_LEFT); + +#if 0 + nk_layout_row_dynamic(ctx, 25, 1); + nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); + + { + struct nk_panel combo; + nk_layout_row_dynamic(ctx, 20, 1); + nk_label(ctx, "background:", NK_TEXT_LEFT); + nk_layout_row_dynamic(ctx, 25, 1); + if (nk_combo_begin_color(ctx, &combo, background, 400)) { + nk_layout_row_dynamic(ctx, 120, 1); + background = nk_color_picker(ctx, background, NK_RGBA); + nk_layout_row_dynamic(ctx, 25, 1); + background.r = + (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1, 1); + background.g = + (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1, 1); + background.b = + (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1, 1); + background.a = + (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1, 1); + nk_combo_end(ctx); + } + } +#endif + } + nk_end(ctx); + } + + /* Draw */ + { + float bg[4]; + nk_color_fv(bg, background); + glViewport(0, 0, window->getWidth(), window->getHeight()); + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(bg[0], bg[1], bg[2], bg[3]); + + Render(prog_id, window->getWidth(), window->getHeight()); + + /* IMPORTANT: `nk_glfw_render` modifies some global OpenGL state + * with blending, scissor, face culling and depth test and defaults + * everything + * back into a default state. Make sure to either save and restore or + * reset your own state after drawing rendering the UI. */ + nk_btgui_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, + MAX_ELEMENT_BUFFER); + } + + window->endRendering(); + } + + nk_btgui_shutdown(); + + delete window; + + return EXIT_SUCCESS; +} |