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