Browse Source

Helpers for caching object transformations.

vectorfields
Vladimír Vondruš 16 years ago
parent
commit
7f817851fa
  1. 23
      src/Object.cpp
  2. 57
      src/Object.h
  3. 23
      src/Test/ObjectTest.cpp
  4. 1
      src/Test/ObjectTest.h

23
src/Object.cpp

@ -41,6 +41,8 @@ void Object::setParent(Object* parent) {
_parent->_children.erase(this); _parent->_children.erase(this);
_parent = parent; _parent = parent;
setDirty();
} }
Matrix4 Object::transformation(bool absolute) { Matrix4 Object::transformation(bool absolute) {
@ -87,4 +89,25 @@ Scene* Object::scene() const {
return 0; return 0;
} }
void Object::setDirty() {
/* The object (and all its children) are already dirty, nothing to do */
if(dirty) return;
dirty = true;
/* Make all children dirty */
for(set<Object*>::iterator it = _children.begin(); it != _children.end(); ++it)
(*it)->setDirty();
}
void Object::setClean() {
/* The object (and all its parents) is already clean, nothing to do */
if(!dirty) return;
dirty = false;
/* Make all parents clean */
if(_parent != 0 && _parent != this) _parent->setClean();
}
} }

57
src/Object.h

@ -45,7 +45,7 @@ class Object {
* *
* Sets all transformations to their default values. * Sets all transformations to their default values.
*/ */
inline Object(Object* parent = 0): _parent(0) { inline Object(Object* parent = 0): _parent(0), dirty(true) {
setParent(parent); setParent(parent);
} }
@ -85,7 +85,10 @@ class Object {
virtual Matrix4 transformation(bool absolute = false); virtual Matrix4 transformation(bool absolute = false);
/** @brief Set transformation matrix */ /** @brief Set transformation matrix */
inline void setTransformation(const Matrix4& transformation) { _transformation = transformation; } inline void setTransformation(const Matrix4& transformation) {
_transformation = transformation;
setDirty();
}
/** /**
* @brief Multiply transformation matrix * @brief Multiply transformation matrix
@ -98,6 +101,7 @@ class Object {
*/ */
inline void multiplyTransformation(const Matrix4& transformation, bool global = true) { inline void multiplyTransformation(const Matrix4& transformation, bool global = true) {
_transformation = global ? transformation*_transformation : _transformation*transformation; _transformation = global ? transformation*_transformation : _transformation*transformation;
setDirty();
} }
/** /**
@ -153,6 +157,54 @@ class Object {
rotate(angle, Vector3(x, y, z), global); rotate(angle, Vector3(x, y, z), global);
} }
/** @{ @name Caching helpers
*
* If the object transformation is used many times when drawing (such
* as e.g. position of light object), it's good to cache these values,
* so they don't have to be computed again on every request.
*
* If the object or any parent is transformed, the transformed object
* and all its children are marked as dirty. If currently active camera
* is transformed, the scene goes through all children and calls
* setDirty() recursively on every clean object (if the object is
* already dirty, it and all its children are skipped, because they are
* dirty too).
*
* These functions are used to manage dirty status of the object. If
* the object doesn't cache anything, it's no need to bother about them,
* but if does, setClean() should be reimplemented and used to
* regenerate the cache. Thus the dirty status is managed only for
* these objects, which are calling setClean().
*/
/**
* @brief Whether the object is dirty
* @return True, if transformation of the object, any parent or camera
* has changed since last asking, false otherwise.
*/
inline bool isDirty() const { return dirty; }
/**
* @brief Set object and all its children as dirty
*
* Recursively calls setDirty() on every child. If the object is already
* marked as dirty, the function does nothing.
* @attention Reimplementations must also call this function!
*/
virtual void setDirty();
/**
* @brief Set object and all its parents as clean
*
* Recursively calls setClean() on every parent. Default implementation
* only marks the object as clean, but if the object does any caching,
* this function should be reimplemented to regenerate the cache.
* @attention Reimplementations must also call this function!
*/
virtual void setClean();
/*@}*/
/** /**
* @brief Draw object * @brief Draw object
* *
@ -164,6 +216,7 @@ class Object {
Object* _parent; Object* _parent;
std::set<Object*> _children; std::set<Object*> _children;
Matrix4 _transformation; Matrix4 _transformation;
bool dirty;
}; };
} }

23
src/Test/ObjectTest.cpp

@ -62,4 +62,27 @@ void ObjectTest::scene() {
QVERIFY(childOfOrphan->scene() == 0); QVERIFY(childOfOrphan->scene() == 0);
} }
void ObjectTest::dirty() {
Scene scene;
Object* childOne = new Object(&scene);
Object* childTwo = new Object(childOne);
Object* childThree = new Object(childTwo);
/* Object is dirty at the beginning */
QVERIFY(childOne->isDirty());
/* Clean the object and all its parents */
childThree->setClean();
QVERIFY(!childThree->isDirty());
QVERIFY(!childTwo->isDirty());
QVERIFY(!childOne->isDirty());
QVERIFY(!scene.isDirty());
/* Mark object and all its children as dirty */
childTwo->setDirty();
QVERIFY(childTwo->isDirty());
QVERIFY(childThree->isDirty());
}
}} }}

1
src/Test/ObjectTest.h

@ -27,6 +27,7 @@ class ObjectTest: public QObject {
private slots: private slots:
void parenting(); void parenting();
void scene(); void scene();
void dirty();
}; };
}} }}

Loading…
Cancel
Save