[802] | 1 | /* |
---|
| 2 | * ORXONOX - the hottest 3D action shooter ever to exist |
---|
| 3 | * |
---|
| 4 | * |
---|
| 5 | * License notice: |
---|
| 6 | * |
---|
| 7 | * This program is free software; you can redistribute it and/or |
---|
| 8 | * modify it under the terms of the GNU General Public License |
---|
| 9 | * as published by the Free Software Foundation; either version 2 |
---|
| 10 | * of the License, or (at your option) any later version. |
---|
| 11 | * |
---|
| 12 | * This program is distributed in the hope that it will be useful, |
---|
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 15 | * GNU General Public License for more details. |
---|
| 16 | * |
---|
| 17 | * You should have received a copy of the GNU General Public License |
---|
| 18 | * along with this program; if not, write to the Free Software |
---|
| 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
---|
| 20 | * |
---|
| 21 | * Author: |
---|
| 22 | * Fabian 'x3n' Landau |
---|
| 23 | * Co-authors: |
---|
| 24 | * ... |
---|
| 25 | * |
---|
| 26 | */ |
---|
| 27 | |
---|
| 28 | #include "ClassTreeMask.h" |
---|
| 29 | #include "Identifier.h" |
---|
| 30 | #include "BaseObject.h" |
---|
| 31 | |
---|
| 32 | namespace orxonox |
---|
| 33 | { |
---|
| 34 | // ############################### |
---|
| 35 | // ### ClassTreeMaskNode ### |
---|
| 36 | // ############################### |
---|
| 37 | ClassTreeMaskNode::ClassTreeMaskNode(const Identifier* subclass, bool bIncluded) |
---|
| 38 | { |
---|
| 39 | this->subclass_ = subclass; |
---|
| 40 | this->bIncluded_ = bIncluded; |
---|
| 41 | } |
---|
| 42 | |
---|
| 43 | ClassTreeMaskNode::~ClassTreeMaskNode() |
---|
| 44 | { |
---|
| 45 | for (std::list<ClassTreeMaskNode*>::iterator it = this->subnodes_.begin(); it != this->subnodes_.end(); ) |
---|
| 46 | delete (*(it++)); |
---|
| 47 | } |
---|
| 48 | |
---|
| 49 | void ClassTreeMaskNode::include() |
---|
| 50 | { |
---|
| 51 | this->bIncluded_ = true; |
---|
| 52 | } |
---|
| 53 | |
---|
| 54 | void ClassTreeMaskNode::exclude() |
---|
| 55 | { |
---|
| 56 | this->bIncluded_ = false; |
---|
| 57 | } |
---|
| 58 | |
---|
| 59 | void ClassTreeMaskNode::setIncluded(bool bIncluded) |
---|
| 60 | { |
---|
| 61 | this->bIncluded_ = bIncluded; |
---|
| 62 | } |
---|
| 63 | |
---|
| 64 | void ClassTreeMaskNode::addSubnode(ClassTreeMaskNode* subnode) |
---|
| 65 | { |
---|
| 66 | this->subnodes_.insert(this->subnodes_.end(), subnode); |
---|
| 67 | } |
---|
| 68 | |
---|
| 69 | bool ClassTreeMaskNode::isIncluded() const |
---|
| 70 | { |
---|
| 71 | return this->bIncluded_; |
---|
| 72 | } |
---|
| 73 | |
---|
| 74 | bool ClassTreeMaskNode::isExcluded() const |
---|
| 75 | { |
---|
| 76 | return (!this->bIncluded_); |
---|
| 77 | } |
---|
| 78 | |
---|
| 79 | const Identifier* ClassTreeMaskNode::getClass() const |
---|
| 80 | { |
---|
| 81 | return this->subclass_; |
---|
| 82 | } |
---|
| 83 | |
---|
| 84 | |
---|
| 85 | // ############################### |
---|
[803] | 86 | // ### ClassTreeMaskIterator ### |
---|
| 87 | // ############################### |
---|
| 88 | ClassTreeMaskIterator::ClassTreeMaskIterator(ClassTreeMaskNode* node) |
---|
| 89 | { |
---|
[807] | 90 | std::list<ClassTreeMaskNode*>::iterator it = this->rootlist_.insert(this->rootlist_.end(), node); |
---|
| 91 | this->nodes_.push(std::pair<std::list<ClassTreeMaskNode*>::iterator, std::list<ClassTreeMaskNode*>::iterator>(it, this->rootlist_.end())); |
---|
[803] | 92 | } |
---|
| 93 | |
---|
| 94 | ClassTreeMaskIterator::~ClassTreeMaskIterator() |
---|
| 95 | { |
---|
| 96 | } |
---|
| 97 | |
---|
| 98 | ClassTreeMaskIterator& ClassTreeMaskIterator::operator++() |
---|
| 99 | { |
---|
| 100 | if ((*this->nodes_.top().first)->subnodes_.begin() != (*this->nodes_.top().first)->subnodes_.end()) |
---|
| 101 | this->nodes_.push(std::pair<std::list<ClassTreeMaskNode*>::iterator, std::list<ClassTreeMaskNode*>::iterator>((*this->nodes_.top().first)->subnodes_.begin(), (*this->nodes_.top().first)->subnodes_.end())); |
---|
| 102 | else |
---|
| 103 | { |
---|
| 104 | do |
---|
| 105 | { |
---|
| 106 | ++this->nodes_.top().first; |
---|
| 107 | if (this->nodes_.top().first == this->nodes_.top().second) |
---|
| 108 | { |
---|
| 109 | this->nodes_.pop(); |
---|
| 110 | continue; |
---|
| 111 | } |
---|
| 112 | |
---|
| 113 | break; |
---|
| 114 | } while (!this->nodes_.empty()); |
---|
| 115 | } |
---|
| 116 | |
---|
| 117 | return *this; |
---|
| 118 | } |
---|
| 119 | |
---|
| 120 | ClassTreeMaskNode* ClassTreeMaskIterator::operator*() const |
---|
| 121 | { |
---|
| 122 | return (*this->nodes_.top().first); |
---|
| 123 | } |
---|
| 124 | |
---|
| 125 | ClassTreeMaskNode* ClassTreeMaskIterator::operator->() const |
---|
| 126 | { |
---|
| 127 | return (*this->nodes_.top().first); |
---|
| 128 | } |
---|
| 129 | |
---|
| 130 | ClassTreeMaskIterator::operator bool() |
---|
| 131 | { |
---|
| 132 | return (!this->nodes_.empty()); |
---|
| 133 | } |
---|
| 134 | |
---|
| 135 | bool ClassTreeMaskIterator::operator==(ClassTreeMaskNode* compare) |
---|
| 136 | { |
---|
| 137 | if (!this->nodes_.empty()) |
---|
| 138 | return ((*this->nodes_.top().first) == compare); |
---|
| 139 | else |
---|
| 140 | return (compare == 0); |
---|
| 141 | } |
---|
| 142 | |
---|
| 143 | bool ClassTreeMaskIterator::operator!=(ClassTreeMaskNode* compare) |
---|
| 144 | { |
---|
| 145 | if (!this->nodes_.empty()) |
---|
| 146 | return ((*this->nodes_.top().first) != compare); |
---|
| 147 | else |
---|
| 148 | return (compare != 0); |
---|
| 149 | } |
---|
| 150 | |
---|
| 151 | |
---|
| 152 | // ############################### |
---|
[802] | 153 | // ### ClassTreeMask ### |
---|
| 154 | // ############################### |
---|
| 155 | ClassTreeMask::ClassTreeMask() |
---|
| 156 | { |
---|
[805] | 157 | this->root_ = new ClassTreeMaskNode(ClassManager<BaseObject>::getIdentifier("BaseObject"), true); |
---|
[802] | 158 | } |
---|
| 159 | |
---|
[807] | 160 | ClassTreeMask::ClassTreeMask(const ClassTreeMask& other) |
---|
| 161 | { |
---|
| 162 | this->root_ = new ClassTreeMaskNode(ClassManager<BaseObject>::getIdentifier("BaseObject"), true); |
---|
| 163 | for (ClassTreeMaskIterator it = other.root_; it; ++it) |
---|
| 164 | this->add(it->getClass(), it->isIncluded()); |
---|
| 165 | } |
---|
| 166 | |
---|
[802] | 167 | ClassTreeMask::~ClassTreeMask() |
---|
| 168 | { |
---|
| 169 | delete this->root_; |
---|
| 170 | } |
---|
| 171 | |
---|
| 172 | void ClassTreeMask::include(const Identifier* subclass) |
---|
| 173 | { |
---|
| 174 | this->add(subclass, true); |
---|
| 175 | } |
---|
| 176 | |
---|
| 177 | void ClassTreeMask::exclude(const Identifier* subclass) |
---|
| 178 | { |
---|
| 179 | this->add(subclass, false); |
---|
| 180 | } |
---|
| 181 | |
---|
| 182 | void ClassTreeMask::add(const Identifier* subclass, bool bInclude) |
---|
| 183 | { |
---|
| 184 | this->add(this->root_, subclass, bInclude); |
---|
| 185 | } |
---|
| 186 | |
---|
| 187 | void ClassTreeMask::add(ClassTreeMaskNode* node, const Identifier* subclass, bool bInclude) |
---|
| 188 | { |
---|
| 189 | // Check if the current node contains exactly the subclass we want to add |
---|
| 190 | if (subclass == node->getClass()) |
---|
| 191 | { |
---|
| 192 | // We're at the right place, just change the mask and return |
---|
| 193 | node->setIncluded(bInclude); |
---|
| 194 | return; |
---|
| 195 | } |
---|
| 196 | else |
---|
| 197 | { |
---|
| 198 | // Search for an already existing node, containing the subclass we want to add |
---|
| 199 | for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it) |
---|
| 200 | { |
---|
| 201 | if (subclass->isA((*it)->getClass())) |
---|
| 202 | { |
---|
| 203 | // We've found an existing node -> delegate the work and return |
---|
| 204 | this->add(*it, subclass, bInclude); |
---|
| 205 | return; |
---|
| 206 | } |
---|
| 207 | } |
---|
| 208 | |
---|
| 209 | // There is no existing node satisfying our needs -> we create a new node |
---|
| 210 | ClassTreeMaskNode* newnode = new ClassTreeMaskNode(subclass, bInclude); |
---|
| 211 | |
---|
| 212 | // Search for nodes that should actually be subnodes of our new node |
---|
| 213 | for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ) |
---|
| 214 | { |
---|
| 215 | if ((*it)->getClass()->isChildOf(subclass)) |
---|
| 216 | { |
---|
| 217 | // We've found a subnode: add it to the new node an erase it from the current node |
---|
| 218 | newnode->addSubnode(*it); |
---|
| 219 | node->subnodes_.erase(it++); |
---|
| 220 | } |
---|
| 221 | else |
---|
| 222 | { |
---|
| 223 | ++it; |
---|
| 224 | } |
---|
| 225 | } |
---|
| 226 | |
---|
| 227 | // Finally add the new node as a subnode to the current node |
---|
| 228 | node->addSubnode(newnode); |
---|
| 229 | } |
---|
| 230 | } |
---|
| 231 | |
---|
| 232 | void ClassTreeMask::reset() |
---|
| 233 | { |
---|
| 234 | delete this->root_; |
---|
[805] | 235 | this->root_ = new ClassTreeMaskNode(ClassManager<BaseObject>::getIdentifier("BaseObject"), true); |
---|
[802] | 236 | } |
---|
| 237 | |
---|
[803] | 238 | bool ClassTreeMask::isIncluded(const Identifier* subclass) const |
---|
[802] | 239 | { |
---|
| 240 | return this->isIncluded(this->root_, subclass); |
---|
| 241 | } |
---|
| 242 | |
---|
[803] | 243 | bool ClassTreeMask::isIncluded(ClassTreeMaskNode* node, const Identifier* subclass) const |
---|
[802] | 244 | { |
---|
[806] | 245 | //std::cout << "1_1: " << subclass->getName() << " (" << subclass << ") / " << node->getClass()->getName() << " (" << node->getClass() << ")" << std::endl; |
---|
[802] | 246 | // Check if the searched subclass is of the same type as the class in the current node or a derivative |
---|
| 247 | if (subclass->isA(node->getClass())) |
---|
| 248 | { |
---|
| 249 | // Check for the special case |
---|
| 250 | if (subclass == node->getClass()) |
---|
| 251 | return node->isIncluded(); |
---|
| 252 | |
---|
| 253 | // Go through the list of subnodes and look for a node containing the searched subclass |
---|
| 254 | for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it) |
---|
| 255 | if (subclass->isA((*it)->getClass())) |
---|
| 256 | return isIncluded(*it, subclass); |
---|
| 257 | |
---|
| 258 | // There is no subnode containing our class -> the rule of the current node takes in effect |
---|
| 259 | return node->isIncluded(); |
---|
| 260 | } |
---|
| 261 | else |
---|
| 262 | { |
---|
| 263 | // The class is not included in the mask: return false |
---|
| 264 | return false; |
---|
| 265 | } |
---|
| 266 | } |
---|
| 267 | |
---|
[803] | 268 | bool ClassTreeMask::isExcluded(const Identifier* subclass) const |
---|
[802] | 269 | { |
---|
| 270 | return (!this->isIncluded(subclass)); |
---|
| 271 | } |
---|
[803] | 272 | |
---|
| 273 | void ClassTreeMask::clean() |
---|
| 274 | { |
---|
| 275 | this->clean(this->root_); |
---|
| 276 | } |
---|
| 277 | |
---|
| 278 | void ClassTreeMask::clean(ClassTreeMaskNode* node) |
---|
| 279 | { |
---|
[808] | 280 | //std::cout << "4_1: " << node->getClass()->getName() << ": " << node->isIncluded() << "\n"; |
---|
[803] | 281 | for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ) |
---|
| 282 | { |
---|
[808] | 283 | //std::cout << "4_2: " << (*it)->getClass()->getName() << ": " << (*it)->isIncluded() << "\n"; |
---|
| 284 | this->clean(*it); |
---|
| 285 | //std::cout << "4_3\n"; |
---|
[803] | 286 | if ((*it)->isIncluded() == node->isIncluded()) |
---|
| 287 | { |
---|
[808] | 288 | //std::cout << "4_4\n"; |
---|
[803] | 289 | node->subnodes_.insert(node->subnodes_.end(), (*it)->subnodes_.begin(), (*it)->subnodes_.end()); |
---|
| 290 | (*it)->subnodes_.clear(); |
---|
[807] | 291 | node->subnodes_.erase(it); |
---|
| 292 | it = node->subnodes_.begin(); |
---|
[808] | 293 | //std::cout << "4_5\n"; |
---|
[803] | 294 | } |
---|
| 295 | else |
---|
| 296 | { |
---|
[808] | 297 | //std::cout << "4_6\n"; |
---|
[803] | 298 | ++it; |
---|
| 299 | } |
---|
| 300 | } |
---|
[808] | 301 | //std::cout << "4_7\n"; |
---|
[803] | 302 | } |
---|
| 303 | |
---|
[807] | 304 | ClassTreeMask& ClassTreeMask::operator=(const ClassTreeMask& other) |
---|
| 305 | { |
---|
| 306 | ClassTreeMask temp(other); |
---|
| 307 | |
---|
| 308 | this->reset(); |
---|
| 309 | |
---|
| 310 | for (ClassTreeMaskIterator it = temp.root_; it; ++it) |
---|
| 311 | this->add(it->getClass(), it->isIncluded()); |
---|
| 312 | |
---|
| 313 | return (*this); |
---|
| 314 | } |
---|
| 315 | |
---|
| 316 | ClassTreeMask& ClassTreeMask::operator+() |
---|
| 317 | { |
---|
| 318 | return (*this); |
---|
| 319 | } |
---|
| 320 | |
---|
| 321 | ClassTreeMask ClassTreeMask::operator-() const |
---|
| 322 | { |
---|
| 323 | return (!(*this)); |
---|
| 324 | } |
---|
| 325 | |
---|
[803] | 326 | ClassTreeMask ClassTreeMask::operator+(const ClassTreeMask& other) const |
---|
| 327 | { |
---|
| 328 | ClassTreeMask newmask; |
---|
| 329 | for (ClassTreeMaskIterator it = this->root_; it; ++it) |
---|
| 330 | { |
---|
| 331 | const Identifier* subclass = it->getClass(); |
---|
| 332 | newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass)); |
---|
| 333 | } |
---|
| 334 | for (ClassTreeMaskIterator it = other.root_; it; ++it) |
---|
| 335 | { |
---|
| 336 | const Identifier* subclass = it->getClass(); |
---|
| 337 | newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass)); |
---|
| 338 | } |
---|
| 339 | newmask.clean(); |
---|
| 340 | |
---|
| 341 | return newmask; |
---|
| 342 | } |
---|
| 343 | |
---|
| 344 | ClassTreeMask ClassTreeMask::operator*(const ClassTreeMask& other) const |
---|
| 345 | { |
---|
| 346 | ClassTreeMask newmask; |
---|
| 347 | for (ClassTreeMaskIterator it = this->root_; it; ++it) |
---|
| 348 | { |
---|
| 349 | const Identifier* subclass = it->getClass(); |
---|
| 350 | newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass)); |
---|
| 351 | } |
---|
| 352 | for (ClassTreeMaskIterator it = other.root_; it; ++it) |
---|
| 353 | { |
---|
| 354 | const Identifier* subclass = it->getClass(); |
---|
| 355 | newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass)); |
---|
| 356 | } |
---|
| 357 | newmask.clean(); |
---|
| 358 | |
---|
| 359 | return newmask; |
---|
| 360 | } |
---|
| 361 | |
---|
[807] | 362 | ClassTreeMask ClassTreeMask::operator-(const ClassTreeMask& other) const |
---|
| 363 | { |
---|
| 364 | return ((*this) * (!other)); |
---|
| 365 | } |
---|
| 366 | |
---|
[803] | 367 | ClassTreeMask ClassTreeMask::operator!() const |
---|
| 368 | { |
---|
| 369 | ClassTreeMask newmask; |
---|
| 370 | for (ClassTreeMaskIterator it = this->root_; it; ++it) |
---|
| 371 | { |
---|
| 372 | const Identifier* subclass = it->getClass(); |
---|
| 373 | newmask.add(subclass, !this->isIncluded(subclass)); |
---|
| 374 | } |
---|
| 375 | return newmask; |
---|
| 376 | } |
---|
| 377 | |
---|
[807] | 378 | ClassTreeMask& ClassTreeMask::operator+=(const ClassTreeMask& other) |
---|
[803] | 379 | { |
---|
[807] | 380 | (*this) = (*this) + other; |
---|
| 381 | return (*this); |
---|
[803] | 382 | } |
---|
| 383 | |
---|
[807] | 384 | ClassTreeMask& ClassTreeMask::operator*=(const ClassTreeMask& other) |
---|
| 385 | { |
---|
| 386 | (*this) = (*this) * other; |
---|
| 387 | return (*this); |
---|
| 388 | } |
---|
| 389 | |
---|
| 390 | ClassTreeMask& ClassTreeMask::operator-=(const ClassTreeMask& other) |
---|
| 391 | { |
---|
| 392 | (*this) = (*this) - other; |
---|
| 393 | return (*this); |
---|
| 394 | } |
---|
| 395 | |
---|
[803] | 396 | ClassTreeMask ClassTreeMask::operator&(const ClassTreeMask& other) const |
---|
| 397 | { |
---|
| 398 | return ((*this) * other); |
---|
| 399 | } |
---|
| 400 | |
---|
| 401 | ClassTreeMask ClassTreeMask::operator|(const ClassTreeMask& other) const |
---|
| 402 | { |
---|
| 403 | return ((*this) + other); |
---|
| 404 | } |
---|
| 405 | |
---|
| 406 | ClassTreeMask ClassTreeMask::operator^(const ClassTreeMask& other) const |
---|
| 407 | { |
---|
| 408 | ClassTreeMask newmask; |
---|
| 409 | for (ClassTreeMaskIterator it = this->root_; it; ++it) |
---|
| 410 | { |
---|
| 411 | const Identifier* subclass = it->getClass(); |
---|
| 412 | newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass)); |
---|
| 413 | } |
---|
| 414 | for (ClassTreeMaskIterator it = other.root_; it; ++it) |
---|
| 415 | { |
---|
| 416 | const Identifier* subclass = it->getClass(); |
---|
| 417 | newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass)); |
---|
| 418 | } |
---|
| 419 | newmask.clean(); |
---|
| 420 | |
---|
| 421 | return newmask; |
---|
| 422 | } |
---|
| 423 | |
---|
| 424 | ClassTreeMask ClassTreeMask::operator~() const |
---|
| 425 | { |
---|
| 426 | return (!(*this)); |
---|
| 427 | } |
---|
[807] | 428 | |
---|
| 429 | ClassTreeMask& ClassTreeMask::operator&=(const ClassTreeMask& other) |
---|
| 430 | { |
---|
| 431 | (*this) = (*this) & other; |
---|
| 432 | return (*this); |
---|
| 433 | } |
---|
| 434 | |
---|
| 435 | ClassTreeMask& ClassTreeMask::operator|=(const ClassTreeMask& other) |
---|
| 436 | { |
---|
| 437 | (*this) = (*this) | other; |
---|
| 438 | return (*this); |
---|
| 439 | } |
---|
| 440 | |
---|
| 441 | ClassTreeMask& ClassTreeMask::operator^=(const ClassTreeMask& other) |
---|
| 442 | { |
---|
| 443 | (*this) = (*this) ^ other; |
---|
| 444 | return (*this); |
---|
| 445 | } |
---|
| 446 | |
---|
| 447 | std::ostream& operator<<(std::ostream& out, const ClassTreeMask& mask) |
---|
| 448 | { |
---|
| 449 | for (ClassTreeMaskIterator it = mask.root_; it; ++it) |
---|
| 450 | { |
---|
| 451 | if (it->isIncluded()) |
---|
| 452 | out << "+"; |
---|
| 453 | else |
---|
| 454 | out << "-"; |
---|
| 455 | |
---|
| 456 | out << it->getClass()->getName() << " "; |
---|
| 457 | } |
---|
| 458 | |
---|
| 459 | return out; |
---|
| 460 | } |
---|
[802] | 461 | } |
---|