//
//
// File author(s): <Julian Andres Garcia Grajales>, (C) 2014
//
// Copyright: this software is licenced under the terms stipulated in the license.txt file located in its root directory
//
//
/*!\file graphics.cpp
\brief This file contains the functions related to the visualization of the electrical part of Neurite by means of OpenGL. It is related to the "g" option of Neurite
*/
#include "graphics.h"
#include "configuration.h"
#include <sys/stat.h>
#include <sys/types.h>
#define WIN_X 400
#define WIN_Y 400
#define WIN_PX_H 800
#define WIN_PX_W 800
#define MAX_V 0.08
#define MIN_V -0.01
#define UNIT_V 0.01
/* global variables */
int img=0, i=0;
extern int numStepsX, numStepsT, open_GL_steps;
extern TYPE xspan, tspan, unit_x;
extern TYPE *neuriteE, **neuriteR, ***neurite,* open_GL_graphE, **open_GL_graphR,*** open_GL_graph;
void runGL()
{
char winName[128] = "Discrete Cable Equation with Hodgkin-Huxley Channels";
/* Initiate Glut */
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(WIN_PX_W, WIN_PX_H);
glutInitWindowPosition(100, 100);
glutCreateWindow(winName);
// Clear the background of our window to white
glClearColor(1,1,1,0);
// Define viewing area
gluOrtho2D(-5,WIN_X+5,-5,WIN_Y+5);
//Glut drawing functions
glutDisplayFunc(display);
glutIdleFunc(display);
//The main loop
glutMainLoop();
}
void display()
{
double color[][3] = {{0,0.5,0}, {0.7,0,0.7}, {0,0,0.7}, {0.7,0,0}};
int sleep = 33333;
//Clear the color buffer
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0,0,0); //Set color to black
// create graph-space and put the names at the axis
renderAxes("Distance from Voltage Source (meters)", "VOLTS");
// render curves
renderCurves(color);
// render neurite
renderNeurites(color, 0, 1, "Control", "Stretched");
// Flush the OpenGL buffers to the window
glFlush();
glutPostRedisplay();
// capture the first set of frames
if(img < open_GL_steps)
{
captureScreen();
}
// properly iterate i
if(i<open_GL_steps-2) {
i++;
} else {
i=0;
}
sleep = (int)(pow(10,23)*tspan/(9*open_GL_steps));
wait(sleep);
}
extern void wait(int microseconds)
{
clock_t endwait;
endwait = clock () + microseconds * CLOCKS_PER_SEC / 1000000;
while (clock() < endwait) {}
}
extern void renderAxes(char *xlabel, char *ylabel)
{
char tmp[8];
int j;
// render graph axes
glBegin(GL_LINE_STRIP);
glVertex2f(5*0.025*WIN_X, 39*0.025*WIN_Y);
glVertex2f(5*0.025*WIN_X, 12*0.025*WIN_Y);
glVertex2f(35*0.025*WIN_X, 12*0.025*WIN_Y);
glEnd();
// render y-axis tick marks and labels
for(j=-1; j<(MAX_V/UNIT_V+1); j++)
{
// tick mark
glBegin(GL_LINES);
glVertex2f(5*0.025*WIN_X, (27*0.025*WIN_Y/(MAX_V - MIN_V))*UNIT_V*j + 15*0.025*WIN_Y);
glVertex2f(4.5*0.025*WIN_X, (27*0.025*WIN_Y/(MAX_V - MIN_V))*UNIT_V*j +15*0.025*WIN_Y);
glEnd();
// label
if(j < 0)
{
snprintf(tmp, 7, "%f", UNIT_V*j-0.065);
renderString(2*0.025*WIN_X, (27*0.025*WIN_Y/(MAX_V - MIN_V))*UNIT_V*j + 15*0.025*WIN_Y, tmp, 'h');
} else {
snprintf(tmp, 7, "%f", UNIT_V*j-0.065);
//fprintf(stdout,"yo=%f\n",UNIT_V*j-0.065);
// if(j==1)exit(0);
renderString(2.4*0.025*WIN_X, (27*0.025*WIN_Y/(MAX_V - MIN_V))*UNIT_V*j + 15*0.025*WIN_Y, tmp, 'h');
}
}
// render x-axis tick marks and labels
for(j=0; j<(xspan/unit_x+1); j++)
{
// tick mark
glBegin(GL_LINES);
glVertex2f((30*0.025*WIN_X/xspan)*unit_x*j + 5*0.025*WIN_X, 12*0.025*WIN_Y);
glVertex2f((30*0.025*WIN_X/xspan)*unit_x*j + 5*0.025*WIN_X, 11.5*0.025*WIN_Y);
glEnd();
// label
snprintf(tmp, 4, "%f", unit_x*1E3*j);
renderString((30*0.025*WIN_X/xspan)*unit_x*j + 4.5*0.025*WIN_X, 10.5*0.025*WIN_Y, tmp, 'h');
}
strcpy(tmp, "E-3");
// snprintf(tmp, 8, "%.1e", xspan); // ****FIX****
renderString(35.5*0.025*WIN_X, 10.5*0.025*WIN_Y, tmp, 'h');
// render x and y axis labels
renderString(0.6*0.025*WIN_X, 29.0*0.025*WIN_Y, ylabel, 'v'); // y-axis
renderString(14*0.025*WIN_X, 9*0.025*WIN_Y, xlabel, 'h'); // x-axis
}
extern void renderString(double x, double y, char *string, char orientation)
{
// orientation == (h)orizontal or (v)ertical
int len, i;
if(orientation == 'h')
glRasterPos2f(x, y);
len = (int) strlen(string);
for (i = 0; i < len; i++)
{
if(orientation == 'v')
glRasterPos2f(x, y-i*5);
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, string[i]);
}
}
extern void renderCurves(double (*color)[3])
{
int j, curv;
int numCurves=1;
glLineWidth(2);
for(curv=0; curv<numCurves; curv++)
{
if (curv < 4)
glColor3f(color[curv][0],color[curv][1],color[curv][2]);
else
glColor3f((rand()%10)/10,(rand()%10)/10,(rand()%10)/10);
glBegin(GL_LINE_STRIP);
for(j=1; j<numStepsX-1; j++)
{
glVertex2f(j*(30*0.025*WIN_X/numStepsX) + 5*0.025*WIN_X, (open_GL_graph[curv][i][j]+0.065)*(27*0.025*WIN_Y/(MAX_V - MIN_V)) + 15*0.025*WIN_Y);
}
glEnd();
}
glLineWidth(1);
}
extern void renderNeurites(double (*color)[3], int curvOne, int curvTwo, char *oneName, char *twoName)
{
int c=0, j, curv;
double Ncolor;
int numCurves=1;
for(curv=0; curv<numCurves; curv++)
{
if (curv < 4)
glColor3f(color[curv][0],color[curv][1],color[curv][2]);
else
glColor3f((rand()%10)/10,(rand()%10)/10,(rand()%10)/10);
if((curv == curvOne) || (curv == curvTwo))
{
if(curv == curvOne)
renderString(0.7*0.025*WIN_X, (-c*2 + 3.2)*0.025*WIN_Y, oneName, 'h');
if(curv == curvTwo)
renderString(0.7*0.025*WIN_X, (-c*2 + 3.2)*0.025*WIN_Y, twoName, 'h');
renderString(0.7*0.025*WIN_X, (-c*2 + 2.4)*0.025*WIN_Y, "Neurite", 'h');
for(j=0; j<numStepsX; j++)
{
Ncolor = open_GL_graph[curv][i][j]*200; // should be 12.5, but boosting for effect
glColor3f(Ncolor,0,1-Ncolor);
glBegin(GL_QUADS);
glVertex2f(j*(0.75*WIN_X/numStepsX) + 0.125*WIN_X, (-c*2 + 2.5)*0.025*WIN_Y);
glVertex2f(j*(0.75*WIN_X/numStepsX) + 0.125*WIN_X, (-c*2 + 3.5)*0.025*WIN_Y);
glVertex2f((j+1)*(0.75*WIN_X/numStepsX) + 0.125*WIN_X, (-c*2 + 3.5)*0.025*WIN_Y);
glVertex2f((j+1)*(0.75*WIN_X/numStepsX) + 0.125*WIN_X, (-c*2 + 2.5)*0.025*WIN_Y);
glEnd();
}
c++;
}
}
}
extern void captureScreen()
{
char fname[250];
char tmp[8];
char *execution_folder = getenv("working_directory");
if (execution_folder != NULL){
sprintf(tmp, "%03d", img);
strcpy (fname, execution_folder);
strcat (fname, "/outputs/GUI_captures/capture_");
strcat (fname, tmp);
strcat (fname, ".bmp");
RgbImage theImage(WIN_PX_H, WIN_PX_W);
theImage.LoadFromOpenglBuffer();
theImage.WriteBmpFile(fname);
img++;
}else{
fprintf(stdout,"ERROR. You did not define the folder to save the pictures for the video\n");
exit(0);
}
if(img==open_GL_steps)
exit(0);
}