Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
OpenSceneGraphHelper.cpp
1 #include "OpenSceneGraphHelper.hh"
2 
3 #include <Utils/TriangleMesh.hh>
4 
5 
6 #include <Base/Image/Image.hh>
7 #include <Filter/Rescale.hh>
8 #include <Gui/biasgl.h>
9 
10 #include <Base/Image/ImageIO.hh>
11 
12 #include <osg/Group>
13 #include <osg/Geode>
14 #include <osg/Geometry>
15 #include <osg/Texture2D>
16 #include <osg/TexEnv>
17 #include <osg/MatrixTransform>
18 #include <osg/Billboard>
19 #include <osg/ShapeDrawable>
20 #include <osg/Point>
21 #include <osg/LineWidth>
22 #include <osg/LineStipple>
23 
24 using namespace std;
25 using namespace BIAS;
26 using namespace BIAS;
27 
28 //unsigned char *gid(Image<unsigned char> &img){return img
29 
30 
31 bool OpenSceneGraphHelper::
32 BIASimageToOSGimage(const BIAS::Image<unsigned char>& in,osg::Image* out,
33  bool copydata)
34 {
35  unsigned int width = in.GetWidth();
36  unsigned int height = in.GetHeight();
37  unsigned int chNum = in.GetChannelCount();
38 
39  BIASASSERT(chNum>0);
40  if(chNum<=4)
41  {
42  GLenum colormode = GL_RGBA;
43  unsigned int colOff = 4;
44  switch(chNum)
45  {
46  case 1: //greyscale image
47  //GL_LUMINANCE: RGBA = (X, X, X, 1)
48  //# GL_ALPHA: RGBA = (0, 0, 0, X)
49  //# GL_INTENSITY: RGBA = (X, X, X, X)
50  colormode = GL_LUMINANCE;
51  colOff = 1;
52  break;
53  case 2: //???
54  colormode = GL_RGB;
55  colOff = 3;
56  break;
57  case 3: //rgb
58  colormode = GL_RGB;
59  colOff = 3;
60  break;
61  case 4:
62  colormode = GL_RGBA;
63  colOff = 4;
64  break;
65  default:
66  BIASERR("unexpected channel count! " << chNum);
67  BIASABORT;
68  }
69  out->allocateImage(width,height,colOff, colormode, GL_UNSIGNED_BYTE);
70 
71  /*the texture pixel data is not needed if the bias image is
72  exported to disc thus slow copying can be avoided.
73  */
74  if(copydata)
75  {
76  void * dest = (void*) out->data();
77  BIASASSERT(dest!=NULL);
78  void* src = (void*) in.GetImageData();
79  BIASASSERT(src!=NULL);
80  if(chNum!=2)
81  {
82  //copy pixel arrays
83  memcpy( dest, src, width*height*colOff );
84  }
85  else
86  {
87  //convert image to rgb ... this might take while....
88  for(unsigned int p=0; p<width*height; p++)
89  {
90  //store data in R and G channels...
91  ((unsigned char*) src)[p*3] = ((unsigned char*) dest)[p*2];
92  ((unsigned char*) src)[p*3+1] = ((unsigned char*) dest)[p*2+1];
93  ((unsigned char*) src)[p*3+2] = 0;
94  }
95  }
96  out->flipVertical() ;
97  }
98  }
99  else
100  {
101  BIASWARN("texture has too many channels! (channelcount>4)");
102  return(false);
103  }
104  return(true);
105 }
106 
107 
108 bool OpenSceneGraphHelper::
109 OSGimageToBIASimage(const osg::Image* in,
111 {
112  if(!in) return false;
113  if(in->getDataType() !=GL_UNSIGNED_BYTE)
114  {
115  BIASWARN("only unsigned byte based textures supported!");
116  return false;
117  }
118  unsigned int width = in->s();
119  unsigned int height = in->t();
120  unsigned int chNum = 3;
121  switch(in->getPixelFormat())
122  {
123  case GL_RGB:
124  chNum = 3;
125  break;
126  case GL_RGBA:
127  chNum = 4;
128  break;
129  case GL_LUMINANCE:
130  chNum = 1;
131  break;
132  default:
133  BIASWARN("unsupported pixel format!");
134  return false;
135  }
136  out.Init(width,height,chNum);
137  void* dest;
138 #if defined WIN32 && defined BIAS_BUILD_SHARED_LIBS
139  // this is a work-around for for W32, SHARED, DEBUG.
140  const Image<unsigned char>* cip = &out;
141  dest = (void*) cip->GetImageData();
142 #else
143  dest = (void*) out.GetImageData();
144 #endif
145  BIASASSERT(dest!=NULL);
146  void* src = (void*) in->data();
147  BIASASSERT(src!=NULL);
148  memcpy( dest, src, width*height*chNum );
149  out.Flip();
150  return true;
151 }
152 
153 
154 
155 
156 osg::Node * OpenSceneGraphHelper::
157 CreateBranchIndexedFaceSets(const TriangleMesh& mesh,
158  const std::string& name)
159 {
160  osg::MatrixTransform* mTrans = new osg::MatrixTransform;
161  mTrans->setName(name);
162  osg::Geode* mGeode = new osg::Geode();
163  osg::Geometry* mGeometry = new osg::Geometry();
164  mGeode->addDrawable(mGeometry);
165  mTrans->addChild(mGeode);
166 
167  const vector<Vector3<double> > &vertexSet = mesh.GetVerticesRef();
168  const vector<Vector2<float> > &texCoordSet = mesh.GetTexCoordsRef();
169  const vector<Vector<int> > &faceIndices =mesh.GetTriangleIndicesRef();
170 
171  //copy vertices:
172  //create new vertex array
173  unsigned int vertNumb = vertexSet.size();
174  osg::Vec3Array* vertices = new osg::Vec3Array(vertNumb);
175  //loop through vertices
176  for(unsigned int vt = 0; vt < vertNumb; vt++)
177  (*vertices)[vt].set(vertexSet[vt][0],vertexSet[vt][1],vertexSet[vt][2]);
178  //attach vertex array to
179  mGeometry->setVertexArray(vertices);
180 
181  //set texture coordinates
182  unsigned int texCoordNumb = texCoordSet.size();
183  if(texCoordNumb!= vertNumb)
184  BIASWARN("Number of texture coordinates does not match vertex number.");
185 
186  osg::Vec2Array* texCoords = new osg::Vec2Array(texCoordNumb);
187  for(unsigned int tc=0; tc<texCoordNumb; tc++)
188  (*texCoords)[tc].set(texCoordSet[tc][0],texCoordSet[tc][1]);
189  mGeometry->setTexCoordArray(0,texCoords);
190 
191  //set faces:
192  //loop through faces
193  unsigned int faceNumb = faceIndices.size();
194 
195  osg::DrawElementsUInt* drawTriangleElmtsU=NULL;
196  osg::DrawElementsUInt* drawQuadsElmtsU=NULL;
197 
198  for(unsigned int fc = 0; fc<faceNumb ; fc++)
199  {
200  // get number of indices of actual face
201  // this number might vary from face to face although most likely triangles
202  // and quads will occure.
203  unsigned int indexNum = faceIndices[fc].Size();
204  osg::DrawElementsUInt* actualFace;
205  switch(indexNum)
206  {
207  case 3:
208  //use for all triangles the same "index buffer"
209  if(drawTriangleElmtsU==NULL)
210  {
211  drawTriangleElmtsU =
212  new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES);
213  mGeometry->addPrimitiveSet(drawTriangleElmtsU);
214  }
215  actualFace = drawTriangleElmtsU;
216  break;
217  case 4:
218  if(drawQuadsElmtsU==NULL)
219  {
220  drawQuadsElmtsU =
221  new osg::DrawElementsUInt(osg::PrimitiveSet::QUADS);
222  mGeometry->addPrimitiveSet(drawQuadsElmtsU);
223  }
224  actualFace = drawQuadsElmtsU;
225  break;
226  default:
227  actualFace =
228  new osg::DrawElementsUInt(osg::PrimitiveSet::POLYGON);
229  mGeometry->addPrimitiveSet(actualFace);
230  }
231  //loop through indices
232  for(unsigned int ix = 0; ix<indexNum; ix++)
233  {
234  //bias stores face indices as int
235  int idx = (faceIndices[fc])[ix];
236  BIASASSERT(idx>=0);
237  actualFace->push_back((unsigned int) idx);
238  }
239  }
240  //is there no color buffer for indexed faces? too bad! :(
241  //set and save texture
242  osg::Image* mImage = new osg::Image;
243 
244  const bool CopyImage = true;
245  if(BIASimageToOSGimage(mesh.GetTextureRef(),mImage,CopyImage)) {
246  osg::ref_ptr< osg::Texture2D > mTex2D = new osg::Texture2D;
247  mTex2D->setImage( mImage );
248 
249  osg::StateSet *ss = new osg::StateSet;
250  ss->setTextureAttributeAndModes(0, mTex2D.get());
251 
252  //disable modulation of texture and vertex colors
253  //because the bias meshes have no vertex color data.
254  osg::TexEnv *txenv = new osg::TexEnv(osg::TexEnv::REPLACE);
255  ss->setTextureAttribute(0, txenv);
256 
257  //delete image after creating opengl texture - is this needed in our case?
258  //mTex2D->setUnRefImageDataAfterApply(true);
259  mGeode->setStateSet(ss);
260  } //biasimage export
261 
262 
263  return mTrans;
264 }
265 
266 bool OpenSceneGraphHelper::OSG2BIASMatrix( const osg::Matrixd& OsgMat,
267  BIAS::Matrix4x4<double>& BiasMat)
268 {
269  const double* pOSDMatD = OsgMat.ptr();
270  double* pBIASMatD = BiasMat.GetData();
271  if(pOSDMatD&&pBIASMatD)
272  {
273  for(int i=0; i<16; i++)
274  {
275  pBIASMatD[i]=pOSDMatD[i];
276  }
277  return true;
278  }
279  return false;
280 }
281 
282 bool OpenSceneGraphHelper::BIAS2OSGMatrix(
283  const BIAS::Matrix4x4<double>& BiasMat,
284  osg::Matrixd& OsgMat)
285 {
286  double* pOSDMatD = OsgMat.ptr();
287  const double* pBIASMatD = BiasMat.GetData();
288  if(pOSDMatD&&pBIASMatD)
289  {
290  for(int i=0; i<16; i++)
291  {
292  pOSDMatD[i]=pBIASMatD[i];
293  }
294  return true;
295  }
296  return false;
297 }
298 
299 bool OpenSceneGraphHelper::AdjustImageSizeToGPULimit(BIAS::Image<unsigned char>& tex)
300 {
303  unsigned char current=0;
304  unsigned char next=1;
305  tmpi[current] = &tex;
306  tmpi[next] = &tp;
307  //int max_texture_size = 0;
308 
309  GLenum format = GL_RGB;
310  GLenum internalFormat = GL_RGB;
311  if(tex.GetChannelCount()==4)
312  {
313  format = GL_RGBA;
314  internalFormat = GL_RGBA;
315  }
316  if((tex.GetChannelCount()<3)||(tex.GetChannelCount()>4))
317  {
318  BIASWARN("AdjustImageSizeToGPULimit not implemented for non rgb(a) images");
319  return false;
320  }
321 
322  /*
323  If target is GL_PROXY_TEXTURE_2D, no data is read from
324  pixels, but all of the texture image state is recalculated,
325  checked for consistency, and checked against the
326  implementation's capabilities. If the implementation cannot
327  handle a texture of the requested texture size, it sets all
328  of the image state to 0, but does not generate an error (see
329  glGetError).
330  */
331  GLint reswidth = 0;
332  glTexImage2D(GL_PROXY_TEXTURE_2D, 0, internalFormat, tex.GetWidth(), tex.GetHeight(), 0, format, GL_UNSIGNED_BYTE, NULL);
333  glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &reswidth);
335  while (reswidth==0)
336  {
337  cout<<"rescaling..."<<endl;
338  if (rescale.DownsampleBy2(*(tmpi[current]),*(tmpi[next]))!=0){
339  BIASERR("error downsampling");
340  return false;
341  }
342  /// swap current and next indeces
343  unsigned char ttt=next;
344  next = current;
345  current = ttt;
346  glTexImage2D(GL_PROXY_TEXTURE_2D, 0, internalFormat, tmpi[next]->GetWidth(), tmpi[next]->GetHeight(), 0, format, GL_UNSIGNED_BYTE, NULL);
347  glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &reswidth);
348  }
349  //glGetIntegerv(GL_MAX_TEXTURE_SIZE,&max_texture_size);
350  //cout<<"max_texture_size "<<max_texture_size<<endl;
351  //if (tmpi[current]->GetWidth()>(unsigned)max_texture_size
352  // || tmpi[current]->GetHeight()>(unsigned)max_texture_size){
353  // // BIASERR("image too big, downsampling");
354  // // downsample
355  // Rescale<unsigned char, unsigned char> rescale;
356  // do {
357  // if (rescale.DownsampleBy2(*(tmpi[current]),*(tmpi[next]))!=0){
358  // BIASERR("error downsampling");
359  // }
360  // // swap current and next indeces
361  // unsigned char ttt=next;
362  // next = current;
363  // current = ttt;
364  // } while ((tmpi[current])->GetWidth()>(unsigned)max_texture_size ||
365  // (tmpi[current])->GetHeight()>(unsigned)max_texture_size);
366  //}
367  if(current==1) tex = *(tmpi[1]);
368  return true;
369 }
370 
371 #define INFO_SEP '='
372 
373 bool OpenSceneGraphHelper::
374 HasInfo(const osg::ref_ptr<osg::Node> node, const string &key, string &value)
375 {
376  if (!node)
377  BEXCEPTION("OpenSceneGraphHelper::HasDescription(): NULL argument.");
378  const osg::Node::DescriptionList &dl = node->getDescriptions();
379  osg::Node::DescriptionList::const_iterator it;
380  for (it=dl.begin(); it!=dl.end(); it++){
381  size_t pos = it->find(key);
382  if (pos!=string::npos){
383  value = it->substr(pos+key.size()+1, it->size()-(pos+key.size())-1);
384  return true;
385  }
386  }
387  return false;
388 }
389 
390 
391 bool OpenSceneGraphHelper::
392 RemoveInfo(osg::ref_ptr<osg::Node> node, const string &key)
393 {
394  if (!node)
395  BEXCEPTION("OpenSceneGraphHelper::RemoveDescription(): NULL argument.");
396  osg::Node::DescriptionList &dl = node->getDescriptions();
397  osg::Node::DescriptionList::iterator it;
398  for (it=dl.begin(); it!=dl.end(); it++){
399  size_t pos = it->find(key);
400  if (pos!=string::npos){
401  dl.erase(it);
402  return true;
403  }
404  }
405  return false;
406 }
407 
408 
409 bool OpenSceneGraphHelper::
410 AddOrSetInfo(const osg::ref_ptr<osg::Node> node,
411  const string &key, const string &value)
412 {
413  if (!node)
414  BEXCEPTION("OpenSceneGraphHelper::AddOrSetInfo(): NULL argument.");
415  bool res = true;
416  string former_val;
417  if (HasInfo(node, key, former_val)){
418  RemoveInfo(node, key);
419  res = false;
420  }
421  if (key.find(INFO_SEP)!=string::npos || value.find(INFO_SEP)!=string::npos){
422  BEXCEPTION("OpenSceneGraphHelper::AddOrSetInfo(): Invalid character \'"
423  <<INFO_SEP<<"\' in key or value.");
424  }
425  node->addDescription(key+INFO_SEP+value);
426  return res;
427 }
428 
429 
430 void OpenSceneGraphHelper::
431 GetInfo(const osg::ref_ptr<osg::Node> node,
432  std::map<std::string, std::string> &key_val)
433 {
434  key_val.clear();
435  const osg::Node::DescriptionList &dl = node->getDescriptions();
436  osg::Node::DescriptionList::const_iterator it;
437  for (it=dl.begin(); it!=dl.end(); it++){
438  size_t pos = it->find(INFO_SEP);
439  if (pos==string::npos){
440  BEXCEPTION("OpenSceneGraphHelper::GetInfo(): Invalid info (missing "
441  <<"separator \'"<<INFO_SEP<<"\'");
442  }
443  string key = it->substr(0, pos);
444  string val = it->substr(pos+1, it->size()-(pos+1));
445  key_val[key] = val;
446  }
447 }
448 
449 
450 osg::ref_ptr<osg::Node> OpenSceneGraphHelper::
451 FindNodeWithInfo(const osg::ref_ptr<osg::Node> CurrentNode,
452  const std::string &key, const string &value)
453 {
454  if (!CurrentNode) {
455  BEXCEPTION("OpenSceneGraphHelper::FindNodeWithInfo(): NULL argument.");
456  }
457  string node_value;
458  if (HasInfo(CurrentNode, key, node_value) &&
459  (value == node_value) ){
460  return CurrentNode;
461  }
462  const osg::ref_ptr<osg::Group> gr = CurrentNode->asGroup();
463  if (gr) {
464  unsigned numchildr = gr->getNumChildren();
465  for(unsigned i=0; i<numchildr; i++){
466  const osg::ref_ptr<osg::Node> res =
467  FindNodeWithInfo(gr->getChild(i), key, value);
468  if (res) return res;
469  }
470  }
471  return NULL;
472 }
473 
474 
475 std::vector<osg::ref_ptr<osg::Node> > OpenSceneGraphHelper::
476 FindNodesWithInfo(const osg::ref_ptr<osg::Node> CurrentNode,
477  const std::string &key)
478 {
479  vector<osg::ref_ptr<osg::Node> > result;
480  FindNodesWithInfoHelper_(CurrentNode, key, result);
481  return result;
482 }
483 
484 
485 void OpenSceneGraphHelper::
486 FindNodesWithInfoHelper_(const osg::ref_ptr<osg::Node> CurrentNode,
487  const std::string &key,
488  std::vector<osg::ref_ptr<osg::Node> > &result)
489 {
490  if (!CurrentNode) {
491  BEXCEPTION("OpenSceneGraphHelper::FindNodeWithInfo(): NULL argument.");
492  }
493  string node_value;
494  if ( HasInfo(CurrentNode, key, node_value) ){
495  result.push_back(CurrentNode);
496  }
497  const osg::ref_ptr<osg::Group> gr = CurrentNode->asGroup();
498  if (gr) {
499  unsigned numchildr = gr->getNumChildren();
500  for(unsigned i=0; i<numchildr; i++){
501  FindNodesWithInfoHelper_(gr->getChild(i), key, result);
502  }
503  }
504 }
505 
506 
507 void OpenSceneGraphHelper::
508 DumpInfo(const osg::ref_ptr<osg::Node> node)
509 {
510  const osg::Node::DescriptionList &dl = node->getDescriptions();
511  osg::Node::DescriptionList::const_iterator it;
512  cout << "Node \""<<node->getName()<<"\":\n";
513  for (it=dl.begin(); it!=dl.end(); it++){
514  cout << " "<<*it<<endl;
515  }
516 }
517 
518 
519 std::ostream &BIAS::operator<<(std::ostream& os, const osg::Matrix& m)
520 {
521  os << "[";
522  for (int y=0; y<4; y++){
523  for (int x=0; x<4; x++){
524  os << m(y,x);
525  if (x!=3) os << " ";
526  }
527  if (y!=3) os << ";\n";
528  }
529  os << "]";
530  return os;
531 
532 }
533 
534 std::ostream &BIAS::operator<<(std::ostream& os, const osg::Vec3& v)
535 {
536  os << "["<<v[0]<<" "<<v[1]<<" "<<v[2]<<"]";
537  return os;
538 }
const std::vector< BIAS::Vector3< double > > & GetVerticesRef() const
const std::vector< BIAS::Vector< int > > & GetTriangleIndicesRef() const
unsigned int GetWidth() const
Definition: ImageBase.hh:312
class Vec3f Vec3
unsigned int GetChannelCount() const
returns the number of Color channels, e.g.
Definition: ImageBase.hh:382
Create and represent a 3D triangle mesh.
Definition: TriangleMesh.hh:84
unsigned int GetHeight() const
Definition: ImageBase.hh:319
class Matrixd Matrix
T * GetData()
get the pointer to the data array of the matrix (for faster direct memeory access) ...
Definition: Matrix.hh:185
std::ostream & operator<<(std::ostream &os, const Array2D< T > &arg)
Definition: Array2D.hh:260
void Init(unsigned int Width, unsigned int Height, unsigned int channels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
calls Init from ImageBase storageType is ignored, just dummy argument
Definition: Image.cpp:421
const StorageType * GetImageData() const
overloaded GetImageData() from ImageBase
Definition: Image.hh:137
const BIAS::Image< unsigned char > & GetTextureRef() const
int DownsampleBy2(const Image< InputStorageType > &src, Image< OutputStorageType > &dst)
Takes the source image that has to have a defined ROI.
Definition: Rescale.cpp:322
int Flip()
flips the image vertically (row order is inverted) In place function return 0 in case of success...
Definition: ImageBase.cpp:834
const std::vector< BIAS::Vector2< float > > & GetTexCoordsRef() const