Skip to content
Snippets Groups Projects
particles_GL.cpp 13.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • //
    // particles_GL.cpp
    //    input particles, display GL
    //    (c) MIT CBA Neil Gershenfeld 6/25/20
    //
    // includes
    //
    #include <iostream>
    #include <cmath>
    #include <GL/glew.h>
    #include <GLFW/glfw3.h>
    
    Amira Abdel-Rahman (admin)'s avatar
    Amira Abdel-Rahman (admin) committed
    #include <cstring>
    
    using namespace std;
    //
    // defines
    //
    #define CPP (8*3*6) // render coordinates per particle
       // 8 triangles * 3 verts * (3 coords + 3 colors)
    #define VPP (8*3) // render vertices per particle
       // 8 triangles * 3 verts
    //
    // global variables
    //
    class vars {
       public:
          float rx = 0;//-0.25; // view rotation
          float ry = 0;//0.67;
          float rz = 0.0;
          float dr = 0.01;
          float tx = 0; // view translation
          float ty = 0;
          float tz = 0;
          float dt = 0.01;
          float sxyz = 0.9; // view scale
          int mx,my; // mouse position
          int mb = -1; // mouse state
          int np; // number of particles
          float xmin,xmax,ymin,ymax,zmin,zmax; // data limits
          float *px,*py,*pz; // particle positions
          float d; // particle pitch
          float size; // particle size
          float* data; // GL drawing buffer
          GLuint program; // GL program
          int width = 1000; // GL window width
          int height = 1000; // GL window height
       } v;
    //
    // GL class
    //
    class GL {
       public:
          //
          // variables
          //
          GLFWwindow* window;
          GLuint vertex;
          GLuint fragment;
          GLuint buffer;
          GLint location;
          //
          // keyboard callback (escape to quit)
          //
          static void keyboard(GLFWwindow* window,int key,int scancode,int action,int mods) {
             GLint location;
             if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
                glfwSetWindowShouldClose(window,GLFW_TRUE);
             else if (key == 'Q' && action == GLFW_PRESS)
                glfwSetWindowShouldClose(window,GLFW_TRUE);
             else if (key == '-' && action == GLFW_PRESS) {
                v.sxyz /= 1.1;
                location = glGetUniformLocation(v.program,"sxyz");
                glUniform1f(location,v.sxyz);
                }
             else if (key == '=' && action == GLFW_PRESS) {
                v.sxyz *= 1.1;
                location = glGetUniformLocation(v.program,"sxyz");
                glUniform1f(location,v.sxyz);
                }
             }
          //
          // scroll callback
          //
          static void scroll(GLFWwindow* window,double x,double y) {
             GLint location;
             if (y > 0) {
                v.sxyz /= 1.1;
                location = glGetUniformLocation(v.program,"sxyz");
                glUniform1f(location,v.sxyz);
                }
             else {
                v.sxyz *= 1.1;
                location = glGetUniformLocation(v.program,"sxyz");
                glUniform1f(location,v.sxyz);
                }
             }
          //
          // mouse cursor callback (left down to rotate)
          //
          static void cursor(GLFWwindow* window,double x,double y) {
             GLint location;
             if (v.mb == GLFW_MOUSE_BUTTON_LEFT) {
                if (v.mx < x)
                   v.ry -= v.dr;
                else if (v.mx > x)
                   v.ry += v.dr;
                v.mx = x;
                if (v.my < y)
                   v.rx -= v.dr;
                else if (v.my > y)
                   v.rx += v.dr;
                v.my = y;
                cerr << "   rotate " << 180*v.rx/M_PI << ' ' << 180*v.ry/M_PI << endl;
                location = glGetUniformLocation(v.program,"rx");
                glUniform1f(location,v.rx);
                location = glGetUniformLocation(v.program,"ry");
                glUniform1f(location,v.ry);
                }
             }
          //
          // mouse button callback
          //
          static void button(GLFWwindow* window,int button,int action,int mods) {
             double x,y;
             if ((button == GLFW_MOUSE_BUTTON_LEFT)
                   && (action == GLFW_PRESS)) {
                glfwGetCursorPos(window,&x,&y);
                v.mb = GLFW_MOUSE_BUTTON_LEFT;
                v.mx = x;
                v.my = y;
                }
             else if ((button == GLFW_MOUSE_BUTTON_LEFT)
                   && (action == GLFW_RELEASE))
                v.mb = -1;
             }
          //
          // drawing loop
          //
          void draw(void (*update)()) {
             update();
             glBufferSubData(GL_ARRAY_BUFFER,0,CPP*v.np*sizeof(float),v.data);
             while (!glfwWindowShouldClose(window)) {
                glfwPollEvents();
                glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);  
                glDrawArrays(GL_TRIANGLES,0,VPP*v.np);
                glfwSwapBuffers(window);
                }
             glfwDestroyWindow(window);
             glfwTerminate();
             }
          //
          // constructor
          //
          GL(int width,int height,char *title) {
             //
             // init GLFW
             //
             if (!glfwInit())
                cerr << "   could not start GLFW" << endl;
             window = glfwCreateWindow(width,height,title,NULL,NULL);
             if (!window)
                cerr << "   could not open window" << endl;
             glfwMakeContextCurrent(window);
             glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
             glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
             glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);
             //
             // init GLEW
             //
             glewExperimental = GL_TRUE;
             glewInit();
             const GLubyte* renderer = glGetString(GL_RENDERER);
             const GLubyte* version = glGetString(GL_VERSION);
             cerr << "   renderer: " << renderer << endl;
             cerr << "   GL version " << version << endl;
             //
             // vertex shader
             //
             const char* vertex_code = R"(
                attribute vec3 position;
                attribute vec3 color;
                varying vec3 fcolor;
                uniform float rx,ry,rz,tx,ty,tz,sxyz;
                mat4 rotatex(float angle) {
                   return mat4(1.0,0.0,0.0,0.0,
                   0.0,cos(angle),-sin(angle),0.0,
                   0.0,sin(angle),cos(angle),0.0,
                   0.0,0.0,0.0,1.0);
                   }
                mat4 rotatey(float angle) {
                   return mat4(cos(angle),0.0,sin(angle),0.0,
                   0.0,1.0,0.0,0.0,
                   -sin(angle),0.0,cos(angle),0.0,
                   0.0,0.0,0.0,1.0);
                   }
                mat4 rotatez(float angle) {
                   return mat4(cos(angle),-sin(angle),0.0,0.0,
                   sin(angle),cos(angle),0.0,0.0,
                   0.0,0.0,1.0,0.0,
                   0.0,0.0,0.0,1.0);
                   }
                mat4 scale(float s) {
                   return mat4(s,0,0.0,0.0,
                   0,s,0.0,0.0,
                   0.0,0.0,s,0.0,
                   0.0,0.0,0.0,1.0);
                   }
                mat4 translate(float dx,float dy,float dz) {
                   return mat4(1.0,0.0,0.0,dx,
                   0.0,1.0,0.0,dy,
                   0.0,0.0,1.0,dz,
                   0.0,0.0,0.0,1.0);
                   }
                void main() {
                   fcolor = color;
                   vec4 vertex = vec4(position,1.0);
                   gl_Position = vertex*rotatex(rx)
                      *rotatey(ry)*rotatez(rz)
                      *translate(tx,ty,tz)*scale(sxyz);
                   }
                )";
             //
             // fragment shader
             //
             const char* fragment_code = R"(
                varying vec3 fcolor;
                float depth;
                void main() {
                   depth = 1.0-1.0*gl_FragCoord.z;
                   gl_FragColor = vec4(depth*fcolor[0],depth*fcolor[1],depth*fcolor[2],1.0);
                   }
                )";
             //
             // compile and link shaders
             //
             v.program = glCreateProgram();
             GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
             GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
             glShaderSource(vertex,1,&vertex_code,NULL);
             glShaderSource(fragment,1,&fragment_code,NULL);
             glCompileShader(vertex);
             glCompileShader(fragment);
             glAttachShader(v.program,vertex);
             glAttachShader(v.program,fragment);
             glLinkProgram(v.program);
             glDetachShader(v.program,vertex);
             glDetachShader(v.program,fragment);
             glUseProgram(v.program);
             //
             // set up buffers
             //
             glGenBuffers(1,&buffer);
             glBindBuffer(GL_ARRAY_BUFFER,buffer);
             glBufferData(GL_ARRAY_BUFFER,CPP*v.np*sizeof(float),
                v.data,GL_DYNAMIC_DRAW);
             location = glGetAttribLocation(v.program,"position");
             glEnableVertexAttribArray(location);
             glVertexAttribPointer(location,3,GL_FLOAT,GL_FALSE,
                6*sizeof(float),0);
             location = glGetAttribLocation(v.program,"color");
             glEnableVertexAttribArray(location);
             glVertexAttribPointer(location,3,GL_FLOAT,GL_FALSE,
                6*sizeof(float),(GLvoid*)(3*sizeof(float)));
             //
             // set up drawing
             //
             glEnable(GL_DEPTH_TEST);
             glDepthMask(GL_TRUE);
             glDepthFunc(GL_LESS);
             glDepthRange(0.0,1.0);
             glEnable(GL_BLEND);
             glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
             //
             // set up view
             //
             location = glGetUniformLocation(v.program,"rx");
             glUniform1f(location,v.rx);
             location = glGetUniformLocation(v.program,"ry");
             glUniform1f(location,v.ry);
             location = glGetUniformLocation(v.program,"rz");
             glUniform1f(location,v.rz);
             location = glGetUniformLocation(v.program,"tx");
             glUniform1f(location,v.tx);
             location = glGetUniformLocation(v.program,"ty");
             glUniform1f(location,v.ty);
             location = glGetUniformLocation(v.program,"tz");
             glUniform1f(location,v.tz);
             location = glGetUniformLocation(v.program,"sxyz");
             glUniform1f(location,v.sxyz);
             //
             // set up callbacks
             //
             glfwSetKeyCallback(window,keyboard);
             glfwSetScrollCallback(window,scroll);
             glfwSetMouseButtonCallback(window,button);
             glfwSetCursorPosCallback(window,cursor);
             }
       };
    //
    // drawing update
    //
    void face(float x0,float y0,float z0,float x1,float y1,float z1,
       float x2,float y2,float z2, int *index) {
       float r = 0.6;
       float g = 1.0;
       float b = 0.6;
       v.data[(*index)++] = x0;
       v.data[(*index)++] = y0;
       v.data[(*index)++] = z0;
       v.data[(*index)++] = r;
       v.data[(*index)++] = g;
       v.data[(*index)++] = b;
       v.data[(*index)++] = x1;
       v.data[(*index)++] = y1;
       v.data[(*index)++] = z1;
       v.data[(*index)++] = r;
       v.data[(*index)++] = g;
       v.data[(*index)++] = b;
       v.data[(*index)++] = x2;
       v.data[(*index)++] = y2;
       v.data[(*index)++] = z2;
       v.data[(*index)++] = r;
       v.data[(*index)++] = g;
       v.data[(*index)++] = b;
       }
    void update() {
       int index = 0;
       float scale = 2/(v.xmax-v.xmin);
       float d = v.size*v.d*scale;
       float xmid = (v.xmax+v.xmin)/2.0;
       float ymid = (v.ymax+v.ymin)/2.0;
       float zmid = (v.zmax+v.zmin)/2.0;
       for (int i = 0; i < v.np; ++i) {
          float x = (v.px[i]-xmid)*scale;
          float y = (v.py[i]-ymid)*scale;
          float z = (zmid-v.pz[i])*scale; // ?
          face(x-d/2,y-d/2,z,x+d/2,y-d/2,z,x,y,z+d/2,&index);
          face(x-d/2,y+d/2,z,x,y,z+d/2,x+d/2,y+d/2,z,&index);
          face(x+d/2,y-d/2,z,x+d/2,y+d/2,z,x,y,z+d/2,&index);
          face(x-d/2,y+d/2,z,x-d/2,y-d/2,z,x,y,z+d/2,&index);
          face(x+d/2,y-d/2,z,x-d/2,y-d/2,z,x,y,z-d/2,&index);
          face(x-d/2,y+d/2,z,x+d/2,y+d/2,z,x,y,z-d/2,&index);
          face(x+d/2,y+d/2,z,x+d/2,y-d/2,z,x,y,z-d/2,&index);
          face(x-d/2,y-d/2,z,x-d/2,y+d/2,z,x,y,z-d/2,&index);
          }
       }
    //
    // main
    //
    int main(int argc, char** argv) {
    
    Amira Abdel-Rahman (admin)'s avatar
    Amira Abdel-Rahman (admin) committed
       if (argc == 1) {
          cerr << "command line: particle source | particles_GL [arguments]" << endl;
          cerr << "   size=(particle size, 1=lattice pitch)" << endl;
    
    Amira Abdel-Rahman (admin)'s avatar
    Amira Abdel-Rahman (admin) committed
       if (nullptr == strstr(argv[1],"size=")) {
          cerr << "particles_GL argument not recognized" << endl;
          return 1;
          }
       else
          v.size = stof(argv[1]+5);
    
       //
       // read and parse inputs
       //
       string s;
       while (1) {
          getline(cin,s);
          if (s.compare("number:") == 0) {
             getline(cin,s);
             v.np = stoi(s);
             v.px = new float[v.np];
             v.py = new float[v.np];
             v.pz = new float[v.np];
             v.data = new float[CPP*v.np];
             }
          else if (s.compare("pitch:") == 0) {
             getline(cin,s);
             v.d = stof(s);
             }
          else if (s.compare("xmin:") == 0) {
             getline(cin,s);
             v.xmin = stof(s);
             }
          else if (s.compare("xmax:") == 0) {
             getline(cin,s);
             v.xmax = stof(s);
             }
          else if (s.compare("ymin:") == 0) {
             getline(cin,s);
             v.ymin = stof(s);
             }
          else if (s.compare("ymax:") == 0) {
             getline(cin,s);
             v.ymax = stof(s);
             }
          else if (s.compare("zmin:") == 0) {
             getline(cin,s);
             v.zmin = stof(s);
             }
          else if (s.compare("zmax:") == 0) {
             getline(cin,s);
             v.zmax = stof(s);
             }
          else if (s.compare("particles:") == 0) {
             for (int i = 0; i < v.np ; ++i) {
                cin.read((char *)&v.px[i],4);
                cin.read((char *)&v.py[i],4);
                cin.read((char *)&v.pz[i],4);
                }
             }
          else if (s.compare("end:") == 0)
             break;
          }
       cerr << "particles_GL:" << endl;
       cerr << "   input " << v.np << " particles" << endl;
       //
       // initialize GL
       //
       GL g(v.width,v.height,(char *)"particles_GL");
       //
       // start drawing loop
       //
       g.draw(update);
       }