/*
Version: $Id: wxmodel.cpp 134 2013-11-22 14:30:58Z gk $
Implementation of GUI interface
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "constructs.h"
#include "wxglmodel.h"
#include "wx/sizer.h"
#include "wx/glcanvas.h"
#include <GL/glu.h>
#include <GL/gl.h>
#include <GL/glut.h>
// The next global variable controls the animation's state and speed.
float RotateAngle = 0.0f; // Angle in degrees of rotation around y-axis
float Azimuth = 20.0; // Rotated up or down by this amount
float AngleStepSize = 3.0f; // Step three degrees at a time
const float AngleStepMax = 10.0f;
const float AngleStepMin = 0.1f;
int WireFrameOn = 1; // == 1 for wire frame mode
GLfloat light_position2[] = { 0, 1,1,0};
enum {
MENU_RUN=1,
MENU_1Hour,
MENU_REFRESH,
MENU_QUIT,
MENU_CS = 100,
MENU_CSUS = 300,
MENU_STRONGTRAIN = 400,
MENU_INTERSTIM = 500,
MENU_PROTO = 600,
};
/*
wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_COMPLETED, wxThreadEvent);
wxDECLARE_EVENT(wxEVT_COMMAND_MYTHREAD_UPDATE, wxThreadEvent);
*/
GLuint raw_texture_load(const char *filename, int width, int height)
{
GLuint texture =0;
unsigned char *data;
FILE *file;
// open texture data
file = fopen(filename, "rb");
if (file == NULL) return 0;
// allocate buffer
int sq;
data = (unsigned char*) malloc(sq = width * height *4 );
cout << "sq=" << sq<<endl;
// read texture data
sq = fread(data,1, width * height *3 , file);
cout << "read "<<sq << endl;
fclose(file);
// allocate a texture name
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &texture);
// select our current texture
glBindTexture(GL_TEXTURE_2D, texture);
// select modulate to mix texture with color for shading
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
// when texture area is small, bilinear filter the closest mipmap
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
// when texture area is large, bilinear filter the first mipmap
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// texture should tile
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
// build our texture mipmaps
//float pixels[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, GL_RGB, GL_FLOAT, pixels);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
// gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
glDisable(GL_TEXTURE_2D);
free(data);
return texture;
}
class MyThread : public wxThread
{
public:
LANetwork* m_network;
MyThread(LAWindow *handler) : wxThread(wxTHREAD_JOINABLE)
{
m_pHandler = handler ;
m_network = handler->network;
}
~MyThread() {}
protected:
virtual ExitCode Entry();
LAWindow *m_pHandler;
};
wxThread::ExitCode MyThread::Entry()
{
this->m_network->RunStore2(3, 1, 180, 0);
exit(0);
return (wxThread::ExitCode)0; // success
}
LAWindow::LAWindow(const wxString& title, LANetwork* netw)
:wxFrame(NULL, wxID_ANY, title, wxDefaultPosition,wxSize(1024, 768))
{
Centre();
timersRun =0;
int args[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 16, 0};
this->network = netw;
this->network_glpanel = new LAGLPane(this, this->network, args);
//this->network_panel->network = this->network;
//this->network->wx_window = this;
//this->network_panel->SetFocus();
wxMenu* m = new wxMenu;
m->Append(MENU_RUN, _("&Run"));
m->Append(MENU_REFRESH, _("Re&fresh"));
m->Append(MENU_QUIT, _("&Quit"));
wxMenuBar* mb = new wxMenuBar;
mb->Append(m, _("&Simulation"));
m = new wxMenu;
for (int i =0; i < network->n_inputs; i++)
m->Append(MENU_CS+i, wxString::Format(wxT("CS %d"), i));
mb->Append(m, _("Run CS"));
m = new wxMenu;
for (int i =0; i < network->n_inputs; i++)
m->Append(MENU_CSUS+i, wxString::Format(wxT("CS+US %d"), i));
mb->Append(m, _("Train"));
m = new wxMenu;
for (int i =1; i < 5; i++)
m->Append(MENU_INTERSTIM+i, wxString::Format(wxT("Interstim %d hours"), i));
mb->Append(m, _("Interstim"));
wxString mprotos[] = {
wxT("Coallocation Protocol"),
wxT("Capacity Protocol"),
};
m = new wxMenu;
for (size_t i =0; i < 2; i++)
{
m->Append(MENU_PROTO+i, mprotos[i]);
}
mb->Append(m, _("Protocols"));
//SetMenuBar(mb);
//
Connect(wxEVT_TIMER, wxCommandEventHandler(LAWindow::OnTimer));
}
void LAWindow::OnQuit(wxCommandEvent& ev)
{
printf("cleaning up... \n");
this->network->Cleanup();
Close(true);
printf("Done\n");
}
void LAWindow::OnTimer(wxCommandEvent& ev)
{
//printf("Window Timer!\n");
timersRun++;
float angle = this->network_glpanel->angle;
angle += 0.2;
if (angle>360.0) angle =0.;
this->network_glpanel->angle =angle;
this->network_glpanel->Refresh(false);
}
/* Menu handlers */
void LAWindow::OnRun(wxCommandEvent& ev)
{
int id = ev.GetId();
printf("Running %d!\n", id);
SetStatusText(wxString::Format(wxT("Wait, running %d..."), id));
if (id >= MENU_PROTO) // Protocols
{
int n = id - MENU_PROTO;
switch (n)
{
case 0:
{
this->network->CreateFearNet(30, 100, 10, 4);
for (int i =0; i < network->n_inputs; i++)
{
SetStatusText(wxString::Format(wxT("Training # %d..."), i));
//network->Stimulate(i, 2);
int mins = 50;
SetStatusText(wxString::Format(wxT("Waiting %d minutes ..."), mins) );
network->Interstim(mins*60);
}
SetStatusText(wxString::Format(wxT("Waiting 8 Hours...")));
network->Interstim((60*8)*60);
FILE* f = fopen("./data/0/memorytest.dat", "w");
network->enablePlasticity = false;
network->ResetCrebLevels();
for (int i =0; i < network->n_inputs; i++)
{
SetStatusText(wxString::Format(wxT("Testing # %d..."), i));
//network->Stimulate(i, 1);
for (nrn_iter ni = network->pyr_list.begin(); ni != network->pyr_list.end(); ++ni)
{
fprintf(f , "%d ", (*ni)->total_spikes);
}
fprintf(f, "\n");
}
network->enablePlasticity = true;
fclose(f);
f = fopen("./data/0/synweights.txt", "w") ;
for (syn_iter si = network->synapses.begin(); si != network->synapses.end(); ++si)
{
LASynapse* syn = *si;
if (syn->isPlastic != -1)
fprintf(f, "%d %d %d %d %f\n", syn->sid, syn->target_branch->bid, syn->target_nrn->nid, syn->source_nrn->input_id, syn->weight);
}
fclose(f);
}
break;
case 2:
break;
case 3:
break;
case 4:
break;
}
}
else if (id >= MENU_INTERSTIM)
network->Interstim((id - MENU_INTERSTIM)*3600);
SetStatusText(wxT("Done!"));
printf("Done running\n");
}
inline static void colormap1(wxBrush& pen, float value )
{
pen.SetColour(250, 250-value*200, value*200);
}
inline static void colormap1(wxPen& pen, float value )
{
pen.SetColour(value*240.0, 0, 250 - value*200.0);
}
static int palette[][3] = {
{200, 50,50},
{50, 200,50},
{250 , 250,100},
{200, 190,3},
{255,0,255 },
{4, 3,200},
{255,0,0 },
{128,0,0 },
{250, 3,3},
{0,255,0},
{128,128,0},
{200, 190,3},
{0,128,0},
{128,0,128},
{0,255,255},
{0,128,128},
{ 50,50,255 },
{4, 200,3},
};
static wxPoint somap[7] = {
wxPoint(30, 10),
wxPoint(30, 10),
wxPoint(40, 10),
wxPoint(40, 10),
wxPoint(40, 10),
wxPoint(35, 1),
wxPoint(30, 10)
};
static wxColour pyrcolor(150, 200, 150);
static wxColour incolor(200, 100, 100);
static wxColour syncolor(30, 200, 20);
static wxColour eltpcolor(200, 30, 20);
static wxColour calccolor(20, 30, 200);
static wxColour firecolor(255, 30,30);
static wxColour branchfirecolor(250, 100,30);
static wxPen pen;
bool LAApp::OnInit()
{
this->network = new LANetwork();
LANetwork::SetRandomSeed(1980);
this->network->CreateFearNet(20, 20, 10, 6);
LAWindow* window = new LAWindow(wxT("LA Model"), this->network);
window->network = network;
window->timer = new wxTimer(window, 13);
window->timer->Start(30);
MyThread* m_pThread = new MyThread(window);
cout << "Starting thread!!\n"<<endl;
int err;
err = m_pThread->Create();
if (err != wxTHREAD_NO_ERROR)
{
perror("TA");
cout << ("Can't create the thread!") << endl;
printf("Error %d\n", err);
delete m_pThread;
m_pThread = NULL;
}
else
{
err = m_pThread->Run() ;
if ( err != wxTHREAD_NO_ERROR )
{
perror("TA");
cout << ("Can't create the thread!") << endl;
printf("Error %d\n", err);
delete m_pThread;
m_pThread = NULL;
}
}
window->Show(true);
return true;
}
IMPLEMENT_APP(LAApp)
BEGIN_EVENT_TABLE(LAWindow, wxFrame)
EVT_MENU(MENU_RUN, LAWindow::OnRun)
EVT_MENU_RANGE(MENU_CS, MENU_CS+20, LAWindow::OnRun)
//EVT_MENU_RANGE(MENU_CSUS, MENU_CSUS+20, LAWindow::OnRun)
EVT_MENU_RANGE(MENU_INTERSTIM, MENU_INTERSTIM+5, LAWindow::OnRun)
//EVT_MENU_RANGE(MENU_STRONGTRAIN, MENU_STRONGTRAIN, LAWindow::OnRun)
EVT_MENU_RANGE(MENU_PROTO, MENU_PROTO+4, LAWindow::OnRun)
EVT_MENU(MENU_QUIT, LAWindow::OnQuit)
END_EVENT_TABLE()
BEGIN_EVENT_TABLE(LAGLPane, wxGLCanvas)
//EVT_MOTION(BasicGLPane::mouseMoved)
//EVT_LEFT_DOWN(BasicGLPane::mouseDown)
//EVT_LEFT_UP(BasicGLPane::mouseReleased)
//EVT_RIGHT_DOWN(BasicGLPane::rightClick)
//EVT_LEAVE_WINDOW(BasicGLPane::mouseLeftWindow)
//EVT_SIZE(BasicGLPane::resized)
//EVT_KEY_DOWN(BasicGLPane::keyPressed)
//EVT_KEY_UP(BasicGLPane::keyReleased)
//EVT_MOUSEWHEEL(BasicGLPane::mouseWheelMoved)
EVT_PAINT(LAGLPane::render)
END_EVENT_TABLE()
// Vertices and faces of a simple cube to demonstrate 3D render
// source: http://www.opengl.org/resources/code/samples/glut_examples/examples/cube.c
GLfloat v[8][3];
GLint faces[6][4] = { /* Vertex indices for the 6 faces of a cube. */
{0, 1, 2, 3}, {3, 2, 6, 7}, {7, 6, 5, 4},
{4, 5, 1, 0}, {5, 6, 2, 1}, {7, 4, 0, 3} };
GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 2.0}; /* Red diffuse light. */
LAGLPane::LAGLPane(wxFrame* parent, LANetwork* net, int* args) :
wxGLCanvas(parent, wxID_ANY, args, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
{
this->m_context = new wxGLContext(this);
SetBackgroundStyle(wxBG_STYLE_CUSTOM);
m_sphereTexture = 0;
//glClearColor (0.0, 0.0, 0.0, 0.0);
this->m_quadric = gluNewQuadric();
m_network = net;
angle =0;
// To avoid flashing on MSW
this->m_sphereq = gluNewQuadric();
}
LAGLPane::~LAGLPane()
{
delete m_context;
}
void LAGLPane::resized(wxSizeEvent& evt)
{
// wxGLCanvas::OnSize(evt);
Refresh();
}
GLfloat light_position[] = { 2, 2,2,0};
GLfloat light_amb[] = { 0.4,0.4, 0.4 } ;
GLfloat myglfog[] = {0.8, 0.8,1.0 , 1.};
/** Inits the OpenGL viewport for drawing in 3D. */
void LAGLPane::prepare3DViewport(int topleft_x, int topleft_y, int bottomrigth_x, int bottomrigth_y)
{
//glClearColor(0.0, 0.0f, 0.0f, 1.0f); // Black Background
}
/** Inits the OpenGL viewport for drawing in 2D. */
void LAGLPane::prepare2DViewport(int topleft_x, int topleft_y, int bottomrigth_x, int bottomrigth_y)
{
}
int LAGLPane::getWidth()
{
return GetSize().x;
}
int LAGLPane::getHeight()
{
return GetSize().y;
}
void LAdrawNeuron()
{
}
GLUquadricObj* myReusableQuadric = 0;
void LAGLPane::drawPyrNeuron( LANeuron* n)
{
glPushMatrix();
glRotatef(-90, 1,0,0);
float b =n->V/90;
if (b < -0.1) b = -0.1;
if (n->isSpiking)
glColor3f(1.0, 1.0, 1.0);
else
glColor3f(0.5, 0.5+b, 0.5-b);
gluCylinder(this->m_quadric, 0.7, 0.02, 0.9, 16, 16);
gluCylinder(this->m_quadric, 0.05, 0.01, 8.2, 8, 8);
glRotatef(90, 1,0,0);
glTranslatef(0, 1.0, 0);
float ang = 0.;
pthread_mutex_lock(&n->network->synapses_mutex);
for (branch_iter bi = n->branches.begin(); bi != n->branches.end(); ++bi)
{
LABranch* b = *bi;
glTranslatef(0, 0.3, 0);
glPushMatrix();
glRotatef(ang, 0,1,0);
ang+= 55;
glColor3f(0.6, 0.6, 0.6);
glBegin(GL_LINES);
glVertex3f(0, 0, 0);
glVertex3f(0, 0, 2);
glEnd();
for (syn_iter si=b->synapses.begin(); si != b->synapses.end(); ++si)
{
LASynapse* s = *si;
if (s->source_nrn->input_id >=0 && s->source_nrn->input_id < 3 )
{
int iid = s->source_nrn->input_id;
if (s->source_nrn->isSpiking)
glColor3f(255, 255, 255);
else if (s->source_nrn->input_id <0)
{
glColor3f(50, 50, 50);
}
else
{
int* p = palette[iid];
if (s->source_nrn->nid%2)
glColor3f(p[0]/500., p[1]/500., p[2]/500.);
else
glColor3f(p[0]/300., p[1]/300., p[2]/300.);
}
glTranslatef(0.0, 0.0, 0.2);
//glRotatef(-90, 1,0,0);
float height = 0.05 + (0.12*(s->weight/3.0));
gluDisk(this->m_quadric, 0, height, 9, 9);
//gluCylinder(this->m_quadric, 0.03, 0.03, height, 8, 8);
//glRotatef(90, 1,0,0);
}
}
glTranslatef(0, -0.08, 0);
glPopMatrix();
}
pthread_mutex_unlock(&n->network->synapses_mutex);
glPopMatrix();
glFlush();
}
void LAGLPane::render( wxPaintEvent& evt)
{
if(!IsShown()) return;
cout<< "Rendering" <<endl;
if (m_sphereTexture ==0)
{
glEnable(GL_TEXTURE_2D);
m_sphereTexture = raw_texture_load("./texture.raw", 256, 256 );
printf("Loaded texture id %d \n", m_sphereTexture);
}
wxGLCanvas::SetCurrent(*m_context);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//prepare3DViewport(0 ,0,getWidth(), getHeight());
int topleft_x= 0, topleft_y =0;
int bottomrigth_x= getWidth(), bottomrigth_y = getHeight();
glClearColor(0.0, 0.0, 0.0, 1.0f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_BLEND);
glViewport(topleft_x, topleft_y, bottomrigth_x-topleft_x, bottomrigth_y-topleft_y);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float ratio_w_h = (float)(bottomrigth_x-topleft_x)/(float)(bottomrigth_y-topleft_y);
gluPerspective(35 /*view angle*/, ratio_w_h, 0.05 /*clip close*/, 200 /*clip far*/);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_diffuse);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable( GL_POLYGON_SMOOTH );
glHint (GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
glLineWidth(2.0);
//glLightfv(GL_LIGHT0, GL_SPECULAR, light_amb);
glTranslatef(1, -4, -18);
glRotatef( this->angle, 0.0, 1, .05);
glPushMatrix();
glRotatef( 90, 1, 0, 0);
gluQuadricDrawStyle(m_sphereq, GLU_LINE);
glColor3f(0.3, 0.4, 0.5);
gluSphere(m_sphereq, 20.2, 32, 16);
glPopMatrix();
/*
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, m_sphereTexture);
gluSphere(m_sphereq, 1.2, 32, 32);
glDisable(GL_TEXTURE_2D);
*/
if (this->m_network && this->m_network->pyr_list.size())
{
int tot =0;
for (nrn_iter ni = this->m_network->pyr_list.begin(); ni != this->m_network->pyr_list.end(); ++ni)
{
LANeuron* n= *ni;
glPushMatrix();
glTranslatef((tot%4)*6.0 - 9., 0., (tot/4)*6.0 - 9.);
drawPyrNeuron(n);
glPopMatrix();
if (tot++>10) break;
}
}
//glFlush();
SwapBuffers();
}