rendered paste body//// influence_map.h// Metaballs_2d//// Created by Simon Harvey on 11-05-10.// Copyright 2011 __MyCompanyName__. All rights reserved.//#include <list>#include <set>#include <map>#include <vector>#include "cinder/Vector.h"#include "cinder/gl/gl.h"using namespace std;using namespace cinder;namespace influence { typedef Vec2<int> index_t; typedef unsigned int square_state_t; typedef enum { UP, RIGHT, DOWN, LEFT } move; const move move_lookup[12] = { DOWN, LEFT, RIGHT, RIGHT, DOWN, LEFT, LEFT, UP, UP, UP, LEFT, LEFT, }; const index_t moves[4] = { index_t(0, -1), index_t(1, 0), index_t(0, 1), index_t(-1, 0) }; class Emitter { public: Vec2f position; float radius; void *owner; Emitter(Vec2f pos, float radius, void *owner) { this->position = pos; this->radius = radius; this->owner = owner; } inline bool might_affect(Vec2f pos) { return abs(pos.x - position.x) <= radius && abs(pos.y - position.y) <= radius; } inline float effect_at(Vec2f pos) { float d2 = position.distanceSquared(pos); if (d2 <= radius*radius) return (radius-sqrt(d2))/radius/* * modifier*/; return 0; } }; typedef map<void *, float> index_influences; bool value_comparer(index_influences::value_type &i1, index_influences::value_type &i2) { return i1.second<i2.second; } class InfluenceMap { public: unsigned int width, height, size_f; std::list<void *> influences; std::set<Emitter *> emitters; InfluenceMap() : width(256), height(256), size_f(4) { } InfluenceMap(unsigned int w, unsigned int h) : width(w), height(h), size_f(4) { } void add_emitter(Emitter *e) { emitters.insert(e); } typedef std::map<index_t, void *> cache_t; cache_t owner_cache; void * compute_owner_at(index_t pos) { set<Emitter *>::iterator it = emitters.begin(); index_influences values; for ( ; it != emitters.end(); it++) { Emitter *e = *it; Vec2f f_pos = pos * (2 << size_f); // position on the field, not on the grid if (e->might_affect(f_pos)) { values[e->owner] += e->effect_at(f_pos); } } //index_influences::value_type best = *values.begin(); /*values.count(); index_influences::iterator itor = std::max_element(values.begin(), values.end(), value_comparer); index_influences::value_type best = *itor;*/ /*if (best.second >= .001) { // treshold return best.first; } else {*/ return 0; //} } void * owner_at(index_t pos) { // calculate if not in cache void * owner; cache_t::iterator it = owner_cache.begin(); if (it == owner_cache.end()) { // compute it! owner = compute_owner_at(pos); } else { owner = it->second; //owner_cache.insert(pos, owner); } return 0; } bool active_at(void *owner, int px, int py) { if (px < 0 || py < 0 || px >= width || py >= height) return false; index_t i = index_t(px, py); return owner_at(i) == owner; } square_state_t state_at(void *owner, index_t i) { return active_at(owner, i.x, i.y) << 3 | active_at(owner, i.x+1, i.y) << 2 | active_at(owner, i.x, i.y+1) << 1 | active_at(owner, i.x+1, i.y+1); } void update () { map<void *, list<index_t> >blobs; set<Emitter *> open(emitters); unsigned int grid_size = 2 << size_f; printf("update\n"); glColor3f(1, 1, 1); while(open.size()) { Emitter e = **open.begin(); open.erase(open.begin()); index_t pos = index_t(e.position.x/grid_size, e.position.y/grid_size); vector<Vec2f> verts; int i = 0; do { square_state_t state = state_at(e.owner, pos); pos += moves[move_lookup[state]]; verts.push_back(Vec2f(pos.x*10.0f, pos.y*10.0f)); i++; } while(true && i < 50); if (verts.size()) { glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2, GL_FLOAT, 0, verts[0]); glDrawArrays(GL_LINE_LOOP, 0, verts.size()); } } } };}