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

SCM Repository

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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5452 - (download) (as text) (annotate)
Mon Oct 23 15:42:55 2017 UTC (20 months, 4 weeks ago) by jhr
File size: 11662 byte(s)
working on porting vr-demo to vis15
/*! \file main.c
 *
 * \author John Reppy
 *
 * Main program for Diderot VR viewer.
 */

/*
 * This code is part of the Diderot Project (http://diderot-language.cs.uchicago.edu)
 *
 * COPYRIGHT (c) 2017 The University of Chicago
 * All rights reserved.
 */

#define GL_GLEXT_PROTOTYPES
#define GLFW_INCLUDE_GLCOREARB
#include <GLFW/glfw3.h>
#if defined(__APPLE_CC__)
  #include <OpenGL/glext.h>
#else
#  include <GL/glext.h>
#endif

#include "util.h"
#include "vr.h"
#include <unistd.h>
#include "teem/air.h"

/* minimum and maximum values from */
#define MIN_VALUE	0
#define MAX_VALUE	2632

/* half the width of the opacity range */
#define OPAC_HALF_WID	150

#define MIN_OPAC_MID	((float)(MIN_VALUE+OPAC_HALF_WID))
#define MAX_OPAC_MID	((float)(MAX_VALUE-OPAC_HALF_WID))

#define OPAC_DELTA	25

/* reduced-size inputs */
#define REDUCED_WID	256
#define REDUCED_HT	184
#define REDUCED_STEP	1


/* full-size inputs */
#define FULL_WID	512
#define FULL_HT		368
#define FULL_STEP	0.5

#define WIDTH   (2*FULL_WID)
#define HEIGHT  (2*FULL_HT)

void ReportError (GLenum err, const char *file, int line, const char *msg)
{
    const char *error;

    switch (err) {
      case GL_INVALID_ENUM: error = "invalid enum"; break;
      case GL_INVALID_VALUE: error = "invalid value"; break;
      case GL_INVALID_OPERATION: error = "invalid operation"; break;
      case GL_INVALID_FRAMEBUFFER_OPERATION: error = "invalid framebuffer operation"; break;
      case GL_OUT_OF_MEMORY: error = "out of memory"; break;
      default: error = "unknown"; break;
    }

    fprintf (stderr, "[%s:%d] %s; %s\n", file, line, error, msg);

    exit (1);
}

static inline void CheckError (const char *file, int line, const char *msg)
{
    GLenum errCode;
    if ((errCode = glGetError()) != GL_NO_ERROR) {
	ReportError (errCode, file, line, msg);
    }
}

#define CHECK(cmd)						\
	do {							\
	    cmd;						\
	    CheckError (__FILE__, __LINE__, "executing " #cmd);	\
	} while (0)

/***** Globals for viewing, etc. *****/

typedef struct {
    bool	init;
    GLuint	wid;
    GLuint	ht;
    GLuint	id;
} TexInfo_t;

VR_world_t	*World;
unsigned int    Width;          // view window width
unsigned int    Height;         // view window height
TexInfo_t	ReducedTexure = {	// Texture ID of reduced image
	false, REDUCED_WID, REDUCED_HT, 0
    };
TexInfo_t	FullTexture = {		// Texture ID of full image
	false, FULL_WID, FULL_HT, 0
    };
struct {
    GLuint	vaoId;
    GLuint	coordId;
    GLuint	ebufId;
}		QuadMesh;
bool		NeedsRedraw;
bool		NeedsRecompute;
float		OpacMid = 550.0;
int		Dir = 0;		/* -1, 0, 1 */


// initialize a texture from a grayscale Nrrd file
void InitTexture (TexInfo_t *txt, Nrrd *img)
{
    if (! txt->init) {
      // generate the TeXID
	CHECK( glGenTextures (1, &(txt->id)) );

      // load the texture data
	CHECK( glBindTexture (GL_TEXTURE_2D, txt->id) );
	CHECK( glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, txt->wid, txt->ht, 0, GL_RGBA, GL_FLOAT, img->data) );
	CHECK( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) );
	CHECK( glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) );
    }
    else {
      // reload the texture data
	CHECK( glBindTexture (GL_TEXTURE_2D, txt->id) );
	CHECK( glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, txt->wid, txt->ht, GL_RGBA, GL_FLOAT, img->data) );
    }
}

#define COORD_ATTR 0

// vertex shader
static const char *VertexShaderSrc = "\
#version 410\n\
uniform mat4 modelView;\n\
uniform mat4 projection;\n\
layout (location = 0) in vec2 coord;\n\
smooth out vec2 texCoord;\n\
\n\
void main ()\n\
{\n\
  gl_Position = projection * modelView * vec4(coord, 0, 1);\n\
  texCoord = coord;\n\
}\n\
";

// fragment shader
static const char *FragShaderSrc = "\
#version 410\n\
uniform sampler2D image;\n\
smooth in vec2	texCoord;\n\
layout (location = 0) out vec4 fragColor;\n\
void main ()\n\
{\n\
    fragColor = vec4(texture(image, texCoord).rgb, 1);\n\
}\n\
    ";

static void CheckCompileStatus (const char *shader, GLuint id)
{
    GLint sts;

    glGetShaderiv (id, GL_COMPILE_STATUS, &sts);
    if (sts != GL_TRUE) {
      /* the compile failed, so report an error */
	glGetShaderiv (id, GL_INFO_LOG_LENGTH, &sts);
	if (sts != 0) {
	    GLchar *log = (GLchar *) malloc(sts);
	    glGetShaderInfoLog (id, sts, 0, log);
	    fprintf (stderr, "Error compiling %s shader:\n%s\n", shader, log);
	    free (log);
	}
	else {
	    fprintf (stderr, "Error compiling %s shader:\n  no log\n", shader);
	}
	exit (1);
    }
}

// Initialize the rendering context
//
static void InitGraphics ()
{
    float coords[4 * 2] = {
	    0.0f, 0.0f,
	    1.0f, 0.0f,
	    1.0f, 1.0f,
	    0.0f, 1.0f,
	};
    unsigned short indices[4] = {0, 1, 2, 3};

  // initialize the shader program
    GLuint vsh = glCreateShader (GL_VERTEX_SHADER);
    glShaderSource (vsh, 1, &VertexShaderSrc, 0);
    glCompileShader (vsh);
    CheckCompileStatus ("vertex", vsh);

    GLuint fsh = glCreateShader (GL_FRAGMENT_SHADER);
    glShaderSource (fsh, 1, &FragShaderSrc, 0);
    glCompileShader (fsh);
    CheckCompileStatus ("fragment", fsh);

    GLuint shaderProg = glCreateProgram ();
    CHECK( glAttachShader (shaderProg, vsh) );
    CHECK( glAttachShader (shaderProg, fsh) );
    CHECK( glLinkProgram (shaderProg) );

    CHECK( glUseProgram (shaderProg) );

  // initialize the VBO
    GLuint vaoId, buffers[2];
    CHECK( glGenVertexArrays (1, &vaoId) );
    CHECK( glGenBuffers (2, buffers) );
    CHECK( glBindVertexArray (vaoId) );

    CHECK( glBindBuffer (GL_ARRAY_BUFFER, buffers[0]) );
    CHECK( glBufferData (GL_ARRAY_BUFFER, sizeof(coords), coords, GL_STATIC_DRAW) );
    CHECK( glVertexAttribPointer (COORD_ATTR, 2, GL_FLOAT, GL_FALSE, 0, 0) );
    CHECK( glEnableVertexAttribArray (COORD_ATTR) );

    CHECK( glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, buffers[1]) );
    CHECK( glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW) );

    QuadMesh.vaoId = vaoId;
    QuadMesh.coordId = buffers[0];
    QuadMesh.ebufId = buffers[1];

  // initialize the transformation matrices
    float projMat[16] = {  // gluOrtho2D (0.0, 1.0, 0.0, 1.0);
	     2,  0,  0,  0,
	     0,  2,  0,  0,
	     0,  0, -2,  0,
	    -1, -1,  0,  1,
	};
    float modelViewMat[16] = { // gluLookAt (0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	     1,  0,  0,  0,
	     0,  1,  0,  0,
	     0,  0, -1,  0,
	     0,  0,  0,  1,
	};
    glUniformMatrix4fv (glGetUniformLocation (shaderProg, "projection"), 1, GL_FALSE, projMat);
    glUniformMatrix4fv (glGetUniformLocation (shaderProg, "modelView"), 1, GL_FALSE, modelViewMat);

  // initialize texture binding
    glUniform1i (glGetUniformLocation (shaderProg, "image"), 0);  // texture unit 0
}

// Callback function called by GLUT to render screen
void Draw (GLuint txtId)
{
  // Clear frame buffer
    glClearColor (0, 0, 0, 1);
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glDisable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);

  // Draw image
    glActiveTexture (GL_TEXTURE0);
    glBindTexture (GL_TEXTURE_2D, txtId);

    glBindVertexArray (QuadMesh.vaoId);
    glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, QuadMesh.ebufId);
    glDrawElements (GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, 0);

}

// Callback function called by GLFW when window size changes
void WindowSizeCB (GLFWwindow *win, int width, int height)
{
  // Set OpenGL viewport and camera
    glViewport(0, 0, width, height);

  // remember width and height
    Width = width;
    Height = height;

    NeedsRedraw = true;
}

void KeyCB (GLFWwindow *win, int key, int scancode, int action, int mods)
{
    switch (key) {
      case GLFW_KEY_ESCAPE:
	glfwSetWindowShouldClose (win, GL_TRUE);
	break;
      case GLFW_KEY_EQUAL: // with shift is '+'
	if ((mods == GLFW_MOD_SHIFT) && (action == GLFW_PRESS) && (Dir >= 0)) {
	    Dir++;
	}
	break;
      case GLFW_KEY_KP_ADD:
	if ((mods == 0) && (action == GLFW_PRESS) && (Dir >= 0))
	    Dir++;
	break;
      case GLFW_KEY_MINUS:
      case GLFW_KEY_KP_SUBTRACT:
	if ((mods == 0) && (action == GLFW_PRESS) && (Dir <= 0))
	    Dir--;
	break;
      default:
	break;
    }
}

void Compute (VR_world_t *wrld, bool fullSize, Nrrd *nRGB)
{
    printf ("computing %s... ", fullSize ? "" : "(fast) "); fflush(stdout);
    double t0 = airTime();
  // setup raycast parameters
    if (fullSize) {
	VR_input_set_imgResU (wrld, FULL_WID);
	VR_input_set_imgResV (wrld, FULL_HT);
	VR_input_set_rayStep (wrld, FULL_STEP);
    }
    else {
	VR_input_set_imgResU (wrld, REDUCED_WID);
	VR_input_set_imgResV (wrld, REDUCED_HT);
	VR_input_set_rayStep (wrld, REDUCED_STEP);
    }
  // recompute
    if (VR_create_strands (wrld)) {
      // error
	fprintf(stderr, "Error initializing world: %s", VR_get_errors(wrld));
	exit(1);
    }
    int nSteps = VR_run (wrld, 0);
    printf(" %d steps in %5.3f seconds\n", nSteps, airTime() - t0);
  // get output image
    if (VR_output_get_outRGBA (wrld, nRGB)) {
      // error
	fprintf(stderr, "Error getting nrrd data: %s", VR_get_errors(wrld));
	exit(1);
    }
}

static void Error (int err, const char *msg)
{
    fprintf(stderr, "[GLFW ERROR  %d] %s\n", err, msg);
}

int main (int argc, const char **argv)
{
    glfwSetErrorCallback (Error);

  // Initialize GLFW
    if (0 == glfwInit()) {
      // An error occured
        fprintf(stderr, "GLFW initialization failed\n");
        return 1;
    }

    glfwWindowHint (GLFW_RESIZABLE, GL_TRUE);
    glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 1);
    glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
    GLFWwindow *win = glfwCreateWindow(WIDTH, HEIGHT, "Diderot VR Demo", NULL, NULL);
    if (win== 0) {
      // A fatal error occured
        fprintf(stderr, "Cannot open GLFW window\n");
        glfwTerminate();
        return 1;
    }
    glfwMakeContextCurrent (win);

    InitGraphics ();

  // Set GLFW event callbacks
    glfwSetWindowSizeCallback (win, WindowSizeCB);
    glfwSetKeyCallback (win, KeyCB);

  // initialize the Diderot program
    VR_world_t *wrld = VR_new_world ();
    if (wrld == 0) {
	fprintf(stderr, "Cannot create world\n");
        glfwTerminate();
	return 1;
    }
    World = wrld;
    VR_init_world (wrld);

  // initialize inputs
    VR_input_set_valOpacMid (wrld, OpacMid);
    VR_input_set_by_name_hand (wrld, "data/vfrhand-nohip.nhdr");

  // nrrd for getting computational state
    Nrrd *nRGB = nrrdNew();

  // Main loop (repeated while window is not closed and [ESC] is not pressed)
    NeedsRecompute = true;
    GLuint txtId;
    while (! glfwWindowShouldClose(win)) {
	if (Dir < 0) {
	    Dir++;
	    float mid = OpacMid - OPAC_DELTA;
	    if (mid >= MIN_OPAC_MID) {
		OpacMid = mid;
		VR_input_set_valOpacMid(World, mid);
		NeedsRecompute = true;
	    }
	}
	else if (Dir > 0) {
	    Dir--;
	    float mid = OpacMid + OPAC_DELTA;
	    if (mid <= MAX_OPAC_MID) {
		OpacMid = mid;
		VR_input_set_valOpacMid(World, mid);
		NeedsRecompute = true;
	    }
	}
	if (NeedsRecompute) {
	    if (Dir != 0) {
		Compute(wrld, false, nRGB);
		InitTexture(&ReducedTexure, nRGB);
		txtId = ReducedTexure.id;
	    }
 	    else {
 		Compute (wrld, true, nRGB);
 		InitTexture(&FullTexture, nRGB);
 		NeedsRecompute = false;
 		txtId = FullTexture.id;
 	    }
	    NeedsRedraw = true;
	}
	if (NeedsRedraw) {
	    Draw (txtId);
	  // Present frame buffer
	    glfwSwapBuffers(win);
	    NeedsRedraw = false;
	}
	if (NeedsRecompute)
	    glfwPollEvents();
	else
	    glfwWaitEvents();
    }

  // shutdown the world
    VR_shutdown (wrld);

  // Terminate GLFW
    glfwTerminate();

    return 0;
}

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