This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "psystem.h" | |
#include <cstddef> | |
#include <cstdio> | |
#include <algorithm> | |
#include <vector> | |
#include "psystem_manager.h" | |
#define REMAP_CACHE 128 | |
namespace { | |
template<typename T> struct type_ { static const int object_id; static const int pointer_id; }; | |
#define PARTICLE_OBJECT_ID(T,ID) template<> const int type_<particle_system::T>::object_id = PID_##ID; | |
#define PARTICLE_POINTER_ID(T,ID) template<> const int type_<particle_system::T>::pointer_id = PID_##ID; | |
PARTICLE_OBJECT_ID(value, VALUE) | |
PARTICLE_OBJECT_ID(lifetime, LIFETIME) | |
PARTICLE_POINTER_ID(object, OBJECT) | |
} | |
class particle_system::attribute { | |
public: | |
virtual ~attribute() {}; | |
virtual int remap(struct particle_remap *map, int n) = 0; | |
virtual void pop_back() = 0; | |
}; | |
namespace { | |
template<typename T> | |
struct attribute_remap : public particle_system::attribute { | |
int remap(struct particle_remap *map, int n) override { | |
T * self = static_cast<T *>(this); | |
for (int i=0;i<n;i++) { | |
if (map[i].component_id != map[0].component_id) | |
return i; | |
if (map[i].to_id != PARTICLE_INVALID) { | |
self->move(map[i].from_id, map[i].to_id); | |
} else { | |
self->shrink(map[i].from_id); | |
} | |
} | |
return n; | |
} | |
}; | |
template<typename T> | |
struct attribute_object final : public attribute_remap<attribute_object<T>> { | |
void move(int from, int to) { | |
data[to] = std::move(data[from]); | |
} | |
void shrink(int n) { | |
data.resize(n); | |
} | |
void pop_back() override { | |
data.pop_back(); | |
} | |
void* pointer(int index) { | |
return reinterpret_cast<void *>(&data[index]); | |
} | |
std::vector<T> data; | |
}; | |
template<typename T> | |
struct attribute_pointer final : public attribute_remap<attribute_pointer<T>> { | |
~attribute_pointer() { | |
for (auto& iter : data) { | |
delete(iter); | |
} | |
} | |
void move(int from, int to) { | |
delete(data[to]); | |
data[to] = data[from]; | |
data[from] = nullptr; | |
} | |
void shrink(int n) { | |
int sz = data.size(); | |
for (int i=n;i<sz;i++) { | |
delete(data[i]); | |
} | |
data.resize(n); | |
} | |
void pop_back() override { | |
delete(data.back()); | |
data.pop_back(); | |
} | |
void* pointer(int index) { | |
return reinterpret_cast<void *>(data[index]); | |
} | |
std::vector<T*> data; | |
}; | |
} | |
template<typename T> | |
struct particle_system::type : public type_<T> { | |
static const int id = type_<T>::object_id; | |
typedef attribute_object<T> container_type; | |
typedef T value_type; | |
}; | |
template <typename T> | |
struct particle_system::type<T*> : public type_<T> { | |
static const int id = type_<T>::pointer_id; | |
typedef attribute_pointer<T> container_type; | |
typedef T value_type; | |
}; | |
particle_system::particle_system() { | |
manager = particlesystem_create(); | |
init<value>(); | |
init<lifetime>(); | |
init<object *>(); | |
} | |
particle_system::~particle_system() { | |
for (int i=0;i<maxid;i++) { | |
delete attribs[i]; | |
} | |
particlesystem_release(manager); | |
} | |
template <typename T> | |
void particle_system::init() { | |
attribs[type<T>::id] = new typename type<T>::container_type; | |
} | |
template <typename T> | |
int particle_system::push_back(T &&v) { | |
int id = type<T>::id; | |
static_cast<typename type<T>::container_type *>(attribs[id])->data.push_back(v); | |
return id; | |
} | |
template <typename T> | |
void particle_system::remove(int index) { | |
particlesystem_remove(manager, type<T>::id, index); | |
} | |
template <typename T> | |
const typename particle_system::type<T>::value_type * particle_system::sibling(int tag, int index) { | |
int sindex = particlesystem_component(manager, tag, index, type<T>::id); | |
if (sindex == PARTICLE_INVALID) | |
return nullptr; | |
return reinterpret_cast<const typename type<T>::value_type *> | |
(static_cast<typename type<T>::container_type *>(attribs[type<T>::id])->pointer(sindex)); | |
} | |
void | |
particle_system::add(const std::initializer_list<int> &a) { | |
if (!particlesystem_add(manager, a.size(), a.begin())) { | |
for (auto id : a) { | |
attribs[id]->pop_back(); | |
} | |
} | |
} | |
template <typename T> | |
struct particle_system::container : public std::vector<T>, particle_system::type<T> { | |
static particle_system::container<T>& convert(attribute *a) { | |
return *static_cast<particle_system::container<T>*>(&static_cast<typename particle_system::type<T>::container_type *>(a)->data); | |
} | |
}; | |
template <typename T> | |
particle_system::container<T>& particle_system::attrib() { | |
return container<T>::convert(attribs[container<T>::id]); | |
} | |
void | |
particle_system::arrange() { | |
struct particle_remap remap[REMAP_CACHE]; | |
struct particle_arrange_context ctx; | |
int n = 0; | |
int cap = sizeof(remap)/sizeof(remap[0]); | |
do { | |
n = particlesystem_arrange(manager, cap, remap, &ctx); | |
int i=0; | |
while (i<n) { | |
int component_id = remap[i].component_id; | |
if (component_id < maxid) { | |
i+=attribs[component_id]->remap(remap+i, n-i); | |
} else { | |
++i; | |
} | |
} | |
} while (n == cap); | |
} | |
int | |
particle_system::size(int pid) { | |
return particlesystem_count(manager, pid); | |
} | |
void | |
particle_system::update_life(float dt) { | |
int index = 0; | |
for (auto &life : attrib<lifetime>()) { | |
printf("lifetime: %f\n", life); | |
life -= dt; | |
if (life <= 0) { | |
printf("REMOVE %d\n", index); | |
remove<lifetime>(index); | |
} | |
++index; | |
} | |
} | |
void | |
particle_system::update_value() { | |
for (auto &v : attrib<value>()) { | |
v.value += v.delta; | |
} | |
} | |
void | |
particle_system::update_print() { | |
int n = size(TAG_PRINT); | |
for (int i = 0;i<n;i++) { | |
const value *v = sibling<value>(TAG_PRINT, i); | |
if (v) { | |
printf("Value = %d ", v->value); | |
} | |
const object *obj = sibling<object *>(TAG_PRINT, i); | |
if (obj) { | |
printf("Object = %d ", obj->value()); | |
} | |
printf("\tParticle %d\n", i); | |
} | |
} | |
void | |
particle_system::test() { | |
/* | |
static const char *names[PARTICLE_COMPONENT] { | |
"value", | |
"lifetime", | |
"object", | |
"print", | |
}; | |
*/ | |
add({ | |
push_back(lifetime(10)), | |
TAG_PRINT, | |
}); | |
add({ | |
push_back(lifetime(20)), | |
push_back(value { 0, 1 }), | |
push_back(new object(42)), | |
TAG_PRINT, | |
}); | |
add({ | |
push_back(lifetime(15)), | |
push_back(value { 0, 10 }), | |
TAG_PRINT, | |
}); | |
add({ | |
push_back(lifetime(17)), | |
push_back(value { 0, 3 }), | |
TAG_PRINT, | |
}); | |
add({ | |
push_back(lifetime(4)), | |
push_back(value { 0, 5 }), | |
TAG_PRINT, | |
}); | |
add({ | |
push_back(lifetime(8)), | |
push_back(value { 0, 20 }), | |
TAG_PRINT, | |
}); | |
for (int i=0;i<10;i++) { | |
printf("== Frame %d ==\n", i); | |
update_life(2.0f); | |
update_value(); | |
update_print(); | |
// particlesystem_debug(manager, names); | |
arrange(); | |
} | |
} | |
int | |
main() { | |
particle_system P; | |
P.test(); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef particle_system_h | |
#define particle_system_h | |
#define PID_VALUE 0 | |
#define PID_OBJECT 1 | |
#define PARTICLE_KEY_COMPONENT 2 // key components | |
#define PID_LIFETIME 2 | |
#define PID_COUNT 3 // number components types of data in particle_system | |
#define TAG_PRINT 3 | |
#define PARTICLE_COMPONENT 4 // total tags and components | |
#include <initializer_list> | |
struct particle_manager; | |
class particle_system { | |
public: | |
struct value { | |
int value; | |
int delta; | |
}; | |
class object { | |
public: | |
object(int v) : v(v) {} | |
int value() const { return v; } | |
private: | |
int v; | |
}; | |
typedef float lifetime; | |
particle_system(); | |
~particle_system(); | |
void test(); | |
void update_life(float dt); | |
void update_value(); | |
void update_print(); | |
static const int maxid = PID_COUNT; | |
private: | |
template <typename T> struct type; | |
void arrange(); | |
void add(const std::initializer_list<int> &a); | |
template <typename T> void init(); | |
template <typename T> int push_back(T &&); | |
template <typename T> void pop_back(); | |
template <typename T> void remove(int index); | |
template <typename T> struct container; | |
template <typename T> const typename type<T>::value_type * sibling(int tag, int index); | |
template <typename T> container<T>& attrib(); | |
int size(int pid); | |
class attribute; | |
attribute * attribs[maxid]; | |
struct particle_manager *manager; | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment