Skip to content
Snippets Groups Projects
graphics.cpp 11.7 KiB
Newer Older
/*
Basic diffusion and FRAP simulation
 Jonathan Ward and Francois Nedelec, Copyright EMBL Nov. 2007-2009

 
To compile on the mac:
 g++ main.cc -framework GLUT -framework OpenGL -o frap

To compile on Windows using Cygwin:
 g++ main.cc -lopengl32 -lglut32 -o frap
 
To compile on Linux:
 g++ main.cc -lglut -lopengl -o frap
*/

#include "params.h"
#ifdef __APPLE__
#  include <GLUT/glut.h>
#else
#  include "GL/glut.h"
#endif
#include <list>
#include <vector>
#include <iostream>
#include <math.h>

#include "../cmath3d/TriangleMesh.h"
#include "../cmath3d_v/TriangleMesh_v.h"


//link to the global params
extern ParamsClass params;
extern ActiveMesh mesh;

///whether the simulation is paused (=1) or not (=0)
int pauseSimulation=1;
///how big chunks of steps should be taken between drawing
int stepGranularity=1;

///OpenGL window size -> to recalculate from windows coords to scene coords
int windowSizeX=0, windowSizeY=0;

float uhel_x = 0.0, uhel_y = 0.0;
float zoom = 1.0;

bool MouseActive = false;
int last_x = 0, last_y = 0;


///manage \e count steps of the simulation and then print and draw
void step(int count)
{
	while ((params.currTime < params.stopTime) && (count > 0))
	{
		//do some job

		params.currTime += params.incrTime;
		--count;
	}
	
	if (params.currTime >= params.stopTime)
	{
		std::cout << "END OF THE SIMULATION HAS BEEN REACHED\n";
		pauseSimulation=1;
	}

	std::cout << "\nnow at time: " << params.currTime << "\n";

	//ask GLUT to call the display function
	glutPostRedisplay();
}


///draws the frame around the playground
void displayFrame(void)
{
    glColor3f(params.sceneBorderColour.r,
	 			  params.sceneBorderColour.g,
	 			  params.sceneBorderColour.b);
    glLineWidth(1);
    glBegin(GL_LINE_LOOP);
    glVertex3f( params.sceneOffset.x , params.sceneOffset.y , params.sceneCentre.z );
    glVertex3f( params.sceneOffset.x + params.sceneSize.x , params.sceneOffset.y , params.sceneCentre.z );
    glVertex3f( params.sceneOffset.x + params.sceneSize.x , params.sceneOffset.y + params.sceneSize.y , params.sceneCentre.z );
    glVertex3f( params.sceneOffset.x , params.sceneOffset.y + params.sceneSize.y , params.sceneCentre.z );
    glEnd();
}

void displayAxes(void)
{
	glLineWidth(2);
	glBegin(GL_LINES);
	glColor3f(1.0,0.0,0.0); //red   -- x axis
	glVertex3f(params.sceneCentre.x,params.sceneCentre.y,params.sceneCentre.z);
	glVertex3f(params.sceneCentre.x+params.sceneSize.x/4.f,params.sceneCentre.y,params.sceneCentre.z);

	glColor3f(0.0,1.0,0.0); //green -- y axis
	glVertex3f(params.sceneCentre.x,params.sceneCentre.y,params.sceneCentre.z);
	glVertex3f(params.sceneCentre.x,params.sceneCentre.y+params.sceneSize.y/4.f,params.sceneCentre.z);

	glColor3f(0.0,0.0,1.0); //blue  -- z axis
	glVertex3f(params.sceneCentre.x,params.sceneCentre.y,params.sceneCentre.z);
	glVertex3f(params.sceneCentre.x,params.sceneCentre.y,params.sceneCentre.z+params.sceneSize.z/4.f);
	glEnd();
	glLineWidth(1);
}


int VertexID=10;
void ActiveMesh::displayMesh(void)
{
	glColor3f(0.8,0.8,0.8);

	/*
	for (unsigned int i=0; i < ID.size(); i+=3)
	{
		//glBegin(GL_TRIANGLES);
		glBegin(GL_LINE_LOOP);
		glNormal3f(norm[i/3].x,norm[i/3].y,norm[i/3].z);
		glVertex3f(Pos[ID[i+0]].x,Pos[ID[i+0]].y,Pos[ID[i+0]].z);
		glVertex3f(Pos[ID[i+1]].x,Pos[ID[i+1]].y,Pos[ID[i+1]].z);
		glVertex3f(Pos[ID[i+2]].x,Pos[ID[i+2]].y,Pos[ID[i+2]].z);
		glEnd();
	}
	*/

	//long unsigned int* id=&ID.front();
	long unsigned int* id=ID.data();
	for (unsigned int i=0; i < ID.size(); i+=3)
	{
		//glBegin(GL_TRIANGLES);
		glBegin(GL_LINE_LOOP);
		glNormal3f(norm[i/3].x,norm[i/3].y,norm[i/3].z);
		glVertex3f(Pos[*id].x,Pos[*id].y,Pos[*id].z); ++id;
		glVertex3f(Pos[*id].x,Pos[*id].y,Pos[*id].z); ++id;
		glVertex3f(Pos[*id].x,Pos[*id].y,Pos[*id].z); ++id;
		glEnd();
	}

	std::vector<size_t> neigs;
	ulm::getVertexImmediateNeighbours(*this,VertexID,neigs);

	glPointSize(4.0f);
	glBegin(GL_POINTS);
	// centre vertex:
	glColor3f(0.0,0.0,1.0);
	glVertex3f(Pos[VertexID].x,Pos[VertexID].y,Pos[VertexID].z);
	// neigs:
	glColor3f(1.0,0.0,0.0);
	for (unsigned int i=0; i < neigs.size(); ++i)
		glVertex3f(Pos[neigs[i]].x,Pos[neigs[i]].y,Pos[neigs[i]].z);
	glEnd();
}


void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT);
	glLoadIdentity();
	glTranslatef(params.sceneCentre.x,params.sceneCentre.y,params.sceneCentre.z);
	glScalef(zoom,zoom,zoom);
	Vector3d<float> eye=params.sceneCentre;
	eye.x+=params.sceneSize.z*sinf(uhel_x)*cosf(uhel_y);
	eye.y+=params.sceneSize.z*sinf(uhel_y);
	eye.z+=params.sceneSize.z*cosf(uhel_x)*cosf(uhel_y);
	gluLookAt(eye.x,eye.y,eye.z, //eye
				 params.sceneCentre.x,params.sceneCentre.y,params.sceneCentre.z, //center
	          //0.0, cosf(-uhel_y), sinf(-uhel_y)); // up
	          0.0, 1.0, 0.0); // up

	displayFrame();
	displayAxes();
	mesh.displayMesh();

	glFlush();
	glutSwapBuffers();
}


// called automatically after a certain amount of time
void timer(int)
{
	 //do simulation and then draw
    step(stepGranularity);

    //ask GLUT to call 'timer' again in 'delay' milli-seconds:
	 //in the meantime, you can inspect the drawing :-)
    if (!pauseSimulation) glutTimerFunc(500, timer, 0);
}

void GetSceneViewSize(const int w,const int h,
							float& xVisF, float& xVisT,
							float& yVisF, float& yVisT)
{
	 //what is the desired size of the scene
	 const float xBound=params.sceneSize.x
	 				+ 2.f*params.sceneOuterBorder.x;
	 const float yBound=params.sceneSize.y
	 				+ 2.f*params.sceneOuterBorder.y;

	 xVisF = params.sceneOffset.x - params.sceneOuterBorder.x;
	 yVisF = params.sceneOffset.y - params.sceneOuterBorder.y;
	 xVisT = xBound + xVisF;
	 yVisT = yBound + yVisF;

    if ( (float)w * yBound < (float)h * xBound )		//equals to  w/h < x/y
	 {
	 	//window is closer to the rectangle than the scene shape
		  yVisF *= ((float)h / float(w)) * (xBound/yBound);
        yVisT *= ((float)h / float(w)) * (xBound/yBound);
	 }
	 else
	 {
		  xVisF *= ((float)w / float(h)) * (yBound/xBound);
        xVisT *= ((float)w / float(h)) * (yBound/xBound);
	 }
}


void printKeysHelp(void)
{
	std::cout << "\nKeys:\n";
	std::cout << "ESC or 'q': quit\n";
}


void printDispayedFeauters(void)
{
	if (pauseSimulation) std::cout << "\nsimulation is now paused\n";
	else std::cout << "\nsimulation is now in progress\n";
	std::cout << "simulation time progress " << params.currTime/params.stopTime*100.f
		<< "%, delta time is " << params.incrTime << " minutes\n";

	std::cout << "viewing: x_ang=" << uhel_x << ", y_ang=" << uhel_y
	          << ", zoom=" << zoom << "\n";

	std::cout << "Currently displayed features:\n";
}


// called when a key is pressed
void keyboard(unsigned char key, int mx, int my)
{
	//required for calculating the mouse position within the scene coords
	float xVisF, yVisF;
	float xVisT, yVisT;
	float sx,sy;

    switch (key) {
        case 27:   //this corresponds to 'escape'
        case 'q':  //quit
            exit(EXIT_SUCCESS);
            break;

		  //control execution of the simulation
        case ' ':  //pause/unpause, refresh every 10 cycles
				if (params.currTime < params.stopTime) pauseSimulation^=1;
				if (!pauseSimulation)
				{
					stepGranularity=1; //= 1 min
					timer(0);
				}
            break;
        case 'z':  //pause/unpause, refresh every 600 cycles
				if (params.currTime < params.stopTime) pauseSimulation^=1;
				if (!pauseSimulation)
				{
					stepGranularity=100; //= 10 min
					timer(0);
				}
            break;
        case 'n':  //pause, advance by one frame
				pauseSimulation=1;
				step(1);
            break;

		  //etc stuff...
        case 'r':  //set scale 1:1
				uhel_x = 0.0;
				uhel_y = 0.0;
				zoom = 1.0;
				glutReshapeWindow(int(params.imgSizeX),int(params.imgSizeY));
				glutPostRedisplay();
            break;
			case 'h': //print help
				printKeysHelp();
				break;
			case 'd': //print what is displayed
				printDispayedFeauters();
				break;
			case 'o':
				zoom -= 0.2f;
				if (zoom < 0.2f) zoom=0.2f;
				glutPostRedisplay();
				break;
			case 'O':
				zoom += 0.2f;
				glutPostRedisplay();
				break;

			case 'v':
				++VertexID;
				glutPostRedisplay();
				break;

			case 'i': //inspect a cell
				GetSceneViewSize(windowSizeX,windowSizeY, xVisF,xVisT,yVisF,yVisT);
				sx=(float)mx              /(float)windowSizeX * (xVisT-xVisF) + xVisF;
				sy=(float)(windowSizeY-my)/(float)windowSizeY * (yVisT-yVisF) + yVisF;

				xVisF=sx=sy; //just to avoid warning, TODO REMOVE
			/*
				for (c=agents.begin(); c != agents.end(); c++)
					if ((*c)->IsPointInCell(Vector3d<float>(sx,sy,0)))
					{
						bool wasSelected=(*c)->isSelected;
						(*c)->isSelected=true;
						(*c)->ReportState();
						(*c)->isSelected=wasSelected;
					}
			*/
				break;
			case 13: //Enter key -- just empty lines
				std::cout << std::endl;
				break;
    }
}


// called when a special key is pressed
void Skeyboard(int key, int mx, int my)
{
	key=mx=my; //TODO REMOVE
	mx=key;    //TODO REMOVE
/*
	//required for calculating the mouse position within the scene coords
	float xVisF, yVisF;
	float xVisT, yVisT;
	float sx,sy;

    switch (key) {
			case GLUT_KEY_LEFT:
				//rotate cell left by 30deg
				GetSceneViewSize(windowSizeX,windowSizeY, xVisF,xVisT,yVisF,yVisT);
				sx=(float)mx              /(float)windowSizeX * (xVisT-xVisF) + xVisF;
				sy=(float)(windowSizeY-my)/(float)windowSizeY * (yVisT-yVisF) + yVisF;

				for (c=agents.begin(); c != agents.end(); c++)
					if ((*c)->IsPointInCell(Vector3d<float>(sx,sy,0)))
					{
						(*c)->desiredDirection += PI/6.f;
						if ((*c)->desiredDirection > PI) 
							(*c)->desiredDirection -= 2.f*PI;
					}
				break;
			case GLUT_KEY_RIGHT:
				//rotate cell left by 30deg
				GetSceneViewSize(windowSizeX,windowSizeY, xVisF,xVisT,yVisF,yVisT);
				sx=(float)mx              /(float)windowSizeX * (xVisT-xVisF) + xVisF;
				sy=(float)(windowSizeY-my)/(float)windowSizeY * (yVisT-yVisF) + yVisF;

				for (c=agents.begin(); c != agents.end(); c++)
					if ((*c)->IsPointInCell(Vector3d<float>(sx,sy,0)))
					{
						(*c)->desiredDirection -= PI/6.f;
						if ((*c)->desiredDirection < -PI) 
							(*c)->desiredDirection += 2.f*PI;
					}
				break;
    }
*/
}

void mouse(int button, int state, int x, int y)
{
	if (state == GLUT_DOWN) MouseActive = true;
	else if (state == GLUT_UP) MouseActive = false;	
	
	last_x=button; //TODO REMOVE
	last_x = x;
	last_y = y;	
}

void MouseMotion(int x, int y) 
{
	if (MouseActive)
	{
		uhel_x -= (float(x - last_x) * 0.01f);
		uhel_y += (float(y - last_y) * 0.01f);
		
		last_x = x;
		last_y = y;

		glutPostRedisplay();
	}
}


// called when the window is reshaped, arguments are the new window size
void reshape(int w, int h)
{
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

	 //remember the new window size...
	 windowSizeX=w; windowSizeY=h;

	 //what will be the final view port
    float xVisF, yVisF;
    float xVisT, yVisT;

	 GetSceneViewSize(w,h,xVisF,xVisT,yVisF,yVisT);
    
    //glOrtho(xVisF, xVisT, yVisF, yVisT, params.sceneCentre.z-params.sceneSize.z,params.sceneCentre.z+params.sceneSize.z);
    glOrtho(xVisF, xVisT, yVisF, yVisT, -1000,1000);
    glMatrixMode(GL_MODELVIEW);
}


void initializeGL(void)
{
	 int Argc=1;
	 char msg[]="TRAgen: A Tool for Generation of Synthetic Time-Lapse Image Sequences of Living Cells";
	 char *Argv[10];
	 Argv[0]=msg;

    glutInit(&Argc, Argv);

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowSize(600, 600); 
    glutInitWindowPosition(100, 100);
    glutCreateWindow(Argv[0]);

    glutKeyboardFunc(keyboard);
    glutSpecialFunc(Skeyboard);
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);

    glutMouseFunc(mouse);
    glutMotionFunc(MouseMotion);

    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_POINT_SMOOTH);
}

void loopGL(void)
{
	glutMainLoop();
}

void closeGL(void)
{
}