aboutsummaryrefslogtreecommitdiff
path: root/dw/imgbuf.hh
blob: d6f41d21542bcb9b116310893cd32de0a314253e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#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

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, heigt,
 * // ...
 * 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 };

   /*
    * 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;

   /*
    * 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 dw
} // namespace core

#endif // __DW_IMGBUF_HH__