//
// bvh.h
//
#ifndef animation_h
#define animation_h
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
class bvh
{
private:
struct Bone
{
std::string name;
unsigned int id;
float offset[3];
unsigned short n;
std::string channels;
unsigned int hierarchy;
unsigned int parent;
std::vector <unsigned int> children;
bool noRot;
std::vector <float> data;
};
float time;
unsigned int frames;
float frameTime;
std::string load(std::string filename);
unsigned int parent(unsigned int id, unsigned int hierarchy);
void parseHierarchy(std::string str);
void parseMotion(std::string str);
public:
bvh(std::string filename);
~bvh();
bool active;
std::vector <Bone> bone;
void demo();
unsigned int getFrames();
float getFrameTime();
unsigned int play();
void rotate(unsigned int frame, unsigned int id);
void show();
};
#endif
//
// bvh.cpp
//
#include "bvh.h"
#include <GL/freeglut.h>
// https://github.com/BandaiNamcoResearchInc/Bandai-Namco-Research-Motiondataset/find/master
bvh::bvh(std::string filename)
{
this->active = true;
this->time = 0;
std::string doc = this->load(filename);
int p = doc.find("MOTION");
std::string hierarchy = doc.substr(0, p);
std::string motion = doc.substr(p);
this->parseHierarchy(hierarchy);
this->parseMotion(motion);
}
bvh::~bvh()
{
}
void bvh::demo()
{
glPointSize(8);
glLineWidth(3);
for(unsigned int id = 0; id < this->bone.size(); id++)
{
glPushMatrix();
glTranslated(this->bone[id].offset[0], this->bone[id].offset[1], this->bone[id].offset[2]);
this->rotate((unsigned int)time, id);
glBegin(GL_POINTS);
glVertex3f(0, 0, 0);
glEnd();
for(unsigned int k = 0; k < this->bone[id].children.size(); k++)
{
glBegin(GL_LINES);
glVertex3f(0, 0, 0);
glVertex3fv(this->bone[this->bone[id].children[k]].offset);
glEnd();
glBegin(GL_POINTS);
glVertex3fv(this->bone[this->bone[id].children[k]].offset);
glEnd();
}
int u = -1;
if(id == this->bone.size() - 1)
{
u = this->bone[id].hierarchy;
}
else
{
u = this->bone[id].hierarchy - this->bone[id + 1].hierarchy;
}
if(u > 0)
{
for(unsigned int k = 0; k < (unsigned int)u + 1; k++)
{
glPopMatrix();
}
}
}
this->play();
}
unsigned int bvh::getFrames()
{
return this->frames;
}
float bvh::getFrameTime()
{
return this->frameTime;
}
std::string bvh::load(std::string filename)
{
std::ifstream in;
in.open(filename, std::ios::in);
if(in.is_open())
{
std::string s, tp;
while(!in.eof())
{
getline(in, s);
tp += s + "\n";
}
in.close();
return tp;
}
else
{
in.close();
std::cout << "file: " << filename << " not found. ERROR\n";
system("pause");
exit(0);
}
}
unsigned int bvh::parent(unsigned int id, unsigned int hierarchy)
{
unsigned int i = id - 1;
while(this->bone[i].hierarchy != hierarchy - 1) // si risale nel vettore finchè l'elemento di gerarchia hierarchy non incontra un elemento di gerarchia hierarchy - 1
{
i--;
}
return i;
}
void bvh::parseHierarchy(std::string str)
{
std::string row;
unsigned int id = 0, hierarchy = 0;
Bone current;
bool h = true;
while(h)
{
int line_feed = str.find("\n");
if(line_feed != -1) // finchè il documento ha una nuova riga
{
row = str.substr(0, line_feed);
if(row.find("ROOT") != -1)
{
current.name = row.substr(row.find("ROOT") + 5); // viene ricavato il nome del primo elemento della gerarchia
current.id = id;
current.hierarchy = hierarchy;
current.noRot = false;
id++;
}
else if(row.find("{") != -1)
{
}
else if(row.find("OFFSET") != -1)
{
std::string s = row.substr(row.find("OFFSET") + 7); // vengono estrapolati i 3 valori dell'offset
current.offset[0] = atof(s.substr(0, s.find(" ")).c_str());
s = s.substr(s.find(" ") + 1);
current.offset[1] = atof(s.substr(0, s.find(" ")).c_str());
s = s.substr(s.find(" ") + 1);
current.offset[2] = atof(s.substr(0, s.find(" ")).c_str());
}
else if(row.find("CHANNELS") != -1)
{
std::string s = row.substr(row.find("CHANNELS") + 9);
unsigned short n = atoi(s.substr(0, s.find(" ")).c_str()); // numero di canali (3 o 6)
s = s.substr(s.find(" ") + 1);
if(n == 6)
{
s = s.substr(30); // salta le stringhe XYZposition
}
current.n = n; // viene salvato anche il numero di canali
current.channels += s[0]; // la stringa channels contiene l'ordine di rotazione
s = s.substr(10);
current.channels += s[0];
s = s.substr(10);
current.channels += s[0];
}
else if(row.find("JOINT") != -1)
{
this->bone.push_back(current);
std::string s = row.substr(row.find("JOINT") + 6);
current.name = s;
current.id = id;
current.channels = "";
hierarchy++;
current.hierarchy = hierarchy;
current.noRot = false;
current.parent = this->parent(id, hierarchy);
id++;
}
else if(row.find("End Site") != -1)
{
this->bone.push_back(current);
current.name = "End Site";
current.id = id;
current.channels = "";
hierarchy++;
current.hierarchy = hierarchy;
current.noRot = true;
current.parent = this->parent(id, hierarchy);
id++;
}
else if(row.find("}") != -1)
{
hierarchy--;
}
str = str.substr(line_feed + 1); // viene eliminata la riga appena letta
}
else // arrivato alla fine del documento
{
this->bone.push_back(current); // viene salvato il dato corrente
for(unsigned int id = 1; id < this->bone.size(); id++) // ricava i figli di ogni elemento
{
this->bone[this->bone[id].parent].children.push_back(id);
}
h = false; // e chiuso il ciclo
}
}
}
void bvh::parseMotion(std::string str)
{
int line_feed = str.find("\n");
str = str.substr(line_feed + 1); // viene eliminata la riga MOTION
//
line_feed = str.find("\n");
std::string row = str.substr(0, line_feed); // viene letta la riga Frames
std::string s = row.substr(row.find("Frames:") + 8);
this->frames = atoi(s.c_str());
str = str.substr(line_feed + 1); // viene eliminata la riga Frames
//
line_feed = str.find("\n");
row = str.substr(0, line_feed); // viene letta la riga Frame Time
s = row.substr(row.find("Frame Time:") + 12);
this->frameTime = atof(s.c_str());
str = str.substr(line_feed + 1); // viene eliminata la riga Frame Time
//
for(unsigned int i = 0; i < this->frames; i++)
{
line_feed = str.find("\n");
row = str.substr(0, line_feed);
for(unsigned int j = 0; j < this->bone.size(); j++) // per ogni elemento
{
if(!this->bone[j].noRot) // solo gli elementi che presentano dati di rotazione
{
if(this->bone[j].n == 6) //
{
for(unsigned short k = 0; k < 3; k++)
{
row = row.substr(row.find(" ") + 1); // sono ignorate le traslazioni
}
}
for(unsigned short k = 0; k < 3; k++) // vengono salvati solo i dati delle rotazioni
{
s = row.substr(0, row.find(" "));
this->bone[j].data.push_back(atof(s.c_str()));
row = row.substr(row.find(" ") + 1);
}
}
}
str = str.substr(line_feed + 1); // elimina la riga letta e passa alla successiva
}
}
unsigned int bvh::play()
{
this->time += .5;
if(this->time > (this->frames - 1))
{
this->time = 0;
}
return (unsigned int) this->time;
}
void bvh::rotate(unsigned int frame, unsigned int id)
{
if(this->active)
{
if(id < this->bone.size()) // la rotazione si applica solo alle ossa contenute nel vettore
{
if(frame > this->frames - 1) // se viene inserito un frame oltre il limite viene richiamato il frame corrispondente
{
frame = frame % this->frames;
}
std::string p = this->bone[id].channels;
if(p == "XYZ")
{
glRotated(this->bone[id].data[frame * 3 ], 1, 0, 0);
glRotated(this->bone[id].data[frame * 3 + 1], 0, 1, 0);
glRotated(this->bone[id].data[frame * 3 + 2], 0, 0, 1);
}
else if(p == "XZY")
{
glRotated(this->bone[id].data[frame * 3 ], 1, 0, 0);
glRotated(this->bone[id].data[frame * 3 + 1], 0, 0, 1);
glRotated(this->bone[id].data[frame * 3 + 2], 0, 1, 0);
}
else if(p == "YXZ")
{
glRotated(this->bone[id].data[frame * 3 ], 0, 1, 0);
glRotated(this->bone[id].data[frame * 3 + 1], 1, 0, 0);
glRotated(this->bone[id].data[frame * 3 + 2], 0, 0, 1);
}
else if(p == "YZX")
{
glRotated(this->bone[id].data[frame * 3 ], 0, 1, 0);
glRotated(this->bone[id].data[frame * 3 + 1], 0, 0, 1);
glRotated(this->bone[id].data[frame * 3 + 2], 1, 0, 0);
}
else if(p == "ZXY")
{
glRotated(this->bone[id].data[frame * 3 ], 0, 0, 1);
glRotated(this->bone[id].data[frame * 3 + 1], 1, 0, 0);
glRotated(this->bone[id].data[frame * 3 + 2], 0, 1, 0);
}
else if(p == "ZYX")
{
glRotated(this->bone[id].data[frame * 3 ], 0, 0, 1);
glRotated(this->bone[id].data[frame * 3 + 1], 0, 1, 0);
glRotated(this->bone[id].data[frame * 3 + 2], 1, 0, 0);
}
}
else
{
std::cout << "ERROR: bone over size in rotate method...\n";
system("pause");
exit(0);
}
}
}
void bvh::show()
{
for(unsigned int i = 0; i < this->bone.size(); i++)
{
std::cout << "id : " << this->bone[i].id << "\n";
std::cout << "name : " << this->bone[i].name << "\n";
std::cout << "hierarchy : " << this->bone[i].hierarchy << "\n";
if(i > 0)
{
std::cout << "parent : " << this->bone[this->bone[i].parent].name << "\n";
}
else
{
std::cout << "parent :\n";
}
std::cout << "children : "; for(unsigned int k = 0; k < this->bone[i].children.size(); k++){std::cout << this->bone[i].children[k] << " ";} std::cout << "\n";
std::cout << "offset : " << this->bone[i].offset[0] << " " << this->bone[i].offset[1] << " " << this->bone[i].offset[2] << "\n";
std::cout << "n channels : " << this->bone[i].n << "\n";
std::cout << "channels : " << this->bone[i].channels << "\n";
std::cout << "\n";
}
system("pause");
}
// main.cpp
#include <GL/freeglut.h>
#include <stdlib.h>
#include <fstream>
#include <iostream>
#include <string>
#include "bvh.h"
int TIME = 0;
unsigned int f = 0;
const float CAMERA_DISTANCE = 10.0f;
int screenWidth;
int screenHeight;
bool mouseLeftDown;
bool mouseRightDown;
bool mouseMiddleDown;
float mouseX, mouseY;
float cameraAngleX;
float cameraAngleY;
float cameraDistance;
bvh *myBvh;
void resizeCallback(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLfloat)(width)/(GLfloat)(height), 0.1f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void boneX(float y, float z, float t)
{
float A[3] = {0, y/2.0f,-z/2.0f};
float B[3] = {0, y/2.0f, z/2.0f};
float C[3] = {0,-y/2.0f, z/2.0f};
float D[3] = {0,-y/2.0f,-z/2.0f};
float E[3] = {t, y/2.0f, z/2.0f};
float F[3] = {t, y/2.0f,-z/2.0f};
float G[3] = {t,-y/2.0f,-z/2.0f};
float H[3] = {t,-y/2.0f, z/2.0f};
glBegin(GL_QUADS);
glVertex3fv(A); glVertex3fv(B); glVertex3fv(C); glVertex3fv(D);
glVertex3fv(E); glVertex3fv(F); glVertex3fv(G); glVertex3fv(H);
glVertex3fv(B); glVertex3fv(E); glVertex3fv(H); glVertex3fv(C);
glVertex3fv(F); glVertex3fv(A); glVertex3fv(D); glVertex3fv(G);
glVertex3fv(A); glVertex3fv(F); glVertex3fv(E); glVertex3fv(B);
glVertex3fv(D); glVertex3fv(C); glVertex3fv(H); glVertex3fv(G);
glEnd();
}
void boneY(float x, float z, float t)
{
float A[3] = { x/2.0f, 0,-z/2.0f};
float B[3] = { x/2.0f, 0, z/2.0f};
float C[3] = {-x/2.0f, 0, z/2.0f};
float D[3] = {-x/2.0f, 0,-z/2.0f};
float E[3] = { x/2.0f, t, z/2.0f};
float F[3] = { x/2.0f, t,-z/2.0f};
float G[3] = {-x/2.0f, t,-z/2.0f};
float H[3] = {-x/2.0f, t, z/2.0f};
glBegin(GL_QUADS);
glVertex3fv(A); glVertex3fv(B); glVertex3fv(C); glVertex3fv(D);
glVertex3fv(E); glVertex3fv(F); glVertex3fv(G); glVertex3fv(H);
glVertex3fv(B); glVertex3fv(E); glVertex3fv(H); glVertex3fv(C);
glVertex3fv(F); glVertex3fv(A); glVertex3fv(D); glVertex3fv(G);
glVertex3fv(A); glVertex3fv(F); glVertex3fv(E); glVertex3fv(B);
glVertex3fv(D); glVertex3fv(C); glVertex3fv(H); glVertex3fv(G);
glEnd();
}
void boneZ(float x, float y, float t)
{
float A[3] = { x/2.0f,-y/2.0f, 0};
float B[3] = { x/2.0f, y/2.0f, 0};
float C[3] = {-x/2.0f, y/2.0f, 0};
float D[3] = {-x/2.0f,-y/2.0f, 0};
float E[3] = { x/2.0f, y/2.0f, t};
float F[3] = { x/2.0f,-y/2.0f, t};
float G[3] = {-x/2.0f,-y/2.0f, t};
float H[3] = {-x/2.0f, y/2.0f, t};
glBegin(GL_QUADS);
glVertex3fv(A); glVertex3fv(B); glVertex3fv(C); glVertex3fv(D);
glVertex3fv(E); glVertex3fv(F); glVertex3fv(G); glVertex3fv(H);
glVertex3fv(B); glVertex3fv(E); glVertex3fv(H); glVertex3fv(C);
glVertex3fv(F); glVertex3fv(A); glVertex3fv(D); glVertex3fv(G);
glVertex3fv(A); glVertex3fv(F); glVertex3fv(E); glVertex3fv(B);
glVertex3fv(D); glVertex3fv(C); glVertex3fv(H); glVertex3fv(G);
glEnd();
}
void axis()
{
glLineWidth(1);
glPushMatrix();
glBegin(GL_LINES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(200.0f, 0.0f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(0.0f, 200.0f, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 0.0f); glVertex3f(0.0f, 0.0f, 200.0f);
glColor3f(1.0f, 1.0f, 1.0f);
glEnd();
glPopMatrix();
}
void shapeBandai()
{
glPushMatrix();
myBvh->rotate(f, 1);
boneX(20,10,-10); // bacino
glPushMatrix();
myBvh->rotate(f, 2);
boneX(10,15,20); // addome
glPushMatrix();
glTranslated(20,0,0);
myBvh->rotate(f, 3);
boneX(10,30,15); // petto
glPushMatrix();
glTranslated(15,0,10);
myBvh->rotate(f, 7);
boneX(10,10,10); // spalla sx
glPushMatrix();
glTranslated(10,0,0);
myBvh->rotate(f, 8);
boneX(10,10,30); // braccio sx
glPushMatrix();
glTranslated(30,0,0);
myBvh->rotate(f, 9);
boneX(10,10,30); // avambraccio sx
glPushMatrix();
glTranslated(30,0,0);
myBvh->rotate(f, 10);
boneX(5,5,10); // mano sx
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPushMatrix();
glTranslated(15,0,-10);
myBvh->rotate(f, 12);
boneX(10,10,-10); // spalla dx
glPushMatrix();
glTranslated(-10,0,0);
myBvh->rotate(f, 13);
boneX(10,10,-30); // braccio dx
glPushMatrix();
glTranslated(-30,0,0);
myBvh->rotate(f, 14);
boneX(10,10,-30); // avambraccio dx
glPushMatrix();
glTranslated(-30,0,0);
myBvh->rotate(f, 15);
boneX(5,5,-10); // mano dx
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPushMatrix();
glTranslated(15,0,0);
myBvh->rotate(f, 4);
boneX(8,8,5); // collo
glPushMatrix();
glTranslated(5,0,0);
myBvh->rotate(f, 5);
boneX(10,10,10); // testa
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPushMatrix();
glTranslated(-10,5,0);
myBvh->rotate(f, 22);
boneX(10,10,-50); // gamba dx
glPushMatrix();
glTranslated(-50,0,0);
myBvh->rotate(f, 23);
boneX(10,10,-50); // tibia dx
glPushMatrix();
glTranslated(-50,0,0);
myBvh->rotate(f, 24);
boneX(5,5,-10); // piede dx
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPushMatrix();
glTranslated(-10,-5,0);
myBvh->rotate(f, 17);
boneX(10,10,50); // gamba dx
glPushMatrix();
glTranslated(50,0,0);
myBvh->rotate(f, 18);
boneX(10,10,50); // tibia dx
glPushMatrix();
glTranslated(50,0,0);
myBvh->rotate(f, 24);
boneX(5,5,10); // piede dx
glPopMatrix();
glPopMatrix();
glPopMatrix();
glPopMatrix();
f = myBvh->play();
}
void displayCallback()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glPushMatrix();
glTranslatef(0, 0, -cameraDistance);
glRotatef(cameraAngleX, 1, 0, 0);
glRotatef(cameraAngleY, 0, 1, 0);
axis();
//myBvh->demo();
shapeBandai();
glPopMatrix();
glutSwapBuffers();
}
std::string readText(std::string filename)
{
std::fstream file;
file.open(filename, std::ios::in);
std::string r;
if(file.is_open())
{
getline(file, r);
file.close();
}
return r;
}
void init()
{
mouseLeftDown = mouseRightDown = mouseMiddleDown = false;
mouseX = mouseY = 0;
cameraAngleX = cameraAngleY = 0.0f;
cameraDistance = CAMERA_DISTANCE;
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
myBvh = new bvh(readText("test.txt"));
}
void mouseCallback(int button, int state, int x, int y)
{
mouseX = x; mouseY = y;
if(button == GLUT_LEFT_BUTTON)
{
if(state == GLUT_DOWN)
{
mouseLeftDown = true;
}
else if(state == GLUT_UP)
{
mouseLeftDown = false;
}
}
else if(button == GLUT_RIGHT_BUTTON)
{
if(state == GLUT_DOWN)
{
mouseRightDown = true;
}
else if(state == GLUT_UP)
{
mouseRightDown = false;
}
}
else if(button == GLUT_MIDDLE_BUTTON)
{
if(state == GLUT_DOWN)
{
mouseMiddleDown = true;
}
else if(state == GLUT_UP)
{
mouseMiddleDown = false;
}
}
}
void mouseMotionCallback(int x, int y)
{
if(mouseLeftDown)
{
cameraAngleY += (x - mouseX);
cameraAngleX += (y - mouseY);
mouseX = x;
mouseY = y;
}
if(mouseRightDown)
{
cameraDistance -= (y - mouseY) * 0.2f;
mouseY = y;
}
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(0, 0);
glutInitWindowSize(640, 480);
glutCreateWindow("bvh");
glutDisplayFunc(displayCallback);
glutReshapeFunc(resizeCallback);
glutIdleFunc(displayCallback);
glutMouseFunc(mouseCallback);
glutMotionFunc(mouseMotionCallback);
init();
glutMainLoop();
return 1;
}
Mi chiamo Cosimo Saccone e sono un programmatore napoletano di 44 anni con oltre 35 anni di esperienza nella programmazione (BASIC, Assembly). Realizzo progetti e programmi utilizzando i principali e più diffusi linguaggi (C, C++, PHP, Javascript, HTML) e software per la grafica (Photoshop, Illustrator, 3dsMax). Anche se la grafica rappresenta il mio principale settore di interesse, non disdegno il lavoro di back-end e di organizzazione dati e sono attento agli aspetti di efficienza e di risparmio delle risorse tipica della programmazione di basso livello (specie nel settore della grafica 3d). Realizzo siti internet, applicativi desktop e servizi di vario tipo. Ho una buona conoscenza della libreria OpenGL per lo sviluppo di applicazioni 3d interattive in C/C++. Cerco di adottare uno stile di programmazione fortemente ordinato e modulare. Possiedo, inoltre, una buona capacità di elaborazione della documentazione. Ho vari hobbies tra cui la pittura, la ginnastica e le lunghe passeggiate in solitudine.
Al fine di migliorare l’esperienza di navigazione sul nostro sito noi di cosimosaccone.com e i nostri partner selezionati elaboriamo i dati personali, compreso l’indirizzo IP e le pagine visitate, in relazione alla tua navigazione nei contenuti del sito, per i seguenti scopi:
Accesso alle informazioni
Dati precisi di geolocalizzazione
Misurazione del pubblico
Pubblicità e contenuti personalizzati
Ti ricordiamo che il termine cookie si riferisce a una porzione di dati inviati al tuo browser da un web server. Il cookie viene memorizzato sul tuo dispositivo e riconosciuto dal sito web che lo ha inviato in ogni navigazione successiva. Se vuoi saperne di più e compiere una scelta diversa, come il rifiuto del trattamento dei tuoi dati personali, clicca qui sulla nostra privacy policy. Potrai sempre modificare le tue scelte e impostare i singolo cookies selezionando il bottone qui sotto.
OK