1 /*
2 Copyright (C) 2009 Andrew Caudwell (acaudwell@gmail.com)
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version
7 3 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "dirnode.h"
19
20 float gGourceMinDirSize = 15.0;
21
22 float gGourceForceGravity = 10.0;
23 float gGourceDirPadding = 1.5;
24
25 bool gGourceNodeDebug = false;
26 bool gGourceGravity = true;
27
28 //debugging
29 int gGourceDirNodeInnerLoops = 0;
30 int gGourceFileInnerLoops = 0;
31
32 std::map<std::string, RDirNode*> gGourceDirMap;
33
RDirNode(RDirNode * parent,const std::string & abspath)34 RDirNode::RDirNode(RDirNode* parent, const std::string & abspath) {
35
36 changePath(abspath);
37
38 parent = 0;
39 setParent(parent);
40
41 accel = spos = prev_accel = vel = vec2(0.0f);
42
43 //NOTE: parent is always being set to 0 so this never gets called ...
44
45 //figure out starting position
46 if(parent !=0) {
47 vec2 parentPos = parent->getPos();
48 vec2 offset;
49
50 pos = parentPos;
51 } else {
52 pos = vec2(0.0f, 0.0f);
53 }
54
55 float padded_file_radius = gGourceFileDiameter * 0.5;
56
57 file_area = padded_file_radius * padded_file_radius * PI;
58
59 visible_count = 0;
60
61 visible = false;
62 position_initialized = false;
63
64 since_node_visible = 0.0;
65 since_last_file_change = 0.0;
66 since_last_node_change = 0.0;
67
68 calcRadius();
69 calcColour();
70 }
71
changePath(const std::string & abspath)72 void RDirNode::changePath(const std::string & abspath) {
73 //fix up path
74
75 gGourceDirMap.erase(this->abspath);
76 this->abspath = abspath;
77
78 if(abspath.empty() || abspath[abspath.size()-1] != '/') {
79 this->abspath += std::string("/");
80 }
81
82 //debugLog("new dirnode %s\n", abspath.c_str());
83
84 gGourceDirMap[this->abspath] = this;
85 }
86
~RDirNode()87 RDirNode::~RDirNode() {
88 for(std::list<RDirNode*>::iterator it = children.begin(); it != children.end(); it++) {
89 delete (*it);
90 }
91
92 gGourceDirMap.erase(abspath);
93 }
94
getTokenOffset() const95 int RDirNode::getTokenOffset() const{
96 return path_token_offset;
97 }
98
fileUpdated(bool userInitiated)99 void RDirNode::fileUpdated(bool userInitiated) {
100 calcRadius();
101
102 since_last_file_change = 0.0;
103
104 nodeUpdated(userInitiated);
105 }
106
nodeUpdated(bool userInitiated)107 void RDirNode::nodeUpdated(bool userInitiated) {
108 if(userInitiated) since_last_node_change = 0.0;
109
110 calcRadius();
111 updateFilePositions();
112 if(visible && noDirs() && noFiles()) visible = false;
113 if(parent !=0) parent->nodeUpdated(true);
114 }
115
rotate(float s,float c)116 void RDirNode::rotate(float s, float c) {
117 pos = rotate_vec2(pos, s, c);
118 spos = rotate_vec2(spos, s, c);
119
120 for(std::list<RDirNode*>::iterator it = children.begin(); it != children.end(); it++) {
121 RDirNode* child = (*it);
122 child->rotate(s, c);
123 }
124 }
125
rotate(float s,float c,const vec2 & centre)126 void RDirNode::rotate(float s, float c, const vec2& centre) {
127
128 pos = rotate_vec2(pos - centre, s, c) + centre;
129 spos = rotate_vec2(spos - centre, s, c) + centre;
130
131 for(std::list<RDirNode*>::iterator it = children.begin(); it != children.end(); it++) {
132 RDirNode* child = (*it);
133 child->rotate(s, c, centre);
134 }
135 }
136
setPos(const vec2 & pos)137 void RDirNode::setPos(const vec2 & pos) {
138 this->pos = pos;
139 }
140
141 //returns true if supplied path prefixes the nodes path
prefixedBy(const std::string & path) const142 bool RDirNode::prefixedBy(const std::string & path) const {
143 if(path.empty()) return false;
144
145 if(path[path.size()-1] != '/')
146 return abspath.find(path + std::string("/")) == 0;
147 else
148 return abspath.find(path) == 0;
149 }
150
getPath() const151 const std::string & RDirNode::getPath() const{
152 return abspath;
153 }
154
getParent() const155 RDirNode* RDirNode::getParent() const{
156 return parent;
157 }
158
159
isDir(const std::string & path) const160 bool RDirNode::isDir(const std::string& path) const {
161
162 if(prefixedBy(path)) return true;
163
164 if(path.find(abspath) != 0) return false;
165
166 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
167 if((*it)->isDir(path)) return true;
168 }
169
170 return false;
171 }
172
173 //finds directories closest to the root directory prefixed by path (eg foo/ may match just foo/ or could also match foo/bar1, foo/bar2, ... if foo/ doesn't exist).
findDirs(const std::string & path,std::list<RDirNode * > & dirs)174 void RDirNode::findDirs(const std::string& path, std::list<RDirNode*>& dirs) {
175
176 if(prefixedBy(path)) {
177 dirs.push_back(this);
178 return;
179 }
180
181 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
182 (*it)->findDirs(path, dirs);
183 }
184 }
185
getFilesRecursive(std::list<RFile * > & files) const186 void RDirNode::getFilesRecursive(std::list<RFile*>& files) const {
187
188 //add this dirs files
189 files.insert(files.begin(), this->files.begin(), this->files.end());
190
191 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
192 (*it)->getFilesRecursive(files);
193 }
194 }
195
getDepth() const196 int RDirNode::getDepth() const{
197 return depth;
198 }
199
adjustPath()200 void RDirNode::adjustPath() {
201
202 //update display path
203 int parent_token_offset = 0;
204
205 path_token_offset = abspath.size();
206
207 if(parent != 0) {
208 parent_token_offset = parent->getTokenOffset();
209
210 //debugLog("abspath.substr arguments: %d %d %s size = %d\n", parent_token_offset, abspath.size()-parent_token_offset-1, abspath.c_str(), abspath.size());
211
212 path_token = abspath.substr(parent_token_offset, abspath.size()-parent_token_offset-1);
213 path_token_offset = abspath.size();
214
215 //debugLog("new token %s\n", path_token.c_str());
216 }
217 }
218
setParent(RDirNode * parent)219 void RDirNode::setParent(RDirNode* parent) {
220 if(parent != 0 && this->parent == parent) return;
221
222 this->parent = parent;
223
224 adjustPath();
225 adjustDepth();
226 }
227
adjustDepth()228 void RDirNode::adjustDepth() {
229
230 if(parent == 0) {
231 depth = 1;
232 } else {
233 depth = parent->getDepth() + 1;
234 }
235
236 for(RDirNode* child : children) {
237 child->adjustDepth();
238 }
239 }
240
addNode(RDirNode * node)241 void RDirNode::addNode(RDirNode* node) {
242 // does this node prefix any other nodes, if so, add them to it
243
244 std::vector<RDirNode*> matches;
245 std::string path = node->getPath();
246
247 //debugLog("adding node %s to %s\n", path.c_str(), abspath.c_str());
248
249 for(std::list<RDirNode*>::iterator it = children.begin(); it != children.end(); ) {
250 RDirNode* child = (*it);
251
252 if(child->prefixedBy(path)) {
253 it = children.erase(it);
254 node->addNode(child);
255 } else {
256 it++;
257 }
258 }
259
260 // add to this node
261 children.push_back(node);
262 node->setParent(this);
263
264 //debugLog("added node %s to %s\n", node->getPath().c_str(), getPath().c_str());
265
266 nodeUpdated(false);
267 }
268
getRoot()269 RDirNode* RDirNode::getRoot() {
270 if(parent==0) return this;
271 return parent->getRoot();
272 }
273
274 // note - you still need to delete the file yourself
removeFile(RFile * f)275 bool RDirNode::removeFile(RFile* f) {
276 //doesnt match this path at all
277 if(f->path.find(abspath) != 0) {
278 return false;
279 }
280
281 //is this dir - add to this node
282 if(f->path.compare(abspath) == 0) {
283
284 for(std::list<RFile*>::iterator it = files.begin(); it != files.end(); it++) {
285 if((*it)==f) {
286 files.erase(it);
287 if(!f->isHidden()) visible_count--;
288
289 fileUpdated(false);
290
291 return true;
292 }
293 }
294
295 return false;
296 }
297
298 //does this belong to one of the children ?
299 for(std::list<RDirNode*>::iterator it = children.begin(); it != children.end(); it++) {
300 RDirNode* node = (*it);
301 bool removed = node->removeFile(f);
302
303 if(removed) {
304 //fprintf(stderr, "%s file removed from a child. child file count=%d, dir count =%d\n", getPath().c_str(), node->fileCount(), node->dirCount());
305 //node->printFiles();
306
307 //node is now empty, reap!
308 if(node->noFiles() && node->noDirs()) {
309 children.erase(it);
310 //fprintf(stderr, "deleting node %s from %s\n", node->getPath().c_str(), getPath().c_str());
311 delete node;
312 nodeUpdated(false);
313 }
314
315 return true;
316 }
317 }
318
319 return false;
320 }
321
322
printFiles()323 void RDirNode::printFiles() {
324 for(std::list<RFile*>::iterator it = files.begin(); it != files.end(); it++) {
325 RFile* file = (*it);
326 fprintf(stderr, "%s: %s %s\n", getPath().c_str(), file->fullpath.c_str() , file->isHidden() ? "hidden " : "");
327 }
328 }
329
330
addVisible()331 void RDirNode::addVisible() {
332 visible_count++;
333 visible = true;
334 }
335
isVisible()336 bool RDirNode::isVisible() {
337
338 if(visible) return true;
339
340 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
341 if((*it)->isVisible()) {
342 visible = true;
343 return true;
344 }
345 }
346
347 return false;
348 }
349
visibleFileCount() const350 int RDirNode::visibleFileCount() const{
351 return visible_count;
352 }
353
fileCount() const354 int RDirNode::fileCount() const{
355 return files.size();
356 }
357
noFiles() const358 bool RDirNode::noFiles() const{
359 return files.empty();
360 }
361
commonPathPrefix(const std::string & str) const362 std::string RDirNode::commonPathPrefix(const std::string & str) const{
363 size_t c = 0;
364 int slash = -1;
365
366 while(c<abspath.size() && c<str.size() && abspath[c] == str[c]) {
367 if(abspath[c] == '/') {
368 slash = c;
369 }
370 c++;
371 }
372
373 if(slash==-1) return "";
374 return str.substr(0,slash+1);
375 }
376
addFile(RFile * f)377 bool RDirNode::addFile(RFile* f) {
378
379 //doesnt match this path at all
380 if(f->path.find(abspath) != 0) {
381
382 if(parent != 0) return false;
383
384 //if this is the root node (ie no parent), we fork it
385 //if we encounter a file with a non matching path to the
386 //current root path. the calling process then checks if
387 //the root now has a parent node, and changes the pointer.
388
389 RDirNode* newparent;
390
391 std::string common = commonPathPrefix(f->path);
392 if(common.size()==0) common = "/";
393
394 newparent = new RDirNode(0, common);
395 newparent->addNode(this);
396 return newparent->addFile(f);
397 }
398
399 //simply change path of node and add this to it
400 if( parent==0 && abspath == "/"
401 && f->path.compare(abspath) != 0 && noFiles() && noDirs()) {
402 debugLog("modifying root path to %s", f->path.c_str());
403 changePath(f->path);
404 }
405
406 //is this dir - add to this node
407 if(f->path.compare(abspath) == 0) {
408 //debugLog("addFile %s to %s\n", f->fullpath.c_str(), abspath.c_str());
409
410 files.push_back(f);
411 if(!f->isHidden()) visible_count++;
412 f->setDir(this);
413
414 fileUpdated(false);
415
416 return true;
417 }
418
419 bool added = false;
420
421 //does this belong to one of the children ?
422 for(std::list<RDirNode*>::iterator it = children.begin(); it != children.end(); it++) {
423 RDirNode* child = (*it);
424
425 added = child->addFile(f);
426
427 if(added) break;
428 }
429
430 if(added && parent != 0) return true;
431
432 //do we have a file in this directory thats fullpath is a prefix of this file, if so
433 //that file is actually a directory - the file should be removed, and a directory with that path added
434 //if this is the root node we do this regardless of if the file was added to a child node
435
436 for(std::list<RFile*>::const_iterator it = files.begin(); it != files.end(); it++) {
437 RFile* file = (*it);
438
439 if(f->path.find(file->fullpath) == 0) {
440 //fprintf(stderr, "removing %s as is actually the directory of %s\n", file->fullpath.c_str(), f->fullpath.c_str());
441 file->remove();
442 break;
443 }
444 }
445
446 if(added) return true;
447
448 //add new child, add it to that
449 //if commonpath is longer than abspath, add intermediate node, else just add at the files path
450 RDirNode* node = new RDirNode(this, f->path);
451
452 node->addFile(f);
453
454 addNode(node);
455
456 // do we have dir nodes, with a common path element greater than abspath,
457 // if so create another node, and move those nodes there
458
459 std::string commonpath;
460 vec2 commonPos;
461 for(std::list<RDirNode*>::iterator it = children.begin(); it != children.end(); it++) {
462 RDirNode* child = (*it);
463
464 std::string common = child->commonPathPrefix(f->path);
465 if(common.size() > abspath.size() && common != f->path) {
466 commonpath = common;
467 commonPos = child->getPos();
468 break;
469 }
470 }
471
472 // redistribute to new common node
473 if(commonpath.size() > abspath.size()) {
474 //debugLog("common path %s\n", commonpath.c_str());
475
476 RDirNode* cnode = new RDirNode(this, commonpath);
477 cnode->setPos(commonPos);
478
479 for(std::list<RDirNode*>::iterator it = children.begin(); it != children.end();) {
480 RDirNode* child = (*it);
481
482 if(child->prefixedBy(commonpath)) {
483 //debugLog("this path = %s, commonpath = %s, path = %s\n", abspath.c_str(), commonpath.c_str(), child->getPath().c_str());
484 it = children.erase(it);
485 cnode->addNode(child);
486 continue;
487 }
488
489 it++;
490 }
491
492 addNode(cnode);
493 }
494
495 return true;
496 }
497
getParentRadius() const498 float RDirNode::getParentRadius() const{
499 return parent_radius;
500 }
501
getRadius() const502 float RDirNode::getRadius() const{
503 return dir_radius;
504 }
505
getRadiusSqrt() const506 float RDirNode::getRadiusSqrt() const{
507 return dir_radius_sqrt;
508 }
509
averageFileColour() const510 vec3 RDirNode::averageFileColour() const{
511
512 vec3 av;
513 int count = 0;
514
515 for(std::list<RFile*>::const_iterator it = files.begin(); it != files.end(); it++) {
516 RFile* file = (*it);
517
518 if(file->isHidden()) continue;
519
520 av += file->getColour();
521
522 count++;
523 }
524
525 if(count>0) av *= (1.0f/(float)count);
526
527 count = 0;
528
529 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end();it++) {
530 RDirNode* child = (*it);
531
532 av += child->averageFileColour();
533 count++;
534 }
535
536 if(count>0) av *= (1.0f/(float)count);
537
538 return av;
539 }
540
getColour() const541 const vec4 & RDirNode::getColour() const{
542 return col;
543 }
544
calcColour()545 void RDirNode::calcColour() {
546
547 // make branch brighter if recently accessed
548 float brightness = std::max(0.6f, 1.0f - std::min(1.0f, since_last_node_change / 3.0f));
549
550 col = vec4(brightness, brightness, brightness, 1.0);
551
552 int fcount = 0;
553
554 for(std::list<RFile*>::iterator it = files.begin(); it != files.end(); it++) {
555 RFile* file = (*it);
556
557 if(file->isHidden()) continue;;
558
559 vec3 filecol = file->getColour() * brightness;
560 float a = file->getAlpha();
561
562 col += vec4(filecol.x, filecol.y, filecol.z, a);
563
564 fcount++;
565 }
566
567 this->col /= (float) fcount + 1.0;
568 }
569
getArea() const570 float RDirNode::getArea() const{
571 return dir_area;
572 }
573
calcRadius()574 void RDirNode::calcRadius() {
575
576 float total_file_area = file_area * visible_count;
577
578 dir_area = total_file_area;
579
580 //float parent_circ = 0.0;
581
582 for(std::list<RDirNode*>::iterator it = children.begin(); it != children.end(); it++) {
583 RDirNode* node = (*it);
584
585 dir_area += node->getArea();
586 // parent_circ += node->getRadiusSqrt();
587 }
588
589 this->dir_radius = std::max(1.0f, (float)sqrt(dir_area)) * gGourceDirPadding;
590 //this->dir_radius_sqrt = sqrt(dir_radius); //dir_radius_sqrt is not used
591
592 // this->parent_radius = std::max(1.0, parent_circ / PI);
593 this->parent_radius = std::max(1.0f, (float) sqrt(total_file_area) * gGourceDirPadding);
594 }
595
distanceToParent() const596 float RDirNode::distanceToParent() const{
597
598 float posd = glm::length(parent->getPos() - pos);
599 float distance = posd - (dir_radius + parent->getParentRadius());
600
601 return distance;
602 }
603
applyForceDir(RDirNode * node)604 void RDirNode::applyForceDir(RDirNode* node) {
605 if(node == this) return;
606
607 vec2 dir = node->getPos() - pos;
608
609 float posd2 = glm::length2(dir);
610 float myradius = getRadius();
611 float your_radius = node->getRadius();
612
613 float sumradius = (myradius + your_radius);
614
615 float distance2 = posd2 - sumradius*sumradius;
616
617 if(distance2>0.0) return;
618
619 float posd = sqrt(posd2);
620
621 float distance = posd - myradius - your_radius;
622
623 //resolve overlap
624 if(posd < 0.00001) {
625 accel += normalise(vec2( (rand() % 100) - 50, (rand() % 100) - 50));
626 return;
627 }
628
629 accel += distance * normalise(dir);
630 }
631
getPos() const632 const vec2 & RDirNode::getPos() const{
633 return pos;
634 }
635
isParent(RDirNode * node) const636 bool RDirNode::isParent(RDirNode* node) const {
637 if(node==parent) return true;
638 if(parent==0) return false;
639
640 return parent->isParent(node);
641 }
642
empty() const643 bool RDirNode::empty() const{
644 return (visible_count==0 && noDirs()) ? true : false;
645 }
646
applyForces(QuadTree & quadtree)647 void RDirNode::applyForces(QuadTree & quadtree) {
648
649 //child nodes
650 for(std::list<RDirNode*>::iterator it = children.begin(); it != children.end(); it++) {
651 RDirNode* node = (*it);
652
653 node->applyForces(quadtree);
654 }
655
656 if(parent == 0) return;
657
658 DirForceFunctor dff(this);
659 quadtree.visitItemsInBounds(quadItemBounds, dff);
660 gGourceDirNodeInnerLoops += dff.getLoopCount();
661
662 //always call on parent no matter how far away
663 applyForceDir(parent);
664
665 //pull towards parent
666 float parent_dist = distanceToParent();
667
668 // * dirs should attract to sit on the radius of the parent dir ie:
669 // should attract to distance_to_parent * normal_to_parent
670
671
672
673 accel += gGourceForceGravity * parent_dist * normalise(parent->getPos() - pos);
674
675 // * dirs should be pushed along the parent_parent to parent normal by a force smaller than the parent radius force
676 RDirNode* pparent = parent->getParent();
677
678 if(pparent != 0) {
679 vec2 parent_edge = (parent->getPos() - pparent->getPos());
680 vec2 parent_edge_normal = normalise(parent_edge);
681
682 vec2 dest = (parent->getPos() + (parent->getRadius() + getRadius()) * parent_edge_normal) - pos;
683
684 accel += dest;
685 }
686
687 // * dirs should repulse from other dirs of this parent
688 const std::list<RDirNode*> & siblings = parent->getChildren();
689 if(!siblings.empty()) {
690 vec2 sib_accel;
691
692 int visible = 1;
693
694 for(std::list<RDirNode*>::const_iterator it = siblings.begin(); it != siblings.end(); it++) {
695 RDirNode* node = (*it);
696
697 if(node == this) continue;
698 if(!node->isVisible()) continue;
699
700 visible++;
701
702 sib_accel -= normalise(node->getPos() - pos);
703 }
704
705 //parent circumfrence divided by the number of visible child nodes
706 if(visible>1) {
707 float slice_size = (parent->getRadius() * PI) / (float) (visible+1);
708 sib_accel *= slice_size;
709
710 accel += sib_accel;
711 }
712 }
713
714 }
715
debug(int indent) const716 void RDirNode::debug(int indent) const{
717 std::string indentstr;
718 while(indentstr.size() < indent) indentstr += " ";
719
720 debugLog("%s%s", indentstr.c_str(), abspath.c_str());
721
722 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
723 RDirNode* node = (*it);
724 node->debug(indent+1);
725 }
726 }
727
totalFileCount() const728 int RDirNode::totalFileCount() const{
729 int total = visibleFileCount();
730
731 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
732 RDirNode* node = (*it);
733 total += node->visibleFileCount();
734 }
735
736 return total;
737 }
738
totalDirCount() const739 int RDirNode::totalDirCount() const{
740 int total = 1;
741
742 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
743 RDirNode* node = (*it);
744 total += node->totalDirCount();
745 }
746
747 return total;
748 }
749
dirCount() const750 int RDirNode::dirCount() const{
751 return children.size();
752 }
753
noDirs() const754 bool RDirNode::noDirs() const{
755 return children.empty();
756 }
757
getChildren() const758 const std::list<RDirNode*> & RDirNode::getChildren() const{
759 return children;
760 }
761
updateSplinePoint(float dt)762 void RDirNode::updateSplinePoint(float dt) {
763 if(parent == 0) return;
764
765 //update the spline point
766 vec2 td = (parent->getPos() - pos) * 0.5f;
767
768 vec2 mid = pos + td;// - td.perpendicular() * pos.normal();// * 10.0;
769
770 vec2 delta = (mid - spos);
771
772 //dont let spos get more than half the length of the distance behind
773 if(glm::length2(delta) > glm::length2(td)) {
774 spos += normalise(delta) * (glm::length(delta) - glm::length(td));
775 }
776
777 spos += delta * std::min(1.0f, dt * 2.0f);
778 }
779
setInitialPosition()780 void RDirNode::setInitialPosition() {
781 RDirNode* parentP = parent->getParent();
782
783 pos = parent->getPos();
784
785 //offset position by some pseudo-randomness
786 if(parentP != 0) {
787 //pos += ((parent->getPos() - parentP->getPos()).normal() * 2.0 + vec2Hash(abspath)).normal();
788 pos += normalise(normalise(parent->getPos() - parentP->getPos()) * 2.0f + vec2Hash(abspath));
789
790 } else {
791 pos += vec2Hash(abspath);
792 }
793
794 //the spline point
795 spos = pos - (parent->getPos() - pos) * 0.5f;
796 position_initialized=true;
797 }
798
move(float dt)799 void RDirNode::move(float dt) {
800
801 //the root node is the centre of the world
802 if(parent == 0) {
803 return;
804 }
805
806 //initial position
807 if(!empty() && !position_initialized) {
808 setInitialPosition();
809 }
810
811 pos += accel * dt;
812
813 if(gGourceSettings.elasticity>0.0) {
814 vec2 diff = (accel - prev_accel);
815
816 float m = dt * gGourceSettings.elasticity;
817
818 vec2 accel3 = prev_accel * (1.0f-m) + diff * m;
819 pos += accel3;
820 prev_accel = accel3;
821 }
822
823 //accel = accel * std::max(0.0f, (1.0f - dt*10.0f));
824 accel = vec2(0.0, 0.0);
825 }
826
getNodeNormal() const827 const vec2 & RDirNode::getNodeNormal() const{
828 return node_normal;
829 }
830
calcFileDest(int max_files,int file_no)831 vec2 RDirNode::calcFileDest(int max_files, int file_no) {
832
833 float arc = 1.0/(float)max_files;
834
835 float frac = arc * 0.5 + arc * file_no;
836
837 vec2 dest = vec2(sinf(frac*PI*2.0), cosf(frac*PI*2.0));
838
839 return dest;
840 }
841
updateFilePositions()842 void RDirNode::updateFilePositions() {
843
844 int max_files = 1;
845 int diameter = 1;
846 int file_no = 0;
847 float d = 0.0;
848
849 int files_left = visible_count;
850
851 for(std::list<RFile*>::iterator it = files.begin(); it!=files.end(); it++) {
852 RFile* f = *it;
853
854 if(f->isHidden()) {
855 f->setDest(vec2(0.0,0.0));
856 f->setDistance(0.0f);
857 continue;
858 }
859
860 vec2 dest = calcFileDest(max_files, file_no);
861
862 f->setDest(dest);
863 f->setDistance(d);
864
865 files_left--;
866 file_no++;
867
868 if(file_no>=max_files) {
869 diameter++;
870 d += gGourceFileDiameter;
871 max_files = (int) std::max(1.0, diameter*PI);
872
873 if(files_left<max_files) {
874 max_files = files_left;
875 }
876
877 file_no=0;
878 }
879 }
880 }
881
calcEdges()882 void RDirNode::calcEdges() {
883
884 if(parent != 0) {
885 spline.update(parent->getProjectedPos(), parent->getColour(), projected_pos, col, projected_spos);
886 }
887
888 for(std::list<RDirNode*>::iterator it = children.begin(); it != children.end(); it++) {
889 RDirNode* child = *it;
890
891 child->calcEdges();
892 }
893 }
894
logic(float dt)895 void RDirNode::logic(float dt) {
896
897 //move
898 move(dt);
899 updateSplinePoint(dt);
900
901 //update node normal
902 if(parent != 0) {
903 node_normal = normalise(pos - parent->getPos());
904 }
905
906 //update files
907 for(std::list<RFile*>::iterator it = files.begin(); it!=files.end(); it++) {
908 RFile* f = *it;
909
910 f->logic(dt);
911 }
912
913 //update child nodes
914 for(std::list<RDirNode*>::iterator it = children.begin(); it != children.end(); it++) {
915 RDirNode* node = (*it);
916
917 node->logic(dt);
918 }
919
920 //update colour
921 calcColour();
922
923 //update tickers
924 if(visible) since_node_visible += dt;
925
926 since_last_file_change += dt;
927 since_last_node_change += dt;
928 }
929
drawDirName(FXFont & dirfont) const930 void RDirNode::drawDirName(FXFont& dirfont) const{
931 if(parent==0) return;
932 if(gGourceSettings.hide_dirnames) return;
933 if(gGourceSettings.dir_name_depth > 0 && gGourceSettings.dir_name_depth < (depth-1)) return;
934
935 if(!gGourceSettings.highlight_dirs && since_last_node_change > 5.0) return;
936
937 float alpha = gGourceSettings.highlight_dirs ? 1.0 : std::max(0.0f, 5.0f - since_last_node_change) / 5.0f;
938
939 vec2 label_pos = spline.getLabelPos();
940
941 dirfont.setAlpha(alpha);
942 dirfont.draw(label_pos.x, label_pos.y, path_token);
943 }
944
calcScreenPos(GLint * viewport,GLdouble * modelview,GLdouble * projection)945 void RDirNode::calcScreenPos(GLint* viewport, GLdouble* modelview, GLdouble* projection) {
946
947 static GLdouble screen_x, screen_y, screen_z;
948
949 gluProject( pos.x, pos.y, 0.0f, modelview, projection, viewport, &screen_x, &screen_y, &screen_z);
950 screen_y = (float)viewport[3] - screen_y;
951 projected_pos.x = screen_x;
952 projected_pos.y = screen_y;
953
954 gluProject( spos.x, spos.y, 0.0f, modelview, projection, viewport, &screen_x, &screen_y, &screen_z);
955 screen_y = (float)viewport[3] - screen_y;
956 projected_spos.x = screen_x;
957 projected_spos.y = screen_y;
958
959 static vec2 selected_offset(5.5f, -2.0f);
960 static vec2 unselected_offset(5.5f, -1.0f);
961
962 if(!gGourceSettings.hide_filenames) {
963
964 //first pass - calculate positions of names
965 for(std::list<RFile*>::const_iterator it = files.begin(); it!=files.end(); it++) {
966 RFile* f = *it;
967 f->calcScreenPos(viewport, modelview, projection);
968 }
969 }
970
971 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
972 RDirNode* node = (*it);
973 node->calcScreenPos(viewport, modelview, projection);
974 }
975 }
976
drawNames(FXFont & dirfont)977 void RDirNode::drawNames(FXFont& dirfont) {
978
979 if(!gGourceSettings.hide_dirnames && isVisible()) {
980 drawDirName(dirfont);
981 }
982
983 if(!gGourceSettings.hide_filenames) {
984
985 if(!(gGourceSettings.hide_filenames || gGourceSettings.hide_files) && in_frustum) {
986 for(std::list<RFile*>::const_iterator it = files.begin(); it!=files.end(); it++) {
987 RFile* f = *it;
988 if(!f->isSelected()) f->drawName();
989 }
990 }
991
992 }
993
994 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
995 RDirNode* node = (*it);
996 node->drawNames(dirfont);
997 }
998 }
999
checkFrustum(const Frustum & frustum)1000 void RDirNode::checkFrustum(const Frustum& frustum) {
1001
1002 in_frustum = frustum.intersects(quadItemBounds);
1003
1004 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
1005 RDirNode* node = (*it);
1006 node->checkFrustum(frustum);
1007 }
1008 }
1009
drawShadows(float dt) const1010 void RDirNode::drawShadows(float dt) const{
1011
1012 if(in_frustum) {
1013
1014 glPushMatrix();
1015 glTranslatef(pos.x, pos.y, 0.0);
1016
1017 //draw files
1018 for(std::list<RFile*>::const_iterator it = files.begin(); it!=files.end(); it++) {
1019 RFile* f = *it;
1020 if(f->isHidden()) continue;
1021
1022 f->drawShadow(dt);
1023 }
1024
1025 glPopMatrix();
1026 }
1027
1028 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
1029 RDirNode* node = (*it);
1030 node->drawShadows(dt);
1031 }
1032 }
1033
updateFilesVBO(quadbuf & buffer,float dt) const1034 void RDirNode::updateFilesVBO(quadbuf& buffer, float dt) const{
1035
1036 if(in_frustum) {
1037
1038 for(std::list<RFile*>::const_iterator it = files.begin(); it!=files.end(); it++) {
1039 RFile* f = *it;
1040
1041 if(f->isHidden()) continue;
1042
1043 vec3 col = f->getColour();
1044 float alpha = f->getAlpha();
1045
1046 buffer.add(f->graphic->textureid, f->getAbsolutePos() - f->dims*0.5f, f->dims, vec4(col.x, col.y, col.z, alpha));
1047 }
1048 }
1049
1050 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
1051 RDirNode* node = (*it);
1052 node->updateFilesVBO(buffer,dt);
1053 }
1054 }
1055
updateBloomVBO(bloombuf & buffer,float dt)1056 void RDirNode::updateBloomVBO(bloombuf& buffer, float dt) {
1057
1058 if(in_frustum && isVisible()) {
1059
1060 float bloom_radius = dir_radius * 2.0 * gGourceSettings.bloom_multiplier;
1061 float bloom_diameter = bloom_radius * 2.0;
1062 vec4 bloom_col = col * gGourceSettings.bloom_intensity;
1063
1064 vec4 bloom_texcoords(bloom_radius, pos.x, pos.y, 0.0f);
1065
1066 vec2 bloom_dims(bloom_diameter, bloom_diameter);
1067
1068 buffer.add(0, pos - bloom_dims*0.5f,bloom_dims, vec4(bloom_col.x, bloom_col.y, bloom_col.z, 1.0f), bloom_texcoords);
1069 }
1070
1071 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
1072 RDirNode* node = (*it);
1073 node->updateBloomVBO(buffer,dt);
1074 }
1075 }
1076
drawFiles(float dt) const1077 void RDirNode::drawFiles(float dt) const{
1078
1079 if(in_frustum) {
1080 glPushMatrix();
1081 glTranslatef(pos.x, pos.y, 0.0);
1082
1083 //draw files
1084
1085 for(std::list<RFile*>::const_iterator it = files.begin(); it!=files.end(); it++) {
1086 RFile* f = *it;
1087 if(f->isHidden()) continue;
1088
1089 f->draw(dt);
1090 }
1091
1092 glPopMatrix();
1093 }
1094
1095 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
1096 RDirNode* node = (*it);
1097 node->drawFiles(dt);
1098 }
1099 }
1100
getSPos() const1101 const vec2 & RDirNode::getSPos() const{
1102 return projected_spos;
1103 }
1104
getProjectedPos() const1105 const vec2 & RDirNode::getProjectedPos() const{
1106 return projected_pos;
1107 }
1108
updateEdgeVBO(quadbuf & buffer) const1109 void RDirNode::updateEdgeVBO(quadbuf& buffer) const {
1110
1111 if(parent!=0 && (!gGourceSettings.hide_root || parent->parent !=0)) spline.drawToVBO(buffer);
1112
1113 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
1114 RDirNode* child = (*it);
1115
1116 if(child->isVisible()) {
1117 child->updateEdgeVBO(buffer);
1118 }
1119 }
1120 }
1121
drawEdgeShadows() const1122 void RDirNode::drawEdgeShadows() const{
1123
1124 if(parent!=0 && (!gGourceSettings.hide_root || parent->parent !=0)) spline.drawShadow();
1125
1126 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
1127 RDirNode* child = (*it);
1128
1129 //draw edge - assumes calcEdges() called before hand so spline will exist
1130 if(child->isVisible()) {
1131 child->drawEdgeShadows();
1132 }
1133 }
1134 }
1135
drawEdges() const1136 void RDirNode::drawEdges() const{
1137
1138 if(parent!=0 && (!gGourceSettings.hide_root || parent->parent !=0)) spline.draw();
1139
1140 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
1141 RDirNode* child = (*it);
1142
1143 //draw edge - assumes calcEdges() called before hand so spline will exist
1144 if(child->isVisible()) {
1145 child->drawEdges();
1146 }
1147 }
1148 }
1149
drawBloom(float dt)1150 void RDirNode::drawBloom(float dt){
1151
1152 if(in_frustum && isVisible()) {
1153
1154 float bloom_radius = dir_radius * 2.0 * gGourceSettings.bloom_multiplier;
1155
1156 vec4 bloom_col = col * gGourceSettings.bloom_intensity;
1157
1158 glColor4f(bloom_col.x, bloom_col.y, bloom_col.z, 1.0);
1159
1160 glPushMatrix();
1161 glTranslatef(pos.x, pos.y, 0.0);
1162
1163 glBegin(GL_QUADS);
1164 glTexCoord2f(1.0f, 1.0f);
1165 glVertex2f(bloom_radius,bloom_radius);
1166 glTexCoord2f(1.0f, 0.0f);
1167 glVertex2f(bloom_radius,-bloom_radius);
1168 glTexCoord2f(0.0f, 0.0f);
1169 glVertex2f(-bloom_radius,-bloom_radius);
1170 glTexCoord2f(0.0f, 1.0f);
1171 glVertex2f(-bloom_radius,bloom_radius);
1172 glEnd();
1173 glPopMatrix();
1174 }
1175
1176 for(std::list<RDirNode*>::const_iterator it = children.begin(); it != children.end(); it++) {
1177 RDirNode* node = (*it);
1178 node->drawBloom(dt);
1179 }
1180 }
1181
updateQuadItemBounds()1182 void RDirNode::updateQuadItemBounds() {
1183 float radius = getRadius();
1184
1185 vec2 radoffset(radius, radius);
1186
1187 //set bounds
1188 quadItemBounds.set(pos - radoffset, pos + radoffset);
1189 }
1190
1191