coeng
diff src/gobj.cc @ 6:2f872a179914
first component test:
- prs, xform, physics components with dependencies
- topological sort of components to update them in the correct order
- debug visualization component
todo: remove draw() from components, doesn't make sense
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 14 Feb 2015 07:27:12 +0200 |
parents | 0e5da17d589c |
children | af24cfbdf9b6 |
line diff
1.1 --- a/src/gobj.cc Sat Feb 14 01:35:42 2015 +0200 1.2 +++ b/src/gobj.cc Sat Feb 14 07:27:12 2015 +0200 1.3 @@ -1,25 +1,27 @@ 1.4 #include <stdio.h> 1.5 +#include <string.h> 1.6 +#include <assert.h> 1.7 #include <algorithm> 1.8 #include "gobj.h" 1.9 1.10 -GameObject::GameObject() 1.11 +GObject::GObject() 1.12 { 1.13 sorted = true; 1.14 } 1.15 1.16 -GameObject::~GameObject() 1.17 +GObject::~GObject() 1.18 { 1.19 for(size_t i=0; i<comp.size(); i++) { 1.20 delete comp[i]; 1.21 } 1.22 } 1.23 1.24 -bool GameObject::add_component(Component *c) 1.25 +bool GObject::add_component(Component *c) 1.26 { 1.27 const char *name = c->get_name(); 1.28 1.29 if(comp_by_name.find(name) != comp_by_name.end()) { 1.30 - fprintf(stderr, "component %s already exists in this game object (%p)\n", name, (void*)this); 1.31 + fprintf(stderr, "component %s already exists in this gobject (%p)\n", name, (void*)this); 1.32 return false; 1.33 } 1.34 1.35 @@ -27,7 +29,7 @@ 1.36 comp.push_back(c); 1.37 comp_by_name[name] = c; 1.38 1.39 - c->gobj = this; 1.40 + c->attach(this); 1.41 } 1.42 catch(...) { 1.43 fprintf(stderr, "failed to add component: %s\n", name); 1.44 @@ -38,10 +40,11 @@ 1.45 return true; 1.46 } 1.47 1.48 -bool GameObject::remove_component(Component *c) 1.49 +bool GObject::remove_component(Component *c) 1.50 { 1.51 for(size_t i=0; i<comp.size(); i++) { 1.52 if(comp[i] == c) { 1.53 + c->detach(); 1.54 comp.erase(comp.begin() + i); 1.55 comp_by_name.erase(c->get_name()); 1.56 return true; 1.57 @@ -50,7 +53,7 @@ 1.58 return false; 1.59 } 1.60 1.61 -bool GameObject::delete_component(Component *c) 1.62 +bool GObject::delete_component(Component *c) 1.63 { 1.64 if(remove_component(c)) { 1.65 delete c; 1.66 @@ -59,7 +62,7 @@ 1.67 return false; 1.68 } 1.69 1.70 -Component *GameObject::get_component(const char *name) const 1.71 +Component *GObject::get_component(const char *name) const 1.72 { 1.73 std::map<std::string, Component*>::const_iterator it; 1.74 if((it = comp_by_name.find(name)) != comp_by_name.end()) { 1.75 @@ -68,13 +71,119 @@ 1.76 return 0; 1.77 } 1.78 1.79 -void GameObject::update() 1.80 +void GObject::update(float dt) 1.81 { 1.82 if(!sorted) { 1.83 - std::sort(comp.begin(), comp.end()); 1.84 + sort_components(); 1.85 + sorted = true; 1.86 } 1.87 1.88 + printf("obj(%p) update\n", (void*)this); 1.89 for(size_t i=0; i<comp.size(); i++) { 1.90 - comp[i]->update(); 1.91 + printf(" updating component: %s\n", comp[i]->get_name()); 1.92 + comp[i]->update(dt); 1.93 } 1.94 } 1.95 + 1.96 +void GObject::draw() const 1.97 +{ 1.98 + // TODO optimization: draw only specific components? 1.99 + for(size_t i=0; i<comp.size(); i++) { 1.100 + comp[i]->draw(); 1.101 + } 1.102 +} 1.103 + 1.104 +struct TopoSucNode { 1.105 + int idx; 1.106 + TopoSucNode *next; 1.107 +}; 1.108 + 1.109 +struct TopoItem { 1.110 + Component *co; 1.111 + int npre; // number of predeccessors 1.112 + TopoSucNode *suc; // successor list 1.113 + TopoItem *qnext, *qprev; // queue list links 1.114 +}; 1.115 + 1.116 +int countq(TopoItem *q) 1.117 +{ 1.118 + int n = 0; 1.119 + while(q) { 1.120 + n++; 1.121 + q = q->qnext; 1.122 + } 1.123 + return n; 1.124 +} 1.125 + 1.126 +// topological sort of components based on update_before() relationships 1.127 +void GObject::sort_components() 1.128 +{ 1.129 + int nitems = (int)comp.size(); 1.130 + TopoItem *items = (TopoItem*)alloca(nitems * sizeof *items); 1.131 + TopoItem *queue = items; 1.132 + 1.133 + // initialize the items 1.134 + for(int i=0; i<nitems; i++) { 1.135 + items[i].co = comp[i]; 1.136 + items[i].npre = 0; 1.137 + items[i].suc = 0; 1.138 + items[i].qnext = i + 1 < nitems ? items + i + 1 : 0; 1.139 + items[i].qprev = i > 0 ? items + i - 1 : 0; 1.140 + } 1.141 + 1.142 + // populate the array 1.143 + for(int i=0; i<nitems; i++) { 1.144 + const char **iter = comp[i]->update_before(); 1.145 + while(*iter) { 1.146 + const char *sucname = *iter++; 1.147 + 1.148 + for(int j=0; j<nitems; j++) { 1.149 + if(j == i) continue; 1.150 + if(strcmp(comp[j]->get_name(), sucname) == 0) { 1.151 + // found a component(j) depending on i, increment its predeccessor counter 1.152 + items[j].npre++; 1.153 + // remove it from the queue 1.154 + if(queue == items + j) { 1.155 + queue = items[j].qnext; 1.156 + assert(items[j].qprev == 0); 1.157 + } 1.158 + if(items[j].qprev) items[j].qprev->qnext = items[j].qnext; 1.159 + if(items[j].qnext) items[j].qnext->qprev = items[j].qprev; 1.160 + items[j].qprev = items[j].qnext = 0; 1.161 + 1.162 + // and add it to our successor list 1.163 + TopoSucNode *n = (TopoSucNode*)alloca(sizeof *n); 1.164 + n->idx = j; 1.165 + n->next = items[i].suc; 1.166 + items[i].suc = n; 1.167 + } 1.168 + } 1.169 + } 1.170 + } 1.171 + 1.172 + // now remove each item from the queue and add it to the sorted list 1.173 + int idx = 0; 1.174 + while(queue) { 1.175 + assert(idx < nitems); 1.176 + comp[idx++] = queue->co; 1.177 + 1.178 + // traverse the successor list, decrementing their predeccessor counts 1.179 + TopoSucNode *n = queue->suc; 1.180 + queue = queue->qnext; 1.181 + 1.182 + while(n) { 1.183 + TopoItem *it = items + n->idx; 1.184 + n = n->next; 1.185 + 1.186 + assert(it->npre > 0); 1.187 + if(--it->npre <= 0) { 1.188 + // if the count reached zero, add it to the queue 1.189 + it->qprev = 0; 1.190 + it->qnext = queue; 1.191 + queue = it; 1.192 + } 1.193 + } 1.194 + } 1.195 + 1.196 + assert(idx == nitems); 1.197 +}