mirror of
https://github.com/devZoGok/vb01.git
synced 2026-08-26 19:43:30 +00:00
310 lines
7.7 KiB
C++
Executable File
310 lines
7.7 KiB
C++
Executable File
#include"root.h"
|
|
#include"node.h"
|
|
#include"mesh.h"
|
|
#include"particleEmitter.h"
|
|
#include"light.h"
|
|
#include"text.h"
|
|
#include"material.h"
|
|
#include"matrix.h"
|
|
#include<glm.hpp>
|
|
#include<glm/gtc/matrix_inverse.hpp>
|
|
|
|
using namespace std;
|
|
using namespace glm;
|
|
|
|
namespace vb01{
|
|
Node::Node(Vector3 pos, Quaternion orientation, Vector3 scale,string name){
|
|
this->pos=pos;
|
|
this->scale=scale;
|
|
this->orientation=orientation;
|
|
this->name=name;
|
|
globalAxis[0]=Vector3::VEC_I;
|
|
globalAxis[1]=Vector3::VEC_J;
|
|
globalAxis[2]=Vector3::VEC_K;
|
|
}
|
|
|
|
Node::~Node(){
|
|
for(Mesh *m : meshes)
|
|
delete m;
|
|
for(Light *l : lights)
|
|
delete l;
|
|
for(ParticleEmitter *p : emitters)
|
|
delete p;
|
|
for(Text *t : texts)
|
|
delete t;
|
|
for(Node *c : children){
|
|
//dettachChild(c);
|
|
delete c;
|
|
}
|
|
}
|
|
|
|
void Node::update(){
|
|
if(visible){
|
|
for(Light *l : lights)
|
|
l->update();
|
|
for(Mesh *m : meshes)
|
|
m->update();
|
|
for(Text *t : texts)
|
|
t->update();
|
|
for(Node *c : children)
|
|
c->update();
|
|
for(ParticleEmitter *p : emitters)
|
|
p->update();
|
|
}
|
|
}
|
|
|
|
void Node::attachChild(Node *child){
|
|
child->setParent(this);
|
|
children.push_back(child);
|
|
child->updateAxis();
|
|
}
|
|
|
|
void Node::dettachChild(Node *child){
|
|
child->setParent(nullptr);
|
|
int id=-1;
|
|
for(int i=0;i<children.size();i++)
|
|
if(children[i]==child){
|
|
id=i;
|
|
break;
|
|
}
|
|
if(id!=-1)
|
|
children.erase(children.begin()+id);
|
|
}
|
|
|
|
void Node::attachMesh(Mesh *mesh){
|
|
meshes.push_back(mesh);
|
|
mesh->setNode(this);
|
|
}
|
|
|
|
void Node::attachParticleEmitter(ParticleEmitter *emitter){
|
|
emitters.push_back(emitter);
|
|
emitter->setNode(this);
|
|
}
|
|
|
|
void Node::addLight(Light *light){
|
|
Root::getSingleton()->numLights++;
|
|
lights.push_back(light);
|
|
light->setNode(this);
|
|
updateShaders();
|
|
}
|
|
|
|
void Node::removeLight(int id){
|
|
Root::getSingleton()->numLights--;
|
|
Light *light=lights[id];
|
|
light->setNode(nullptr);
|
|
lights.erase(lights.begin()+id);
|
|
updateShaders();
|
|
}
|
|
|
|
void Node::addText(Text *text){
|
|
texts.push_back(text);
|
|
text->setNode(this);
|
|
}
|
|
|
|
void Node::lookAt(Vector3 newDir, Vector3 newUp, Node *node){
|
|
adjustDir(newDir, node);
|
|
adjustUp(newUp, node);
|
|
}
|
|
|
|
void Node::lookAt(Vector3 newDir, Node *node){
|
|
adjustDir(newDir, node);
|
|
}
|
|
|
|
void Node::adjustDir(Vector3 newDir, Node *node){
|
|
Vector3 parAxis[]{
|
|
node->getGlobalAxis(0),
|
|
node->getGlobalAxis(1),
|
|
node->getGlobalAxis(2)
|
|
};
|
|
newDir=(parAxis[0]*newDir.x+parAxis[1]*newDir.y+parAxis[2]*newDir.z).norm();
|
|
|
|
float angle=globalAxis[2].getAngleBetween(newDir);
|
|
Vector3 rotAxis=globalAxis[2].cross(newDir).norm();
|
|
if(rotAxis==Vector3::VEC_ZERO)
|
|
rotAxis=globalAxis[1];
|
|
|
|
Quaternion oldRot = node->localToGlobalOrientation(orientation);
|
|
Quaternion newRot = node->globalToLocalOrientation(Quaternion(angle,rotAxis));
|
|
setOrientation(newRot*oldRot);
|
|
}
|
|
|
|
void Node::adjustUp(Vector3 newUp, Node *node){
|
|
Vector3 parAxis[]{
|
|
node->getGlobalAxis(0),
|
|
node->getGlobalAxis(1),
|
|
node->getGlobalAxis(2)
|
|
};
|
|
newUp=(parAxis[0]*newUp.x+parAxis[1]*newUp.y+parAxis[2]*newUp.z).norm();
|
|
|
|
mat3 mat;
|
|
mat[0][0]=globalAxis[0].x;
|
|
mat[1][0]=globalAxis[0].y;
|
|
mat[2][0]=globalAxis[0].z;
|
|
mat[0][1]=globalAxis[1].x;
|
|
mat[1][1]=globalAxis[1].y;
|
|
mat[2][1]=globalAxis[1].z;
|
|
mat[0][2]=globalAxis[2].x;
|
|
mat[1][2]=globalAxis[2].y;
|
|
mat[2][2]=globalAxis[2].z;
|
|
mat=inverse(mat);
|
|
|
|
vec3 nu=vec3(newUp.x,newUp.y,newUp.z)*mat;
|
|
newUp=(globalAxis[0]*nu.x+globalAxis[1]*nu.y).norm();
|
|
float angle=globalAxis[1].getAngleBetween(newUp);
|
|
|
|
Quaternion oldRot = node->localToGlobalOrientation(orientation);
|
|
Quaternion newRot = node->globalToLocalOrientation(Quaternion(angle*(nu.x<0?1:-1),globalAxis[2]));
|
|
setOrientation(newRot*oldRot);
|
|
}
|
|
|
|
void Node::getDescendants(Node *node, vector<Node*> &descendants){
|
|
for(int i=0;i<node->getNumChildren();i++){
|
|
if(node->getChild(i)->getNumChildren()>0)
|
|
getDescendants(node->getChild(i),descendants);
|
|
else
|
|
descendants.push_back(node->getChild(i));
|
|
}
|
|
}
|
|
|
|
vector<Node*> Node::getAncestors(Node *node, Node *topAncestor){
|
|
vector<Node*> ancestors;
|
|
Node *parent = node;
|
|
if(!topAncestor)
|
|
topAncestor = Root::getSingleton()->getRootNode();
|
|
|
|
while(parent){
|
|
ancestors.push_back(parent);
|
|
if(parent == topAncestor)
|
|
break;
|
|
parent = parent->getParent();
|
|
}
|
|
return ancestors;
|
|
}
|
|
|
|
void Node::updateAxis(){
|
|
Vector3 parGlobalAxis[3]{
|
|
parent->getGlobalAxis(0),
|
|
parent->getGlobalAxis(1),
|
|
parent->getGlobalAxis(2)
|
|
};
|
|
|
|
float rotAngle = orientation.getAngle();
|
|
Vector3 rotAxis = orientation.getAxis();
|
|
Vector3 newAxis = (parGlobalAxis[0] * rotAxis.x + parGlobalAxis[1] * rotAxis.y + parGlobalAxis[2] * rotAxis.z).norm();
|
|
Quaternion rotQuat=Quaternion(rotAngle,newAxis);
|
|
|
|
for(int i = 0; i < 3; i++)
|
|
globalAxis[i] = (rotQuat * parGlobalAxis[i]).norm();
|
|
for(Node *ch : children)
|
|
ch->updateAxis();
|
|
}
|
|
|
|
Vector3 Node::localToGlobalPosition(Vector3 localPos){
|
|
vector<Node*> ancestors = getAncestors(this);
|
|
Vector3 origin = Vector3::VEC_ZERO;
|
|
Quaternion quat;
|
|
|
|
adjustPosOrRot(ancestors, origin, quat, true);
|
|
|
|
return origin + globalAxis[0] * localPos.x + globalAxis[1] * localPos.y + globalAxis[2] * localPos.z;
|
|
}
|
|
|
|
Vector3 Node::globalToLocalPosition(Vector3 globalPos){
|
|
mat3 mat;
|
|
mat[0][0]=globalAxis[0].x;
|
|
mat[1][0]=globalAxis[0].y;
|
|
mat[2][0]=globalAxis[0].z;
|
|
mat[0][1]=globalAxis[1].x;
|
|
mat[1][1]=globalAxis[1].y;
|
|
mat[2][1]=globalAxis[1].z;
|
|
mat[0][2]=globalAxis[2].x;
|
|
mat[1][2]=globalAxis[2].y;
|
|
mat[2][2]=globalAxis[2].z;
|
|
mat=inverse(mat);
|
|
|
|
vec3 local = vec3(globalPos.x, globalPos.y, globalPos.z) * mat;
|
|
return Vector3(local.x, local.y, local.z);
|
|
}
|
|
|
|
Quaternion Node::localToGlobalOrientation(Quaternion localRot){
|
|
Vector3 vec;
|
|
Quaternion origin = Quaternion::QUAT_W;
|
|
vector<Node*> ancestors = getAncestors(this);
|
|
|
|
adjustPosOrRot(ancestors, vec, origin, true);
|
|
|
|
return localRot * origin;
|
|
}
|
|
|
|
Quaternion Node::globalToLocalOrientation(Quaternion globalRot){
|
|
Vector3 vec;
|
|
Quaternion origin = globalRot;
|
|
vector<Node*> ancestors = getAncestors(this);
|
|
|
|
adjustPosOrRot(ancestors, vec, origin, false);
|
|
|
|
return origin;
|
|
}
|
|
|
|
void Node::adjustPosOrRot(vector<Node*> ancestors, Vector3 &adjustablePos, Quaternion &adjustableRot, bool localToGlobal){
|
|
Vector3 pOrigin = Vector3::VEC_ZERO;
|
|
Quaternion rOrigin = Quaternion::QUAT_W;
|
|
|
|
while(!ancestors.empty()){
|
|
int id = ancestors.size() - 1;
|
|
Vector3 parAxis[]{
|
|
ancestors[id]->getGlobalAxis(0),
|
|
ancestors[id]->getGlobalAxis(1),
|
|
ancestors[id]->getGlobalAxis(2)
|
|
};
|
|
|
|
Vector3 p = ancestors[id]->getPosition();
|
|
pOrigin = pOrigin + parAxis[0] * p.x + parAxis[1] * p.y + parAxis[2] * p.z;
|
|
|
|
float angle = ancestors[id]->getOrientation().getAngle();
|
|
Vector3 axis = ancestors[id]->getOrientation().getAxis();
|
|
Vector3 rotAxis = (parAxis[0] * axis.x + parAxis[1] * axis.y + parAxis[2] * axis.z).norm();
|
|
|
|
Quaternion o;
|
|
if(localToGlobal){
|
|
o = Quaternion(angle, rotAxis);
|
|
rOrigin = rOrigin * o;
|
|
}
|
|
else{
|
|
o = Quaternion(-angle, rotAxis);
|
|
rOrigin = o * rOrigin;
|
|
}
|
|
|
|
ancestors.pop_back();
|
|
}
|
|
|
|
adjustablePos = pOrigin;
|
|
adjustableRot = rOrigin;
|
|
}
|
|
|
|
void Node::updateShaders(){
|
|
Root *root=Root::getSingleton();
|
|
Node *rootNode=Root::getSingleton()->getRootNode();
|
|
vector<Node*> descendants;
|
|
rootNode->getDescendants(rootNode,descendants);
|
|
descendants.push_back(rootNode);
|
|
for(Node *n : descendants){
|
|
vector<Mesh*> meshes=n->getMeshes();
|
|
for(Mesh *m : meshes){
|
|
Material *mat=m->getMaterial();
|
|
string str="const int numLights="+to_string(root->numLights>0?root->numLights:1)+";";
|
|
|
|
if(mat){
|
|
//mat->getShader()->editShader(true,'=',';',str);
|
|
mat->getShader()->editShader(Shader::FRAGMENT_SHADER,1,str);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Node::setOrientation(Quaternion q){
|
|
this->orientation=q;
|
|
updateAxis();
|
|
}
|
|
}
|