blob: d093426f9e860fe0ebb0eee57cf74cfc1747b00c [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19// -=- PixelBuffer.cxx
20//
21// The PixelBuffer class encapsulates the PixelFormat and dimensions
22// of a block of pixel data.
23
24#include <rfb/Exception.h>
25#include <rfb/LogWriter.h>
26#include <rfb/PixelBuffer.h>
27
28using namespace rfb;
29using namespace rdr;
30
31static LogWriter vlog("PixelBuffer");
32
33
34// -=- Generic pixel buffer class
35
36PixelBuffer::PixelBuffer(const PixelFormat& pf, int w, int h, ColourMap* cm)
37 : format(pf), width_(w), height_(h), colourmap(cm) {}
38PixelBuffer::PixelBuffer() : width_(0), height_(0), colourmap(0) {}
39
40PixelBuffer::~PixelBuffer() {}
41
42
43void PixelBuffer::setPF(const PixelFormat &pf) {format = pf;}
44const PixelFormat& PixelBuffer::getPF() const {return format;}
45ColourMap* PixelBuffer::getColourMap() const {return colourmap;}
46
47
48void
49PixelBuffer::getImage(void* imageBuf, const Rect& r, int outStride) {
50 int inStride;
51 const U8* data = getPixelsR(r, &inStride);
52 // We assume that the specified rectangle is pre-clipped to the buffer
53 int bytesPerPixel = format.bpp/8;
54 int inBytesPerRow = inStride * bytesPerPixel;
55 if (!outStride) outStride = r.width();
56 int outBytesPerRow = outStride * bytesPerPixel;
57 int bytesPerMemCpy = r.width() * bytesPerPixel;
58 U8* imageBufPos = (U8*)imageBuf;
59 const U8* end = data + (inBytesPerRow * r.height());
60 while (data < end) {
61 memcpy(imageBufPos, data, bytesPerMemCpy);
62 imageBufPos += outBytesPerRow;
63 data += inBytesPerRow;
64 }
65}
66
67/* ***
68Pixel PixelBuffer::getPixel(const Point& p) {
69 int stride;
70 Rect r = Rect(p.x, p.y, p.x+1, p.y+1);
71 switch(format.bpp) {
72 case 8: return *((rdr::U8*)getDataAt(r, &stride));
73 case 16: return *((rdr::U16*)getDataAt(r, &stride));
74 case 32: return *((rdr::U32*)getDataAt(r, &stride));
75 default: return 0;
76 };
77}
78*/
79
80
81FullFramePixelBuffer::FullFramePixelBuffer(const PixelFormat& pf, int w, int h,
82 rdr::U8* data_, ColourMap* cm)
83 : PixelBuffer(pf, w, h, cm), data(data_)
84{
85}
86
87FullFramePixelBuffer::FullFramePixelBuffer() : data(0) {}
88
89FullFramePixelBuffer::~FullFramePixelBuffer() {}
90
91
92int FullFramePixelBuffer::getStride() const { return width(); }
93
94rdr::U8* FullFramePixelBuffer::getPixelsRW(const Rect& r, int* stride)
95{
96 *stride = getStride();
97 return &data[(r.tl.x + (r.tl.y * *stride)) * format.bpp/8];
98}
99
100
101void FullFramePixelBuffer::fillRect(const Rect& r, Pixel pix) {
102 int stride;
103 U8* data = getPixelsRW(r, &stride);
104 int bytesPerPixel = getPF().bpp/8;
105 int bytesPerRow = bytesPerPixel * stride;
106 int bytesPerFill = bytesPerPixel * r.width();
107
108 U8* end = data + (bytesPerRow * r.height());
109 while (data < end) {
110 switch (bytesPerPixel) {
111 case 1:
112 memset(data, pix, bytesPerFill);
113 break;
114 case 2:
115 {
116 U16* optr = (U16*)data;
117 U16* eol = optr + r.width();
118 while (optr < eol)
119 *optr++ = pix;
120 }
121 break;
122 case 4:
123 {
124 U32* optr = (U32*)data;
125 U32* eol = optr + r.width();
126 while (optr < eol)
127 *optr++ = pix;
128 }
129 break;
130 }
131 data += bytesPerRow;
132 }
133}
134
135void FullFramePixelBuffer::imageRect(const Rect& r, const void* pixels, int srcStride) {
136 int bytesPerPixel = getPF().bpp/8;
137 int destStride;
138 U8* dest = getPixelsRW(r, &destStride);
139 int bytesPerDestRow = bytesPerPixel * destStride;
140 if (!srcStride) srcStride = r.width();
141 int bytesPerSrcRow = bytesPerPixel * srcStride;
142 int bytesPerFill = bytesPerPixel * r.width();
143 const U8* src = (const U8*)pixels;
144 U8* end = dest + (bytesPerDestRow * r.height());
145 while (dest < end) {
146 memcpy(dest, src, bytesPerFill);
147 dest += bytesPerDestRow;
148 src += bytesPerSrcRow;
149 }
150}
151
152void FullFramePixelBuffer::maskRect(const Rect& r, const void* pixels, const void* mask_) {
153 Rect cr = getRect().intersect(r);
154 if (cr.is_empty()) return;
155 int stride;
156 U8* data = getPixelsRW(cr, &stride);
157 U8* mask = (U8*) mask_;
158 int w = cr.width();
159 int h = cr.height();
160 int bpp = getPF().bpp;
161 int pixelStride = r.width();
162 int maskStride = (r.width() + 7) / 8;
163
164 Point offset = Point(cr.tl.x-r.tl.x, cr.tl.y-r.tl.y);
165 mask += offset.y * maskStride;
166 for (int y = 0; y < h; y++) {
167 int cy = offset.y + y;
168 for (int x = 0; x < w; x++) {
169 int cx = offset.x + x;
170 U8* byte = mask + (cx / 8);
171 int bit = 7 - cx % 8;
172 if ((*byte) & (1 << bit)) {
173 switch (bpp) {
174 case 8:
175 ((U8*)data)[y * stride + x] = ((U8*)pixels)[cy * pixelStride + cx];
176 break;
177 case 16:
178 ((U16*)data)[y * stride + x] = ((U16*)pixels)[cy * pixelStride + cx];
179 break;
180 case 32:
181 ((U32*)data)[y * stride + x] = ((U32*)pixels)[cy * pixelStride + cx];
182 break;
183 }
184 }
185 }
186 mask += maskStride;
187 }
188}
189
190void FullFramePixelBuffer::maskRect(const Rect& r, Pixel pixel, const void* mask_) {
191 Rect cr = getRect().intersect(r);
192 if (cr.is_empty()) return;
193 int stride;
194 U8* data = getPixelsRW(cr, &stride);
195 U8* mask = (U8*) mask_;
196 int w = cr.width();
197 int h = cr.height();
198 int bpp = getPF().bpp;
199 int maskStride = (r.width() + 7) / 8;
200
201 Point offset = Point(cr.tl.x-r.tl.x, cr.tl.y-r.tl.y);
202 mask += offset.y * maskStride;
203 for (int y = 0; y < h; y++) {
204 for (int x = 0; x < w; x++) {
205 int cx = offset.x + x;
206 U8* byte = mask + (cx / 8);
207 int bit = 7 - cx % 8;
208 if ((*byte) & (1 << bit)) {
209 switch (bpp) {
210 case 8:
211 ((U8*)data)[y * stride + x] = pixel;
212 break;
213 case 16:
214 ((U16*)data)[y * stride + x] = pixel;
215 break;
216 case 32:
217 ((U32*)data)[y * stride + x] = pixel;
218 break;
219 }
220 }
221 }
222 mask += maskStride;
223 }
224}
225
226void FullFramePixelBuffer::copyRect(const Rect &rect, const Point &move_by_delta) {
227 int stride;
228 U8* data = getPixelsRW(getRect(), &stride);
229 // We assume that the specified rectangle is pre-clipped to the buffer
230 unsigned int bytesPerPixel, bytesPerRow, bytesPerMemCpy;
231 Rect srect = rect.translate(move_by_delta.negate());
232 bytesPerPixel = getPF().bpp/8;
233 bytesPerRow = stride * bytesPerPixel;
234 bytesPerMemCpy = rect.width() * bytesPerPixel;
235 if (move_by_delta.y <= 0) {
236 U8* dest = data + rect.tl.x*bytesPerPixel + rect.tl.y*bytesPerRow;
237 U8* src = data + srect.tl.x*bytesPerPixel + srect.tl.y*bytesPerRow;
238 for (int i=rect.tl.y; i<rect.br.y; i++) {
239 memmove(dest, src, bytesPerMemCpy);
240 dest += bytesPerRow;
241 src += bytesPerRow;
242 }
243 } else {
244 U8* dest = data + rect.tl.x*bytesPerPixel + (rect.br.y-1)*bytesPerRow;
245 U8* src = data + srect.tl.x*bytesPerPixel + (srect.br.y-1)*bytesPerRow;
246 for (int i=rect.tl.y; i<rect.br.y; i++) {
247 memmove(dest, src, bytesPerMemCpy);
248 dest -= bytesPerRow;
249 src -= bytesPerRow;
250 }
251 }
252}
253
254
255// -=- Managed pixel buffer class
256// Automatically allocates enough space for the specified format & area
257
258ManagedPixelBuffer::ManagedPixelBuffer()
259 : datasize(0), own_colourmap(false)
260{
261 checkDataSize();
262};
263
264ManagedPixelBuffer::ManagedPixelBuffer(const PixelFormat& pf, int w, int h)
265 : FullFramePixelBuffer(pf, w, h, 0, 0), datasize(0), own_colourmap(false)
266{
267 checkDataSize();
268};
269
270ManagedPixelBuffer::~ManagedPixelBuffer() {
271 if (data) delete [] data;
272 if (colourmap && own_colourmap) delete colourmap;
273};
274
275
276void
277ManagedPixelBuffer::setPF(const PixelFormat &pf) {
278 format = pf; checkDataSize();
279};
280void
281ManagedPixelBuffer::setSize(int w, int h) {
282 width_ = w; height_ = h; checkDataSize();
283};
284
285
286void
287ManagedPixelBuffer::setColourMap(ColourMap* cm, bool own_cm) {
288 if (colourmap && own_colourmap) delete colourmap;
289 colourmap = cm;
290 own_colourmap = own_cm;
291}
292
293inline void
294ManagedPixelBuffer::checkDataSize() {
295 unsigned long new_datasize = width_ * height_ * (format.bpp/8);
296 if (datasize < new_datasize) {
297 vlog.debug("reallocating managed buffer (%dx%d)", width_, height_);
298 if (data) {
299 delete [] data;
300 datasize = 0; data = 0;
301 }
302 if (new_datasize) {
303 data = new U8[new_datasize];
304 if (!data)
305 throw Exception("rfb::ManagedPixelBuffer unable to allocate buffer");
306 datasize = new_datasize;
307 }
308 }
309};