coeng

changeset 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
files Makefile src/co_dbgvis.cc src/co_dbgvis.h src/co_phys.cc src/co_phys.h src/co_xform.cc src/co_xform.h src/comp.cc src/comp.h src/gobj.cc src/gobj.h src/sim.cc src/sim.h src/test.cc
diffstat 14 files changed, 511 insertions(+), 42 deletions(-) [+]
line diff
     1.1 --- a/Makefile	Sat Feb 14 01:35:42 2015 +0200
     1.2 +++ b/Makefile	Sat Feb 14 07:27:12 2015 +0200
     1.3 @@ -1,5 +1,6 @@
     1.4  ccsrc = $(wildcard src/*.cc)
     1.5  obj = $(ccsrc:.cc=.o)
     1.6 +dep = $(obj:.o=.d)
     1.7  bin = test
     1.8  
     1.9  warn = -pedantic -Wall
    1.10 @@ -18,6 +19,15 @@
    1.11  $(bin): $(obj)
    1.12  	$(CXX) -o $@ $(obj) $(LDFLAGS)
    1.13  
    1.14 +-include $(dep)
    1.15 +
    1.16 +%.d: %.cc
    1.17 +	@$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@
    1.18 +
    1.19  .PHONY: clean
    1.20  clean:
    1.21  	rm -f $(obj) $(bin)
    1.22 +
    1.23 +.PHONY: cleandep
    1.24 +cleandep:
    1.25 +	rm -f $(dep)
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/co_dbgvis.cc	Sat Feb 14 07:27:12 2015 +0200
     2.3 @@ -0,0 +1,48 @@
     2.4 +#ifndef __APPLE__
     2.5 +#include <GL/glut.h>
     2.6 +#else
     2.7 +#include <GLUT/glut.h>
     2.8 +#endif
     2.9 +#include "co_dbgvis.h"
    2.10 +#include "gobj.h"
    2.11 +
    2.12 +static CoSphereVis reg_co_sphere;
    2.13 +
    2.14 +static Component *cons_sphere() { return new CoSphereVis; }
    2.15 +
    2.16 +
    2.17 +CoSphereVis::CoSphereVis()
    2.18 +	: color(1, 1, 1)
    2.19 +{
    2.20 +	name = "spherevis";
    2.21 +	radius = 1.0;
    2.22 +	co_xform = 0;
    2.23 +
    2.24 +	register_component(name, cons_sphere);
    2.25 +}
    2.26 +
    2.27 +void CoSphereVis::update(float dt)
    2.28 +{
    2.29 +	if(!co_xform) {
    2.30 +		co_xform = COCAST(CoXForm, gobj->get_component("xform"));
    2.31 +	}
    2.32 +}
    2.33 +
    2.34 +void CoSphereVis::draw() const
    2.35 +{
    2.36 +	if(co_xform) {
    2.37 +		Matrix4x4 xform = co_xform->xform.transposed();
    2.38 +
    2.39 +		glPushMatrix();
    2.40 +		glMultMatrixf(xform.m[0]);
    2.41 +	}
    2.42 +
    2.43 +	float diffuse[] = { color.x, color.y, color.z, 1.0f };
    2.44 +	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, diffuse);
    2.45 +
    2.46 +	glutSolidSphere(radius, 16, 8);
    2.47 +
    2.48 +	if(co_xform) {
    2.49 +		glPopMatrix();
    2.50 +	}
    2.51 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/co_dbgvis.h	Sat Feb 14 07:27:12 2015 +0200
     3.3 @@ -0,0 +1,22 @@
     3.4 +#ifndef CO_DBGVIS_H_
     3.5 +#define CO_DBGVIS_H_
     3.6 +
     3.7 +#include "gobj.h"
     3.8 +#include "comp.h"
     3.9 +#include "co_xform.h"
    3.10 +
    3.11 +class CoSphereVis : public Component {
    3.12 +protected:
    3.13 +	CoXForm *co_xform;
    3.14 +
    3.15 +public:
    3.16 +	float radius;
    3.17 +	Vector3 color;
    3.18 +
    3.19 +	CoSphereVis();
    3.20 +
    3.21 +	void update(float dt);
    3.22 +	void draw() const;
    3.23 +};
    3.24 +
    3.25 +#endif	// CO_DBGVIS_H_
     4.1 --- a/src/co_phys.cc	Sat Feb 14 01:35:42 2015 +0200
     4.2 +++ b/src/co_phys.cc	Sat Feb 14 07:27:12 2015 +0200
     4.3 @@ -1,4 +1,6 @@
     4.4 +#include <assert.h>
     4.5  #include "co_phys.h"
     4.6 +#include "sim.h"
     4.7  
     4.8  static CoRigid reg_co_rigid;
     4.9  
    4.10 @@ -15,6 +17,42 @@
    4.11  	register_component(name, cons_rigid);
    4.12  }
    4.13  
    4.14 -void CoRigid::update()
    4.15 +const char **CoRigid::update_before() const
    4.16  {
    4.17 +	static const char *before[] = { "prs", 0 };
    4.18 +	return before;
    4.19  }
    4.20 +
    4.21 +void CoRigid::add_impulse(const Vector3 &v)
    4.22 +{
    4.23 +	impulse += v;
    4.24 +}
    4.25 +
    4.26 +void CoRigid::update(float dt)
    4.27 +{
    4.28 +	if(!gobj) return;
    4.29 +
    4.30 +	if(!co_prs) {
    4.31 +		if(!(co_prs = COCAST(CoPRS, gobj->get_component("prs")))) {
    4.32 +			assert(co_prs);
    4.33 +			return;
    4.34 +		}
    4.35 +	}
    4.36 +
    4.37 +	float damping = world ? world->get_damping() : 0.005;
    4.38 +
    4.39 +	Vector3 newpos = co_prs->pos + vel * dt;
    4.40 +
    4.41 +	Vector3 accel = impulse;
    4.42 +	impulse.x = impulse.y = impulse.z = 0.0f;	// reset impulse
    4.43 +
    4.44 +	if(world) {
    4.45 +		accel += world->get_gravity();
    4.46 +	}
    4.47 +
    4.48 +	vel = (vel - vel * damping * dt) + accel * dt;
    4.49 +
    4.50 +	// TODO collisions
    4.51 +
    4.52 +	co_prs->pos = newpos;
    4.53 +}
     5.1 --- a/src/co_phys.h	Sat Feb 14 01:35:42 2015 +0200
     5.2 +++ b/src/co_phys.h	Sat Feb 14 07:27:12 2015 +0200
     5.3 @@ -3,15 +3,27 @@
     5.4  
     5.5  #include <vmath/vmath.h>
     5.6  #include "comp.h"
     5.7 +#include "co_xform.h"
     5.8 +
     5.9 +class SimWorld;
    5.10  
    5.11  class CoRigid : public Component {
    5.12 +protected:
    5.13 +	CoPRS *co_prs; // cached PRS component of the parent object
    5.14 +
    5.15 +	const char **update_before() const;
    5.16 +
    5.17  public:
    5.18 +	SimWorld *world;
    5.19  	float mass, elast, friction;
    5.20 -	Vector3 pos, vel;
    5.21 +	Vector3 vel, force;
    5.22 +	Vector3 impulse;
    5.23  
    5.24  	CoRigid();
    5.25  
    5.26 -	void update();
    5.27 +	void add_impulse(const Vector3 &v);
    5.28 +
    5.29 +	void update(float dt);
    5.30  };
    5.31  
    5.32  #endif	// COMP_PHYS_H_
     6.1 --- a/src/co_xform.cc	Sat Feb 14 01:35:42 2015 +0200
     6.2 +++ b/src/co_xform.cc	Sat Feb 14 07:27:12 2015 +0200
     6.3 @@ -15,20 +15,28 @@
     6.4  	register_component(name, cons_xform);
     6.5  }
     6.6  
     6.7 +// ---- class CoPRS ----
     6.8 +
     6.9  CoPRS::CoPRS()
    6.10 +	: scale(1, 1, 1)
    6.11  {
    6.12  	name = "prs";
    6.13  
    6.14  	register_component(name, cons_prs);
    6.15  }
    6.16  
    6.17 -void CoPRS::update()
    6.18 +const char **CoPRS::update_before() const
    6.19 +{
    6.20 +	static const char *before[] = { "xform", 0 };
    6.21 +	return before;
    6.22 +}
    6.23 +
    6.24 +void CoPRS::update(float dt)
    6.25  {
    6.26  	if(!gobj) return;
    6.27  
    6.28  	if(!co_xform) {
    6.29 -		Component *co = gobj->get_component("xform");
    6.30 -		if(!co || !(co_xform = dynamic_cast<CoXForm*>(co))) {
    6.31 +		if(!(co_xform = COCAST(CoXForm, gobj->get_component("xform")))) {
    6.32  			assert(co_xform);
    6.33  			return;
    6.34  		}
     7.1 --- a/src/co_xform.h	Sat Feb 14 01:35:42 2015 +0200
     7.2 +++ b/src/co_xform.h	Sat Feb 14 07:27:12 2015 +0200
     7.3 @@ -12,16 +12,18 @@
     7.4  };
     7.5  
     7.6  class CoPRS : public Component {
     7.7 -private:
     7.8 +protected:
     7.9  	CoXForm *co_xform;	// cached xform component of the parent object
    7.10  
    7.11 +	const char **update_before() const;
    7.12 +
    7.13  public:
    7.14  	Vector3 pos, scale;
    7.15  	Quaternion rot;
    7.16  
    7.17  	CoPRS();
    7.18  
    7.19 -	void update();
    7.20 +	void update(float dt);
    7.21  };
    7.22  
    7.23  
     8.1 --- a/src/comp.cc	Sat Feb 14 01:35:42 2015 +0200
     8.2 +++ b/src/comp.cc	Sat Feb 14 07:27:12 2015 +0200
     8.3 @@ -10,28 +10,41 @@
     8.4  {
     8.5  	name = "unknown";
     8.6  	gobj = 0;
     8.7 -	upd_prio = 0;
     8.8  }
     8.9  
    8.10  Component::~Component()
    8.11  {
    8.12  }
    8.13  
    8.14 +void Component::attach(GObject *gobj)
    8.15 +{
    8.16 +	this->gobj = gobj;
    8.17 +}
    8.18 +
    8.19 +void Component::detach()
    8.20 +{
    8.21 +	gobj = 0;
    8.22 +}
    8.23 +
    8.24 +const char **Component::update_before() const
    8.25 +{
    8.26 +	static const char *before[] = { 0 };
    8.27 +	return before;
    8.28 +}
    8.29 +
    8.30  const char *Component::get_name() const
    8.31  {
    8.32  	return name;
    8.33  }
    8.34  
    8.35 -void Component::update()
    8.36 +void Component::update(float dt)
    8.37  {
    8.38  }
    8.39  
    8.40 -bool Component::operator <(const Component &c) const
    8.41 +void Component::draw() const
    8.42  {
    8.43 -	return upd_prio < c.upd_prio;
    8.44  }
    8.45  
    8.46 -
    8.47  void register_component(const char *name, Component *(*cons_func)())
    8.48  {
    8.49  	if(!early_comp_cons) {
     9.1 --- a/src/comp.h	Sat Feb 14 01:35:42 2015 +0200
     9.2 +++ b/src/comp.h	Sat Feb 14 07:27:12 2015 +0200
     9.3 @@ -3,13 +3,31 @@
     9.4  
     9.5  #include <string>
     9.6  
     9.7 -class GameObject;
     9.8 +#ifdef NDEBUG
     9.9 +#define COCAST(type, x)	((type*)x)
    9.10 +#else
    9.11 +#define COCAST(type, x)	dynamic_cast<type*>(x)
    9.12 +#endif
    9.13 +
    9.14 +class GObject;
    9.15  
    9.16  class Component {
    9.17  protected:
    9.18  	const char *name;
    9.19 -	GameObject *gobj;
    9.20 -	int upd_prio;	// update priority (0: normal)
    9.21 +	GObject *gobj;
    9.22 +
    9.23 +	/* attach/detach to a particular GObject.
    9.24 +	 * This is only called from GObject::add_component and
    9.25 +	 * GObject::remove_component respectively
    9.26 +	 */
    9.27 +	virtual void attach(GObject *gobj);
    9.28 +	virtual void detach();
    9.29 +
    9.30 +	/* Returns an array of component names which depend on this and
    9.31 +	 * must not be updated first if both exist in the same object.
    9.32 +	 * Terminated by a null pointer.
    9.33 +	 */
    9.34 +	virtual const char **update_before() const;
    9.35  
    9.36  public:
    9.37  	Component();
    9.38 @@ -17,11 +35,10 @@
    9.39  
    9.40  	const char *get_name() const;
    9.41  
    9.42 -	virtual void update();
    9.43 +	virtual void update(float dt);
    9.44 +	virtual void draw() const;
    9.45  
    9.46 -	bool operator <(const Component &c) const;	// for sorting based on priority
    9.47 -
    9.48 -	friend class GameObject;
    9.49 +	friend class GObject;
    9.50  };
    9.51  
    9.52  void register_component(const char *name, Component *(*cons_func)());
    10.1 --- a/src/gobj.cc	Sat Feb 14 01:35:42 2015 +0200
    10.2 +++ b/src/gobj.cc	Sat Feb 14 07:27:12 2015 +0200
    10.3 @@ -1,25 +1,27 @@
    10.4  #include <stdio.h>
    10.5 +#include <string.h>
    10.6 +#include <assert.h>
    10.7  #include <algorithm>
    10.8  #include "gobj.h"
    10.9  
   10.10 -GameObject::GameObject()
   10.11 +GObject::GObject()
   10.12  {
   10.13  	sorted = true;
   10.14  }
   10.15  
   10.16 -GameObject::~GameObject()
   10.17 +GObject::~GObject()
   10.18  {
   10.19  	for(size_t i=0; i<comp.size(); i++) {
   10.20  		delete comp[i];
   10.21  	}
   10.22  }
   10.23  
   10.24 -bool GameObject::add_component(Component *c)
   10.25 +bool GObject::add_component(Component *c)
   10.26  {
   10.27  	const char *name = c->get_name();
   10.28  
   10.29  	if(comp_by_name.find(name) != comp_by_name.end()) {
   10.30 -		fprintf(stderr, "component %s already exists in this game object (%p)\n", name, (void*)this);
   10.31 +		fprintf(stderr, "component %s already exists in this gobject (%p)\n", name, (void*)this);
   10.32  		return false;
   10.33  	}
   10.34  
   10.35 @@ -27,7 +29,7 @@
   10.36  		comp.push_back(c);
   10.37  		comp_by_name[name] = c;
   10.38  
   10.39 -		c->gobj = this;
   10.40 +		c->attach(this);
   10.41  	}
   10.42  	catch(...) {
   10.43  		fprintf(stderr, "failed to add component: %s\n", name);
   10.44 @@ -38,10 +40,11 @@
   10.45  	return true;
   10.46  }
   10.47  
   10.48 -bool GameObject::remove_component(Component *c)
   10.49 +bool GObject::remove_component(Component *c)
   10.50  {
   10.51  	for(size_t i=0; i<comp.size(); i++) {
   10.52  		if(comp[i] == c) {
   10.53 +			c->detach();
   10.54  			comp.erase(comp.begin() + i);
   10.55  			comp_by_name.erase(c->get_name());
   10.56  			return true;
   10.57 @@ -50,7 +53,7 @@
   10.58  	return false;
   10.59  }
   10.60  
   10.61 -bool GameObject::delete_component(Component *c)
   10.62 +bool GObject::delete_component(Component *c)
   10.63  {
   10.64  	if(remove_component(c)) {
   10.65  		delete c;
   10.66 @@ -59,7 +62,7 @@
   10.67  	return false;
   10.68  }
   10.69  
   10.70 -Component *GameObject::get_component(const char *name) const
   10.71 +Component *GObject::get_component(const char *name) const
   10.72  {
   10.73  	std::map<std::string, Component*>::const_iterator it;
   10.74  	if((it = comp_by_name.find(name)) != comp_by_name.end()) {
   10.75 @@ -68,13 +71,119 @@
   10.76  	return 0;
   10.77  }
   10.78  
   10.79 -void GameObject::update()
   10.80 +void GObject::update(float dt)
   10.81  {
   10.82  	if(!sorted) {
   10.83 -		std::sort(comp.begin(), comp.end());
   10.84 +		sort_components();
   10.85 +		sorted = true;
   10.86  	}
   10.87  
   10.88 +	printf("obj(%p) update\n", (void*)this);
   10.89  	for(size_t i=0; i<comp.size(); i++) {
   10.90 -		comp[i]->update();
   10.91 +		printf("  updating component: %s\n", comp[i]->get_name());
   10.92 +		comp[i]->update(dt);
   10.93  	}
   10.94  }
   10.95 +
   10.96 +void GObject::draw() const
   10.97 +{
   10.98 +	// TODO optimization: draw only specific components?
   10.99 +	for(size_t i=0; i<comp.size(); i++) {
  10.100 +		comp[i]->draw();
  10.101 +	}
  10.102 +}
  10.103 +
  10.104 +struct TopoSucNode {
  10.105 +	int idx;
  10.106 +	TopoSucNode *next;
  10.107 +};
  10.108 +
  10.109 +struct TopoItem {
  10.110 +	Component *co;
  10.111 +	int npre;			// number of predeccessors
  10.112 +	TopoSucNode *suc;	// successor list
  10.113 +	TopoItem *qnext, *qprev;	// queue list links
  10.114 +};
  10.115 +
  10.116 +int countq(TopoItem *q)
  10.117 +{
  10.118 +	int n = 0;
  10.119 +	while(q) {
  10.120 +		n++;
  10.121 +		q = q->qnext;
  10.122 +	}
  10.123 +	return n;
  10.124 +}
  10.125 +
  10.126 +// topological sort of components based on update_before() relationships
  10.127 +void GObject::sort_components()
  10.128 +{
  10.129 +	int nitems = (int)comp.size();
  10.130 +	TopoItem *items = (TopoItem*)alloca(nitems * sizeof *items);
  10.131 +	TopoItem *queue = items;
  10.132 +
  10.133 +	// initialize the items
  10.134 +	for(int i=0; i<nitems; i++) {
  10.135 +		items[i].co = comp[i];
  10.136 +		items[i].npre = 0;
  10.137 +		items[i].suc = 0;
  10.138 +		items[i].qnext = i + 1 < nitems ? items + i + 1 : 0;
  10.139 +		items[i].qprev = i > 0 ? items + i - 1 : 0;
  10.140 +	}
  10.141 +
  10.142 +	// populate the array
  10.143 +	for(int i=0; i<nitems; i++) {
  10.144 +		const char **iter = comp[i]->update_before();
  10.145 +		while(*iter) {
  10.146 +			const char *sucname = *iter++;
  10.147 +
  10.148 +			for(int j=0; j<nitems; j++) {
  10.149 +				if(j == i) continue;
  10.150 +				if(strcmp(comp[j]->get_name(), sucname) == 0) {
  10.151 +					// found a component(j) depending on i, increment its predeccessor counter
  10.152 +					items[j].npre++;
  10.153 +					// remove it from the queue
  10.154 +					if(queue == items + j) {
  10.155 +						queue = items[j].qnext;
  10.156 +						assert(items[j].qprev == 0);
  10.157 +					}
  10.158 +					if(items[j].qprev) items[j].qprev->qnext = items[j].qnext;
  10.159 +					if(items[j].qnext) items[j].qnext->qprev = items[j].qprev;
  10.160 +					items[j].qprev = items[j].qnext = 0;
  10.161 +
  10.162 +					// and add it to our successor list
  10.163 +					TopoSucNode *n = (TopoSucNode*)alloca(sizeof *n);
  10.164 +					n->idx = j;
  10.165 +					n->next = items[i].suc;
  10.166 +					items[i].suc = n;
  10.167 +				}
  10.168 +			}
  10.169 +		}
  10.170 +	}
  10.171 +
  10.172 +	// now remove each item from the queue and add it to the sorted list
  10.173 +	int idx = 0;
  10.174 +	while(queue) {
  10.175 +		assert(idx < nitems);
  10.176 +		comp[idx++] = queue->co;
  10.177 +
  10.178 +		// traverse the successor list, decrementing their predeccessor counts
  10.179 +		TopoSucNode *n = queue->suc;
  10.180 +		queue = queue->qnext;
  10.181 +
  10.182 +		while(n) {
  10.183 +			TopoItem *it = items + n->idx;
  10.184 +			n = n->next;
  10.185 +
  10.186 +			assert(it->npre > 0);
  10.187 +			if(--it->npre <= 0) {
  10.188 +				// if the count reached zero, add it to the queue
  10.189 +				it->qprev = 0;
  10.190 +				it->qnext = queue;
  10.191 +				queue = it;
  10.192 +			}
  10.193 +		}
  10.194 +	}
  10.195 +
  10.196 +	assert(idx == nitems);
  10.197 +}
    11.1 --- a/src/gobj.h	Sat Feb 14 01:35:42 2015 +0200
    11.2 +++ b/src/gobj.h	Sat Feb 14 07:27:12 2015 +0200
    11.3 @@ -1,29 +1,32 @@
    11.4 -#ifndef GAMEOBJECT_H_
    11.5 -#define GAMEOBJECT_H_
    11.6 +#ifndef GOBJECT_H_
    11.7 +#define GOBJECT_H_
    11.8  
    11.9  #include <vector>
   11.10  #include <map>
   11.11  #include <string>
   11.12  #include "comp.h"
   11.13  
   11.14 -class GameObject {
   11.15 +class GObject {
   11.16  private:
   11.17  	std::vector<Component*> comp;
   11.18  	std::map<std::string, Component*> comp_by_name;
   11.19  
   11.20  	bool sorted;
   11.21  
   11.22 +	void sort_components();
   11.23 +
   11.24  public:
   11.25 -	GameObject();
   11.26 -	~GameObject();
   11.27 +	GObject();
   11.28 +	~GObject();
   11.29  
   11.30 -	bool add_component(Component *c);	// takes ownership
   11.31 -	bool remove_component(Component *c);
   11.32 +	bool add_component(Component *c);		// takes ownership
   11.33 +	bool remove_component(Component *c);	// whoever calls this, now has ownership
   11.34  	bool delete_component(Component *c);
   11.35  
   11.36  	Component *get_component(const char *name) const;
   11.37  
   11.38 -	void update();
   11.39 +	void update(float dt = 0.0f);
   11.40 +	void draw() const;
   11.41  };
   11.42  
   11.43 -#endif	// GAMEOBJECT_H_
   11.44 +#endif	// GOBJECT_H_
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/sim.cc	Sat Feb 14 07:27:12 2015 +0200
    12.3 @@ -0,0 +1,66 @@
    12.4 +#include <algorithm>
    12.5 +#include "sim.h"
    12.6 +
    12.7 +SimWorld::SimWorld()
    12.8 +	: gravity(0, -9, 0)
    12.9 +{
   12.10 +	damping = 0.005;
   12.11 +}
   12.12 +
   12.13 +void SimWorld::add_object(GObject *obj)
   12.14 +{
   12.15 +	CoRigid *co = COCAST(CoRigid, obj->get_component("phys"));
   12.16 +	if(co) {
   12.17 +		add_rigid_body(co);
   12.18 +	} else {
   12.19 +		fprintf(stderr, "SimWorld::add_object: trying to add object without rigid body component\n");
   12.20 +	}
   12.21 +}
   12.22 +
   12.23 +void SimWorld::add_rigid_body(CoRigid *co)
   12.24 +{
   12.25 +	if(std::find(rigid.begin(), rigid.end(), co) == rigid.end()) {
   12.26 +		rigid.push_back(co);
   12.27 +		co->world = this;
   12.28 +	}
   12.29 +}
   12.30 +
   12.31 +void SimWorld::remove_object(GObject *obj)
   12.32 +{
   12.33 +	CoRigid *co = COCAST(CoRigid, obj->get_component("phys"));
   12.34 +	if(co) {
   12.35 +		remove_rigid_body(co);
   12.36 +	} else {
   12.37 +		fprintf(stderr, "SimWorld::remove_object: failed to remove object without rigid body component\n");
   12.38 +	}
   12.39 +}
   12.40 +
   12.41 +void SimWorld::remove_rigid_body(CoRigid *co)
   12.42 +{
   12.43 +	std::list<CoRigid*>::iterator it = std::find(rigid.begin(), rigid.end(), co);
   12.44 +	if(it != rigid.end()) {
   12.45 +		rigid.erase(it);
   12.46 +	} else {
   12.47 +		fprintf(stderr, "SimWorld::remove_rigid_body: failed to remove missing rigid body\n");
   12.48 +	}
   12.49 +}
   12.50 +
   12.51 +void SimWorld::set_damping(float damping)
   12.52 +{
   12.53 +	this->damping = damping;
   12.54 +}
   12.55 +
   12.56 +float SimWorld::get_damping() const
   12.57 +{
   12.58 +	return damping;
   12.59 +}
   12.60 +
   12.61 +void SimWorld::set_gravity(const Vector3 &v)
   12.62 +{
   12.63 +	gravity = v;
   12.64 +}
   12.65 +
   12.66 +const Vector3 &SimWorld::get_gravity() const
   12.67 +{
   12.68 +	return gravity;
   12.69 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/sim.h	Sat Feb 14 07:27:12 2015 +0200
    13.3 @@ -0,0 +1,30 @@
    13.4 +#ifndef COENG_SIM_H_
    13.5 +#define COENG_SIM_H_
    13.6 +
    13.7 +#include <list>
    13.8 +#include "co_phys.h"
    13.9 +#include "gobj.h"
   13.10 +
   13.11 +class SimWorld {
   13.12 +private:
   13.13 +	std::list<CoRigid*> rigid;
   13.14 +	Vector3 gravity;
   13.15 +	float damping;
   13.16 +
   13.17 +public:
   13.18 +	SimWorld();
   13.19 +
   13.20 +	void add_object(GObject *obj);	// convenience function, calls add_rigid_body
   13.21 +	void add_rigid_body(CoRigid *co);
   13.22 +
   13.23 +	void remove_object(GObject *obj);	// convenience function, calls remove_rigid_body
   13.24 +	void remove_rigid_body(CoRigid *co);
   13.25 +
   13.26 +	void set_damping(float damping);
   13.27 +	float get_damping() const;
   13.28 +
   13.29 +	void set_gravity(const Vector3 &v);
   13.30 +	const Vector3 &get_gravity() const;
   13.31 +};
   13.32 +
   13.33 +#endif	// COENG_SIM_H_
    14.1 --- a/src/test.cc	Sat Feb 14 01:35:42 2015 +0200
    14.2 +++ b/src/test.cc	Sat Feb 14 07:27:12 2015 +0200
    14.3 @@ -1,6 +1,7 @@
    14.4  #include <stdio.h>
    14.5  #include <stdlib.h>
    14.6  #include <assert.h>
    14.7 +#include <vector>
    14.8  
    14.9  #ifndef __APPLE__
   14.10  #include <GL/glut.h>
   14.11 @@ -8,6 +9,11 @@
   14.12  #include <GLUT/glut.h>
   14.13  #endif
   14.14  
   14.15 +#include "gobj.h"
   14.16 +#include "co_xform.h"
   14.17 +#include "co_dbgvis.h"
   14.18 +#include "sim.h"
   14.19 +
   14.20  static bool init();
   14.21  static void cleanup();
   14.22  static void display();
   14.23 @@ -17,6 +23,11 @@
   14.24  static void mouse(int bn, int st, int x, int y);
   14.25  static void motion(int x, int y);
   14.26  
   14.27 +float cam_theta, cam_phi = 25, cam_dist = 8;
   14.28 +
   14.29 +std::vector<GObject*> objects;
   14.30 +SimWorld simworld;
   14.31 +
   14.32  
   14.33  int main(int argc, char **argv)
   14.34  {
   14.35 @@ -26,7 +37,7 @@
   14.36  	glutCreateWindow("component system test");
   14.37  
   14.38  	glutDisplayFunc(display);
   14.39 -	glutIdleFunc(idle);
   14.40 +	//glutIdleFunc(idle);
   14.41  	glutReshapeFunc(reshape);
   14.42  	glutKeyboardFunc(keyb);
   14.43  	glutMouseFunc(mouse);
   14.44 @@ -46,6 +57,26 @@
   14.45  	glEnable(GL_DEPTH_TEST);
   14.46  	glEnable(GL_CULL_FACE);
   14.47  
   14.48 +	glEnable(GL_LIGHTING);
   14.49 +	glEnable(GL_LIGHT0);
   14.50 +	float ldir[] = {-1, 1, 2, 0};
   14.51 +	glLightfv(GL_LIGHT0, GL_POSITION, ldir);
   14.52 +
   14.53 +	GObject *obj = new GObject;
   14.54 +	obj->add_component(new CoSphereVis);
   14.55 +	obj->add_component(new CoXForm);
   14.56 +	obj->add_component(new CoPRS);
   14.57 +	obj->add_component(new CoRigid);
   14.58 +	COCAST(CoPRS, obj->get_component("prs"))->pos = Vector3(5, 1, 0);
   14.59 +	objects.push_back(obj);
   14.60 +
   14.61 +	obj = new GObject;
   14.62 +	obj->add_component(new CoSphereVis);
   14.63 +	obj->add_component(new CoXForm);
   14.64 +	obj->add_component(new CoPRS);
   14.65 +	COCAST(CoPRS, obj->get_component("prs"))->pos = Vector3(-5, 1, 0);
   14.66 +	objects.push_back(obj);
   14.67 +
   14.68  	return true;
   14.69  }
   14.70  
   14.71 @@ -53,10 +84,48 @@
   14.72  {
   14.73  }
   14.74  
   14.75 +static void update()
   14.76 +{
   14.77 +	static unsigned int prev_upd;
   14.78 +	unsigned int msec = glutGet(GLUT_ELAPSED_TIME);
   14.79 +	float dt = (float)(msec - prev_upd) / 1000.0f;
   14.80 +	prev_upd = msec;
   14.81 +
   14.82 +	for(size_t i=0; i<objects.size(); i++) {
   14.83 +		objects[i]->update(dt);
   14.84 +	}
   14.85 +}
   14.86 +
   14.87  static void display()
   14.88  {
   14.89 +	update();
   14.90 +
   14.91  	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   14.92  
   14.93 +	glMatrixMode(GL_MODELVIEW);
   14.94 +	glLoadIdentity();
   14.95 +	glTranslatef(0, 0, -cam_dist);
   14.96 +	glRotatef(cam_phi, 1, 0, 0);
   14.97 +	glRotatef(cam_theta, 0, 1, 0);
   14.98 +
   14.99 +	float floor_col[] = {0.2, 0.8, 0.2, 1};
  14.100 +	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, floor_col);
  14.101 +
  14.102 +	glBegin(GL_QUADS);
  14.103 +	glNormal3f(0, 1, 0);
  14.104 +	glVertex3f(-10, 0, 10);
  14.105 +	glVertex3f(10, 0, 10);
  14.106 +	glVertex3f(10, 0, -10);
  14.107 +	glVertex3f(-10, 0, -10);
  14.108 +	glEnd();
  14.109 +
  14.110 +	for(size_t i=0; i<objects.size(); i++) {
  14.111 +		CoSphereVis *co = COCAST(CoSphereVis, objects[i]->get_component("spherevis"));
  14.112 +		if(co) {
  14.113 +			co->draw();
  14.114 +		}
  14.115 +	}
  14.116 +
  14.117  	glutSwapBuffers();
  14.118  	assert(glGetError() == GL_NO_ERROR);
  14.119  }
  14.120 @@ -83,13 +152,35 @@
  14.121  	}
  14.122  }
  14.123  
  14.124 -static int bnstate[16];
  14.125 +static bool bnstate[16];
  14.126  static int prev_x, prev_y;
  14.127  
  14.128  static void mouse(int bn, int st, int x, int y)
  14.129  {
  14.130 +	bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN;
  14.131 +	prev_x = x;
  14.132 +	prev_y = y;
  14.133  }
  14.134  
  14.135  static void motion(int x, int y)
  14.136  {
  14.137 +	int dx = x - prev_x;
  14.138 +	int dy = y - prev_y;
  14.139 +	prev_x = x;
  14.140 +	prev_y = y;
  14.141 +
  14.142 +	if(bnstate[0]) {
  14.143 +		cam_theta += dx * 0.5;
  14.144 +		cam_phi += dy * 0.5;
  14.145 +
  14.146 +		if(cam_phi < -90) cam_phi = -90;
  14.147 +		if(cam_phi > 90) cam_phi = 90;
  14.148 +
  14.149 +		glutPostRedisplay();
  14.150 +	}
  14.151 +	if(bnstate[2]) {
  14.152 +		cam_dist += dy * 0.1;
  14.153 +
  14.154 +		if(cam_dist < 0.0) cam_dist = 0.0;
  14.155 +	}
  14.156  }