Commit 13504b2c authored by Christopher Tenter's avatar Christopher Tenter

custom properties in PolyLine refs #2244

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@19354 383ad7c9-94d9-4d36-a494-682f7c89f535
parent 76c2a64d
......@@ -518,6 +518,36 @@ void
PolyLineNodeT<PolyLine>::
updateVBO() {
// register custom properties defined in polyline
for (unsigned int i = 0; i < polyline_.get_num_custom_properties(); ++i) {
typename PolyLine::CustomPropertyHandle proph = polyline_.enumerate_custom_property_handles(i);
const void* propDataBuf = polyline_.get_custom_property_buffer(proph);
typename std::map< typename PolyLine::CustomPropertyHandle, int >::iterator mapEntry = polylinePropMap_.find(proph);
// insert newly defined properties
if (mapEntry == polylinePropMap_.end()) {
// setup element description
ACG::VertexElement desc;
unsigned int propSize;
polyline_.get_custom_property_shader_binding(proph, &propSize, &desc.shaderInputName_, &desc.type_);
// assume aligned memory without byte padding
desc.numElements_ = propSize / VertexDeclaration::getGLTypeSize(desc.type_);
desc.pointer_ = 0;
polylinePropMap_[proph] = addCustomBuffer(desc, propDataBuf);
}
else // otherwise update pointer of property data buffer
setCustomBuffer(mapEntry->second, propDataBuf);
}
// Update the vertex declaration based on the input data:
vertexDecl_.clear();
......@@ -650,7 +680,6 @@ getRenderObjects(ACG::IRenderer* _renderer, ACG::GLState& _state , const ACG::S
// draw after scene-meshes
ro.priority = 1;
// Update the vbo only if required.
if ( updateVBO_ )
updateVBO();
......@@ -698,7 +727,6 @@ getRenderObjects(ACG::IRenderer* _renderer, ACG::GLState& _state , const ACG::S
geomTemplateLineWidth += "Wireframe/geom_line2quad.tpl";
switch (props->primitive()) {
case ACG::SceneGraph::DrawModes::PRIMITIVE_POINT:
......
......@@ -188,6 +188,9 @@ private:
/// Custom vertex data for shader based rendering
std::vector< std::pair<ACG::VertexElement, const void*> > customBuffers_;
/// Map from custom properties in PolyLine to id in customBuffers_
std::map< typename PolyLine::CustomPropertyHandle, int> polylinePropMap_;
/** \brief Trigger an update of the vbo
*
* If the polyLine is changed, you have to call this function to update the buffers.
......
......@@ -149,6 +149,24 @@ PolyLineT<PointT>::
ref_count_escalars_ = _line.ref_count_escalars_;
ref_count_eselections_ = _line.ref_count_eselections_;
ref_count_epreimage_direction_ = _line.ref_count_epreimage_direction_;
// copy custom properties
for (typename CustomPropertyMap::const_iterator it = _line.custom_properties.begin(); it != _line.custom_properties.end(); ++it) {
const CustomProperty* src = it->second;
CustomProperty* dst = new CustomProperty;
dst->name = src->name;
dst->ref_count = src->ref_count;
dst->prop_size = src->prop_size;
dst->prop_data = src->prop_data;
dst->datatype = src->datatype;
dst->shader_binding = src->shader_binding;
custom_properties[it->first] = dst;
}
}
//-----------------------------------------------------------------------------
......@@ -176,6 +194,10 @@ clear()
escalars_.clear();
eselections_.clear();
epreimage_direction_.clear();
for (typename CustomPropertyMap::iterator it = custom_properties.begin(); it != custom_properties.end(); ++it)
delete it->second;
custom_properties.clear();
}
//-----------------------------------------------------------------------------
......@@ -230,6 +252,15 @@ resize( unsigned int _n)
escalars_.resize( _n);
if( edge_preimage_directions_available())
epreimage_direction_.resize( _n);
for (typename CustomPropertyMap::iterator it = custom_properties.begin(); it != custom_properties.end(); ++it) {
CustomProperty* p = it->second;
p->prop_data.resize(p->prop_size * _n);
}
}
else
{
......@@ -290,6 +321,18 @@ add_point(const Point& _p)
if( edge_preimage_directions_available())
epreimage_direction_.push_back(Point(0,0,0));
for (typename CustomPropertyMap::iterator it = custom_properties.begin(); it != custom_properties.end(); ++it) {
CustomProperty* p = it->second;
size_t cur_size = p->prop_data.size();
p->prop_data.resize(cur_size + p->prop_size);
if (p->buffer())
memset(p->buffer() + cur_size, 0, p->prop_size);
}
}
//-----------------------------------------------------------------------------
......@@ -343,6 +386,16 @@ insert_point(int _idx, const Point& _p)
if( edge_preimage_directions_available())
epreimage_direction_.insert(epreimage_direction_.begin()+_idx, Point(0,0,0));
// custom properties: insert byte-wise
for (typename CustomPropertyMap::iterator it = custom_properties.begin(); it != custom_properties.end(); ++it) {
CustomProperty* p = it->second;
unsigned int offset = p->prop_size * _idx;
for (unsigned int i = 0; i < p->prop_size; ++i)
p->prop_data.insert(p->prop_data.begin() + offset, 0);
}
}
......@@ -399,6 +452,17 @@ delete_point(int _idx)
if( edge_preimage_directions_available())
epreimage_direction_.erase(epreimage_direction_.begin()+_idx);
// custom properties: delete byte-wise
for (typename CustomPropertyMap::iterator it = custom_properties.begin(); it != custom_properties.end(); ++it) {
CustomProperty* p = it->second;
unsigned int offset = p->prop_size * _idx;
for (unsigned int i = 0; i < p->prop_size; ++i)
p->prop_data.erase(p->prop_data.begin() + offset);
}
}
......@@ -2048,6 +2112,301 @@ split_into_one_per_component(MeshT &_mesh,
}
}
template <class PointT>
typename PolyLineT<PointT>::CustomPropertyHandle PolyLineT<PointT>::CustomProperty::handle() const {
return (CustomPropertyHandle)(this);
}
template <class PointT>
typename PolyLineT<PointT>::CustomProperty* PolyLineT<PointT>::custom_prop(CustomPropertyHandle _handle) {
return reinterpret_cast<CustomProperty*>(_handle);
}
template <class PointT>
const typename PolyLineT<PointT>::CustomProperty* PolyLineT<PointT>::custom_prop(CustomPropertyHandle _handle) const {
return reinterpret_cast<const CustomProperty*>(_handle);
}
template <class PointT>
typename PolyLineT<PointT>::CustomPropertyHandle PolyLineT<PointT>::
request_custom_property(const std::string& _name,
unsigned int _prop_size) {
typename CustomPropertyMap::iterator entry = custom_properties.find(_name);
CustomProperty* pcontainer = 0;
if (entry == custom_properties.end()) {
// create new property container
pcontainer = new CustomProperty;
pcontainer->name = _name;
pcontainer->ref_count = 1;
pcontainer->prop_size = _prop_size;
pcontainer->datatype = 0;
pcontainer->prop_data.resize(n_vertices() * _prop_size, 0);
custom_properties[_name] = pcontainer;
cprop_enum.push_back(pcontainer);
} else {
pcontainer = entry->second;
if (++pcontainer->ref_count < 1)
pcontainer->ref_count = 1;
}
return pcontainer->handle();
}
template <class PointT>
void PolyLineT<PointT>::
release_custom_property(CustomPropertyHandle _prop_handle) {
if (_prop_handle) {
CustomProperty* p = custom_prop(_prop_handle);
if (--p->ref_count <= 0)
p->prop_data.clear();
}
}
template <class PointT>
void PolyLineT<PointT>::
release_custom_property(const std::string& _name) {
typename CustomPropertyMap::iterator entry = custom_properties.find(_name);
if (entry != custom_properties.end()) {
CustomProperty* p = entry->second;
release_custom_property(p->handle());
}
}
template <class PointT>
typename PolyLineT<PointT>::CustomPropertyHandle PolyLineT<PointT>::
get_custom_property_handle(const std::string& _name) const {
typename CustomPropertyMap::const_iterator it = custom_properties.find(_name);
if (it == custom_properties.end())
return 0;
return it->second->handle();
}
template <class PointT>
const std::string& PolyLineT<PointT>::
get_custom_property_name(CustomPropertyHandle _property_handle) const {
CustomProperty* p = custom_prop(_property_handle);
if (p)
return p->name;
std::cerr << "PolyLineT::get_custom_property_name - invalid handle" << std::endl;
return 0;
}
template <class PointT>
void PolyLineT<PointT>::
set_custom_property(CustomPropertyHandle _property_handle,
unsigned int _i,
const void* _data) {
if (!_data) {
std::cerr << "PolyLineT::set_custom_property - invalid data" << std::endl;
return;
}
if (_property_handle) {
CustomProperty* p = custom_prop(_property_handle);
unsigned int offset = p->prop_size * _i;
// check out of range
if (offset + p->prop_size > p->prop_data.size()) {
std::cerr << "PolyLineT::set_custom_property - out of range access" << std::endl;
return;
}
// copy data byte-wise
memcpy(p->buffer() + offset, _data, p->prop_size);
}
else
std::cerr << "PolyLineT::set_custom_property - invalid handle" << std::endl;
}
template <class PointT>
void PolyLineT<PointT>::
set_custom_property(const std::string& _name,
unsigned int _i,
const void* _data) {
typename CustomPropertyMap::iterator entry = custom_properties.find(_name);
if (entry != custom_properties.end()) {
CustomProperty* p = entry->second;
set_custom_property(p->handle(), _i, _data);
}
}
template <class PointT>
void PolyLineT<PointT>::
get_custom_property(CustomPropertyHandle _property_handle,
unsigned int _i,
void* _dst) const {
if (!_dst) {
std::cerr << "PolyLineT::get_custom_property - invalid destination address" << std::endl;
return;
}
if (_property_handle) {
CustomProperty* p = custom_prop(_property_handle);
unsigned int offset = p->prop_size * _i;
// check out of range
if (offset + p->prop_size >= p->prop_data.size()) {
std::cerr << "PolyLineT::get_custom_property - out of range access" << std::endl;
return;
}
// copy data byte-wise
memcpy(_dst, p->buffer() + offset, p->prop_size);
}
else
std::cerr << "PolyLineT::get_custom_property - invalid handle" << std::endl;
}
template <class PointT>
void PolyLineT<PointT>::
get_custom_property(const std::string& _name,
unsigned int _i,
void* _data) const {
typename CustomPropertyMap::const_iterator entry = custom_properties.find(_name);
if (entry != custom_properties.end()) {
const CustomProperty* p = entry->second;
get_custom_property(p->handle(), _i, _data);
}
}
template <class PointT>
bool PolyLineT<PointT>::
custom_property_available(CustomPropertyHandle _property_handle) const {
const CustomProperty* p = custom_prop(_property_handle);
if (p)
return p->ref_count > 0;
return false;
}
template <class PointT>
bool PolyLineT<PointT>::
custom_property_available(const std::string& _name) const {
typename CustomPropertyMap::const_iterator entry = custom_properties.find(_name);
if (entry != custom_properties.end()) {
const CustomProperty* p = entry->second;
return custom_property_available(p->handle());
}
return false;
}
template <class PointT>
void PolyLineT<PointT>::
bind_custom_property_to_shader(CustomPropertyHandle _property_handle, const std::string& _shader_input_name, unsigned int _datatype) {
CustomProperty* p = custom_prop(_property_handle);
if (p) {
p->datatype = _datatype;
p->shader_binding = _shader_input_name;
} else
std::cerr << "PolyLineT::bind_custom_property_to_shader - invalid handle" << std::endl;
}
template <class PointT>
bool PolyLineT<PointT>::
get_custom_property_shader_binding(CustomPropertyHandle _property_handle, unsigned int* _propsize, const char** _input_name, unsigned int* _datatype) const {
const CustomProperty* p = custom_prop(_property_handle);
if (p) {
if (_propsize)
*_propsize = p->prop_size;
if (_input_name)
*_input_name = p->shader_binding.c_str();
if (_datatype)
*_datatype = p->datatype;
return !p->shader_binding.empty() && p->datatype;
}
else
std::cerr << "PolyLineT::get_custom_property_shader_binding - invalid handle" << std::endl;
return false;
}
template <class PointT>
const void* PolyLineT<PointT>::
get_custom_property_buffer(CustomPropertyHandle _property_handle) const {
const CustomProperty* p = custom_prop(_property_handle);
if (p)
return p->buffer();
else
std::cerr << "PolyLineT::get_custom_property_buffer - invalid handle" << std::endl;
return 0;
}
template <class PointT>
unsigned int PolyLineT<PointT>::
get_num_custom_properties() const {
return custom_properties.size();
}
template <class PointT>
typename PolyLineT<PointT>::CustomPropertyHandle PolyLineT<PointT>::
enumerate_custom_property_handles(unsigned int _i) const {
if (_i < get_num_custom_properties())
return cprop_enum[_i]->handle();
else
return 0;
}
//=============================================================================
} // namespace ACG
//=============================================================================
......@@ -95,7 +95,7 @@ public:
PolyLineT(const PolyLineT& _line);
/// Destructor
~PolyLineT() {}
~PolyLineT() {clear();}
/** \brief Check if the polyline is marked as closed
*
......@@ -440,6 +440,112 @@ public:
Point & preimage_direction(unsigned int _i) { return epreimage_direction_[_i];}
const Point & preimage_direction(unsigned int _i) const { return epreimage_direction_[_i];}
// ############################### Custom Property Handling #############################
/*
A custom property is identified by its name and requires the size in bytes of one property element (example: float3 prop has size 12).
PolyLine allocates an internal buffer for properties, so no buffer management is required.
On resize/add_point, custom properties of the newly inserted vertices are filled with 0.
Optionally, it is possible to use properties in vertex shaders by defining a shader binding.
If rendered via PolyLineNode, these properties are then automatically available in vertex shaders (no additional management required).
However, it is still necessary to trigger a vbo update function whenever data of properties is changed.
Example: add float3 data to each vertex and use these in a vertex shader
// request new property with name "myCustomData", that stores 3 * sizeof(float) = 12 bytes
PolyLine::CustomPropertyHandle myPropHandle = line->request_custom_property("myCustomData", 12);
// bind property to a vertex shader as input id "a2v_UserData" with coordinates of type GL_FLOAT
line->bind_custom_property_to_shader(myPropHandle, "a2v_UserData", GL_FLOAT);
// set property data
for each vertex i:
Vec3f x = computeCustomData(i);
line->set_custom_property(myPropHandle, x.data());
// trigger vbo update in rendering node of the polyline (ie. PolyLineNode)
lineNode->update();
these vertex properties are then available in any vertex shader used to render the polyline:
in vec3 a2v_UserData;
void main()
{
...
}
*/
typedef void* CustomPropertyHandle;
// request properties, returns handle of custom property
CustomPropertyHandle request_custom_property(const std::string& _name, unsigned int _prop_size);
// release properties
void release_custom_property(const std::string& _name);
void release_custom_property(CustomPropertyHandle _prop_handle);
// property availability
bool custom_property_available(CustomPropertyHandle _property_handle) const;
bool custom_property_available(const std::string& _name) const;
// property access by handle (byte-wise)
void set_custom_property(CustomPropertyHandle _property_handle, unsigned int _vertex, const void* _data);
void get_custom_property(CustomPropertyHandle _property_handle, unsigned int _vertex, void* _dst) const;
// property access by name (byte-wise), (slower than by handle)
void set_custom_property(const std::string& _name, unsigned int _vertex, const void* _data);
void get_custom_property(const std::string& _name, unsigned int _vertex, void* _dst) const;
/** \brief Binding to vertex shader (optional)
*
* Bind custom vertex properties to input names in vertex shaders.
* The number of coordinates of a property is assumed to be _prop_size / bytesize(_datatype),
* so the property size provided via request_custom_property has to be a multiple of bytesize(_datatype).
*
* @param _property_handle handle of property
* @param _shader_input_name name id of input data in the vertex shader
* @param _datatype type of one property data coordinate, ie GL_FLOAT, GL_UNSIGNED_BYTE ...
*/
void bind_custom_property_to_shader(CustomPropertyHandle _property_handle, const std::string& _shader_input_name, unsigned int _datatype);
/** \brief Get shader binding information
*
* The property has to be bound via bind_custom_property_to_shader before.
*
* @param _property_handle handle of property
* @param _propsize [out] receives size in bytes of one property element
* @param _input_name [out] receives pointer to name id of input data in the vertex shader
* @param _datatype [out] receives type of property coordinates
* @return true if property shader binding has been specified, false otherwise
*/
bool get_custom_property_shader_binding(CustomPropertyHandle _property_handle, unsigned int* _propsize, const char** _input_name, unsigned int* _datatype) const;
// helper functions:
// get property handle by name, returns 0 if unavailable
CustomPropertyHandle get_custom_property_handle(const std::string& _name) const;
// get name of property by handle
const std::string& get_custom_property_name(CustomPropertyHandle _property_handle) const;
// get number of custom properties
unsigned int get_num_custom_properties() const;
// get pointer to buffer that stores property data for all vertices
const void* get_custom_property_buffer(CustomPropertyHandle _property_handle) const;
// enumerate custom property handles via indices in range [0, get_num_custom_properties() - 1]
CustomPropertyHandle enumerate_custom_property_handles(unsigned int _i) const;
// ############################### SelectionWrappers ############################
bool vertex_selected(unsigned int _i) { return (_i < vselections_.size() ? vertex_selection(_i) == 1 : false); }
......@@ -582,6 +688,43 @@ private:
unsigned int ref_count_escalars_;
unsigned int ref_count_eselections_;
unsigned int ref_count_epreimage_direction_;
// ############################### Custom Property Handling #############################
struct CustomProperty
{
std::string name;
int ref_count;
// size in bytes of one property element
unsigned int prop_size;
// property data in byte array
std::vector<char> prop_data;
// data type (GL_FLOAT, GL_DOUBLE, GL_UNSIGNED_BYTE...)
unsigned int datatype;