2024-03-19 17:45:12 +08:00

260 lines
9.8 KiB
C++

/**************************************************************************************/
/* */
/* Visualization Library */
/* http://visualizationlibrary.org */
/* */
/* Copyright (c) 2005-2020, Michele Bosi */
/* All rights reserved. */
/* */
/* Redistribution and use in source and binary forms, with or without modification, */
/* are permitted provided that the following conditions are met: */
/* */
/* - Redistributions of source code must retain the above copyright notice, this */
/* list of conditions and the following disclaimer. */
/* */
/* - Redistributions in binary form must reproduce the above copyright notice, this */
/* list of conditions and the following disclaimer in the documentation and/or */
/* other materials provided with the distribution. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
/* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
/* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
/* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
/* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
/* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* */
/**************************************************************************************/
#ifndef CameraReadPixels_INCLUDE_ONCE
#define CameraReadPixels_INCLUDE_ONCE
#include <vlGraphics/Camera.hpp>
#include <vlCore/Say.hpp>
#include <vlCore/Log.hpp>
#include <vlGraphics/RenderEventCallback.hpp>
#include <vlGraphics/BufferObject.hpp>
#include <vlCore/Image.hpp>
namespace vl
{
//-----------------------------------------------------------------------------
// vl::readPixels()
//-----------------------------------------------------------------------------
/** Reads a rectangular pixel area from the specified read buffer and stores it in an Image.
*
* If 'store_in_pixel_buffer_object' is true the data will be copied in the GPU memory using the GL_EXT_pixel_buffer_object
* extension, while the local buffer will be deallocated.
*
* \note
* The image returned by this function might seem flipped upside down. */
inline void readPixels(Image* image, int x, int y, int w, int h, EReadDrawBuffer read_buffer, bool store_in_pixel_buffer_object)
{
// clears OpenGL errors
glGetError();
#if defined(VL_OPENGL)
glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
#endif
glPixelStorei( GL_PACK_ALIGNMENT, 1);
#if defined(VL_OPENGL)
glPixelStorei( GL_PACK_ROW_LENGTH, w);
glPixelStorei( GL_PACK_SKIP_PIXELS, 0);
glPixelStorei( GL_PACK_SKIP_ROWS, 0);
glPixelStorei( GL_PACK_SWAP_BYTES, 0);
glPixelStorei( GL_PACK_LSB_FIRST, 0);
if (Has_GL_Version_1_2||Has_GL_Version_3_0||Has_GL_Version_4_0) // Texture 3D but excluding EOS
{
glPixelStorei( GL_PACK_IMAGE_HEIGHT, 0 );
glPixelStorei( GL_PACK_SKIP_IMAGES, 0 );
}
int prev = 0;
glGetIntegerv( GL_READ_BUFFER, &prev ); VL_CHECK_OGL()
glReadBuffer( read_buffer );
#endif
#ifndef NDEBUG
if (glGetError() != GL_NO_ERROR)
{
Log::print(Say("Image::readPixels() error: %s:%n\n"
"You seem to have specified a wrong read buffer for the bound render target,\n"
"for example you might have specified a RDB_BACK_LEFT but the active camera\n"
"is bound to a FBO (Framebuffer Object) render target or the selected\n"
"read buffer is FBO-specific (like RDB_COLOR_ATTACHMENT0_EXT) but the active\n"
"camera is not bound to a FBO render target. \n") << __FILE__ << __LINE__
);
VL_TRAP()
}
#endif
bool supports_pbo = Has_GL_ARB_pixel_buffer_object||Has_GL_EXT_pixel_buffer_object||Has_GL_Version_2_1;
if (store_in_pixel_buffer_object && supports_pbo)
{
// mic fixme: test
BufferObject* glbuf = cast<BufferObject>(image->imageBuffer()); VL_CHECK(glbuf);
int bytes = image->requiredMemory2D(w, h, 1, image->format(), image->type());
// allocates the PBO
glbuf->setBufferData( bytes, NULL, glbuf->usage() );
// bind the pbo
VL_glBindBuffer( GL_PIXEL_PACK_BUFFER, glbuf->handle() );
// read pixels into the pbo
glReadPixels( x, y, w, h, image->format(), image->type(), 0);
// unbind the pbo
VL_glBindBuffer( GL_PIXEL_PACK_BUFFER, 0 );
// deallocates the local storage and sets up the image configuration
image->reset(w, h, 0, 1, image->format(), image->type(), false);
// test GPU -> local copy
//if (w != image->width() || h != image->height() || image->dimension() != ID_2D || image->pixels() == NULL)
// image->allocate2D( w, h, 1, image->format(), image->type() );
//glbuf->downloadBufferObject();
}
else
{
if (w != image->width() || h != image->height() || image->dimension() != ID_2D || image->pixels() == NULL)
image->allocate2D( w, h, 1, image->format(), image->type() );
glReadPixels( x, y, w, h, image->format(), image->type(), image->pixels() );
}
#if defined(VL_OPENGL)
// restore read buffer
glReadBuffer( prev );
glPopClientAttrib();
#endif
VL_CHECK_OGL()
}
//-----------------------------------------------------------------------------
// ReadPixels
//-----------------------------------------------------------------------------
/**
* A RenderEventCallback that copyes a rectangular pixel area from a source
* buffer to an Image at the end of a rendering.
*
* The actual copy is performed using the function Image::readPixels().
* Using the function setSavePath() the Image will be saved
* on the specified location.
*
* \sa
* - Image
* - Image::readPixels()
* - RenderEventCallback
*/
class ReadPixels: public RenderEventCallback
{
VL_INSTRUMENT_CLASS(vl::ReadPixels, RenderEventCallback)
public:
ReadPixels():
mX ( 0 ),
mY ( 0 ),
mWidth ( 0 ),
mHeight ( 0 ),
mReadBuffer ( RDB_BACK_LEFT ),
mStoreInPixelBufferObject(false)
{
VL_DEBUG_SET_OBJECT_NAME()
}
ReadPixels(int x, int y, int width, int height, EReadDrawBuffer read_buffer, Image* image, bool store_in_pbo):
mX ( x ),
mY ( y ),
mWidth ( width ),
mHeight ( height ),
mReadBuffer ( read_buffer ),
mImage ( image ),
mStoreInPixelBufferObject( store_in_pbo )
{
VL_DEBUG_SET_OBJECT_NAME()
}
virtual bool onRenderingStarted(const RenderingAbstract*)
{
readPixels();
return true;
}
virtual bool onRenderingFinished(const RenderingAbstract*)
{
readPixels();
return true;
}
virtual bool onRendererStarted(const RendererAbstract*)
{
readPixels();
return true;
}
virtual bool onRendererFinished(const RendererAbstract*)
{
readPixels();
return true;
}
void setup(int x, int y, int width, int height, EReadDrawBuffer read_buffer, bool store_in_pbo)
{
mX = x;
mY = y;
mWidth = width;
mHeight = height;
mReadBuffer = read_buffer;
mStoreInPixelBufferObject = store_in_pbo;
}
void setX(int x) { mX = x; }
void setY(int y) { mY = y; }
void setWidth(int width) { mWidth = width; }
void setHeight(int height) { mHeight = height; }
void setReadBuffer(EReadDrawBuffer buffer) { mReadBuffer = buffer; }
void setImage(Image* image) { mImage = image; }
void setSavePath(const String& path) { mSavePath = path; }
int x() const { return mX; }
int y() const { return mY; }
int width() const { return mWidth; }
int height() const { return mHeight; }
EReadDrawBuffer readBuffer() const { return mReadBuffer; }
Image* image() { return mImage.get(); }
const Image* image() const { return mImage.get(); }
const String& savePath() const { return mSavePath; }
void setStoreInPixelBufferObject( bool use_pbo ) { mStoreInPixelBufferObject = use_pbo; }
bool storeInPixelBufferObject() const { return mStoreInPixelBufferObject; }
protected:
void readPixels()
{
if (mImage.get() == NULL)
mImage = new Image;
vl::readPixels(mImage.get(), mX, mY, mWidth, mHeight, mReadBuffer, storeInPixelBufferObject() );
if ( savePath().length() )
{
if (!saveImage(mImage.get(), savePath()))
Log::error( Say("ReadPixels: unknown format for file: '%s'\n") << savePath() );
}
}
protected:
int mX;
int mY;
int mWidth;
int mHeight;
EReadDrawBuffer mReadBuffer;
ref<Image> mImage;
String mSavePath;
bool mStoreInPixelBufferObject;
};
}
#endif