framework2
678 строк · 18.5 Кб
1
2#include "ofNode.h"3#include "of3dGraphics.h"4
5//----------------------------------------
6ofNode::ofNode()7:parent(nullptr)8,localTransformMatrix(1)9,legacyCustomDrawOverrided(true){10setPosition({0.f, 0.f, 0.f});11setOrientation({0.f, 0.f, 0.f});12setScale(1.f);13position.disableEvents();14scale.disableEvents();15orientation.disableEvents();16}
17
18//----------------------------------------
19ofNode::~ofNode(){20if(parent){21parent->removeListener(*this);22}23
24// clearParent() will remove children of this element as a side-effect.25// This changes the "children", and so we can't use a normal foreach26// loop, but must use the following construction to deal with newly27// invalidated iterators:28while (!children.empty()){29(*children.begin())->clearParent();30}31}
32
33//----------------------------------------
34ofNode::ofNode(const ofNode & node)35:parent(node.parent)36,axis(node.axis)37,localTransformMatrix(node.localTransformMatrix)38,legacyCustomDrawOverrided(true){39if(parent){40parent->addListener(*this);41}42position = node.position;43orientation = node.orientation;44scale = node.scale;45position.disableEvents();46scale.disableEvents();47orientation.disableEvents();48}
49
50//----------------------------------------
51ofNode::ofNode(ofNode && node)52:parent(node.parent)53,position(std::move(node.position))54,orientation(std::move(node.orientation))55,scale(std::move(node.scale))56,axis(std::move(node.axis))57,localTransformMatrix(std::move(node.localTransformMatrix))58,legacyCustomDrawOverrided(std::move(node.legacyCustomDrawOverrided))59,children(std::move(node.children)){60if(parent){61parent->addListener(*this);62}63}
64
65//----------------------------------------
66ofNode & ofNode::operator=(const ofNode & node){67if(this == &node) return *this;68parent = node.parent;69position = node.position;70orientation = node.orientation;71scale = node.scale;72axis = node.axis;73position.disableEvents();74scale.disableEvents();75orientation.disableEvents();76localTransformMatrix = node.localTransformMatrix;77legacyCustomDrawOverrided = true;78if(parent){79parent->addListener(*this);80}81return *this;82}
83
84//----------------------------------------
85ofNode & ofNode::operator=(ofNode && node){86if(this == &node) return *this;87parent = node.parent;88position = std::move(node.position);89orientation = std::move(node.orientation);90scale = std::move(node.scale);91axis = std::move(node.axis);92localTransformMatrix = std::move(node.localTransformMatrix);93legacyCustomDrawOverrided = std::move(node.legacyCustomDrawOverrided);94children = std::move(node.children);95if(parent){96parent->addListener(*this);97}98return *this;99}
100
101//----------------------------------------
102void ofNode::addListener(ofNode & node){103position.addListener(&node, &ofNode::onParentPositionChanged);104orientation.addListener(&node, &ofNode::onParentOrientationChanged);105scale.addListener(&node, &ofNode::onParentScaleChanged);106position.enableEvents();107orientation.enableEvents();108scale.enableEvents();109children.insert(&node);110}
111
112//----------------------------------------
113void ofNode::removeListener(ofNode & node){114position.removeListener(&node, &ofNode::onParentPositionChanged);115orientation.removeListener(&node, &ofNode::onParentOrientationChanged);116scale.removeListener(&node, &ofNode::onParentScaleChanged);117if(position.getNumListeners()==0){118position.disableEvents();119scale.disableEvents();120orientation.disableEvents();121}122children.erase(&node);123}
124
125//----------------------------------------
126void ofNode::setParent(ofNode& parent, bool bMaintainGlobalTransform) {127if (this->parent)128{129// we need to make sure to clear before130// re-assigning parenthood.131clearParent(bMaintainGlobalTransform);132}133if(bMaintainGlobalTransform) {134auto postParentPosition = position - parent.getGlobalPosition();135auto postParentOrientation = orientation.get() * glm::inverse(parent.getGlobalOrientation());136auto postParentScale = scale / parent.getGlobalScale();137parent.addListener(*this);138setOrientation(postParentOrientation);139setPosition(postParentPosition);140setScale(postParentScale);141} else {142parent.addListener(*this);143}144this->parent = &parent;145}
146
147//----------------------------------------
148void ofNode::clearParent(bool bMaintainGlobalTransform) {149if(parent){150parent->removeListener(*this);151}152if(bMaintainGlobalTransform && parent) {153auto orientation = getGlobalOrientation();154auto position = getGlobalPosition();155auto scale = getGlobalScale();156this->parent = nullptr;157setOrientation(orientation);158setPosition(position);159setScale(scale);160}else{161this->parent = nullptr;162}163
164}
165
166//----------------------------------------
167ofNode* ofNode::getParent() const {168return parent;169}
170
171//----------------------------------------
172void ofNode::setPosition(float px, float py, float pz) {173setPosition({px, py, pz});174}
175
176//----------------------------------------
177void ofNode::setPosition(const glm::vec3& p) {178position = p;179createMatrix();180onPositionChanged();181}
182
183//----------------------------------------
184void ofNode::setGlobalPosition(float px, float py, float pz) {185setGlobalPosition({px, py, pz});186}
187
188//----------------------------------------
189void ofNode::setGlobalPosition(const glm::vec3& p) {190if(parent == nullptr) {191setPosition(p);192} else {193auto newP = glm::inverse(parent->getGlobalTransformMatrix()) * glm::vec4(p, 1.0);194setPosition(glm::vec3(newP) / newP.w);195}196}
197
198//----------------------------------------
199glm::vec3 ofNode::getPosition() const {200return position;201}
202
203//----------------------------------------
204float ofNode::getX() const {205return position->x;206}
207
208//----------------------------------------
209float ofNode::getY() const {210return position->y;211}
212
213//----------------------------------------
214float ofNode::getZ() const {215return position->z;216}
217
218//----------------------------------------
219void ofNode::setOrientation(const glm::quat& q) {220orientation = q;221createMatrix();222onOrientationChanged();223}
224
225//----------------------------------------
226void ofNode::setOrientation(const glm::vec3& eulerAngles) {227glm::quat q(glm::radians(eulerAngles));228setOrientation(q);229}
230
231//----------------------------------------
232void ofNode::setGlobalOrientation(const glm::quat& q) {233if(parent == nullptr) {234setOrientation(q);235} else {236auto invParent = glm::inverse(parent->getGlobalOrientation());237auto m44 = invParent * q;238setOrientation(m44);239}240}
241
242//----------------------------------------
243glm::quat ofNode::getOrientationQuat() const {244return orientation;245}
246
247//----------------------------------------
248glm::vec3 ofNode::getOrientationEuler() const {249return getOrientationEulerDeg();250}
251
252//----------------------------------------
253glm::vec3 ofNode::getOrientationEulerDeg() const {254auto euler = glm::eulerAngles(orientation.get());255return {ofRadToDeg(euler.x), ofRadToDeg(euler.y), ofRadToDeg(euler.z)};256}
257
258//----------------------------------------
259glm::vec3 ofNode::getOrientationEulerRad() const {260return glm::eulerAngles(orientation.get());261}
262
263//----------------------------------------
264void ofNode::setScale(float s) {265setScale(s, s, s);266}
267
268//----------------------------------------
269void ofNode::setScale(float sx, float sy, float sz) {270setScale({sx, sy, sz});271}
272
273//----------------------------------------
274void ofNode::setScale(const glm::vec3& s) {275this->scale = s;276createMatrix();277onScaleChanged();278}
279
280//----------------------------------------
281glm::vec3 ofNode::getScale() const {282return scale;283}
284
285//----------------------------------------
286void ofNode::move(float x, float y, float z) {287move({x, y, z});288}
289
290//----------------------------------------
291void ofNode::move(const glm::vec3& offset) {292position += offset;293createMatrix();294onPositionChanged();295}
296
297//----------------------------------------
298void ofNode::truck(float amount) {299move(getXAxis() * amount);300}
301
302//----------------------------------------
303void ofNode::boom(float amount) {304move(getYAxis() * amount);305}
306
307//----------------------------------------
308void ofNode::dolly(float amount) {309move(getZAxis() * amount);310}
311
312//----------------------------------------
313void ofNode::tilt(float degrees) {314rotateDeg(degrees, getXAxis());315}
316
317//----------------------------------------
318void ofNode::pan(float degrees) {319rotateDeg(degrees, getYAxis());320}
321
322//----------------------------------------
323void ofNode::roll(float degrees) {324rotateDeg(degrees, getZAxis());325}
326
327//----------------------------------------
328void ofNode::tiltDeg(float degrees) {329rotateDeg(degrees, getXAxis());330}
331
332//----------------------------------------
333void ofNode::panDeg(float degrees) {334rotateDeg(degrees, getYAxis());335}
336
337//----------------------------------------
338void ofNode::rollDeg(float degrees) {339rotateDeg(degrees, getZAxis());340}
341
342//----------------------------------------
343void ofNode::tiltRad(float radians) {344rotateRad(radians, getXAxis());345}
346
347//----------------------------------------
348void ofNode::panRad(float radians) {349rotateRad(radians, getYAxis());350}
351
352//----------------------------------------
353void ofNode::rollRad(float radians) {354rotateRad(radians, getZAxis());355}
356
357//----------------------------------------
358void ofNode::rotate(const glm::quat& q) {359orientation = q * (const glm::quat&)orientation;360createMatrix();361onOrientationChanged();362}
363
364//----------------------------------------
365void ofNode::rotate(float degrees, const glm::vec3& v) {366rotateDeg(degrees, v);367}
368
369//----------------------------------------
370void ofNode::rotateDeg(float degrees, const glm::vec3& v) {371rotate(glm::angleAxis(ofDegToRad(degrees), v));372}
373
374//----------------------------------------
375void ofNode::rotateRad(float radians, const glm::vec3& v) {376rotate(glm::angleAxis(radians, v));377}
378
379//----------------------------------------
380void ofNode::rotate(float degrees, float vx, float vy, float vz) {381rotateDeg(degrees, vx, vy, vz);382}
383
384//----------------------------------------
385void ofNode::rotateDeg(float degrees, float vx, float vy, float vz) {386rotate(glm::angleAxis(ofDegToRad(degrees), glm::vec3(vx, vy, vz)));387}
388
389//----------------------------------------
390void ofNode::rotateRad(float radians, float vx, float vy, float vz) {391rotate(glm::angleAxis(radians, glm::vec3(vx, vy, vz)));392}
393
394//----------------------------------------
395void ofNode::rotateAround(const glm::quat& q, const glm::vec3& point) {396// ofLogVerbose("ofNode") << "rotateAround(const glm::quat& q, const glm::vec3& point) not implemented yet";397// glm::mat4 m = getLocalTransformMatrix();398// m.setTranslation(point);399// m.rotate(q);400
401setGlobalPosition(q * (getGlobalPosition() - point) + point);402
403onOrientationChanged();404onPositionChanged();405}
406
407//----------------------------------------
408void ofNode::rotateAround(float degrees, const glm::vec3& axis, const glm::vec3& point) {409rotateAroundDeg(degrees, axis, point);410}
411
412//----------------------------------------
413void ofNode::rotateAroundDeg(float degrees, const glm::vec3& axis, const glm::vec3& point) {414rotateAround(glm::angleAxis(ofDegToRad(degrees), axis), point);415}
416
417//----------------------------------------
418void ofNode::rotateAroundRad(float radians, const glm::vec3& axis, const glm::vec3& point) {419rotateAround(glm::angleAxis(radians, axis), point);420}
421
422//----------------------------------------
423void ofNode::lookAt(const glm::vec3& lookAtPosition){424auto relPosition = (getGlobalPosition() - lookAtPosition);425auto radius = glm::length(relPosition);426if(radius>0){427float latitude = acos(relPosition.y / radius) - glm::half_pi<float>();428float longitude = atan2(relPosition.x , relPosition.z);429glm::quat q = glm::angleAxis(0.f, glm::vec3(0,0,1)) * glm::angleAxis(longitude, glm::vec3(0,1,0)) * glm::angleAxis(latitude, glm::vec3(1,0,0));430setGlobalOrientation(q);431}432}
433
434//----------------------------------------
435void ofNode::lookAt(const glm::vec3& lookAtPosition, glm::vec3 upVector) {436if(parent){437auto upVector4 = glm::inverse(parent->getGlobalTransformMatrix()) * glm::vec4(upVector, 1.0);438upVector = glm::vec3(upVector4) / upVector4.w;439}440auto zaxis = glm::normalize(getGlobalPosition() - lookAtPosition);441if (glm::length(zaxis) > 0) {442auto xaxis = glm::normalize(glm::cross(upVector, zaxis));443auto yaxis = glm::cross(zaxis, xaxis);444glm::mat3 m;445m[0] = xaxis;446m[1] = yaxis;447m[2] = zaxis;448
449setGlobalOrientation(glm::toQuat(m));450}451}
452
453//----------------------------------------
454void ofNode::lookAt(const ofNode& lookAtNode){455lookAt(lookAtNode.getGlobalPosition());456}
457
458//----------------------------------------
459void ofNode::lookAt(const ofNode& lookAtNode, const glm::vec3& upVector) {460lookAt(lookAtNode.getGlobalPosition(), upVector);461}
462
463//----------------------------------------
464void ofNode::updateAxis() {465if(scale->x>0) axis[0] = glm::vec3(getLocalTransformMatrix()[0]/scale->x);466if(scale->y>0) axis[1] = glm::vec3(getLocalTransformMatrix()[1]/scale->y);467if(scale->z>0) axis[2] = glm::vec3(getLocalTransformMatrix()[2]/scale->z);468}
469
470//----------------------------------------
471glm::vec3 ofNode::getXAxis() const {472return axis[0];473}
474
475//----------------------------------------
476glm::vec3 ofNode::getYAxis() const {477return axis[1];478}
479
480//----------------------------------------
481glm::vec3 ofNode::getZAxis() const {482return axis[2];483}
484
485//----------------------------------------
486glm::vec3 ofNode::getSideDir() const {487return getXAxis();488}
489
490//----------------------------------------
491glm::vec3 ofNode::getLookAtDir() const {492return -getZAxis();493}
494
495//----------------------------------------
496glm::vec3 ofNode::getUpDir() const {497return getYAxis();498}
499
500//----------------------------------------
501float ofNode::getPitch() const {502return getPitchDeg();503}
504
505//----------------------------------------
506float ofNode::getHeading() const {507return getHeadingDeg();508}
509
510//----------------------------------------
511float ofNode::getRoll() const {512return getRollDeg();513}
514
515//----------------------------------------
516float ofNode::getPitchDeg() const {517return getOrientationEulerDeg().x;518}
519
520//----------------------------------------
521float ofNode::getHeadingDeg() const {522return getOrientationEulerDeg().y;523}
524
525//----------------------------------------
526float ofNode::getRollDeg() const {527return getOrientationEulerDeg().z;528}
529
530//----------------------------------------
531float ofNode::getPitchRad() const {532return getOrientationEulerRad().x;533}
534
535//----------------------------------------
536float ofNode::getHeadingRad() const {537return getOrientationEulerRad().y;538}
539
540//----------------------------------------
541float ofNode::getRollRad() const {542return getOrientationEulerRad().z;543}
544
545//----------------------------------------
546const glm::mat4& ofNode::getLocalTransformMatrix() const {547return localTransformMatrix;548}
549
550//----------------------------------------
551glm::mat4 ofNode::getGlobalTransformMatrix() const {552if(parent) return parent->getGlobalTransformMatrix() * getLocalTransformMatrix();553else return getLocalTransformMatrix();554}
555
556//----------------------------------------
557glm::vec3 ofNode::getGlobalPosition() const {558return glm::vec3(getGlobalTransformMatrix()[3]);559}
560
561//----------------------------------------
562glm::quat ofNode::getGlobalOrientation() const {563if (parent) return parent->getGlobalOrientation() * getOrientationQuat();564return getOrientationQuat();565}
566
567//----------------------------------------
568glm::vec3 ofNode::getGlobalScale() const {569if(parent) return getScale()*parent->getGlobalScale();570else return getScale();571}
572
573//----------------------------------------
574void ofNode::orbit(float longitude, float latitude, float radius, const glm::vec3& centerPoint) {575orbitDeg(longitude, latitude, radius, centerPoint);576}
577
578//----------------------------------------
579void ofNode::orbit(float longitude, float latitude, float radius, ofNode& centerNode) {580orbitDeg(longitude, latitude, radius, centerNode);581}
582
583//----------------------------------------
584void ofNode::orbitDeg(float longitude, float latitude, float radius, ofNode& centerNode) {585orbitDeg(longitude, latitude, radius, centerNode.getGlobalPosition());586}
587
588//----------------------------------------
589void ofNode::orbitDeg(float longitude, float latitude, float radius, const glm::vec3& centerPoint) {590glm::quat q =591glm::angleAxis(ofDegToRad(longitude), glm::vec3(0, 1, 0))592* glm::angleAxis(ofDegToRad(latitude), glm::vec3(1, 0, 0));593
594glm::vec4 p { 0.f, 0.f, 1.f, 0.f }; // p is a direction, not a position, so .w == 0595
596p = q * p; // rotate p on unit sphere based on quaternion597p = p * radius; // scale p by radius from its position on unit sphere598
599setGlobalPosition(centerPoint + p);600setOrientation(q);601
602onOrientationChanged();603onPositionChanged();604}
605
606//----------------------------------------
607void ofNode::orbitRad(float longitude, float latitude, float radius, ofNode& centerNode) {608orbitRad(longitude, latitude, radius, centerNode.getGlobalPosition());609}
610
611//----------------------------------------
612void ofNode::orbitRad(float longitude, float latitude, float radius, const glm::vec3& centerPoint) {613glm::quat q =614glm::angleAxis(longitude, glm::vec3(0, 1, 0))615* glm::angleAxis(latitude, glm::vec3(1, 0, 0));616
617glm::vec4 p { 0.f, 0.f, 1.f, 0.f }; // p is a direction, not a position, so .w == 0618
619p = q * p; // rotate p on unit sphere based on quaternion620p = p * radius; // scale p by radius from its position on unit sphere621
622setGlobalPosition(centerPoint + p);623setOrientation(q);624
625onOrientationChanged();626onPositionChanged();627}
628
629//----------------------------------------
630void ofNode::resetTransform() {631setPosition({0.f,0.f,0.f});632setOrientation({0.f,0.f,0.f});633setScale({1.f,1.f,1.f});634}
635
636//----------------------------------------
637void ofNode::draw() const{638ofGetCurrentRenderer()->draw(*this);639}
640
641//----------------------------------------
642void ofNode::customDraw(const ofBaseRenderer * renderer) const{643const_cast<ofNode*>(this)->customDraw();644if(!legacyCustomDrawOverrided){645renderer->drawBox(10);646renderer->draw(ofMesh::axis(20),OF_MESH_FILL);647}648}
649
650//----------------------------------------
651void ofNode::customDraw(){652legacyCustomDrawOverrided = false;653}
654
655//----------------------------------------
656void ofNode::transformGL(ofBaseRenderer * renderer) const {657if( renderer == nullptr ) {658renderer = ofGetCurrentRenderer().get();659}660renderer->pushMatrix();661renderer->multMatrix( getGlobalTransformMatrix() );662}
663
664//----------------------------------------
665void ofNode::restoreTransformGL(ofBaseRenderer * renderer) const {666if( renderer == nullptr ) {667renderer = ofGetCurrentRenderer().get();668}669renderer->popMatrix();670}
671
672//----------------------------------------
673void ofNode::createMatrix() {674localTransformMatrix = glm::translate(glm::mat4(1.0), toGlm(position));675localTransformMatrix = localTransformMatrix * glm::toMat4((const glm::quat&)orientation);676localTransformMatrix = glm::scale(localTransformMatrix, toGlm(scale));677
678updateAxis();679}
680
681
682