// // setup of the image generation stage // static void createAcquisitionStage() { size_t num_ports = win->getMFPort()->size(); if (num_ports == 0) return; UInt32 width = win->getWidth(); UInt32 height = win->getHeight(); Real32 a = Real32(width) / Real32(height); width = UInt32(a*height); Viewport* vp = staticVp; Node* internalRoot = rootNode(mgr->getRoot()); // // Setup the FBO // spSimpleFBO.reset(new SimpleFBO(width, height, true, true, true, false)); //spSimpleFBO->fbo()->setPostProcessOnDeactivate(true); //spSimpleFBO->colorBuffer(0)->setReadBack(true); // // We would like to render the scene but won't detach it from its parent. // The VisitSubTree allows just that. // VisitSubTreeUnrecPtr visitor = VisitSubTree::create(); visitor->setSubTreeRoot(internalRoot); NodeUnrecPtr visit_node = makeNodeFor(visitor); // // The stage object does provide a render target for the frame buffer attachment. // SimpleStage has a camera, a background and the left, right, top, bottom // fields to let you restrict rendering to a sub-rectangle of your FBO, i.e. // they give you a viewport. // SimpleStageUnrecPtr stage = SimpleStage::create(); stage->setRenderTarget(spSimpleFBO->fbo()); stage->setCamera (vp->getCamera()); stage->setBackground (vp->getBackground()); // // Give the stage core a place to live // NodeUnrecPtr stage_node = makeNodeFor(stage); stage_node->addChild(visit_node); // // root // | // +- SimpleStage // | // +- VisitSubTree -> ApplicationScene // NodeUnrecPtr root = makeCoredNode<Group>(); root->addChild(stage_node); // // Give the root node a place to live, i.e. create a passive // viewport and add it to the window. // ViewportUnrecPtr stage_viewport = PassiveViewport::create(); stage_viewport->setRoot (stage_node); stage_viewport->setBackground(vp->getBackground()); stage_viewport->setCamera (vp->getCamera()); win->addPort(stage_viewport); mgr->update(); win->renderNoFinish(mgr->getRenderAction()); win->frameExit(); win->deactivate (); //ImageUnrecPtr col_image = Image::create(); //col_image->set(Image::OSG_RGBA_PF, width, height); //TextureObjChunk* texObj = spSimpleFBO->colorTexObj(0); //texObj->getImage()->subImage(0, 0, 0, width, height, 1, col_image); //col_image->write("d:/my_Test_opensg.png"); win->subPortByObj(stage_viewport); }
// // GrabForeground based solution // static void writeHiResScreenShot( const char* name, UInt32 width, UInt32 height) { size_t num_ports = win->getMFPort()->size(); if (num_ports == 0) return; // // calc image dimensions // UInt32 winWidth = win->getWidth(); UInt32 winHeight = win->getHeight(); if (width < winWidth ) width = winWidth; if (height < winHeight) height = winHeight; Real32 a = Real32(winWidth) / Real32(winHeight); width = UInt32(a*height); // // output stream for writing the final image // std::ofstream stream(name, std::ios::binary); if (stream.good() == false) return; // // Tile image used for foreground grabbing // ImageUnrecPtr grab_image = Image::create(); GrabForegroundUnrecPtr grabber = GrabForeground::create(); grabber->setImage (grab_image); grabber->setActive (true); grabber->setAutoResize(false); // // We tile the final image and render each tile with the screen resolution // into the window. The more tiles we use the bigger the resolution of the // final image gets with respect to a provided measure of length. // typedef boost::tuple<TileCameraDecoratorUnrecPtr, bool> TupleT; std::vector<TupleT> decorators; decorators.resize(num_ports); // // Setup the tile camera decorators for each viewport of the window and // disable the tile property of tileable viewport backgrounds. // for (size_t i = 0; i < num_ports; ++i) { Viewport* vp = win->getPort(i); TileCameraDecoratorUnrecPtr decorator = TileCameraDecorator::create(); decorator->setFullSize (width, height); decorator->setDecoratee(vp->getCamera()); vp->setCamera(decorator); bool bTiled = false; TileableBackground* tbg = dynamic_cast<TileableBackground*>(vp->getBackground()); if (tbg) { bTiled = tbg->getTile(); tbg->setTile(false); } // // remember the decorator and the background tile prop setting // decorators[i] = boost::make_tuple(decorator, bTiled); } // // Add the grabber to the forgrounds of the first viewport // Viewport* vp0 = win->getPort(0); vp0->addForeground(grabber); // // We write the image in simple ppm format. This one starts with a description // header which we output once on first write. // bool write_header = true; // // Calc the max y start position (width). We process the tiles from bottom // up and from left tp right as determined by the image format. // UInt32 yPosLast = 0; for (; yPosLast < height-winHeight; yPosLast += winHeight); // // Process from bottom to top // for (Int32 yPos = yPosLast; yPos >= 0; yPos -= winHeight) { UInt32 ySize = std::min(winHeight, height - yPos); // // Collect the tile images for each row, i.e. we write the // image in row manner to disk. This way the main memory is // only moderately stressed. // std::vector<ImageUnrecPtr> vecColImages; // // Process from left to right // for (UInt32 xPos = 0; xPos < width; xPos += winWidth) { UInt32 xSize = std::min(winWidth, width - xPos); // // The current tile image // ImageUnrecPtr col_image = Image::create(); col_image->set(Image::OSG_RGBA_PF, xSize, ySize); // // Adapt the tile camera decorator boxes to the current tile // for (size_t i = 0; i < num_ports; ++i) { Viewport* vp = win->getPort(i); vp->setSize(0, 0, xSize, ySize); TileCameraDecorator* decorator = decorators[i].get<0>(); decorator->setSize( xPos / float(width), yPos / float(height), (xPos + xSize) / float(width), (yPos + ySize) / float(height) ); } // // Adapt the grabber image size to the current tile dimension // grab_image->set(Image::OSG_RGBA_PF, xSize, ySize); // // render the tile // mgr->redraw(); // // Copy the image into the tile image stored for later processing // col_image->setSubData(0, 0, 0, xSize, ySize, 1, grabber->getImage()->getData()); vecColImages.push_back(col_image); } // // Write the image format header once // if (write_header) { write_header = false; if (!writePNMImagesHeader(vecColImages, width, height, stream)) break; } // // Write the current column // if (!writePNMImagesData(vecColImages, stream)) break; // // Forget the current column images // vecColImages.clear(); } // // restore window and cleanup // vp0->removeObjFromForegrounds(grabber); for (size_t i = 0; i < num_ports; ++i) { Viewport* vp = win->getPort(i); vp->setCamera(decorators[i].get<0>()->getDecoratee()); vp->setSize(0, 0, 1, 1); TileableBackground* tbg = dynamic_cast<TileableBackground*>(vp->getBackground()); if (tbg) tbg->setTile(decorators[i].get<1>()); } }
// // FBO solution // static void writeHiResScreenShotFBO(const char* name, UInt32 width, UInt32 height) { size_t num_ports = win->getMFPort()->size(); if (num_ports == 0) return; // // calc image dimensions // UInt32 winWidth = win->getWidth(); UInt32 winHeight = win->getHeight(); if (width < winWidth ) width = winWidth; if (height < winHeight) height = winHeight; Real32 a = Real32(winWidth) / Real32(winHeight); width = UInt32(a*height); // // output stream for writing the final image // std::ofstream stream(name, std::ios::binary); if (stream.good() == false) return; // // Setup the FBO // FrameBufferObjectUnrecPtr fbo = FrameBufferObject::create(); // // We use two render buffers. One for the color buffer and one for the depth and // stencil buffer. This example does not take credit of the stencil buffer. There- // fore a depth buffer would suffice. However, the use of the combined depth and // stencil buffer is useful in other contextes and hence used. // RenderBufferUnrecPtr colBuf = RenderBuffer::create(); RenderBufferUnrecPtr dsBuf = RenderBuffer::create(); // // As we would like to read back the FBO color buffer, we must provide a fitting // image. // ImageUnrecPtr buffer_image = Image::create(); buffer_image->set(Image::OSG_RGBA_PF, winWidth, winHeight); colBuf->setImage(buffer_image); // // We must setup the internal image formats of the two render buffers accordingly. // colBuf->setInternalFormat(GL_RGBA); dsBuf ->setInternalFormat(GL_DEPTH24_STENCIL8_EXT); // // we must inform the FBO about the actual used color render buffers. // fbo->editMFDrawBuffers()->push_back(GL_COLOR_ATTACHMENT0_EXT); // // The FBO takes responsibility of the render buffers. Notice, that the shared // depth/stencil buffer is provided twice. As the depth render buffer and as the // stencil render buffer. // fbo->setColorAttachment (colBuf, 0); fbo->setDepthAttachment (dsBuf); fbo->setStencilAttachment(dsBuf); // // Also the FBO must be sized correctly. // fbo->setWidth (winWidth ); fbo->setHeight(winHeight); // // In order to read the color buffer back next two statements are necessary. // fbo->setPostProcessOnDeactivate(true); fbo->getColorAttachments(0)->setReadBack(true); // // We tile the final image and render each tile with the screen resolution // into the FBO. The more tiles we use the bigger the resolution of the // final image gets with respect to a provided measure of length. // typedef boost::tuple<TileCameraDecoratorUnrecPtr, bool, SimpleStageUnrecPtr, ViewportUnrecPtr> TupleT; std::vector<TupleT> decorators; decorators.resize(num_ports); // // Remember the stage viewports for later cleanup // std::stack<ViewportUnrecPtr> stage_viewports; // // Setup the tile camera decorators for each viewport of the window and // disable the tile property of tileable viewport backgrounds. // for (size_t i = 0; i < num_ports; ++i) { Viewport* vp = win->getPort(i); TileCameraDecoratorUnrecPtr decorator = TileCameraDecorator::create(); decorator->setFullSize (width, height); decorator->setDecoratee(vp->getCamera()); vp->setCamera(decorator); bool bTiled = false; TileableBackground* tbg = dynamic_cast<TileableBackground*>(vp->getBackground()); if (tbg) { bTiled = tbg->getTile(); tbg->setTile(false); } // // The scene manager root node does not provide the illumination of the // scene. This is governed internally by the manager. However, to take // credit of the illumination we scan to the final parent of the scene // graph. // Node* internalRoot = rootNode(mgr->getRoot()); // // We would like to render the scene but won't detach it from its parent. // The VisitSubTree allows just that. // VisitSubTreeUnrecPtr visitor = VisitSubTree::create(); visitor->setSubTreeRoot(internalRoot); NodeUnrecPtr visit_node = makeNodeFor(visitor); // // We clone the camera of the first viewport and do not swap the buffer on later // rendering. This way the image generation process is not noticable in the // window. // CameraUnrecPtr camera = dynamic_pointer_cast<Camera>(vp->getCamera()->shallowCopy()); // // The stage object does provide a render target for the frame buffer attachment. // SimpleStage has a camera, a background and the left, right, top, bottom // fields to let you restrict rendering to a sub-rectangle of your FBO, i.e. // they give you a viewport. // SimpleStageUnrecPtr stage = SimpleStage::create(); stage->setRenderTarget(fbo); stage->setCamera (decorator); stage->setBackground (vp->getBackground()); // // Give the stage core a place to live // NodeUnrecPtr stage_node = makeNodeFor(stage); stage_node->addChild(visit_node); // // root // | // +- SimpleStage // | // +- VisitSubTree -> ApplicationScene // NodeUnrecPtr root = makeCoredNode<Group>(); root->addChild(stage_node); // // Give the root node a place to live, i.e. create a passive // viewport and add it to the window. // ViewportUnrecPtr stage_viewport = PassiveViewport::create(); stage_viewport->setRoot (root); stage_viewport->setBackground(vp->getBackground()); stage_viewport->setCamera (camera); win->addPort(stage_viewport); // // remember the decorator, the background tile prop setting and the stage setup // decorators[i] = boost::make_tuple(decorator, bTiled, stage, stage_viewport); } // // We write the image in simple ppm format. This one starts with a description // header which we output once on first write. // bool write_header = true; // // Calc the max y start position (width). We process the tiles from bottom // up and from left tp right as determined by the image format. // UInt32 yPosLast = 0; for (; yPosLast < height-winHeight; yPosLast += winHeight); // // Process from bottom to top // for (Int32 yPos = yPosLast; yPos >= 0; yPos -= winHeight) { UInt32 ySize = std::min(winHeight, height - yPos); // // Collect the tile images for each row, i.e. we write the // image in row manner to disk. This way the main memory is // only moderately stressed. // std::vector<ImageUnrecPtr> vecColImages; // // Process from left to right // for (UInt32 xPos = 0; xPos < width; xPos += winWidth) { UInt32 xSize = std::min(winWidth, width - xPos); // // The current tile image // ImageUnrecPtr col_image = Image::create(); col_image->set(Image::OSG_RGBA_PF, xSize, ySize); // // Adapt the tile camera decorator boxes to the current tile // for (size_t i = 0; i < num_ports; ++i) { // // this tile does not fill the whole FBO - adjust to only render // to a part of it // decorators[i].get<2>()->setLeft (0.f); decorators[i].get<2>()->setRight (xSize / float(winWidth)); decorators[i].get<2>()->setBottom(0.f); decorators[i].get<2>()->setTop (ySize / float(winHeight)); TileCameraDecorator* decorator = decorators[i].get<0>(); decorator->setSize( xPos / float(width), yPos / float(height), (xPos + xSize) / float(width), (yPos + ySize) / float(height) ); } // // render the tile // mgr->update(); win->renderNoFinish(mgr->getRenderAction()); win->frameExit(); win->deactivate (); // // Copy the image into the tile image stored for later processing // if(fbo) { RenderBuffer* grabber = dynamic_cast<RenderBuffer*>(fbo->getColorAttachments(0)); if(grabber) { grabber->getImage()->subImage(0, 0, 0, xSize, ySize, 1, col_image); } } vecColImages.push_back(col_image); } // // Write the image format header once // if (write_header) { write_header = false; if (!writePNMImagesHeader(vecColImages, width, height, stream)) break; } // // Write the current column // if (!writePNMImagesData(vecColImages, stream)) break; // // Forget the current column images // vecColImages.clear(); } // // restore window and cleanup // for (size_t i = 0; i < num_ports; ++i) { win->subPortByObj(decorators[i].get<3>()); Viewport* vp = win->getPort(i); vp->setCamera(decorators[i].get<0>()->getDecoratee()); vp->setSize(0, 0, 1, 1); TileableBackground* tbg = dynamic_cast<TileableBackground*>(vp->getBackground()); if (tbg) tbg->setTile(decorators[i].get<1>()); } }
void SortLastWindow::serverRender(Window *serverWindow, UInt32 id, RenderActionBase *action ) { ViewportUnrecPtr serverPort = NULL; Viewport *clientPort = NULL; UInt32 sv = 0; UInt32 cv = 0; // duplicate viewports for(cv = 0, sv = 0; cv < getMFPort()->size(); ++cv) { clientPort = getPort(cv); if(serverWindow->getMFPort()->size() <= sv) { // create new port serverPort = Viewport::create(); serverWindow->addPort(serverPort); } else { serverPort = serverWindow->getPort(sv); } // duplicate values if(getWidth() && getHeight()) { serverPort->setSize(clientPort->calcPixelLeft (), clientPort->calcPixelBottom(), clientPort->calcPixelRight (), clientPort->calcPixelTop ()); } else { serverPort->setSize(0,0,0,0); } serverPort->setCamera (clientPort->getCamera ()); serverPort->setRoot (clientPort->getRoot ()); serverPort->setBackground(clientPort->getBackground()); // ignore statistics foreground serverPort->clearForegrounds(); for(UInt32 f = 0 ; f < serverPort->getMFForegrounds()->size(); ++f) { Foreground *fg = clientPort->getForegrounds(f); StatisticsForeground *sfg = dynamic_cast<StatisticsForeground *>(fg); if(sfg == NULL) { serverPort->addForeground(fg); } } serverPort->setTravMask(clientPort->getTravMask()); sv++; } // remove unused ports while(serverWindow->getMFPort()->size() > sv) { serverWindow->subPort(sv); } // setup visible nodes setupNodes(id); // render the viewports serverWindow->activate(); serverWindow->frameInit(); action->setWindow(serverWindow); if(getComposer() != NULL) getComposer()->startFrame(); for(sv = 0; sv < serverWindow->getMFPort()->size(); ++sv) { Viewport *vp = serverWindow->getPort(sv); if(getComposer() != NULL) getComposer()->startViewport(vp); // render vp->render(action); // compose single viewport if(getComposer() != NULL) getComposer()->composeViewport(vp); } // compose whole window if(getComposer() != NULL) getComposer()->composeWindow(); }