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 +}