234 lines
7.4 KiB
C++
234 lines
7.4 KiB
C++
#ifndef __DW_IMGBUF_HH__
|
|
#define __DW_IMGBUF_HH__
|
|
|
|
#ifndef __INCLUDED_FROM_DW_CORE_HH__
|
|
# error Do not include this file directly, use "core.hh" instead.
|
|
#endif
|
|
|
|
#include "../lout/debug.hh"
|
|
|
|
namespace dw {
|
|
namespace core {
|
|
|
|
/**
|
|
* \brief The platform independent interface for image buffers.
|
|
*
|
|
* %Image buffers depend on the platform (see \ref dw-images-and-backgrounds),
|
|
* but have this general, platform independent interface. The purpose of
|
|
* an image buffer is
|
|
*
|
|
* <ol>
|
|
* <li> storing the image data,
|
|
* <li> handling scaled versions of this buffer, and
|
|
* <li> drawing.
|
|
* </ol>
|
|
*
|
|
* The latter must be done independently from the window.
|
|
*
|
|
* <h3>Creating</h3>
|
|
*
|
|
* %Image buffers are created by calling dw::core::Platform::createImgbuf.
|
|
*
|
|
* <h3>Storing %Image Data</h3>
|
|
*
|
|
* dw::core::Imgbuf supports five image types, which are listed in the table
|
|
* below. The representation defines, how the colors are stored within
|
|
* the data, which is passed to dw::core::Imgbuf::copyRow.
|
|
*
|
|
* <table>
|
|
* <tr><th>Type (dw::core::Imgbuf::Type) <th>Bytes per
|
|
* Pixel <th>Representation
|
|
* <tr><td>dw::core::Imgbuf::RGB <td>3 <td>red, green, blue
|
|
* <tr><td>dw::core::Imgbuf::RGBA <td>4 <td>red, green, blue, alpha
|
|
* <tr><td>dw::core::Imgbuf::GRAY <td>1 <td>gray value
|
|
* <tr><td>dw::core::Imgbuf::INDEXED <td>1 <td>index to colormap
|
|
* <tr><td>dw::core::Imgbuf::INDEXED_ALPHA <td>1 <td>index to colormap
|
|
* </table>
|
|
*
|
|
* The last two types need a colormap, which is set by
|
|
* dw::core::Imgbuf::setCMap, which must be called before
|
|
* dw::core::Imgbuf::copyRow. This function expects the colors as 32 bit
|
|
* unsigned integers, which have the format 0xrrbbgg (for indexed
|
|
* images), or 0xaarrggbb (for indexed alpha), respectively.
|
|
*
|
|
*
|
|
* <h3>Scaling</h3>
|
|
*
|
|
* The buffer with the original size, which was created by
|
|
* dw::core::Platform::createImgbuf, is called root buffer. Imgbuf provides
|
|
* the ability to scale buffers. Generally, both root buffers, as well as
|
|
* scaled buffers, may be shared, memory management is done by reference
|
|
* counters.
|
|
*
|
|
* Via dw::core::Imgbuf::getScaledBuf, you can retrieve a scaled buffer.
|
|
* Generally, something like this must work always, in an efficient way:
|
|
*
|
|
* \code
|
|
* dw::core::Imgbuf *curBuf, *oldBuf;
|
|
* int width, height,
|
|
* // ...
|
|
* oldBuf = curBuf;
|
|
* curBuf = oldBuf->getScaledBuf(oldBuf, width, height);
|
|
* oldBuf->unref();
|
|
* \endcode
|
|
*
|
|
* \em oldBuf may both be a root buffer, or a scaled buffer.
|
|
*
|
|
* The root buffer keeps a list of all children, and all methods
|
|
* operating on the image data (dw::core::Imgbuf::copyRow and
|
|
* dw::core::Imgbuf::setCMap) are delegated to the scaled buffers, when
|
|
* processed, and inherited, when a new scaled buffer is created. This
|
|
* means, that they must only be performed for the root buffer.
|
|
*
|
|
* A possible implementation could be (dw::fltk::FltkImgbuf does it this way):
|
|
*
|
|
* <ul>
|
|
* <li> If the method is called with an already scaled image buffer, this is
|
|
* delegated to the root buffer.
|
|
*
|
|
* <li> If the given size is the original size, the root buffer is
|
|
* returned, with an increased reference counter.
|
|
*
|
|
* <li> Otherwise, if this buffer has already been scaled to the given
|
|
* size, return this scaled buffer, with an increased reference
|
|
* counter.
|
|
*
|
|
* <li> Otherwise, return a new scaled buffer with reference counter 1.
|
|
* </ul>
|
|
*
|
|
* Special care is to be taken, when the root buffer is not used anymore,
|
|
* i.e. after dw::core::Imgbuf::unref the reference counter is 0, but there
|
|
* are still scaled buffers. Since all methods operating on the image data
|
|
* (dw::core::Imgbuf::copyRow and dw::core::Imgbuf::setCMap) are called for
|
|
* the root buffer, the root buffer is still needed, and so must not be
|
|
* deleted at this point. This is, how dw::fltk::FltkImgbuf solves this
|
|
* problem:
|
|
*
|
|
* <ul>
|
|
* <li> dw::fltk::FltkImgbuf::unref does, for root buffers, check, not only
|
|
* whether dw::fltk::FltkImgbuf::refCount is 0, but also, whether
|
|
* there are children left. When the latter is the case, the buffer
|
|
* is not deleted.
|
|
*
|
|
* <li> There is an additional check in dw::fltk::FltkImgbuf::detachScaledBuf,
|
|
* which deals with the case, that dw::fltk::FltkImgbuf::refCount is 0,
|
|
* and the last scaled buffer is removed.
|
|
* </ul>
|
|
*
|
|
* In the following example:
|
|
*
|
|
* \code
|
|
* dw::fltk::FltkPlatform *platform = new dw::fltk::FltkPlatform ();
|
|
* dw::core::Layout *layout = new dw::core::Layout (platform);
|
|
*
|
|
* dw::core::Imgbuf *rootbuf =
|
|
* layout->createImgbuf (dw::core::Imgbuf::RGB, 100, 100);
|
|
* dw::core::Imgbuf *scaledbuf = rootbuf->getScaledBuf (50, 50);
|
|
* rootbuf->unref ();
|
|
* scaledbuf->unref ();
|
|
* \endcode
|
|
*
|
|
* the root buffer is not deleted, when dw::core::Imgbuf::unref is called,
|
|
* since a scaled buffer is left. After calling dw::core::Imgbuf::unref for
|
|
* the scaled buffer, it is deleted, and after it, the root buffer.
|
|
*
|
|
* <h3>Drawing</h3>
|
|
*
|
|
* dw::core::Imgbuf provides no methods for drawing, instead, this is
|
|
* done by the views (implementation of dw::core::View).
|
|
*
|
|
* There are two situations, when drawing is necessary:
|
|
*
|
|
* <ol>
|
|
* <li> To react on expose events, the function dw::core::View::drawImage
|
|
* should be used, with the following parameters:
|
|
* <ul>
|
|
* <li> of course, the image buffer,
|
|
* <li> where the root of the image would be displayed (as \em xRoot
|
|
* and \em yRoot), and
|
|
* <li> the region within the image, which should be displayed (\em x,
|
|
* \em y, \em width, \em height).
|
|
* </ul>
|
|
*
|
|
* <li> When a row has been copied, it has to be drawn. To determine the
|
|
* area, which has to be drawn, the dw::core::Imgbuf::getRowArea
|
|
* should be used. The result can then passed
|
|
* to dw::core::View::drawImage.
|
|
* </ol>
|
|
*
|
|
* \sa \ref dw-images-and-backgrounds
|
|
*/
|
|
class Imgbuf: public lout::object::Object, public lout::signal::ObservedObject
|
|
{
|
|
public:
|
|
enum Type { RGB, RGBA, GRAY, INDEXED, INDEXED_ALPHA };
|
|
|
|
inline Imgbuf () {
|
|
DBG_OBJ_CREATE ("dw::core::Imgbuf");
|
|
DBG_OBJ_BASECLASS (lout::object::Object);
|
|
DBG_OBJ_BASECLASS (lout::signal::ObservedObject);
|
|
}
|
|
|
|
inline ~Imgbuf () {
|
|
DBG_OBJ_DELETE ();
|
|
}
|
|
|
|
/*
|
|
* Methods called from the image decoding
|
|
*/
|
|
|
|
virtual void setCMap (int *colors, int num_colors) = 0;
|
|
virtual void copyRow (int row, const byte *data) = 0;
|
|
virtual void newScan () = 0;
|
|
|
|
/*
|
|
* Methods called from dw::Image
|
|
*/
|
|
|
|
virtual Imgbuf* getScaledBuf (int width, int height) = 0;
|
|
virtual void getRowArea (int row, dw::core::Rectangle *area) = 0;
|
|
virtual int getRootWidth () = 0;
|
|
virtual int getRootHeight () = 0;
|
|
|
|
|
|
/**
|
|
* Creates an image buffer with same parameters (type, gamma etc.)
|
|
* except size.
|
|
*/
|
|
virtual Imgbuf *createSimilarBuf (int width, int height) = 0;
|
|
|
|
/**
|
|
* Copies another image buffer into this image buffer.
|
|
*/
|
|
virtual void copyTo (Imgbuf *dest, int xDestRoot, int yDestRoot,
|
|
int xSrc, int ySrc, int widthSrc, int heightSrc) = 0;
|
|
|
|
/*
|
|
* Reference counting.
|
|
*/
|
|
|
|
virtual void ref () = 0;
|
|
virtual void unref () = 0;
|
|
|
|
/**
|
|
* \todo Comment
|
|
*/
|
|
virtual bool lastReference () = 0;
|
|
|
|
|
|
/**
|
|
* \todo Comment
|
|
*/
|
|
virtual void setDeleteOnUnref (bool deleteOnUnref) = 0;
|
|
|
|
/**
|
|
* \todo Comment
|
|
*/
|
|
virtual bool isReferred () = 0;
|
|
};
|
|
|
|
} // namespace core
|
|
} // namespace dw
|
|
|
|
#endif // __DW_IMGBUF_HH__
|