coeng

view src/gobj.cc @ 7:af24cfbdf9b6

adding collision detection
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 14 Feb 2015 10:08:00 +0200
parents 2f872a179914
children 8cce82794f90
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 for(size_t i=0; i<comp.size(); i++) {
82 comp[i]->update(dt);
83 }
84 }
86 void GObject::draw() const
87 {
88 // TODO optimization: draw only specific components?
89 for(size_t i=0; i<comp.size(); i++) {
90 comp[i]->draw();
91 }
92 }
94 struct TopoSucNode {
95 int idx;
96 TopoSucNode *next;
97 };
99 struct TopoItem {
100 Component *co;
101 int npre; // number of predeccessors
102 TopoSucNode *suc; // successor list
103 TopoItem *qnext, *qprev; // queue list links
104 };
106 int countq(TopoItem *q)
107 {
108 int n = 0;
109 while(q) {
110 n++;
111 q = q->qnext;
112 }
113 return n;
114 }
116 // topological sort of components based on update_before() relationships
117 void GObject::sort_components()
118 {
119 int nitems = (int)comp.size();
120 TopoItem *items = (TopoItem*)alloca(nitems * sizeof *items);
121 TopoItem *queue = items;
123 // initialize the items
124 for(int i=0; i<nitems; i++) {
125 items[i].co = comp[i];
126 items[i].npre = 0;
127 items[i].suc = 0;
128 items[i].qnext = i + 1 < nitems ? items + i + 1 : 0;
129 items[i].qprev = i > 0 ? items + i - 1 : 0;
130 }
132 // populate the array
133 for(int i=0; i<nitems; i++) {
134 const char **iter = comp[i]->update_before();
135 while(*iter) {
136 const char *sucname = *iter++;
138 for(int j=0; j<nitems; j++) {
139 if(j == i) continue;
140 if(strcmp(comp[j]->get_name(), sucname) == 0) {
141 // found a component(j) depending on i, increment its predeccessor counter
142 items[j].npre++;
143 // remove it from the queue
144 if(queue == items + j) {
145 queue = items[j].qnext;
146 assert(items[j].qprev == 0);
147 }
148 if(items[j].qprev) items[j].qprev->qnext = items[j].qnext;
149 if(items[j].qnext) items[j].qnext->qprev = items[j].qprev;
150 items[j].qprev = items[j].qnext = 0;
152 // and add it to our successor list
153 TopoSucNode *n = (TopoSucNode*)alloca(sizeof *n);
154 n->idx = j;
155 n->next = items[i].suc;
156 items[i].suc = n;
157 }
158 }
159 }
160 }
162 // now remove each item from the queue and add it to the sorted list
163 int idx = 0;
164 while(queue) {
165 assert(idx < nitems);
166 comp[idx++] = queue->co;
168 // traverse the successor list, decrementing their predeccessor counts
169 TopoSucNode *n = queue->suc;
170 queue = queue->qnext;
172 while(n) {
173 TopoItem *it = items + n->idx;
174 n = n->next;
176 assert(it->npre > 0);
177 if(--it->npre <= 0) {
178 // if the count reached zero, add it to the queue
179 it->qprev = 0;
180 it->qnext = queue;
181 queue = it;
182 }
183 }
184 }
186 assert(idx == nitems);
187 }