Files
vb01/node.cpp

526 lines
13 KiB
C++
Executable File

#include "root.h"
#include "bone.h"
#include "mesh.h"
#include "text.h"
#include "util.h"
#include "light.h"
#include "matrix.h"
#include "material.h"
#include "skeleton.h"
#include "shaderAsset.h"
#include "particleEmitter.h"
#include "assetManager.h"
#include "animationController.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, Animatable::Type type) : Animatable(type, name){
this->pos = pos;
this->scale = scale;
this->orientation = orientation;
if(type == Animatable::NONE)
type = Animatable::NODE;
}
Node::~Node(){
for(Mesh *m : meshes)
delete m;
for(Light *l : lights){
removeLight(l);
delete l;
}
for(ParticleEmitter *p : emitters)
delete p;
for(Text *t : texts)
delete t;
for(Node *c : children)
delete c;
}
void Node::update(){
bool render = true;
Node *ancestor = this;
while(ancestor){
render = ancestor->isVisible();
ancestor = ancestor->getParent();
if(!render) break;
}
for(Light *l : lights)
l->update(render);
if(render){
for(Mesh *m : meshes)
m->update();
for(Text *t : texts)
t->update();
for(ParticleEmitter *p : emitters)
p->update();
for(Skeleton *sk : skeletons)
sk->update();
}
for(Driver *driver : drivers)
driver->drive(getDriverValue(driver->getType()));
}
Node* Node::clone(){
vector<Node*> originalDescendants = vector<Node*>{this};
getDescendants(originalDescendants);
int numDescendants = originalDescendants.size();
vector<Node*> clonedDescendants;
for(int i = 0; i < numDescendants; i++){
Node *original = originalDescendants[i];
Bone *originalBone = dynamic_cast<Bone*>(original);
Node *clone = nullptr;
if(originalBone){
Bone *boneClone = new Bone(originalBone->getName(), originalBone->getLength(), originalBone->getPosition(), originalBone->getOrientation(), originalBone->getScale());
boneClone->setIkChainLength(originalBone->getIkChainLength());
boneClone->setIkTarget(originalBone->getIkTarget());
clone = boneClone;
}
else
clone = new Node(original->getPosition(), original->getOrientation(), original->getScale(), original->getName());
for(int j = 0; j < i; j++)
if(original->getParent() == originalDescendants[j]){
clonedDescendants[j]->attachChild(clone);
break;
}
clonedDescendants.push_back(clone);
}
for(int i = 0; i < numDescendants; i++){
Node *original = originalDescendants[i];
for(Skeleton *skel : original->getSkeletons()){
Skeleton *sk = new Skeleton(skel->getAttachableName());
for(Bone *bone : skel->getBones())
for(int j = 0; j < numDescendants; j++)
if(bone == originalDescendants[j]){
sk->addBone(dynamic_cast<Bone*>(clonedDescendants[j]), nullptr);
break;
}
clonedDescendants[i]->addSkeleton(sk);
}
for(Mesh *mesh : original->getMeshes()){
Mesh *m = new Mesh(MeshData(mesh->getMeshBase()));
if(mesh->getMeshBase().fullSkeletonName != "")
for(int j = 0; j < numDescendants; j++)
for(int k = 0; k < clonedDescendants[j]->getNumSkeletons(); k++)
if(
clonedDescendants[j]->getName() == originalDescendants[j]->getName() &&
clonedDescendants[j]->getSkeleton(k)->getAttachableName() == mesh->getMeshBase().fullSkeletonName
){
m->setSkeleton(clonedDescendants[j]->getSkeleton(k));
break;
}
clonedDescendants[i]->attachMesh(m);
}
}
for(int i = 0; i < numDescendants; i++){
for(Driver *driver : originalDescendants[i]->getDrivers()){
Animatable *animatable = nullptr;
for(int j = 0; j < numDescendants; j++){
if(originalDescendants[j] == driver->getAnimatable()){
animatable = clonedDescendants[j];
break;
}
for(int k = 0; k < originalDescendants[j]->getNumMeshes(); k++){
for(int l = 0; l < originalDescendants[j]->getMesh(k)->getMeshBase().numShapeKeys; l++)
if(originalDescendants[j]->getMesh(k)->getShapeKey(l)->name == driver->getAnimatable()->getName()){
animatable = clonedDescendants[j]->getMesh(k)->getShapeKey(l);
break;
}
}
}
Driver *dr = new Driver(animatable, driver->getKeyframeChannel(), driver->getType());
clonedDescendants[i]->addDriver(dr);
}
}
return clonedDescendants[0];
}
float Node::getDriverValue(Driver::VariableType type){
float driverValue;
switch(type){
case Driver::POS_X:
driverValue = pos.x;
break;
case Driver::POS_Y:
driverValue = pos.y;
break;
case Driver::POS_Z:
driverValue = pos.z;
break;
case Driver::ROT_W:
driverValue = orientation.w;
break;
case Driver::ROT_X:
driverValue = orientation.x;
break;
case Driver::ROT_Y:
driverValue = orientation.y;
break;
case Driver::ROT_Z:
driverValue = orientation.z;
break;
case Driver::SCALE_X:
driverValue = scale.x;
break;
case Driver::SCALE_Y:
driverValue = scale.y;
break;
case Driver::SCALE_Z:
driverValue = scale.z;
break;
}
return driverValue;
}
void Node::attachChild(Node *child){
child->setParent(this);
children.push_back(child);
child->updateAxis();
child->onAttached();
}
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->onAttached(this);
}
void Node::addSkeleton(Skeleton *skeleton){
skeleton->onAttached(this);
skeletons.push_back(skeleton);
}
void Node::attachParticleEmitter(ParticleEmitter *emitter){
emitters.push_back(emitter);
emitter->onAttached(this);
}
void Node::addLight(Light *light){
Root::getSingleton()->shiftNumLights(true);
lights.push_back(light);
light->onAttached(this);
updateShaders();
}
void Node::removeLight(Light *light){
for(int i = 0; i < lights.size(); i++)
if(lights[i] == light){
lights.erase(lights.begin() + i);
Root::getSingleton()->shiftNumLights(false);
updateShaders();
break;
}
}
void Node::removeLight(int id){
Root::getSingleton()->shiftNumLights(false);
Light *light = lights[id];
lights.erase(lights.begin() + id);
updateShaders();
}
void Node::addText(Text *text){
texts.push_back(text);
text->onAttached(this);
}
void Node::lookAt(Vector3 newDir, Vector3 newUp){
adjustDir(newDir);
adjustUp(newUp);
}
void Node::lookAt(Vector3 newDir){
adjustDir(newDir);
}
void Node::adjustDir(Vector3 newDir){
float angle = Vector3(0, 0, 1).getAngleBetween(newDir);
Vector3 rotAxis = Vector3(0, 0, 1).cross(newDir).norm();
if(rotAxis == Vector3::VEC_ZERO)
rotAxis = Vector3::VEC_I;
setOrientation(Quaternion(angle, rotAxis));
}
void Node::adjustUp(Vector3 newUp){
Vector3 xDir = orientation * Vector3(1, 0, 0),
yDir = orientation * Vector3(0, 1, 0),
zDir = orientation * Vector3(0, 0, 1);
//newUp = Vector3(newUp.x, newUp.y, 0).norm();
if(newUp != Vector3::VEC_ZERO){
float angle = yDir.getAngleBetween(newUp);
bool forw = (xDir.getAngleBetween(newUp) < PI / 2);
setOrientation(Quaternion(angle * (forw ? -1 : 1), zDir) * orientation);
}
}
void Node::getDescendants(vector<Node*> &descendants){
for(Node *child : getChildren()){
descendants.push_back(child);
if(!child->getChildren().empty())
child->getDescendants(descendants);
}
}
vector<Node*> Node::getAncestors(Node *topAncestor){
vector<Node*> ancestors;
Node *parent = this;
while(parent){
ancestors.push_back(parent);
if(parent == topAncestor)
break;
parent = parent->getParent();
}
return ancestors;
}
void Node::updateAxis(){
Vector3 parGlobalAxis[3]{
parent ? parent->getGlobalAxis(0) : Vector3::VEC_I,
parent ? parent->getGlobalAxis(1) : Vector3::VEC_J,
parent ? parent->getGlobalAxis(2) : Vector3::VEC_K
};
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();
Vector3 origin = Vector3::VEC_ZERO;
while(!ancestors.empty()){
int id = ancestors.size() - 1;
Node *par = ancestors[id]->getParent();
Vector3 parAxis[] = {
par ? par->getGlobalAxis(0) : Vector3::VEC_I,
par ? par->getGlobalAxis(1) : Vector3::VEC_J,
par ? par->getGlobalAxis(2) : Vector3::VEC_K
};
Vector3 p = ancestors[id]->getPosition();
origin = origin + parAxis[0] * p.x + parAxis[1] * p.y+parAxis[2] * p.z;
ancestors.pop_back();
}
return origin + globalAxis[0] * localPos.x + globalAxis[1] * localPos.y + globalAxis[2] * localPos.z;
}
Vector3 Node::globalToLocalPosition(Vector3 globalPos){
Vector3 currentGlobalPos = localToGlobalPosition(Vector3::VEC_ZERO);
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 - currentGlobalPos.x, globalPos.y - currentGlobalPos.y, globalPos.z - currentGlobalPos.z) * mat;
return Vector3(local.x, local.y, local.z);
}
Quaternion Node::adjustRot(Quaternion adjustableRot, bool localToGlobal){
vector<Node*> ancestors = getAncestors();
Quaternion rOrigin = (localToGlobal ? Quaternion::QUAT_W : adjustableRot);
while(!ancestors.empty()){
int id = (localToGlobal ? ancestors.size() - 1 : 0);
Node *node = ancestors[id], *nodePar = node->getParent();
Vector3 parAxis[]{
nodePar ? nodePar->getGlobalAxis(0) : Vector3::VEC_I,
nodePar ? nodePar->getGlobalAxis(1) : Vector3::VEC_J,
nodePar ? nodePar->getGlobalAxis(2) : Vector3::VEC_K
};
Vector3 axis = node->getOrientation().getAxis();
axis = (parAxis[0] * axis.x + parAxis[1] * axis.y + parAxis[2] * axis.z).norm();
float angle = node->getOrientation().getAngle();
if(localToGlobal){
rOrigin = Quaternion(angle, axis) * rOrigin;
ancestors.pop_back();
if(ancestors.empty()){
Vector3 ax = adjustableRot.getAxis();
ax = (globalAxis[0] * ax.x + globalAxis[1] * ax.y + globalAxis[2] * ax.z).norm();
return Quaternion(adjustableRot.getAngle(), ax) * rOrigin;
}
}
else{
rOrigin = rOrigin * Quaternion(angle, axis).conj();
ancestors.pop_back();
if(ancestors.empty())
return rOrigin;
}
}
}
Quaternion Node::localToGlobalOrientation(Quaternion localRot){
return adjustRot(localRot, true);
}
Quaternion Node::globalToLocalOrientation(Quaternion globalRot){
return adjustRot(globalRot, false);
}
Node* Node::findDescendant(string name, bool allDescendants){
vector<Node*> descendants = children;
if(allDescendants){
descendants.clear();
getDescendants(descendants);
}
for(Node *desc : descendants)
if(desc->getName() == name)
return desc;
return nullptr;
}
void Node::updateShaders(){
Root *root = Root::getSingleton();
AssetManager *am = AssetManager::getSingleton();
ShaderAsset *sa = (ShaderAsset*)am->getAsset(root->getLibPath() + "texture.frag");
string shaderStr = sa->shaderString;
int numLights = root->getNumLights();
string str1 = "const int numLights = " + to_string(numLights > 0 ? numLights : 1) + ";";
int a1 = findNthOccurence(shaderStr, "\n", 0);
int a2 = findNthOccurence(shaderStr, "\n", 1);
shaderStr.replace(a1 + 1, a2 - a1 - 1, str1);
string str2 = "const bool checkLights = " + string(numLights > 0 ? "true" : "false") + ";";
a1 = findNthOccurence(shaderStr, "\n", 1);
a2 = findNthOccurence(shaderStr, "\n", 2);
shaderStr.replace(a1 + 1, a2 - a1 - 1, str2);
ShaderAsset sa2(sa->path, shaderStr);
am->editAsset(sa->path, sa2);
}
void Node::setOrientation(Quaternion q){
this->orientation = q;
updateAxis();
}
void Node::animate(float value, KeyframeChannel keyframeChannel){
Vector3 newPos = pos, newScale = scale;
Quaternion newRot = orientation;
switch(keyframeChannel.type){
case KeyframeChannel::POS_X:
newPos.x = value;
break;
case KeyframeChannel::POS_Y:
newPos.y = value;
break;
case KeyframeChannel::POS_Z:
newPos.z = value;
break;
case KeyframeChannel::ROT_W:
newRot.w = value;
break;
case KeyframeChannel::ROT_X:
newRot.x = value;
break;
case KeyframeChannel::ROT_Y:
newRot.y = value;
break;
case KeyframeChannel::ROT_Z:
newRot.z = value;
break;
case KeyframeChannel::SCALE_X:
newScale.x = value;
break;
case KeyframeChannel::SCALE_Y:
newScale.y = value;
break;
case KeyframeChannel::SCALE_Z:
newScale.z = value;
break;
}
setPosition(newPos);
setOrientation(newRot);
setScale(newScale);
}
}