1 #ifndef MSP_GL_INSTANCEARRAY_H_
2 #define MSP_GL_INSTANCEARRAY_H_
5 #include <msp/core/noncopyable.h>
6 #include "programdata.h"
7 #include "renderable.h"
8 #include "vertexarray.h"
9 #include "vertexsetup.h"
18 class InstanceArrayBase: public Renderable, public NonCopyable
21 class Loader: public DataFile::ObjectLoader<InstanceArrayBase>
24 static ActionMap shared_actions;
27 Loader(InstanceArrayBase &);
30 virtual void init_actions();
33 virtual void instance() = 0;
48 std::uint16_t array_index;
49 std::uint16_t next_free;
51 std::uint16_t block_index;
52 std::uint16_t index_in_block;
56 VertexArray instance_data;
57 Buffer *instance_buffer = 0;
58 VertexSetup vtx_setup;
59 int matrix_location = -1;
60 unsigned matrix_offset = 0;
61 std::size_t instance_size;
62 std::size_t default_count;
63 std::vector<Block> storage;
64 std::vector<Slot> slots;
65 std::vector<int> array_order;
68 std::size_t instance_count = 0;
71 InstanceArrayBase(const Object &, std::size_t);
75 void add_block(std::size_t);
76 std::size_t allocate();
77 char *get_address(std::size_t) const;
78 std::size_t find_index(char *) const;
79 void release(std::size_t);
81 template<typename T, typename A>
90 void update_instance_matrix(std::size_t, const Matrix &);
93 std::size_t size() const { return instance_count; }
95 virtual void render(Renderer &, Tag) const;
98 template<typename T, typename A>
99 inline T *InstanceArrayBase::create(A &array)
101 size_t index = allocate();
102 return new(get_address(index)) T(object, array, index);
106 inline void InstanceArrayBase::destroy(T *obj)
108 char *addr = reinterpret_cast<char *>(obj);
110 release(find_index(addr));
114 inline void InstanceArrayBase::destroy_all()
116 for(unsigned i=0; i<slots.size(); ++i)
118 reinterpret_cast<T *>(get_address(i))->~T();
123 Stores and renders multiple instances of an Object in an efficient manner.
125 The instance specific transform is passed to the shader in an attribute with
126 the name instance_transform. The attribute should have the type vec4[3]. Each
127 elements of the array corresponds to a row of the transform matrix.
129 If the Mesh or Technique of the Object is changed during the lifetime of the
130 InstanceArray, behaviour is undefined.
132 The instance type must have a constructor accepting a const Object &. If it
133 has a virtual function with the signature void set_matrix(const Matrix &), it
134 will be used to update the instance matrix. The original function is also
137 Instance created by the array have stable addresses. However after an instance
138 is removed, its address may later be reused for another instance.
140 template<typename T = ObjectInstance>
141 class InstanceArray: public InstanceArrayBase
144 class Loader: public DataFile::DerivedObjectLoader<InstanceArray, InstanceArrayBase::Loader>
147 Loader(InstanceArray &a): DataFile::DerivedObjectLoader<InstanceArray, InstanceArrayBase::Loader>(a) { }
150 virtual void instance();
154 class Instance: public T
157 InstanceArray &array;
161 Instance(const Object &o, InstanceArray &a, unsigned i): T(o), array(a), index(i) { }
163 virtual void set_matrix(const Matrix &);
167 InstanceArray(const Object &o): InstanceArrayBase(o, sizeof(Instance)) { }
168 ~InstanceArray() { destroy_all<T>(); }
170 T &append() { return *create<Instance>(*this); }
171 void remove(T &obj) { destroy(&obj); }
176 inline void InstanceArray<T>::Instance::set_matrix(const Matrix &m)
179 array.update_instance_matrix(index, *this->get_matrix());
184 void InstanceArray<T>::Loader::instance()
186 T &inst = this->obj.append();
187 this->load_sub(inst);