coeng

view src/gobj.cc @ 8:8cce82794f90

seems to work nicely
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 15 Feb 2015 05:14:20 +0200
parents af24cfbdf9b6
children
line source
1 #include <stdio.h>
2 #include <string.h>
3 #include <assert.h>
4 #include <algorithm>
5 #include "gobj.h"
7 GObject::GObject()
8 {
9 sorted = true;
10 }
12 GObject::~GObject()
13 {
14 for(size_t i=0; i<comp.size(); i++) {
15 delete comp[i];
16 }
17 }
19 bool GObject::add_component(Component *c)
20 {
21 const char *name = c->get_name();
23 if(comp_by_name.find(name) != comp_by_name.end()) {
24 fprintf(stderr, "component %s already exists in this gobject (%p)\n", name, (void*)this);
25 return false;
26 }
28 try {
29 comp.push_back(c);
30 comp_by_name[name] = c;
32 c->attach(this);
33 }
34 catch(...) {
35 fprintf(stderr, "failed to add component: %s\n", name);
36 return false;
37 }
39 sorted = false;
40 return true;
41 }
43 bool GObject::remove_component(Component *c)
44 {
45 for(size_t i=0; i<comp.size(); i++) {
46 if(comp[i] == c) {
47 c->detach();
48 comp.erase(comp.begin() + i);
49 comp_by_name.erase(c->get_name());
50 return true;
51 }
52 }
53 return false;
54 }
56 bool GObject::delete_component(Component *c)
57 {
58 if(remove_component(c)) {
59 delete c;
60 return true;
61 }
62 return false;
63 }
65 Component *GObject::get_component(const char *name) const
66 {
67 std::map<std::string, Component*>::const_iterator it;
68 if((it = comp_by_name.find(name)) != comp_by_name.end()) {
69 return it->second;
70 }
71 return 0;
72 }
74 void GObject::update(float dt)
75 {
76 if(!sorted) {
77 sort_components();
78 sorted = true;
79 }
81 //printf("updating components\n");
82 for(size_t i=0; i<comp.size(); i++) {
83 //printf(" %s\n", comp[i]->get_name());
84 comp[i]->update(dt);
85 }
86 }
88 void GObject::draw() const
89 {
90 // TODO optimization: draw only specific components?
91 for(size_t i=0; i<comp.size(); i++) {
92 comp[i]->draw();
93 }
94 }
96 struct TopoSucNode {
97 int idx;
98 TopoSucNode *next;
99 };
101 struct TopoItem {
102 Component *co;
103 int npre; // number of predeccessors
104 TopoSucNode *suc; // successor list
105 TopoItem *qnext, *qprev; // queue list links
106 };
108 int countq(TopoItem *q)
109 {
110 int n = 0;
111 while(q) {
112 n++;
113 q = q->qnext;
114 }
115 return n;
116 }
118 // topological sort of components based on update_before() relationships
119 void GObject::sort_components()
120 {
121 int nitems = (int)comp.size();
122 TopoItem *items = (TopoItem*)alloca(nitems * sizeof *items);
123 TopoItem *queue = items;
125 // initialize the items
126 for(int i=0; i<nitems; i++) {
127 items[i].co = comp[i];
128 items[i].npre = 0;
129 items[i].suc = 0;
130 items[i].qnext = i + 1 < nitems ? items + i + 1 : 0;
131 items[i].qprev = i > 0 ? items + i - 1 : 0;
132 }
134 // populate the array
135 for(int i=0; i<nitems; i++) {
136 const char **iter = comp[i]->update_before();
137 while(*iter) {
138 const char *sucname = *iter++;
140 for(int j=0; j<nitems; j++) {
141 if(j == i) continue;
142 if(strcmp(comp[j]->get_name(), sucname) == 0) {
143 // found a component(j) depending on i, increment its predeccessor counter
144 items[j].npre++;
145 // remove it from the queue
146 if(queue == items + j) {
147 queue = items[j].qnext;
148 assert(items[j].qprev == 0);
149 }
150 if(items[j].qprev) items[j].qprev->qnext = items[j].qnext;
151 if(items[j].qnext) items[j].qnext->qprev = items[j].qprev;
152 items[j].qprev = items[j].qnext = 0;
154 // and add it to our successor list
155 TopoSucNode *n = (TopoSucNode*)alloca(sizeof *n);
156 n->idx = j;
157 n->next = items[i].suc;
158 items[i].suc = n;
159 }
160 }
161 }
162 }
164 // now remove each item from the queue and add it to the sorted list
165 int idx = 0;
166 while(queue) {
167 assert(idx < nitems);
168 comp[idx++] = queue->co;
170 // traverse the successor list, decrementing their predeccessor counts
171 TopoSucNode *n = queue->suc;
172 queue = queue->qnext;
174 while(n) {
175 TopoItem *it = items + n->idx;
176 n = n->next;
178 assert(it->npre > 0);
179 if(--it->npre <= 0) {
180 // if the count reached zero, add it to the queue
181 it->qprev = 0;
182 it->qnext = queue;
183 queue = it;
184 }
185 }
186 }
188 assert(idx == nitems);
189 }