1 // OpenSG example: dyndrawing1.cpp
4 // This example shows how to create a render setup that allows the rendering
5 // of a complex scene in its first viewport and on request (key '1') switches
6 // into a 'dynamic' mode that allows you to render additional scenery dynamically.
9 // In some domains such as CAD it is possible that the render scene is very
10 // complex so that it is not possible to reach any reasonable frame rate.
11 // However you still need to be able to draw dynamic content in such a scenery.
12 // Imagine for instance that you must dynamically resposion some 100 lines of grafic.
15 // Separate the static and the dynamic rendering and render the static scenery from
16 // an image. This is of course limited to dynamic modifications that leave the static
17 // scenenry rendered from one perspective. Still it is very useful.
20 // The complex scene is rendered into a FBO that is subsequentely given to a
21 // FBOBackground used by the dynamic viewport, i.e. the viewport that should handle
25 // a) mouse => standard navigator
27 // '1': toggle between static and dynamic mode
36 #include <boost/tuple/tuple.hpp>
37 #include <boost/scoped_ptr.hpp>
38 #include <boost/random.hpp>
39 #include <boost/random/lagged_fibonacci.hpp>
41 #ifdef OSG_BUILD_ACTIVE
44 #include <OSGConfig.h>
45 #include <OSGSimpleGeometry.h>
46 #include <OSGGLUTWindow.h>
47 #include <OSGGradientBackground.h>
48 #include <OSGSimpleSceneManager.h>
49 #include <OSGSceneFileHandler.h>
50 #include <OSGAction.h>
51 #include <OSGFrameBufferObject.h>
52 #include <OSGRenderBuffer.h>
53 #include <OSGTextureBuffer.h>
54 #include <OSGSimpleStage.h>
55 #include <OSGPassiveViewport.h>
56 #include <OSGVisitSubTree.h>
58 #include <OSGTextureObjChunk.h>
59 #include <OSGFBOBackground.h>
63 #include <OpenSG/OSGGLUT.h>
64 #include <OpenSG/OSGConfig.h>
65 #include <OpenSG/OSGSimpleGeometry.h>
66 #include <OpenSG/OSGGLUTWindow.h>
67 #include <OpenSG/OSGGradientBackground.h>
68 #include <OpenSG/OSGSimpleSceneManager.h>
69 #include <OpenSG/OSGSceneFileHandler.h>
70 #include <OpenSG/OSGAction.h>
71 #include <OpenSG/OSGFrameBufferObject.h>
72 #include <OpenSG/OSGRenderBuffer.h>
73 #include <OpenSG/OSGTextureBuffer.h>
74 #include <OpenSG/OSGSimpleStage.h>
75 #include <OpenSG/OSGPassiveViewport.h>
76 #include <OpenSG/OSGVisitSubTree.h>
77 #include <OpenSG/OSGImage.h>
78 #include <OpenSG/OSGTextureObjChunk.h>
79 #include <OpenSG/OSGFBOBackground.h>
83 OSG_USING_NAMESPACE
// just for convenience but not recommended
85 //#define USE_MULTISAMPLING
88 // The number of tori to render
89 // ============================
92 const int max_tori
= 500;
94 const int max_tori
= 10000;
98 // Helper class for building FBO used by SimpleFBO see below
99 // =========================================================
107 , pixel_format(Image::OSG_RGBA_PF
)
108 , type(Image::OSG_UINT8_IMAGEDATA
)
112 ~TextureData() {texObj
= NULL
; image
= NULL
; }
118 TextureObjChunkUnrecPtr texObj
;
122 typedef std::vector
<TextureData
> VecTextureDataT
;
125 FBOBuilder(const VecTextureDataT
& buffers
, bool depth
, bool stencil
, const TextureData
& ds_buffer
)
126 : _buffers(buffers
) , _depth(depth
) , _stencil(stencil
) , _ds_buffer(ds_buffer
) {}
130 FrameBufferObjectTransitPtr
operator()(UInt32 width
, UInt32 height
) const;
133 VecTextureDataT _buffers
;
136 TextureData _ds_buffer
;
139 FrameBufferObjectTransitPtr
FBOBuilder::operator()(
146 FrameBufferObjectUnrecPtr fbo
= FrameBufferObject::create();
148 // multiple color buffers
150 for (UInt32 idx
= 0; idx
< _buffers
.size(); ++idx
) {
154 if (_buffers
[idx
].enable
) {
155 ImageUnrecPtr texImg
= (_buffers
[idx
].image
== NULL
? Image::create() : _buffers
[idx
].image
);
156 TextureObjChunkUnrecPtr texObj
= (_buffers
[idx
].texObj
== NULL
? TextureObjChunk::create() : _buffers
[idx
].texObj
);
157 TextureBufferUnrecPtr texBuf
= TextureBuffer::create();
159 if (_buffers
[idx
].image
== NULL
)
160 texImg
->set(_buffers
[idx
].pixel_format
,
161 width
, height
, 1, 1, 1, 0.f
, NULL
,
163 _buffers
[idx
].main_memory
);
165 texObj
->setImage(texImg
);
166 texBuf
->setTexture(texObj
);
168 fbo
->setColorAttachment(texBuf
, idx
);
171 // no, then use simple render buffer
174 RenderBufferUnrecPtr renBuf
= RenderBuffer::create();
175 renBuf
->setInternalFormat(_buffers
[idx
].pixel_format
);
176 fbo
->setColorAttachment(renBuf
, idx
);
178 fbo
->editMFDrawBuffers()->push_back(GL_COLOR_ATTACHMENT0_EXT
+ idx
);
181 // a sole depth buffer
183 if (_depth
&& !_stencil
) {
187 if (_ds_buffer
.enable
) {
188 ImageUnrecPtr texImg
= (_ds_buffer
.image
== NULL
? Image::create() : _ds_buffer
.image
);
189 TextureObjChunkUnrecPtr texObj
= (_ds_buffer
.texObj
== NULL
? TextureObjChunk::create() : _ds_buffer
.texObj
);
190 TextureBufferUnrecPtr texBuf
= TextureBuffer::create();
192 if (_ds_buffer
.image
== NULL
)
193 texImg
->set(_ds_buffer
.pixel_format
,
194 width
, height
, 1, 1, 1, 0.f
, NULL
,
196 _ds_buffer
.main_memory
);
198 texObj
->setImage(texImg
);
200 if (_ds_buffer
.texObj
== NULL
) {
201 texObj
->setInternalFormat(GL_DEPTH_COMPONENT24
);
202 texObj
->setExternalFormat(GL_DEPTH_COMPONENT24
);
204 texBuf
->setTexture(texObj
);
206 fbo
->setDepthAttachment(texBuf
);
209 // no, then use simple render buffer
212 RenderBufferUnrecPtr renBuf
= RenderBuffer::create();
213 renBuf
->setInternalFormat(GL_DEPTH_COMPONENT24
);
214 fbo
->setDepthAttachment(renBuf
);
218 // or a combined depth/stencil buffer
220 if (_depth
&& _stencil
) {
224 if (_ds_buffer
.enable
) {
225 ImageUnrecPtr texImg
= (_ds_buffer
.image
== NULL
? Image::create() : _ds_buffer
.image
);
226 TextureObjChunkUnrecPtr texObj
= (_ds_buffer
.texObj
== NULL
? TextureObjChunk::create() : _ds_buffer
.texObj
);
227 TextureBufferUnrecPtr texBuf
= TextureBuffer::create();
229 if (_ds_buffer
.image
== NULL
)
230 texImg
->set(GL_DEPTH_STENCIL_EXT
,
231 width
, height
, 1, 1, 1, 0.f
, NULL
,
232 GL_UNSIGNED_INT_24_8
,
233 _ds_buffer
.main_memory
);
235 texObj
->setImage(texImg
);
236 texObj
->setInternalFormat(GL_DEPTH24_STENCIL8_EXT
);
237 texObj
->setExternalFormat(GL_DEPTH_STENCIL_EXT
);
238 texBuf
->setTexture(texObj
);
240 fbo
->setDepthAttachment(texBuf
);
241 fbo
->setStencilAttachment(texBuf
);
244 // no, then use simple render buffer
247 RenderBufferUnrecPtr renBuf
= RenderBuffer::create();
248 renBuf
->setInternalFormat(GL_DEPTH24_STENCIL8
);
249 fbo
->setDepthAttachment(renBuf
);
250 fbo
->setStencilAttachment(renBuf
);
254 fbo
->setWidth (width
);
255 fbo
->setHeight(height
);
257 return FrameBufferObjectTransitPtr(fbo
);
261 // Convenience helper object wrapping the FBO uses FBOBuilder internally
262 // =====================================================================
267 SimpleFBO(UInt32 width
,
270 bool depth_stencil_textured
,
271 bool read_back_color
= true,
272 bool read_back_depth_stencil
= false);
274 SimpleFBO(UInt32 width
,
276 const std::vector
<FBOBuilder::TextureData
>& buffers
,
279 const FBOBuilder::TextureData
& ds_buffer
);
281 ~SimpleFBO() { _fbo
= NULL
; }
284 FrameBufferObject
* fbo () const { return _fbo
; }
286 FrameBufferAttachment
* colorBuffer (UInt32 idx
= 0) const { return _fbo
? _fbo
->getColorAttachments(idx
) : NULL
; }
287 FrameBufferAttachment
* depthBuffer () const { return _fbo
? _fbo
->getDepthAttachment() : NULL
; }
288 FrameBufferAttachment
* stencilBuffer () const { return _fbo
? _fbo
->getStencilAttachment() : NULL
;}
290 TextureObjChunk
* colorTexObj (UInt32 idx
= 0) const;
291 TextureObjChunk
* depthTexObj () const;
292 TextureObjChunk
* stencilTexObj () const;
295 FrameBufferObjectRecPtr _fbo
;
298 SimpleFBO::SimpleFBO(
302 bool depth_stencil_textured
,
303 bool read_back_color
,
304 bool read_back_depth_stencil
)
307 FBOBuilder::TextureData color_data
;
308 color_data
.enable
= color_textured
;
309 color_data
.main_memory
= read_back_color
;
311 FBOBuilder::TextureData depth_stencil_data
;
312 depth_stencil_data
.enable
= depth_stencil_textured
;
313 depth_stencil_data
.main_memory
= read_back_depth_stencil
;
315 FBOBuilder::VecTextureDataT color_vec
;
316 color_vec
.push_back(color_data
);
318 FBOBuilder
fbo_builder(color_vec
, true, true, depth_stencil_data
);
320 _fbo
= fbo_builder(width
, height
);
323 SimpleFBO::SimpleFBO(
326 const std::vector
<FBOBuilder::TextureData
>& buffers
,
329 const FBOBuilder::TextureData
& ds_buffer
)
332 FBOBuilder
fbo_builder(buffers
, depth
, stencil
, ds_buffer
);
334 _fbo
= fbo_builder(width
, height
);
337 TextureObjChunk
* SimpleFBO::colorTexObj(UInt32 idx
) const
339 TextureBuffer
* texBuf
= dynamic_cast<TextureBuffer
*>(colorBuffer(idx
));
341 return texBuf
->getTexture();
346 TextureObjChunk
* SimpleFBO::depthTexObj() const
348 TextureBuffer
* texBuf
= dynamic_cast<TextureBuffer
*>(depthBuffer());
350 return texBuf
->getTexture();
355 TextureObjChunk
* SimpleFBO::stencilTexObj() const
357 TextureBuffer
* texBuf
= dynamic_cast<TextureBuffer
*>(stencilBuffer());
359 return texBuf
->getTexture();
366 // function forward declarations
367 // =============================
369 static void cleanup(void);
370 static void display(void);
371 static void reshape(int w
, int h
);
372 static void mouse(int button
, int state
, int x
, int y
);
373 static void motion(int x
, int y
);
374 static void keyboard(unsigned char k
, int, int);
375 static int setupGLUT(int *argc
, char *argv
[]);
376 static int doMain(int argc
, char *argv
[]);
378 static NodeTransitPtr
createStaticScene();
379 static NodeTransitPtr
createDynamicScene();
380 static void createAcquisitionStage();
381 static void createDynamicViewport();
382 static void enableStaticScene();
383 static Node
* rootNode(Node
* node
);
386 // global state of example
387 // =======================
389 SimpleSceneManagerRefPtr mgr
;
390 NodeRefPtr staticScene
;
391 NodeRefPtr dynamicScene
;
392 GLUTWindowRefPtr win
;
393 ViewportRefPtr staticVp
;
394 ViewportRefPtr dynamicVp
;
397 boost::scoped_ptr
<SimpleFBO
> spSimpleFBO
;
400 // functions implementation
401 // ========================
404 static void cleanup(void)
414 static void display(void)
420 static void reshape(int w
, int h
)
426 static void mouse(int button
, int state
, int x
, int y
)
429 mgr
->mouseButtonRelease(button
, x
, y
);
431 mgr
->mouseButtonPress(button
, x
, y
);
436 static void motion(int x
, int y
)
438 mgr
->mouseMove(x
, y
);
442 static void keyboard(unsigned char k
, int, int)
453 std::exit(EXIT_SUCCESS
);
459 UInt32 width
= win
->getWidth();
460 UInt32 height
= win
->getHeight();
462 std::cout
<< "Creating acquisition stage "
463 << width
<< "x" << height
467 createAcquisitionStage();
468 createDynamicViewport();
481 static int setupGLUT(int *argc
, char *argv
[])
483 glutInit(argc
, argv
);
486 GLUT_RGB
| GLUT_DEPTH
| GLUT_STENCIL
| GLUT_DOUBLE
487 #ifdef USE_MULTISAMPLING
492 int winid
= glutCreateWindow("OpenSG");
494 glutReshapeFunc(reshape
);
495 glutDisplayFunc(display
);
496 glutIdleFunc(display
);
497 glutMouseFunc(mouse
);
498 glutMotionFunc(motion
);
499 glutKeyboardFunc(keyboard
);
507 static int doMain(int argc
, char *argv
[])
509 preloadSharedObject("OSGFileIO");
510 preloadSharedObject("OSGImageFileIO");
514 int winid
= setupGLUT(&argc
, argv
);
516 win
= GLUTWindow::create();
517 win
->setGlutId(winid
);
522 FWARNING(("No file given!\n"));
523 FWARNING(("Supported file formats:\n"));
525 std::list
<const char*> suffixes
;
526 SceneFileHandler::the()->getSuffixList(suffixes
);
528 for(std::list
<const char*>::iterator it
= suffixes
.begin();
529 it
!= suffixes
.end();
532 FWARNING(("%s\n", *it
));
535 staticScene
= createStaticScene();
539 staticScene
= SceneFileHandler::the()->read(argv
[1]);
542 dynamicScene
= createDynamicScene();
546 mgr
= SimpleSceneManager::create();
548 NodeUnrecPtr root
= makeCoredNode
<Group
>();
549 root
->addChild(staticScene
);
554 GradientBackgroundUnrecPtr background
= GradientBackground::create();
555 background
->addLine(Color3f(0,0,0), 0);
556 background
->addLine(Color3f(1,1,1), 1);
558 staticVp
= win
->getPort(0);
559 staticVp
->setBackground(background
);
561 camera
= staticVp
->getCamera();
569 // create an arbitrarly complex render scene
571 static NodeTransitPtr
createStaticScene()
573 NodeUnrecPtr root
= makeCoredNode
<Group
>();
575 typedef boost::mt19937 base_generator_type
;
576 static base_generator_type
generator(0);
577 static boost::uniform_01
<float> value
;
578 static boost::variate_generator
< base_generator_type
, boost::uniform_01
<float> > die(generator
, value
);
580 for (int i
= 0; i
< max_tori
; ++i
) {
581 NodeUnrecPtr scene
= makeTorus(.5, 2, 32, 32);
583 TransformUnrecPtr transformCore
= Transform::create();
588 float x
= 500.f
* die();
589 float y
= 500.f
* die();
590 float z
= 500.f
* die();
599 float a
= TwoPi
* die();
603 mat
.setTranslate(x
,y
,z
);
606 transformCore
->setMatrix(mat
);
608 NodeUnrecPtr trafo
= makeNodeFor(transformCore
);
610 trafo
->addChild(scene
);
612 root
->addChild(trafo
);
615 return NodeTransitPtr(root
);
618 static NodeTransitPtr
createDynamicScene()
620 NodeUnrecPtr scene
= makeCylinder(30, 100, 16, true, true, true);
621 return NodeTransitPtr(scene
);
625 // setup of the image generation stage
627 static void createAcquisitionStage()
629 size_t num_ports
= win
->getMFPort()->size();
633 UInt32 width
= win
->getWidth();
634 UInt32 height
= win
->getHeight();
636 Real32 a
= Real32(width
) / Real32(height
);
637 width
= UInt32(a
*height
);
639 Viewport
* vp
= staticVp
;
641 Node
* internalRoot
= rootNode(mgr
->getRoot());
646 spSimpleFBO
.reset(new SimpleFBO(width
, height
, true, true, true, false));
648 //spSimpleFBO->fbo()->setPostProcessOnDeactivate(true);
649 //spSimpleFBO->colorBuffer(0)->setReadBack(true);
652 // We would like to render the scene but won't detach it from its parent.
653 // The VisitSubTree allows just that.
655 VisitSubTreeUnrecPtr visitor
= VisitSubTree::create();
656 visitor
->setSubTreeRoot(internalRoot
);
657 NodeUnrecPtr visit_node
= makeNodeFor(visitor
);
660 // The stage object does provide a render target for the frame buffer attachment.
661 // SimpleStage has a camera, a background and the left, right, top, bottom
662 // fields to let you restrict rendering to a sub-rectangle of your FBO, i.e.
663 // they give you a viewport.
665 SimpleStageUnrecPtr stage
= SimpleStage::create();
666 stage
->setRenderTarget(spSimpleFBO
->fbo());
667 stage
->setCamera (vp
->getCamera());
668 stage
->setBackground (vp
->getBackground());
670 // Give the stage core a place to live
672 NodeUnrecPtr stage_node
= makeNodeFor(stage
);
673 stage_node
->addChild(visit_node
);
680 // +- VisitSubTree -> ApplicationScene
682 NodeUnrecPtr root
= makeCoredNode
<Group
>();
683 root
->addChild(stage_node
);
686 // Give the root node a place to live, i.e. create a passive
687 // viewport and add it to the window.
689 ViewportUnrecPtr stage_viewport
= PassiveViewport::create();
690 stage_viewport
->setRoot (stage_node
);
691 stage_viewport
->setBackground(vp
->getBackground());
692 stage_viewport
->setCamera (vp
->getCamera());
694 win
->addPort(stage_viewport
);
697 win
->renderNoFinish(mgr
->getRenderAction());
701 //ImageUnrecPtr col_image = Image::create();
702 //col_image->set(Image::OSG_RGBA_PF, width, height);
704 //TextureObjChunk* texObj = spSimpleFBO->colorTexObj(0);
705 //texObj->getImage()->subImage(0, 0, 0, width, height, 1, col_image);
706 //col_image->write("d:/my_Test_opensg.png");
708 win
->subPortByObj(stage_viewport
);
711 static void createDynamicViewport()
713 win
->subPortByObj(staticVp
);
715 FBOBackgroundUnrecPtr fboBckgnd
= FBOBackground::create();
716 fboBckgnd
->setFrameBufferObject(spSimpleFBO
->fbo());
718 NodeUnrecPtr root
= makeCoredNode
<Group
>();
719 root
->addChild(dynamicScene
);
723 dynamicVp
= Viewport::create();
724 dynamicVp
->setRoot (rootNode(root
));
725 dynamicVp
->setBackground(fboBckgnd
);
726 dynamicVp
->setCamera (camera
);
727 dynamicVp
->setSize (0,0, 1,1);
729 mgr
->getNavigator()->setViewport(dynamicVp
);
731 win
->addPort(dynamicVp
);
736 static void enableStaticScene()
738 win
->subPortByObj(dynamicVp
);
741 NodeUnrecPtr root
= makeCoredNode
<Group
>();
742 root
->addChild(staticScene
);
745 mgr
->getNavigator()->setViewport(staticVp
);
747 staticVp
->setCamera(camera
);
749 win
->addPort(staticVp
);
752 static Node
* rootNode(Node
* node
)
757 node
= node
->getParent();
765 int main(int argc
, char *argv
[])
767 int ret
= doMain(argc
, argv
);