-
Amira Abdel-Rahman (admin) authoredAmira Abdel-Rahman (admin) authored
strain_GL.cpp 14.68 KiB
//
// strain_GL.cpp
// input strain, display GL
// (c) MIT CBA Neil Gershenfeld 7/1/20
// reads from stdin
// strain_source | strain_GL size scale rx ry rz sxyz perspective
//
// includes
//
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
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; // view rotation
float ry;
float rz;
float dr = 0.01;
float tx = 0; // view translation
float ty = 0;
float tz = 0;
float dt = 0.01;
float sxyz; // view scale
float scale; // strain scale multiplier
float perspective; // view perspective
int mx,my; // mouse position
int mb = -1; // mouse state
int np; // number of particles
float fraction; // fixed top and bottom particle fraction
float xmin,xmax,ymin,ymax,zmin,zmax; // data limits
float *px,*py,*pz; // particle positions
float *s; // strain
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) {
glfwDestroyWindow(window);
glfwTerminate();
cerr << endl;
exit(0);
}
else if (key == 'Q' && action == GLFW_PRESS) {
glfwDestroyWindow(window);
glfwTerminate();
cerr << endl;
exit(0);
}
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);
}
cerr << '\r' << " scale " << v.sxyz << " " << flush;
}
//
// 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 << '\r' << " rotate " << v.rx << ' ' << v.ry << " " << flush;
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;
}
//
// update and draw buffer
//
void draw(void (*update)()) {
glfwPollEvents();
update();
glBufferSubData(GL_ARRAY_BUFFER,0,CPP*v.np*sizeof(float),v.data);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES,0,VPP*v.np);
glfwSwapBuffers(window);
}
//
// constructor
//
GL(int width,int height,char *title) {
//
// init GLFW
//
if (!glfwInit())
cerr << " could not start GLFW" << endl;
glfwWindowHint(GLFW_SAMPLES,4);
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,perspective;
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 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);
}
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,perspective,1.0);
}
void main() {
fcolor = color;
vec4 vertex = vec4(position,1.0);
gl_Position = vertex*rotatex(rx)
*rotatey(ry)*rotatez(rz)
*translate(tx,ty,-.9*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);
glEnable(GL_MULTISAMPLE);
//
// 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);
location = glGetUniformLocation(v.program,"perspective");
glUniform1f(location,v.perspective);
//
// 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, float r, float g, float b, int *index) {
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;
float r,g,b;
for (int i = 0; i < v.np; ++i) {
if ((i < v.np*v.fraction) || (i > v.np*(1-v.fraction))) {
r = 0.6;
g = 0.6;
b = 1.0;
}
else {
r = 0.6+v.scale*v.s[i];
g = 1.0-v.scale*v.s[i];
b = 0.6;
}
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,r,g,b,&index);
face(x-d/2,y+d/2,z,x,y,z+d/2,x+d/2,y+d/2,z,r,g,b,&index);
face(x+d/2,y-d/2,z,x+d/2,y+d/2,z,x,y,z+d/2,r,g,b,&index);
face(x-d/2,y+d/2,z,x-d/2,y-d/2,z,x,y,z+d/2,r,g,b,&index);
face(x+d/2,y-d/2,z,x-d/2,y-d/2,z,x,y,z-d/2,r,g,b,&index);
face(x-d/2,y+d/2,z,x+d/2,y+d/2,z,x,y,z-d/2,r,g,b,&index);
face(x+d/2,y+d/2,z,x+d/2,y-d/2,z,x,y,z-d/2,r,g,b,&index);
face(x-d/2,y-d/2,z,x-d/2,y+d/2,z,x,y,z-d/2,r,g,b,&index);
}
}
//
// main
//
int main(int argc, char** argv) {
if (argc != 8) {
cerr << "command line: strain_source | strain_GL size scale rx ry rz sxyz perspective" << endl;
return 1;
}
v.size = stof(argv[1]);
v.scale = stof(argv[2]);
v.rx = stof(argv[3]);
v.ry = stof(argv[4]);
v.rz = stof(argv[5]);
v.sxyz = stof(argv[6]);
v.perspective = stof(argv[7]);
//
// 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.s = 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("fraction:") == 0) {
getline(cin,s);
v.fraction = stof(s);
}
else if (s.compare("continue:") == 0)
break;
}
cerr << "strain_GL:" << endl;
cerr << " input " << v.np << " particles" << endl;
//
// initialize GL
//
GL g(v.width,v.height,(char *)"strain_GL");
//
// start main loop
//
int count = 0;
char str[100];
while (1) {
getline(cin,s);
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("strain:") == 0)
for (int i = 0; i < v.np ; ++i)
cin.read((char *)&v.s[i],4);
else if (s.compare("continue:") == 0) {
//
// update GL
//
g.draw(update);
//
// uncomment to save images
//
//sprintf(str,"import -window strain_GL images/%04d.jpg",count++);
//int result = system(str);
}
}
}