Home My Page Projects Code Snippets Project Openings diderot
Summary Activity Tracker Tasks SCM

SCM Repository

[diderot] Annotation of /examples/vr-demo/main.c
ViewVC logotype

Annotation of /examples/vr-demo/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5452 - (view) (download) (as text)

1 : jhr 2058 /*! \file main.c
2 :     *
3 :     * \author John Reppy
4 :     *
5 :     * Main program for Diderot VR viewer.
6 :     */
7 :    
8 :     /*
9 : jhr 3349 * This code is part of the Diderot Project (http://diderot-language.cs.uchicago.edu)
10 :     *
11 : jhr 5452 * COPYRIGHT (c) 2017 The University of Chicago
12 : jhr 2058 * All rights reserved.
13 :     */
14 :    
15 : jhr 3213 #define GL_GLEXT_PROTOTYPES
16 :     #define GLFW_INCLUDE_GLCOREARB
17 :     #include <GLFW/glfw3.h>
18 :     #if defined(__APPLE_CC__)
19 :     #include <OpenGL/glext.h>
20 :     #else
21 :     # include <GL/glext.h>
22 :     #endif
23 :    
24 : jhr 2058 #include "util.h"
25 : jhr 2063 #include "vr.h"
26 : jhr 2058 #include <unistd.h>
27 : jhr 2079 #include "teem/air.h"
28 : jhr 2058
29 : jhr 2061 /* minimum and maximum values from */
30 :     #define MIN_VALUE 0
31 :     #define MAX_VALUE 2632
32 :    
33 :     /* half the width of the opacity range */
34 :     #define OPAC_HALF_WID 150
35 :    
36 :     #define MIN_OPAC_MID ((float)(MIN_VALUE+OPAC_HALF_WID))
37 :     #define MAX_OPAC_MID ((float)(MAX_VALUE-OPAC_HALF_WID))
38 :    
39 : jhr 2079 #define OPAC_DELTA 25
40 : jhr 2067
41 : jhr 2079 /* reduced-size inputs */
42 :     #define REDUCED_WID 256
43 :     #define REDUCED_HT 184
44 :     #define REDUCED_STEP 1
45 : jhr 2058
46 :    
47 : jhr 2079 /* full-size inputs */
48 :     #define FULL_WID 512
49 :     #define FULL_HT 368
50 :     #define FULL_STEP 0.5
51 :    
52 :     #define WIDTH (2*FULL_WID)
53 :     #define HEIGHT (2*FULL_HT)
54 :    
55 : jhr 3214 void ReportError (GLenum err, const char *file, int line, const char *msg)
56 : jhr 2058 {
57 : jhr 3214 const char *error;
58 :    
59 :     switch (err) {
60 :     case GL_INVALID_ENUM: error = "invalid enum"; break;
61 :     case GL_INVALID_VALUE: error = "invalid value"; break;
62 :     case GL_INVALID_OPERATION: error = "invalid operation"; break;
63 :     case GL_INVALID_FRAMEBUFFER_OPERATION: error = "invalid framebuffer operation"; break;
64 :     case GL_OUT_OF_MEMORY: error = "out of memory"; break;
65 :     default: error = "unknown"; break;
66 :     }
67 :    
68 :     fprintf (stderr, "[%s:%d] %s; %s\n", file, line, error, msg);
69 :    
70 :     exit (1);
71 :     }
72 :    
73 :     static inline void CheckError (const char *file, int line, const char *msg)
74 :     {
75 : jhr 2058 GLenum errCode;
76 :     if ((errCode = glGetError()) != GL_NO_ERROR) {
77 : jhr 3214 ReportError (errCode, file, line, msg);
78 : jhr 2058 }
79 :     }
80 :    
81 : jhr 3214 #define CHECK(cmd) \
82 :     do { \
83 :     cmd; \
84 :     CheckError (__FILE__, __LINE__, "executing " #cmd); \
85 :     } while (0)
86 :    
87 : jhr 2058 /***** Globals for viewing, etc. *****/
88 :    
89 : jhr 2079 typedef struct {
90 :     bool init;
91 :     GLuint wid;
92 :     GLuint ht;
93 :     GLuint id;
94 :     } TexInfo_t;
95 :    
96 : jhr 5452 VR_world_t *World;
97 : jhr 2058 unsigned int Width; // view window width
98 :     unsigned int Height; // view window height
99 : jhr 2079 TexInfo_t ReducedTexure = { // Texture ID of reduced image
100 :     false, REDUCED_WID, REDUCED_HT, 0
101 :     };
102 :     TexInfo_t FullTexture = { // Texture ID of full image
103 :     false, FULL_WID, FULL_HT, 0
104 :     };
105 : jhr 3213 struct {
106 :     GLuint vaoId;
107 :     GLuint coordId;
108 :     GLuint ebufId;
109 :     } QuadMesh;
110 : jhr 2063 bool NeedsRedraw;
111 :     bool NeedsRecompute;
112 : jhr 2067 float OpacMid = 550.0;
113 : jhr 2079 int Dir = 0; /* -1, 0, 1 */
114 : jhr 2058
115 :    
116 : jhr 2079 // initialize a texture from a grayscale Nrrd file
117 :     void InitTexture (TexInfo_t *txt, Nrrd *img)
118 :     {
119 :     if (! txt->init) {
120 :     // generate the TeXID
121 : jhr 3214 CHECK( glGenTextures (1, &(txt->id)) );
122 : jhr 2079
123 :     // load the texture data
124 : jhr 3214 CHECK( glBindTexture (GL_TEXTURE_2D, txt->id) );
125 :     CHECK( glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, txt->wid, txt->ht, 0, GL_RGBA, GL_FLOAT, img->data) );
126 :     CHECK( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) );
127 :     CHECK( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) );
128 : jhr 2079 }
129 :     else {
130 :     // reload the texture data
131 : jhr 3214 CHECK( glBindTexture (GL_TEXTURE_2D, txt->id) );
132 :     CHECK( glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, txt->wid, txt->ht, GL_RGBA, GL_FLOAT, img->data) );
133 : jhr 2079 }
134 :     }
135 :    
136 : jhr 3213 #define COORD_ATTR 0
137 :    
138 :     // vertex shader
139 :     static const char *VertexShaderSrc = "\
140 :     #version 410\n\
141 :     uniform mat4 modelView;\n\
142 :     uniform mat4 projection;\n\
143 :     layout (location = 0) in vec2 coord;\n\
144 : jhr 3214 smooth out vec2 texCoord;\n\
145 : jhr 3213 \n\
146 :     void main ()\n\
147 :     {\n\
148 :     gl_Position = projection * modelView * vec4(coord, 0, 1);\n\
149 :     texCoord = coord;\n\
150 :     }\n\
151 :     ";
152 :    
153 :     // fragment shader
154 :     static const char *FragShaderSrc = "\
155 :     #version 410\n\
156 :     uniform sampler2D image;\n\
157 : jhr 3214 smooth in vec2 texCoord;\n\
158 : jhr 3213 layout (location = 0) out vec4 fragColor;\n\
159 :     void main ()\n\
160 :     {\n\
161 :     fragColor = vec4(texture(image, texCoord).rgb, 1);\n\
162 :     }\n\
163 :     ";
164 :    
165 : jhr 3214 static void CheckCompileStatus (const char *shader, GLuint id)
166 :     {
167 :     GLint sts;
168 :    
169 :     glGetShaderiv (id, GL_COMPILE_STATUS, &sts);
170 :     if (sts != GL_TRUE) {
171 :     /* the compile failed, so report an error */
172 :     glGetShaderiv (id, GL_INFO_LOG_LENGTH, &sts);
173 :     if (sts != 0) {
174 :     GLchar *log = (GLchar *) malloc(sts);
175 :     glGetShaderInfoLog (id, sts, 0, log);
176 :     fprintf (stderr, "Error compiling %s shader:\n%s\n", shader, log);
177 :     free (log);
178 :     }
179 :     else {
180 :     fprintf (stderr, "Error compiling %s shader:\n no log\n", shader);
181 :     }
182 :     exit (1);
183 :     }
184 :     }
185 :    
186 : jhr 3213 // Initialize the rendering context
187 :     //
188 :     static void InitGraphics ()
189 :     {
190 :     float coords[4 * 2] = {
191 :     0.0f, 0.0f,
192 :     1.0f, 0.0f,
193 :     1.0f, 1.0f,
194 :     0.0f, 1.0f,
195 :     };
196 :     unsigned short indices[4] = {0, 1, 2, 3};
197 :    
198 :     // initialize the shader program
199 :     GLuint vsh = glCreateShader (GL_VERTEX_SHADER);
200 :     glShaderSource (vsh, 1, &VertexShaderSrc, 0);
201 :     glCompileShader (vsh);
202 : jhr 3214 CheckCompileStatus ("vertex", vsh);
203 : jhr 3213
204 :     GLuint fsh = glCreateShader (GL_FRAGMENT_SHADER);
205 :     glShaderSource (fsh, 1, &FragShaderSrc, 0);
206 :     glCompileShader (fsh);
207 : jhr 3214 CheckCompileStatus ("fragment", fsh);
208 : jhr 3213
209 :     GLuint shaderProg = glCreateProgram ();
210 : jhr 3214 CHECK( glAttachShader (shaderProg, vsh) );
211 :     CHECK( glAttachShader (shaderProg, fsh) );
212 :     CHECK( glLinkProgram (shaderProg) );
213 : jhr 3213
214 : jhr 3214 CHECK( glUseProgram (shaderProg) );
215 : jhr 3213
216 :     // initialize the VBO
217 :     GLuint vaoId, buffers[2];
218 : jhr 3214 CHECK( glGenVertexArrays (1, &vaoId) );
219 :     CHECK( glGenBuffers (2, buffers) );
220 :     CHECK( glBindVertexArray (vaoId) );
221 : jhr 3213
222 : jhr 3214 CHECK( glBindBuffer (GL_ARRAY_BUFFER, buffers[0]) );
223 :     CHECK( glBufferData (GL_ARRAY_BUFFER, sizeof(coords), coords, GL_STATIC_DRAW) );
224 :     CHECK( glVertexAttribPointer (COORD_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0) );
225 :     CHECK( glEnableVertexAttribArray (COORD_ATTR) );
226 : jhr 3213
227 : jhr 3214 CHECK( glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffers[1]) );
228 :     CHECK( glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW) );
229 : jhr 3213
230 :     QuadMesh.vaoId = vaoId;
231 :     QuadMesh.coordId = buffers[0];
232 :     QuadMesh.ebufId = buffers[1];
233 :    
234 :     // initialize the transformation matrices
235 :     float projMat[16] = { // gluOrtho2D (0.0, 1.0, 0.0, 1.0);
236 :     2, 0, 0, 0,
237 :     0, 2, 0, 0,
238 :     0, 0, -2, 0,
239 :     -1, -1, 0, 1,
240 :     };
241 :     float modelViewMat[16] = { // gluLookAt (0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
242 :     1, 0, 0, 0,
243 :     0, 1, 0, 0,
244 :     0, 0, -1, 0,
245 :     0, 0, 0, 1,
246 :     };
247 :     glUniformMatrix4fv (glGetUniformLocation (shaderProg, "projection"), 1, GL_FALSE, projMat);
248 :     glUniformMatrix4fv (glGetUniformLocation (shaderProg, "modelView"), 1, GL_FALSE, modelViewMat);
249 :    
250 :     // initialize texture binding
251 :     glUniform1i (glGetUniformLocation (shaderProg, "image"), 0); // texture unit 0
252 :     }
253 :    
254 : jhr 2058 // Callback function called by GLUT to render screen
255 : jhr 2079 void Draw (GLuint txtId)
256 : jhr 2058 {
257 :     // Clear frame buffer
258 :     glClearColor (0, 0, 0, 1);
259 :     glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
260 :    
261 :     glDisable(GL_DEPTH_TEST);
262 :     glDisable(GL_CULL_FACE);
263 :    
264 :     // Draw image
265 : jhr 2079 glActiveTexture (GL_TEXTURE0);
266 :     glBindTexture (GL_TEXTURE_2D, txtId);
267 : jhr 3214
268 : jhr 3213 glBindVertexArray (QuadMesh.vaoId);
269 :     glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, QuadMesh.ebufId);
270 :     glDrawElements (GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, 0);
271 : jhr 2058
272 :     }
273 :    
274 :     // Callback function called by GLFW when window size changes
275 : jhr 3213 void WindowSizeCB (GLFWwindow *win, int width, int height)
276 : jhr 2058 {
277 :     // Set OpenGL viewport and camera
278 :     glViewport(0, 0, width, height);
279 :    
280 :     // remember width and height
281 :     Width = width;
282 :     Height = height;
283 :    
284 : jhr 2080 NeedsRedraw = true;
285 : jhr 2058 }
286 :    
287 : jhr 3213 void KeyCB (GLFWwindow *win, int key, int scancode, int action, int mods)
288 : jhr 2067 {
289 : jhr 2079 switch (key) {
290 : jhr 3213 case GLFW_KEY_ESCAPE:
291 :     glfwSetWindowShouldClose (win, GL_TRUE);
292 :     break;
293 :     case GLFW_KEY_EQUAL: // with shift is '+'
294 :     if ((mods == GLFW_MOD_SHIFT) && (action == GLFW_PRESS) && (Dir >= 0)) {
295 : jhr 2079 Dir++;
296 : jhr 3213 }
297 : jhr 2079 break;
298 : jhr 3213 case GLFW_KEY_KP_ADD:
299 :     if ((mods == 0) && (action == GLFW_PRESS) && (Dir >= 0))
300 :     Dir++;
301 :     break;
302 :     case GLFW_KEY_MINUS:
303 :     case GLFW_KEY_KP_SUBTRACT:
304 :     if ((mods == 0) && (action == GLFW_PRESS) && (Dir <= 0))
305 : jhr 2079 Dir--;
306 :     break;
307 :     default:
308 :     break;
309 : jhr 2067 }
310 :     }
311 :    
312 : jhr 5452 void Compute (VR_world_t *wrld, bool fullSize, Nrrd *nRGB)
313 : jhr 2058 {
314 : jhr 3214 printf ("computing %s... ", fullSize ? "" : "(fast) "); fflush(stdout);
315 : jhr 2079 double t0 = airTime();
316 :     // setup raycast parameters
317 :     if (fullSize) {
318 : jhr 5452 VR_input_set_imgResU (wrld, FULL_WID);
319 :     VR_input_set_imgResV (wrld, FULL_HT);
320 :     VR_input_set_rayStep (wrld, FULL_STEP);
321 : jhr 2079 }
322 :     else {
323 : jhr 5452 VR_input_set_imgResU (wrld, REDUCED_WID);
324 :     VR_input_set_imgResV (wrld, REDUCED_HT);
325 :     VR_input_set_rayStep (wrld, REDUCED_STEP);
326 : jhr 2079 }
327 :     // recompute
328 : jhr 5452 if (VR_create_strands (wrld)) {
329 : jhr 2079 // error
330 : jhr 5452 fprintf(stderr, "Error initializing world: %s", VR_get_errors(wrld));
331 : jhr 2079 exit(1);
332 :     }
333 : jhr 5452 int nSteps = VR_run (wrld, 0);
334 : jhr 2079 printf(" %d steps in %5.3f seconds\n", nSteps, airTime() - t0);
335 :     // get output image
336 : jhr 5452 if (VR_output_get_outRGBA (wrld, nRGB)) {
337 : jhr 2058 // error
338 : jhr 5452 fprintf(stderr, "Error getting nrrd data: %s", VR_get_errors(wrld));
339 : jhr 2063 exit(1);
340 : jhr 2058 }
341 :     }
342 :    
343 : jhr 3213 static void Error (int err, const char *msg)
344 :     {
345 :     fprintf(stderr, "[GLFW ERROR %d] %s\n", err, msg);
346 :     }
347 :    
348 : jhr 2058 int main (int argc, const char **argv)
349 :     {
350 : jhr 3213 glfwSetErrorCallback (Error);
351 :    
352 : jhr 2058 // Initialize GLFW
353 :     if (0 == glfwInit()) {
354 :     // An error occured
355 :     fprintf(stderr, "GLFW initialization failed\n");
356 :     return 1;
357 :     }
358 :    
359 : jhr 3213 glfwWindowHint (GLFW_RESIZABLE, GL_TRUE);
360 :     glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 4);
361 :     glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 1);
362 :     glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
363 :     glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
364 :     GLFWwindow *win = glfwCreateWindow(WIDTH, HEIGHT, "Diderot VR Demo", NULL, NULL);
365 :     if (win== 0) {
366 : jhr 5452 // A fatal error occured
367 : jhr 2058 fprintf(stderr, "Cannot open GLFW window\n");
368 :     glfwTerminate();
369 :     return 1;
370 :     }
371 : jhr 3213 glfwMakeContextCurrent (win);
372 : jhr 2058
373 : jhr 3213 InitGraphics ();
374 :    
375 : jhr 2058 // Set GLFW event callbacks
376 : jhr 3213 glfwSetWindowSizeCallback (win, WindowSizeCB);
377 :     glfwSetKeyCallback (win, KeyCB);
378 : jhr 2058
379 :     // initialize the Diderot program
380 : jhr 5452 VR_world_t *wrld = VR_new_world ();
381 : jhr 3213 if (wrld == 0) {
382 :     fprintf(stderr, "Cannot create world\n");
383 :     glfwTerminate();
384 :     return 1;
385 :     }
386 : jhr 2067 World = wrld;
387 : jhr 5452 VR_init_world (wrld);
388 : jhr 2058
389 : jhr 2067 // initialize inputs
390 : jhr 5452 VR_input_set_valOpacMid (wrld, OpacMid);
391 :     VR_input_set_by_name_hand (wrld, "data/vfrhand-nohip.nhdr");
392 : jhr 2067
393 : jhr 2058 // nrrd for getting computational state
394 : jhr 2061 Nrrd *nRGB = nrrdNew();
395 : jhr 2058
396 :     // Main loop (repeated while window is not closed and [ESC] is not pressed)
397 : jhr 2062 NeedsRecompute = true;
398 : jhr 2079 GLuint txtId;
399 : jhr 3213 while (! glfwWindowShouldClose(win)) {
400 : jhr 2079 if (Dir < 0) {
401 :     Dir++;
402 :     float mid = OpacMid - OPAC_DELTA;
403 :     if (mid >= MIN_OPAC_MID) {
404 :     OpacMid = mid;
405 : jhr 5452 VR_input_set_valOpacMid(World, mid);
406 : jhr 2079 NeedsRecompute = true;
407 :     }
408 :     }
409 :     else if (Dir > 0) {
410 :     Dir--;
411 :     float mid = OpacMid + OPAC_DELTA;
412 :     if (mid <= MAX_OPAC_MID) {
413 :     OpacMid = mid;
414 : jhr 5452 VR_input_set_valOpacMid(World, mid);
415 : jhr 2079 NeedsRecompute = true;
416 :     }
417 :     }
418 : jhr 2061 if (NeedsRecompute) {
419 : jhr 2079 if (Dir != 0) {
420 :     Compute(wrld, false, nRGB);
421 :     InitTexture(&ReducedTexure, nRGB);
422 :     txtId = ReducedTexure.id;
423 : jhr 2067 }
424 : jhr 2079 else {
425 :     Compute (wrld, true, nRGB);
426 :     InitTexture(&FullTexture, nRGB);
427 :     NeedsRecompute = false;
428 :     txtId = FullTexture.id;
429 :     }
430 : jhr 2063 NeedsRedraw = true;
431 : jhr 2061 }
432 :     if (NeedsRedraw) {
433 : jhr 2079 Draw (txtId);
434 : jhr 3213 // Present frame buffer
435 :     glfwSwapBuffers(win);
436 : jhr 2063 NeedsRedraw = false;
437 : jhr 2061 }
438 : jhr 2079 if (NeedsRecompute)
439 :     glfwPollEvents();
440 :     else
441 :     glfwWaitEvents();
442 : jhr 2058 }
443 :    
444 :     // shutdown the world
445 : jhr 5452 VR_shutdown (wrld);
446 : jhr 2058
447 : jhr 2063 // Terminate GLFW
448 : jhr 2058 glfwTerminate();
449 :    
450 :     return 0;
451 :     }

root@smlnj-gforge.cs.uchicago.edu
ViewVC Help
Powered by ViewVC 1.0.0