🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

541 lines
15 KiB

  1. #define USE_OPENGL2
  2. #include "OpenGLWindow/OpenGLInclude.h"
  3. #ifdef _WIN32
  4. #include "OpenGLWindow/Win32OpenGLWindow.h"
  5. #elif defined __APPLE__
  6. #include "OpenGLWindow/MacOpenGLWindow.h"
  7. #else
  8. // assume linux
  9. #include "OpenGLWindow/X11OpenGLWindow.h"
  10. #endif
  11. #ifdef _WIN32
  12. #include <sys/stat.h>
  13. #include <sys/types.h>
  14. #include <time.h>
  15. #else
  16. #include <fcntl.h>
  17. #include <sys/mman.h>
  18. #include <sys/stat.h>
  19. #endif
  20. #include <cstdio>
  21. #include <cstdlib>
  22. #include <string>
  23. #include <cstring>
  24. #ifdef USE_NATIVEFILEDIALOG
  25. #include <nfd.h>
  26. #endif
  27. #define NK_INCLUDE_FIXED_TYPES
  28. #define NK_INCLUDE_STANDARD_IO
  29. #define NK_INCLUDE_DEFAULT_ALLOCATOR
  30. #define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
  31. #define NK_INCLUDE_FONT_BAKING
  32. #define NK_INCLUDE_DEFAULT_FONT
  33. #define NK_IMPLEMENTATION
  34. #define NK_BTGUI_GL2_IMPLEMENTATION
  35. #include "nuklear.h"
  36. #include "nuklear_btgui_gl2.h"
  37. #include "exr-io.h"
  38. b3gDefaultOpenGLWindow* window = 0;
  39. int gWidth = 512;
  40. int gHeight = 512;
  41. GLuint gTexId;
  42. float gIntensityScale = 1.0;
  43. float gGamma = 1.0;
  44. int gExrWidth, gExrHeight;
  45. float* gExrRGBA;
  46. int gMousePosX, gMousePosY;
  47. struct nk_context* ctx;
  48. #define MAX_VERTEX_BUFFER 512 * 1024
  49. #define MAX_ELEMENT_BUFFER 128 * 1024
  50. void checkErrors(std::string desc) {
  51. GLenum e = glGetError();
  52. if (e != GL_NO_ERROR) {
  53. fprintf(stderr, "OpenGL error in \"%s\": %d (%d)\n", desc.c_str(), e, e);
  54. exit(20);
  55. }
  56. }
  57. void keyboardCallback(int keycode, int state) {
  58. // printf("hello key %d, state %d\n", keycode, state);
  59. if (keycode == 27) {
  60. if (window) window->setRequestExit();
  61. }
  62. }
  63. void mouseMoveCallback(float x, float y) {
  64. // printf("Mouse Move: %f, %f\n", x, y);
  65. gMousePosX = (int)x;
  66. gMousePosY = (int)y;
  67. // @todo { move to nuklear_btgui_gl2.h }
  68. nk_btgui_update_mouse_pos((int)x, (int)y);
  69. }
  70. void mouseButtonCallback(int button, int state, float x, float y) {
  71. nk_btgui_update_mouse_state((button == 0) && (state == 1), 0, 0);
  72. }
  73. void resizeCallback(float width, float height) {
  74. GLfloat h = (GLfloat)height / (GLfloat)width;
  75. GLfloat xmax, znear, zfar;
  76. znear = 1.0f;
  77. zfar = 1000.0f;
  78. xmax = znear * 0.5f;
  79. gWidth = width;
  80. gHeight = height;
  81. }
  82. GLuint GenTexture(int w, int h, const float* rgba)
  83. {
  84. // Create floating point RGBA texture
  85. GLuint texHandle;
  86. glGenTextures(1, &texHandle);
  87. glActiveTexture(GL_TEXTURE0);
  88. glBindTexture(GL_TEXTURE_2D, texHandle);
  89. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  90. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  91. // @todo { Use GL_RGBA32F for internal texture format. }
  92. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_FLOAT, rgba);
  93. checkErrors("GenTexture");
  94. return texHandle;
  95. }
  96. bool
  97. LoadShader(
  98. GLenum shaderType, // GL_VERTEX_SHADER or GL_FRAGMENT_SHADER(or maybe GL_COMPUTE_SHADER)
  99. GLuint& shader,
  100. const char* shaderSourceFilename)
  101. {
  102. GLint val = 0;
  103. // free old shader/program
  104. if (shader != 0) glDeleteShader(shader);
  105. static GLchar srcbuf[16384];
  106. FILE *fp = fopen(shaderSourceFilename, "rb");
  107. if (!fp) {
  108. fprintf(stderr, "failed to load shader: %s\n", shaderSourceFilename);
  109. return false;
  110. }
  111. fseek(fp, 0, SEEK_END);
  112. size_t len = ftell(fp);
  113. rewind(fp);
  114. len = fread(srcbuf, 1, len, fp);
  115. srcbuf[len] = 0;
  116. fclose(fp);
  117. static const GLchar *src = srcbuf;
  118. shader = glCreateShader(shaderType);
  119. glShaderSource(shader, 1, &src, NULL);
  120. glCompileShader(shader);
  121. glGetShaderiv(shader, GL_COMPILE_STATUS, &val);
  122. if (val != GL_TRUE) {
  123. char log[4096];
  124. GLsizei msglen;
  125. glGetShaderInfoLog(shader, 4096, &msglen, log);
  126. printf("%s\n", log);
  127. assert(val == GL_TRUE && "failed to compile shader");
  128. }
  129. printf("Load shader [ %s ] OK\n", shaderSourceFilename);
  130. return true;
  131. }
  132. bool
  133. LinkShader(
  134. GLuint& prog,
  135. GLuint& vertShader,
  136. GLuint& fragShader)
  137. {
  138. GLint val = 0;
  139. if (prog != 0) {
  140. glDeleteProgram(prog);
  141. }
  142. prog = glCreateProgram();
  143. glAttachShader(prog, vertShader);
  144. glAttachShader(prog, fragShader);
  145. glLinkProgram(prog);
  146. glGetProgramiv(prog, GL_LINK_STATUS, &val);
  147. assert(val == GL_TRUE && "failed to link shader");
  148. printf("Link shader OK\n");
  149. return true;
  150. }
  151. void
  152. Render(GLuint prog_id, int w, int h)
  153. {
  154. glDisable(GL_DEPTH_TEST);
  155. glUseProgram(prog_id);
  156. glActiveTexture(GL_TEXTURE0);
  157. glBindTexture(GL_TEXTURE_2D, gTexId);
  158. glEnable(GL_TEXTURE_2D);
  159. GLint texLoc = glGetUniformLocation(prog_id, "tex");
  160. assert(texLoc >= 0);
  161. glUniform1i(texLoc, 0); // TEXTURE0
  162. GLint intensityScaleLoc = glGetUniformLocation(prog_id, "intensity_scale");
  163. if (intensityScaleLoc >= 0) {
  164. glUniform1f(intensityScaleLoc, gIntensityScale);
  165. }
  166. GLint gammaLoc = glGetUniformLocation(prog_id, "gamma");
  167. if (gammaLoc >= 0) {
  168. glUniform1f(gammaLoc, gGamma);
  169. }
  170. GLint pos_id = glGetAttribLocation(prog_id, "in_position");
  171. assert(pos_id >= 0);
  172. GLint texcoord_id = glGetAttribLocation(prog_id, "in_texcoord");
  173. assert(texcoord_id >= 0);
  174. const float vertices[] = {-1, -1, -1, 1, 1, 1, 1, -1};
  175. const float texcoords[] = {0, 1, 0, 0, 1, 0, 1, 1};
  176. glVertexAttribPointer(pos_id, 2, GL_FLOAT, GL_FALSE, 0, (const void*)(vertices));
  177. glVertexAttribPointer(texcoord_id, 2, GL_FLOAT, GL_FALSE, 0, (const void*)(texcoords));
  178. glEnableVertexAttribArray(pos_id);
  179. glEnableVertexAttribArray(texcoord_id);
  180. glDrawArrays(GL_QUADS, 0, 4);
  181. glDisableVertexAttribArray(pos_id);
  182. glDisableVertexAttribArray(texcoord_id);
  183. checkErrors("render");
  184. glUseProgram(0);
  185. checkErrors("UseProgram(0)");
  186. glEnable(GL_DEPTH_TEST);
  187. glDisable(GL_TEXTURE_2D);
  188. }
  189. void InspectPixel(float rgba[4], int x, int y) {
  190. if (x < 0) x = 0;
  191. if (x > (gExrWidth-1)) x = gExrWidth - 1;
  192. if (y < 0) y = 0;
  193. if (y > (gExrHeight-1)) y = gExrHeight - 1;
  194. rgba[0] = gExrRGBA[4 * (y * gExrWidth + x) + 0];
  195. rgba[1] = gExrRGBA[4 * (y * gExrWidth + x) + 1];
  196. rgba[2] = gExrRGBA[4 * (y * gExrWidth + x) + 2];
  197. rgba[3] = gExrRGBA[4 * (y * gExrWidth + x) + 3];
  198. }
  199. int main(int argc, char** argv) {
  200. const char *filename = NULL;
  201. const char *layername = NULL;
  202. #ifdef USE_NATIVEFILEDIALOG
  203. if (argc < 2) {
  204. nfdchar_t *outPath = NULL;
  205. nfdresult_t result = NFD_OpenDialog( "exr", NULL, &outPath );
  206. if ( result == NFD_OKAY )
  207. {
  208. puts("Success!");
  209. filename = strdup(outPath);
  210. }
  211. else if ( result == NFD_CANCEL )
  212. {
  213. puts("User pressed cancel.");
  214. exit(-1);
  215. }
  216. else
  217. {
  218. printf("Error: %s\n", NFD_GetError() );
  219. exit(-1);
  220. }
  221. } else {
  222. filename = argv[1];
  223. if (argc > 2) {
  224. layername = argv[2];
  225. }
  226. }
  227. #else
  228. if (argc < 2) {
  229. printf("Usage: exrview input.exr [layer name]\n");
  230. exit(-1);
  231. }
  232. filename = argv[1];
  233. if (argc > 2) {
  234. layername = argv[2];
  235. }
  236. #endif
  237. {
  238. bool ret = exrio::GetEXRLayers(filename);
  239. if (!ret) {
  240. exit(-1);
  241. }
  242. }
  243. {
  244. bool ret = exrio::LoadEXRRGBA(&gExrRGBA, &gExrWidth, &gExrHeight, filename, layername);
  245. if (!ret) {
  246. exit(-1);
  247. }
  248. }
  249. window = new b3gDefaultOpenGLWindow;
  250. b3gWindowConstructionInfo ci;
  251. #ifdef USE_OPENGL2
  252. ci.m_openglVersion = 2;
  253. #endif
  254. ci.m_width = gExrWidth;
  255. ci.m_height = gExrHeight;
  256. window->createWindow(ci);
  257. char title[1024];
  258. sprintf(title, "%s (%d x %d)", filename, gExrWidth, gExrHeight);
  259. window->setWindowTitle(title);
  260. #ifndef __APPLE__
  261. #ifndef _WIN32
  262. //some Linux implementations need the 'glewExperimental' to be true
  263. glewExperimental = GL_TRUE;
  264. #endif
  265. if (glewInit() != GLEW_OK) {
  266. fprintf(stderr, "Failed to initialize GLEW\n");
  267. exit(-1);
  268. }
  269. if (!GLEW_VERSION_2_1) {
  270. fprintf(stderr, "OpenGL 2.1 is not available\n");
  271. exit(-1);
  272. }
  273. #endif
  274. checkErrors("init");
  275. window->setMouseButtonCallback(mouseButtonCallback);
  276. window->setMouseMoveCallback(mouseMoveCallback);
  277. checkErrors("mouse");
  278. window->setKeyboardCallback(keyboardCallback);
  279. checkErrors("keyboard");
  280. window->setResizeCallback(resizeCallback);
  281. checkErrors("resize");
  282. struct nk_color background;
  283. background = nk_rgb(28,48,62);
  284. {
  285. // Upload EXR image to OpenGL texture.
  286. gTexId = GenTexture(gExrWidth, gExrHeight, gExrRGBA);
  287. if (gTexId == 0) {
  288. fprintf(stderr, "OpenGL texture error\n");
  289. exit(-1);
  290. }
  291. }
  292. /* GUI */
  293. ctx = nk_btgui_init(window, NK_BTGUI3_DEFAULT);
  294. /* Load Fonts: if none of these are loaded a default font will be used */
  295. {
  296. struct nk_font_atlas* atlas;
  297. nk_btgui_font_stash_begin(&atlas);
  298. /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas,
  299. * "../../../extra_font/DroidSans.ttf", 14, 0);*/
  300. /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas,
  301. * "../../../extra_font/Roboto-Regular.ttf", 14, 0);*/
  302. /*struct nk_font *future = nk_font_atlas_add_from_file(atlas,
  303. * "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
  304. /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas,
  305. * "../../../extra_font/ProggyClean.ttf", 12, 0);*/
  306. /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas,
  307. * "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
  308. /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas,
  309. * "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
  310. struct nk_font *droid = nk_font_atlas_add_from_file(atlas,
  311. "./DroidSans.ttf", 14, 0);
  312. nk_btgui_font_stash_end();
  313. if (droid) {
  314. nk_style_set_font(ctx, &droid->handle);
  315. }
  316. // Color
  317. struct nk_color table[NK_COLOR_COUNT];
  318. table[NK_COLOR_TEXT] = nk_rgba(210, 210, 210, 255);
  319. table[NK_COLOR_WINDOW] = nk_rgba(57, 67, 71, 245);
  320. table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 230);
  321. table[NK_COLOR_BORDER] = nk_rgba(46, 46, 46, 255);
  322. table[NK_COLOR_BUTTON] = nk_rgba(48, 48, 48, 255);
  323. table[NK_COLOR_BUTTON_HOVER] = nk_rgba(58, 93, 121, 255);
  324. table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(63, 98, 126, 255);
  325. table[NK_COLOR_TOGGLE] = nk_rgba(50, 58, 61, 255);
  326. table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 53, 56, 255);
  327. table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(48, 83, 111, 255);
  328. table[NK_COLOR_SELECT] = nk_rgba(57, 67, 61, 255);
  329. table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(48, 83, 111, 255);
  330. table[NK_COLOR_SLIDER] = nk_rgba(50, 58, 61, 255);
  331. table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(48, 83, 111, 245);
  332. table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255);
  333. table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255);
  334. table[NK_COLOR_PROPERTY] = nk_rgba(50, 58, 61, 255);
  335. table[NK_COLOR_EDIT] = nk_rgba(50, 58, 61, 225);
  336. table[NK_COLOR_EDIT_CURSOR] = nk_rgba(210, 210, 210, 255);
  337. table[NK_COLOR_COMBO] = nk_rgba(50, 58, 61, 255);
  338. table[NK_COLOR_CHART] = nk_rgba(50, 58, 61, 255);
  339. table[NK_COLOR_CHART_COLOR] = nk_rgba(48, 83, 111, 255);
  340. table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255);
  341. table[NK_COLOR_SCROLLBAR] = nk_rgba(50, 58, 61, 255);
  342. table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(48, 83, 111, 255);
  343. table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255);
  344. table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255);
  345. table[NK_COLOR_TAB_HEADER] = nk_rgba(48, 83, 111, 255);
  346. nk_style_from_table(ctx, table);
  347. }
  348. checkErrors("start");
  349. GLuint vert_id = 0, frag_id = 0, prog_id = 0;
  350. {
  351. bool ret = LoadShader(GL_VERTEX_SHADER, vert_id, "shader.vert");
  352. if (!ret) {
  353. fprintf(stderr, "Failed to compile vertex shader.\n");
  354. exit(-1);
  355. }
  356. }
  357. checkErrors("vertex shader load");
  358. {
  359. bool ret = LoadShader(GL_FRAGMENT_SHADER, frag_id, "shader.frag");
  360. if (!ret) {
  361. fprintf(stderr, "Failed to compile fragment shader.\n");
  362. exit(-1);
  363. }
  364. }
  365. checkErrors("fragment shader load");
  366. {
  367. bool ret = LinkShader(prog_id, vert_id, frag_id);
  368. if (!ret) {
  369. fprintf(stderr, "Failed to link shader.\n");
  370. exit(-1);
  371. }
  372. }
  373. checkErrors("link shader");
  374. while (!window->requestedExit()) {
  375. window->startRendering();
  376. glClear(GL_COLOR_BUFFER_BIT);
  377. checkErrors("begin frame");
  378. nk_btgui_new_frame();
  379. float pixel[4];
  380. InspectPixel(pixel, gMousePosX, gMousePosY);
  381. /* GUI */
  382. {
  383. //struct nk_panel layout;
  384. if (nk_begin(ctx, "UI", nk_rect(50, 50, 350, 250),
  385. NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE |
  386. NK_WINDOW_MINIMIZABLE | NK_WINDOW_TITLE)) {
  387. nk_layout_row_static(ctx, 30, 300, 1);
  388. //if (nk_button_label(ctx, "button", NK_BUTTON_DEFAULT))
  389. // fprintf(stdout, "button pressed\n");
  390. nk_label(ctx, "Intensity", NK_TEXT_LEFT);
  391. if (nk_slider_float(ctx, 0, &gIntensityScale, 10.0, 0.1f)) {
  392. fprintf(stdout, "Intensity: %f\n", gIntensityScale);
  393. }
  394. nk_label(ctx, "Display gamma", NK_TEXT_LEFT);
  395. if (nk_slider_float(ctx, 0, &gGamma, 10.0, 0.01f)) {
  396. fprintf(stdout, "Gamma: %f\n", gGamma);
  397. }
  398. nk_label(ctx, "RAW pixel value", NK_TEXT_LEFT);
  399. char txt[1024];
  400. sprintf(txt, "(%d, %d) = %f, %f, %f, %f", gMousePosX, gMousePosY, pixel[0], pixel[1], pixel[2], pixel[3]);
  401. nk_text(ctx, txt, strlen(txt), NK_TEXT_LEFT);
  402. #if 0
  403. nk_layout_row_dynamic(ctx, 25, 1);
  404. nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);
  405. {
  406. struct nk_panel combo;
  407. nk_layout_row_dynamic(ctx, 20, 1);
  408. nk_label(ctx, "background:", NK_TEXT_LEFT);
  409. nk_layout_row_dynamic(ctx, 25, 1);
  410. if (nk_combo_begin_color(ctx, &combo, background, 400)) {
  411. nk_layout_row_dynamic(ctx, 120, 1);
  412. background = nk_color_picker(ctx, background, NK_RGBA);
  413. nk_layout_row_dynamic(ctx, 25, 1);
  414. background.r =
  415. (nk_byte)nk_propertyi(ctx, "#R:", 0, background.r, 255, 1, 1);
  416. background.g =
  417. (nk_byte)nk_propertyi(ctx, "#G:", 0, background.g, 255, 1, 1);
  418. background.b =
  419. (nk_byte)nk_propertyi(ctx, "#B:", 0, background.b, 255, 1, 1);
  420. background.a =
  421. (nk_byte)nk_propertyi(ctx, "#A:", 0, background.a, 255, 1, 1);
  422. nk_combo_end(ctx);
  423. }
  424. }
  425. #endif
  426. }
  427. nk_end(ctx);
  428. }
  429. /* Draw */
  430. {
  431. float bg[4];
  432. nk_color_fv(bg, background);
  433. glViewport(0, 0, window->getWidth(), window->getHeight());
  434. glClear(GL_COLOR_BUFFER_BIT);
  435. glClearColor(bg[0], bg[1], bg[2], bg[3]);
  436. Render(prog_id, window->getWidth(), window->getHeight());
  437. /* IMPORTANT: `nk_glfw_render` modifies some global OpenGL state
  438. * with blending, scissor, face culling and depth test and defaults
  439. * everything
  440. * back into a default state. Make sure to either save and restore or
  441. * reset your own state after drawing rendering the UI. */
  442. nk_btgui_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER,
  443. MAX_ELEMENT_BUFFER);
  444. }
  445. window->endRendering();
  446. }
  447. nk_btgui_shutdown();
  448. delete window;
  449. return EXIT_SUCCESS;
  450. }