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
32 std::uint16_t array_index;
33 std::uint16_t next_free;
35 std::uint16_t block_index;
36 std::uint16_t index_in_block;
40 VertexArray instance_data;
41 Buffer *instance_buffer = 0;
42 VertexSetup vtx_setup;
43 int matrix_location = -1;
44 unsigned matrix_offset = 0;
45 std::size_t instance_size;
46 std::size_t default_count;
47 std::vector<Block> storage;
48 std::vector<Slot> slots;
49 std::vector<int> array_order;
52 std::size_t instance_count = 0;
55 InstanceArrayBase(const Object &, std::size_t);
59 void add_block(std::size_t);
60 std::size_t allocate();
61 char *get_address(std::size_t) const;
62 std::size_t find_index(char *) const;
63 void release(std::size_t);
65 template<typename T, typename A>
74 void update_instance_matrix(std::size_t, const Matrix &);
77 std::size_t size() const { return instance_count; }
79 virtual void render(Renderer &, Tag) const;
82 template<typename T, typename A>
83 inline T *InstanceArrayBase::create(A &array)
85 size_t index = allocate();
86 return new(get_address(index)) T(object, array, index);
90 inline void InstanceArrayBase::destroy(T *obj)
92 char *addr = reinterpret_cast<char *>(obj);
94 release(find_index(addr));
98 inline void InstanceArrayBase::destroy_all()
100 for(unsigned i=0; i<slots.size(); ++i)
102 reinterpret_cast<T *>(get_address(i))->~T();
107 Stores and renders multiple instances of an Object in an efficient manner.
109 The instance specific transform is passed to the shader in an attribute with
110 the name instance_transform. The attribute should have the type vec4[3]. Each
111 elements of the array corresponds to a row of the transform matrix.
113 If the Mesh or Technique of the Object is changed during the lifetime of the
114 InstanceArray, behaviour is undefined.
116 The instance type must have a constructor accepting a const Object &. If it
117 has a virtual function with the signature void set_matrix(const Matrix &), it
118 will be used to update the instance matrix. The original function is also
121 Instance created by the array have stable addresses. However after an instance
122 is removed, its address may later be reused for another instance.
124 template<typename T = ObjectInstance>
125 class InstanceArray: public InstanceArrayBase
128 class Instance: public T
131 InstanceArray &array;
135 Instance(const Object &o, InstanceArray &a, unsigned i): T(o), array(a), index(i) { }
137 virtual void set_matrix(const Matrix &);
141 InstanceArray(const Object &o): InstanceArrayBase(o, sizeof(Instance)) { }
142 ~InstanceArray() { destroy_all<T>(); }
144 T &append() { return *create<Instance>(*this); }
145 void remove(T &obj) { destroy(&obj); }
150 inline void InstanceArray<T>::Instance::set_matrix(const Matrix &m)
153 array.update_instance_matrix(index, *this->get_matrix());