-
Amira Abdel-Rahman (admin) authoredAmira Abdel-Rahman (admin) authored
bonds_GL.cpp 13.01 KiB
/*
draw only active links
*/
//
// bonds_GL.cpp
// input bonds, display GL
// (c) MIT CBA Neil Gershenfeld 6/25/20
// reads from stdin
// bonds_source | bonds_GL size
//
// includes
//
#include <iostream>
#include <cmath>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
using namespace std;
//
// defines
//
#define CPP (12*2*6) // render coordinates per particle
// 12 lines * 2 verts * (3 coords + 3 colors)
#define VPP (12*2) // render vertices per particle
// 12 lines * 2 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 = 1; // particle size
int lpp; // links per particle
int *nlinks,*links; // links
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_LINES,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);
}
};
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;
float r = 0.6;
float g = 1.0;
float b = 0.6;
for (int i = 0; i < v.np; ++i) {
float x0 = (v.px[i]-xmid)*scale;
float y0 = (v.py[i]-ymid)*scale;
float z0 = (zmid-v.pz[i])*scale; // ?
for (int j = 0; j < v.nlinks[i]; ++j) {
float x1 = (v.px[v.links[12*i+j]]-xmid)*scale;
float y1 = (v.py[v.links[12*i+j]]-ymid)*scale;
float z1 = (zmid-v.pz[v.links[12*i+j]])*scale; // ?
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++] = x0+(x1-x0)/2.5;
v.data[index++] = y0+(y1-y0)/2.5;
v.data[index++] = z0+(z1-z0)/2.5;
v.data[index++] = r;
v.data[index++] = g;
v.data[index++] = b;
}
}
}
//
// main
//
int main(int argc, char** argv) {
if (argc != 1) {
cerr << "command line: bonds_source | bonds_GL" << endl;
return 1;
}
//
// 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("links per particle:") == 0) {
getline(cin,s);
v.lpp = stoi(s);
}
else if (s.compare("nlinks:") == 0) {
v.nlinks = new int[v.np];
for (int i = 0; i < v.np; ++i)
cin.read((char *)&v.nlinks[i],4);
}
else if (s.compare("links:") == 0) {
v.links = new int[v.lpp*v.np];
for (int i = 0; i < v.lpp*v.np; ++i)
cin.read((char *)&v.links[i],4);
}
else if (s.compare("end:") == 0)
break;
}
cerr << "bonds_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);
}