I write a small animation program with OpenSceneGraph(osg). In each frame, I should update the models(vertex position,normal, color and other stuff) in the scene.
Now I shoudl convert the data to osg in each frame. The code is like:
cog_.vertex_->clear();
cog_.vertex_->push_back(osg::Vec3(1.0,1.0,1.0));
However these convertion is very time consuming. So I'm wondering how to access data directly via pointer. I tried but failed. The following is what I did, hope someone can help me to find the problem, or tell me better solution:
First, I wrap the a pointer to osg::Vec3,
class vec3_map : public osg::Vec3
{
public:
typedef osg::Vec3::value_type value_type;
osg::Vec3::value_type* p_;
vec3_map() :p_(0) {}
vec3_map(osg::Vec3::value_type*p, int offset = 0) :p_(p+offset){}
inline value_type& x() { return *(p_+0); }
inline value_type& y() { return *(p_+1); }
inline value_type& z() { return *(p_+2); }
// some other stuff
};
When I want to build an array of vec3_map, I found that osg use a tempalte to typedef Vec3Array, but there isn't any type for a pointer, so I choose the closet one (I know pointer is a variable with unsigned long int type):
typedef osg::TemplateArray<vec3_map, osg::Array::UIntArrayType, 1, GL_UNSIGNED_INT> Vec3_map_Array;
With this definition, I can rewrite my problem to the following:
#define BOOST_ALL_NO_LIB
#include <boost/shared_ptr.hpp>
#include <fstream>
#include <vector>
#include <osg/Group>
#include <osg/Geometry>
#include <osgViewer/Viewer>
#include <osg/Vec3>
class vec3_map : public osg::Vec3
{
public:
typedef osg::Vec3::value_type value_type;
osg::Vec3::value_type* p_;
vec3_map() :p_(0) {}
vec3_map(osg::Vec3::value_type*p, int offset = 0) :p_(p + offset) {}
inline value_type* ptr() { return p_; }
inline const value_type* ptr() const { return p_; }
inline value_type& operator [] (int i) { return *(p_ + i); }
inline value_type operator [] (int i) const { return *(p_ + i); }
inline value_type& x() { return *(p_ + 0); }
inline value_type& y() { return *(p_ + 1); }
inline value_type& z() { return *(p_ + 2); }
inline value_type x() const { return *(p_); }
inline value_type y() const { return *(p_ + 1); }
inline value_type z() const { return *(p_ + 2); }
};
typedef osg::TemplateArray<vec3_map, osg::Array::UIntArrayType, 1, GL_UNSIGNED_INT> Vec3_map_Array;
struct point_data
{
point_data(float xx, float yy, float zz) { x = xx; y = yy; z = zz; }
float x;
float y;
float z;
};
osg::Geode* create_point_node(boost::shared_ptr<std::vector<point_data> > ptr)
{
osg::Geode *geode_ = new osg::Geode;
osg::Geometry* geometry_ = new osg::Geometry;
Vec3_map_Array* vertex_ = new Vec3_map_Array;
osg::DrawElementsUInt* point_idx_ = new osg::DrawElementsUInt;
vertex_->reserve(ptr->size());
point_idx_->reserve(ptr->size());
vec3_map vm;
std::vector<point_data> & pd = *ptr;
for (size_t i = 0; i < ptr->size(); ++i)
{
vertex_->push_back(vec3_map(&(pd[i].x)));
point_idx_->push_back(i);
}
geometry_->setVertexArray(vertex_);
geometry_->addPrimitiveSet(point_idx_);
geode_->addDrawable(geometry_);
return geode_;
}
int main(int argc, char *argv[])
{
boost::shared_ptr<std::vector<point_data> > pd(new std::vector<point_data>);
pd->push_back(point_data(1.0, 1.0, 1.0));
pd->push_back(point_data(2.0, 2.0, 2.0));
osgViewer::Viewer viewer;
osg::Node *node = create_point_node(pd);
viewer.setSceneData(node);
return viewer.run();
}
However, this problem crashes. I'm not sure whether I can do something like this.
Related
I'm attempting to get a basic constant forward-iterator to work in C++.
namespace Rcpp {
class SparseMatrix {
public:
IntegerVector i, p;
NumericVector x;
int begin_col(int j) { return p[j]; };
int end_col(int j) { return p[j + 1]; };
class iterator {
public:
int index;
iterator(SparseMatrix& g) : parent(g) {}
iterator(int ind) { index = ind; }; // ERROR!
bool operator!=(int x) const { return index != x; };
iterator operator++(int) { ++index; return (*this); };
int row() { return parent.i[index]; };
double value() { return parent.x[index]; };
private:
SparseMatrix& parent;
};
};
}
My intention is to use the iterator in contexts similar to the following:
// sum of values in column 7
Rcpp::SparseMatrix A(nrow, ncol, fill::random);
double sum = 0;
for(Rcpp::SparseMatrix::iterator it = A.begin_col(7); it != A.end_col(7); it++)
sum += it.value();
Two questions:
The compiler throws an error on the line indicated above: uninitialized reference member in 'class Rcpp::SparseMatrix&' [-fpermissive]. How can this be fixed?
How might double value() { return parent.x[index]; }; be re-worked to return a pointer to the value rather than a copy of the value?
A little context on the SparseMatrix class: like a dgCMatrix in R, this object of class SparseMatrix consists of three vectors:
i holds row pointers for every element in x
p gives indices in i which correspond to the start of each column
x contains non-zero values
Thanks to #Evg, here's the solution:
namespace Rcpp {
class SparseMatrix {
public:
IntegerVector i, p;
NumericVector x;
class iterator {
public:
int index;
iterator(SparseMatrix& g, int ind) : parent(g) { index = ind; }
bool operator!=(iterator x) const { return index != x.index; };
iterator& operator++() { ++index; return (*this); };
int row() { return parent.i[index]; };
double& value() { return parent.x[index]; };
private:
SparseMatrix& parent;
};
iterator begin_col(int j) { return iterator(*this, p[j]); };
iterator end_col(int j) { return iterator(*this, p[j + 1]); };
};
}
And it can be used as follows, for instance, to calculate colSums:
//[[Rcpp::export]]
Rcpp::NumericVector Rcpp_colSums(Rcpp::SparseMatrix& A) {
Rcpp::NumericVector sums(A.cols());
for (int i = 0; i < A.cols(); ++i)
for (Rcpp::SparseMatrix::iterator it = A.begin_col(i); it != A.end_col(i); it++)
sums(i) += it.value();
return sums;
}
And, the above function is faster than RcppArmadillo, RcppEigen, and R::Matrix equivalents when microbenchmarked from R!
Edit:
The above syntax is inspired by Armadillo. I've come to realize that a slightly different syntax (which involves fewer constructions) gives an iterator similar to Eigen:
class col_iterator {
public:
col_iterator(SparseMatrix& ptr, int col) : ptr(ptr) { indx = ptr.p[col]; max_index = ptr.p[col + 1]; }
operator bool() const { return (indx != max_index); }
col_iterator& operator++() { ++indx; return *this; }
const double& value() const { return ptr.x[indx]; }
int row() const { return ptr.i[indx]; }
private:
SparseMatrix& ptr;
int indx, max_index;
};
Which can then be used like this:
int col = 0;
for (Rcpp::SparseMatrix::col_iterator it(A, col); it; ++it)
Rprintf("row: %3d, value: %10.2e", it.row(), it.value());
I'm writing C++98 (sorry), but working with a C library, which has many objects stored in data structures of the form:
struct c_container
{
size_t len;
int data[1];
};
struct c_container *make_container(size_t n)
{
if (n == 0)
return NULL;
struct c_container *rv = (struct c_container *)malloc(sizeof(rv->len) + n*sizeof(rv->data));
rv->len = n;
return rv;
}
I'd like to do C++-style iteration using BOOST_FOREACH, but this doesn't work. (The "old style" of manually calling the range_begin and range_end functions does work).
inline int *range_begin(c_container *c)
{
return c ? &c->data[0] : NULL;
}
inline int *range_end(c_container *c)
{
return c ? &c->data[c->len] : NULL;
}
inline const int *range_begin(const c_container *c)
{
return c ? &c->data[0] : NULL;
}
inline const int *range_end(const c_container *c)
{
return c ? &c->data[c->len] : NULL;
}
namespace boost
{
template<>
struct range_mutable_iterator<c_container *>
{
typedef int *type;
};
template<>
struct range_const_iterator<c_container *>
{
typedef const int *type;
};
}
int main()
{
c_container *coll = make_container(3);
coll->data[0] = 1;
coll->data[1] = 42;
coll->data[2] = -1;
BOOST_FOREACH(int i, coll)
{
std::cout << i << std::endl;
}
}
This is all that should be necessary, according to http://www.boost.org/doc/libs/1_65_1/doc/html/foreach/extensibility.html (and I've tested it with classes)
However, that example uses a class, whereas I'm using a pointer to a class. Based on my investigation, it appears to be using the codepath that is only intended for const char * and const wchar_t *:
In file included from boost-foreach.cpp:6:0:
/usr/include/boost/foreach.hpp: In function ‘bool boost::foreach_detail_::done(const boost::foreach_detail_::auto_any_base&, const boost::foreach_detail_::auto_any_base&, boost::foreach_detail_::type2type<T*, C>*) [with T = c_container, C = mpl_::bool_<false>, const boost::foreach_detail_::auto_any_base& = const boost::foreach_detail_::auto_any_base&]’:
boost-foreach.cpp:65:5: instantiated from here
/usr/include/boost/foreach.hpp:749:57: error: no match for ‘operator!’ in ‘!* boost::foreach_detail_::auto_any_cast [with T = c_container*, C = mpl_::bool_<false>, typename boost::mpl::if_<C, const T, T>::type = c_container*, const boost::foreach_detail_::auto_any_base& = const boost::foreach_detail_::auto_any_base&](((const boost::foreach_detail_::auto_any_base&)((const boost::foreach_detail_::auto_any_base*)cur)))’
/usr/include/boost/foreach.hpp:749:57: note: candidate is: operator!(bool) <built-in>
Is there some additional boost trait to specialize or something?
It seems to be difficult to define the range functions for pointer types. But you can define them for c_container directly. The code looks like this:
#include <cstdlib>
#include <iostream>
#include <boost/foreach.hpp>
struct c_container
{
size_t len;
int data[1];
};
struct c_container *make_container(size_t n)
{
if (n == 0)
return NULL;
struct c_container *rv = (struct c_container *)malloc(sizeof(rv->len) + n * sizeof(rv->data));
rv->len = n;
return rv;
}
inline int *range_begin(c_container &c)
{
return c.len > 0 ? &c.data[0] : NULL;
}
inline int *range_end(c_container &c)
{
return c.len > 0 ? &c.data[c.len] : NULL;
}
inline const int *range_begin(const c_container &c)
{
return c.len > 0 ? &c.data[0] : NULL;
}
inline const int *range_end(const c_container &c)
{
return c.len > 0 ? &c.data[c.len] : NULL;
}
namespace boost
{
template<>
struct range_mutable_iterator<c_container>
{
typedef int *type;
};
template<>
struct range_const_iterator<c_container>
{
typedef const int *type;
};
}
#define MY_FOREACH(x, y) BOOST_FOREACH(x, *y)
int main()
{
c_container *coll = make_container(3);
coll->data[0] = 1;
coll->data[1] = 42;
coll->data[2] = -1;
//BOOST_FOREACH(int i, *coll)
MY_FOREACH(int i, coll)
{
std::cout << i << std::endl;
}
}
Note that the BOOST_FOREACH loop does not iterate over a pointer type. As a workaround you may define your own FOREACH that does so as shown in the code above.
Suppose I have a simple vector class where elements are accessed through a proxy class.
Vector class:
class vec {
public:
vec(int len) {
length = len;
data = new double [len];
}
proxy operator[](int i) {
if (i >= 0 && i < length) {
return proxy(i, data);
}
else {
std::cerr << "AHHHH!\n";
exit(1);
}
}
private:
int length;
double * data;
};
Proxy class:
class proxy {
public:
proxy(int i, double * d) {
index = i;
data = d;
}
void operator=(double rhs) {
data[index] = rhs;
}
private:
int index;
double * data;
};
How can I assign elements from the vector (or rather, from the proxy) to a variable of type double? In other words, how do I accomplish the following:
int main() {
vec a(2);
double x = 3.14;
a[0] = x; // Works!
x = a[0]; // How to make work?
return 0;
}
Unfortunately, I can't write something like:
friend double operator=(double & lhs, const proxy & p) { ... }
since operator= must be a member.
Add a conversion function to your proxy class:
class proxy
{
public:
operator double() const { return data[index]; }
// ...
};
I'm trying to code a game with Allegro 4 and I've hit a weird bump. The linker is claiming an undefined reference to the destructor in two of my classes, but I've done nothing with it. What could be the issue? Here is my code:
Entity.h:
#pragma once
#include <allegro.h>
struct Rectangle
{
int x;
int y;
int w;
int h;
};
typedef enum {
FACE,
POOP
} EntityType;
class Entity
{
private:
EntityType m_EntityType;
BITMAP *m_Sprite;
int m_Score;
int m_X;
int m_Y;
Rectangle *m_Hitbox;
public:
Entity();
virtual ~Entity() {destroy_bitmap(m_Sprite);}
BITMAP *GetSprite() {return m_Sprite;}
int GetScore() {return m_Score;}
int GetX() {return m_X;}
int GetY() {return m_Y;}
Rectangle GetHitbox() {return *m_Hitbox;}
void SetSprite(EntityType type);
void SetScore(int value) {m_Score = value;}
void SetX(int value) {m_X = value;}
void SetY(int value) {m_Y = value;}
void SetHitbox(EntityType type);
};
Entity.cpp:
#include "Entity.h"
void Entity::SetSprite(EntityType type)
{
if (type == FACE)
m_Sprite = load_bitmap("face.bmp", NULL);
else if (type == POOP)
m_Sprite = load_bitmap("poop.bmp", NULL);
}
void Entity::SetHitbox(EntityType type)
{
if (type == FACE)
{
GetHitbox().x = m_X;
GetHitbox().y = m_Y;
GetHitbox().w = m_X + 32;
GetHitbox().h = m_Y + 32;
}
else if (type == POOP)
{
GetHitbox().x = m_X;
GetHitbox().y = m_Y;
GetHitbox().w = m_X + 16;
GetHitbox().h = m_Y + 16;
}
}
Here is my code.
#include <map>
#include <string>
#include <algorithm>
class maptest {
public:
int doubler(int val) { return val * 2; }
int halver(int val) { return val / 2; }
int negativer(int val) { return val > 0 ? -val : val; }
};
int main() {
const char* const ID[] = {"doubler", "halver", "negativer" };
int ID_SIZE = sizeof(ID) / sizeof(*ID);
//signature of maths functions
typedef int (maptest::*mathfunc)(int);
mathfunc mfuncs[] = { &maptest::doubler, &maptest::halver, &maptest::negativer};
std::map<std::string, mathfunc> mathmap;
for(int i = 0; i < ID_SIZE; ++i) {
mathmap.insert(std::make_pair(ID[i], mfuncs[i]));
}
//C2064: term does not evaluate to a function taking 1 argument
int result = *mathmap["doubler"](3);
return 0;
}
I think this would work if there was no parameter to be passed to the functions. But how do I pass a parameter in this way?
Your mathfuncs are member functions, so you need an object on which to invoke them:
maptest mt;
int result = (mt.*(mathmap["doubler"]))(3);
Alternatively, you could make your member functions static:
class maptest {
public:
static int doubler(int val) { return val * 2; }
static int halver(int val) { return val / 2; }
static int negativer(int val) { return val > 0 ? -val : val; }
};
And then define mathfunc accordingly:
typedef int (*mathfunc)(int);
And this would allow you to invoke them the way you are invoking them in your original post:
typedef int (*mathfunc)(int);
Notice, that a way to make this design more flexible is to make use of std::function, which would allow you to pass any type of callable object. For instance:
typedef std::function<int(int)> mathfunc;
mathfunc mfuncs[] = {
&maptest::doubler,
&maptest::halver,
&maptest::negativer,
[] (int i) { return i * 2; } // <== A LAMBDA...
};
You are invoking non static member function.
do the following.
maptest t;
int (maptest::*tptr) (int) = mathmap["doubler"];
int result = (t.*tptr)(2);
Hope this helps.