X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Frender%2Finstancearray.h;h=6f4048ece6ea580dfcdf30f78de4d8388c82d3a5;hb=85d86a0d7cddce83578629e5817b6e1b50061540;hp=627051f75b123a973ef878546fddd762708afe59;hpb=7aaec9a70b8d7733429bec043f8e33e02956f266;p=libs%2Fgl.git diff --git a/source/render/instancearray.h b/source/render/instancearray.h index 627051f7..6f4048ec 100644 --- a/source/render/instancearray.h +++ b/source/render/instancearray.h @@ -2,8 +2,11 @@ #define MSP_GL_INSTANCEARRAY_H_ #include +#include #include "programdata.h" #include "renderable.h" +#include "vertexarray.h" +#include "vertexsetup.h" namespace Msp { namespace GL { @@ -11,19 +14,143 @@ namespace GL { class Buffer; class Object; class ObjectInstance; -class VertexArray; -class VertexSetup; + +class InstanceArrayBase: public Renderable, public NonCopyable +{ +protected: + class Loader: public DataFile::ObjectLoader + { + private: + static ActionMap shared_actions; + + public: + Loader(InstanceArrayBase &); + + private: + virtual void init_actions(); + + protected: + virtual void instance() = 0; + }; + +private: + struct Block + { + char *begin = 0; + char *end = 0; + }; + + struct Slot + { + bool used = false; + union + { + std::uint16_t array_index; + std::uint16_t next_free; + }; + std::uint16_t block_index; + std::uint16_t index_in_block; + }; + + const Object &object; + VertexArray instance_data; + Buffer *instance_buffer = 0; + VertexSetup vtx_setup; + int matrix_location = -1; + unsigned matrix_offset = 0; + std::size_t instance_size; + std::size_t default_count; + std::vector storage; + std::vector slots; + std::vector array_order; + int first_free = -1; + int last_free = -1; + std::size_t instance_count = 0; + +protected: + InstanceArrayBase(const Object &, std::size_t); + ~InstanceArrayBase(); + +private: + void add_block(std::size_t); + std::size_t allocate(); + char *get_address(std::size_t) const; + std::size_t find_index(char *) const; + void release(std::size_t); +protected: + template + T *create(A &); + + template + void destroy(T *); + + template + void destroy_all(); + + void update_instance_matrix(std::size_t, const Matrix &); + +public: + std::size_t size() const { return instance_count; } + + virtual void render(Renderer &, Tag) const; +}; + +template +inline T *InstanceArrayBase::create(A &array) +{ + size_t index = allocate(); + return new(get_address(index)) T(object, array, index); +} + +template +inline void InstanceArrayBase::destroy(T *obj) +{ + char *addr = reinterpret_cast(obj); + obj->~T(); + release(find_index(addr)); +} + +template +inline void InstanceArrayBase::destroy_all() +{ + for(unsigned i=0; i(get_address(i))->~T(); +} + /** -Renders multiple instances of an Object in an efficient manner. If instanced -rendering is supported, only one draw call per Batch needs to be issued. +Stores and renders multiple instances of an Object in an efficient manner. + +The instance specific transform is passed to the shader in an attribute with +the name instance_transform. The attribute should have the type vec4[3]. Each +elements of the array corresponds to a row of the transform matrix. + +If the Mesh or Technique of the Object is changed during the lifetime of the +InstanceArray, behaviour is undefined. -Changing the Mesh of the Object while an InstanceArray exists is not supported. +The instance type must have a constructor accepting a const Object &. If it +has a virtual function with the signature void set_matrix(const Matrix &), it +will be used to update the instance matrix. The original function is also +called. + +Instance created by the array have stable addresses. However after an instance +is removed, its address may later be reused for another instance. */ -class InstanceArray: public Renderable +template +class InstanceArray: public InstanceArrayBase { public: - template + class Loader: public DataFile::DerivedObjectLoader + { + public: + Loader(InstanceArray &a): DataFile::DerivedObjectLoader(a) { } + + protected: + virtual void instance(); + }; + +private: class Instance: public T { private: @@ -36,45 +163,28 @@ public: virtual void set_matrix(const Matrix &); }; -private: - const Object &object; - std::vector instances; - VertexArray *instance_data; - Buffer *instance_buffer; - VertexSetup *vtx_setup; - int matrix_location; - unsigned matrix_offset; - public: - InstanceArray(const Object &); - ~InstanceArray(); - - void set_matrix_attribute(const std::string &); + InstanceArray(const Object &o): InstanceArrayBase(o, sizeof(Instance)) { } + ~InstanceArray() { destroy_all(); } - template - T &append(); -private: - void append(ObjectInstance *); - void update_instance_matrix(unsigned); -public: - void remove(ObjectInstance &); - - virtual void render(Renderer &, const Tag &) const; + T &append() { return *create(*this); } + void remove(T &obj) { destroy(&obj); } }; + template -T &InstanceArray::append() +inline void InstanceArray::Instance::set_matrix(const Matrix &m) { - Instance *inst = new Instance(object, *this, instances.size()); - append(inst); - return *inst; + T::set_matrix(m); + array.update_instance_matrix(index, *this->get_matrix()); } + template -void InstanceArray::Instance::set_matrix(const Matrix &m) +void InstanceArray::Loader::instance() { - T::set_matrix(m); - array.update_instance_matrix(index); + T &inst = this->obj.append(); + this->load_sub(inst); } } // namespace GL