blob: 4c57d1b03e26e151e16800141b1cd6faec50b42a [file] [log] [blame]
Pierre Ossmana2739342011-03-08 16:53:07 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 * Copyright 2011 Pierre Ossman <ossman@cendio.se> for Cendio AB
3 *
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <rfb/PixelFormat.h>
23#include <rfb/Exception.h>
24#include <rfb/ColourMap.h>
25#include <rfb/TrueColourMap.h>
26#include <rfb/PixelBuffer.h>
27#include <rfb/ColourCube.h>
28#include <rfb/PixelTransformer.h>
29
30using namespace rfb;
31
32static void noTransFn(void* table_,
33 const PixelFormat& inPF, void* inPtr, int inStride,
34 const PixelFormat& outPF, void* outPtr, int outStride,
35 int width, int height)
36{
37 rdr::U8* ip = (rdr::U8*)inPtr;
38 rdr::U8* op = (rdr::U8*)outPtr;
39 int inStrideBytes = inStride * (inPF.bpp/8);
40 int outStrideBytes = outStride * (outPF.bpp/8);
41 int widthBytes = width * (outPF.bpp/8);
42
43 while (height > 0) {
44 memcpy(op, ip, widthBytes);
45 ip += inStrideBytes;
46 op += outStrideBytes;
47 height--;
48 }
49}
50
51#define BPPOUT 8
52#include "transInitTempl.h"
53#define BPPIN 8
54#include "transTempl.h"
55#undef BPPIN
56#define BPPIN 16
57#include "transTempl.h"
58#undef BPPIN
59#define BPPIN 32
60#include "transTempl.h"
61#undef BPPIN
62#undef BPPOUT
63
64#define BPPOUT 16
65#include "transInitTempl.h"
66#define BPPIN 8
67#include "transTempl.h"
68#undef BPPIN
69#define BPPIN 16
70#include "transTempl.h"
71#undef BPPIN
72#define BPPIN 32
73#include "transTempl.h"
74#undef BPPIN
75#undef BPPOUT
76
77#define BPPOUT 32
78#include "transInitTempl.h"
79#define BPPIN 8
80#include "transTempl.h"
81#undef BPPIN
82#define BPPIN 16
83#include "transTempl.h"
84#undef BPPIN
85#define BPPIN 32
86#include "transTempl.h"
87#undef BPPIN
88#undef BPPOUT
89
90
91// Translation functions. Note that transSimple* is only used for 8/16bpp and
92// transRGB* is used for 16/32bpp
93
94static transFnType transSimpleFns[][3] = {
95 { transSimple8to8, transSimple8to16, transSimple8to32 },
96 { transSimple16to8, transSimple16to16, transSimple16to32 },
97};
98static transFnType transRGBFns[][3] = {
99 { transRGB16to8, transRGB16to16, transRGB16to32 },
100 { transRGB32to8, transRGB32to16, transRGB32to32 }
101};
102static transFnType transRGBCubeFns[][3] = {
103 { transRGBCube16to8, transRGBCube16to16, transRGBCube16to32 },
104 { transRGBCube32to8, transRGBCube32to16, transRGBCube32to32 }
105};
106
107// Table initialisation functions.
108
109typedef void (*initCMtoTCFnType)(rdr::U8** tablep, const PixelFormat& inPF,
110 ColourMap* cm, const PixelFormat& outPF);
111typedef void (*initTCtoTCFnType)(rdr::U8** tablep, const PixelFormat& inPF,
112 const PixelFormat& outPF);
113typedef void (*initCMtoCubeFnType)(rdr::U8** tablep, const PixelFormat& inPF,
114 ColourMap* cm, ColourCube* cube);
115typedef void (*initTCtoCubeFnType)(rdr::U8** tablep, const PixelFormat& inPF,
116 ColourCube* cube);
117
118
119static initCMtoTCFnType initSimpleCMtoTCFns[] = {
120 initSimpleCMtoTC8, initSimpleCMtoTC16, initSimpleCMtoTC32
121};
122
123static initTCtoTCFnType initSimpleTCtoTCFns[] = {
124 initSimpleTCtoTC8, initSimpleTCtoTC16, initSimpleTCtoTC32
125};
126
127static initCMtoCubeFnType initSimpleCMtoCubeFns[] = {
128 initSimpleCMtoCube8, initSimpleCMtoCube16, initSimpleCMtoCube32
129};
130
131static initTCtoCubeFnType initSimpleTCtoCubeFns[] = {
132 initSimpleTCtoCube8, initSimpleTCtoCube16, initSimpleTCtoCube32
133};
134
135static initTCtoTCFnType initRGBTCtoTCFns[] = {
136 initRGBTCtoTC8, initRGBTCtoTC16, initRGBTCtoTC32
137};
138
139static initTCtoCubeFnType initRGBTCtoCubeFns[] = {
140 initRGBTCtoCube8, initRGBTCtoCube16, initRGBTCtoCube32
141};
142
143
144PixelTransformer::PixelTransformer(bool econ)
145 : economic(econ), cmCallback(0), table(0), transFn(0), cube(0)
146{
147}
148
149PixelTransformer::~PixelTransformer()
150{
151 delete [] table;
152}
153
154void PixelTransformer::init(const PixelFormat& inPF_, ColourMap* inCM_,
155 const PixelFormat& outPF_, ColourCube* cube_,
156 setCMFnType cmCallback_, void *cbData_)
157{
158 inPF = inPF_;
159 inCM = inCM_;
160
161 outPF = outPF_;
162 cube = cube_;
163 cmCallback = cmCallback_;
164 cbData = cbData_;
165
166 if (table)
167 delete [] table;
168 table = NULL;
169 transFn = NULL;
170
171 if ((inPF.bpp != 8) && (inPF.bpp != 16) && (inPF.bpp != 32))
172 throw Exception("PixelTransformer: bpp in not 8, 16 or 32");
173
174 if ((outPF.bpp != 8) && (outPF.bpp != 16) && (outPF.bpp != 32))
175 throw Exception("PixelTransformer: bpp out not 8, 16 or 32");
176
177 if (!outPF.trueColour) {
178 if (outPF.bpp != 8)
179 throw Exception("PixelTransformer: outPF has color map but not 8bpp");
180
181 if (!inPF.trueColour) {
182 if (inPF.bpp != 8)
183 throw Exception("PixelTransformer: inPF has colorMap but not 8bpp");
184 if (!inCM)
185 throw Exception("PixelTransformer: inPF has colorMap but no colour map specified");
186
187 // CM to CM/Cube
188
189 if (cube) {
190 transFn = transSimpleFns[0][0];
191 (*initSimpleCMtoCubeFns[0]) (&table, inPF, inCM, cube);
192 } else {
193 transFn = noTransFn;
194 setColourMapEntries(0, 256);
195 }
196 return;
197 }
198
199 // TC to CM/Cube
200
201 ColourCube defaultCube(6,6,6);
202 if (!cube) cube = &defaultCube;
203
204 if ((inPF.bpp > 16) || (economic && (inPF.bpp == 16))) {
205 transFn = transRGBCubeFns[inPF.bpp/32][0];
206 (*initRGBTCtoCubeFns[0]) (&table, inPF, cube);
207 } else {
208 transFn = transSimpleFns[inPF.bpp/16][0];
209 (*initSimpleTCtoCubeFns[0]) (&table, inPF, cube);
210 }
211
212 if (cube != &defaultCube)
213 return;
214
215 if (!cmCallback)
216 throw Exception("PixelTransformer: Neither colour map callback nor colour cube provided");
217
218 cmCallback(0, 216, cube, cbData);
219 cube = 0;
220 return;
221 }
222
223 if (inPF.equal(outPF)) {
224 transFn = noTransFn;
225 return;
226 }
227
228 if (!inPF.trueColour) {
229
230 // CM to TC
231
232 if (inPF.bpp != 8)
233 throw Exception("PixelTransformer: inPF has colorMap but not 8bpp");
234 if (!inCM)
235 throw Exception("PixelTransformer: inPF has colorMap but no colour map specified");
236
237 transFn = transSimpleFns[0][outPF.bpp/16];
238 (*initSimpleCMtoTCFns[outPF.bpp/16]) (&table, inPF, inCM, outPF);
239 return;
240 }
241
242 // TC to TC
243
244 if ((inPF.bpp > 16) || (economic && (inPF.bpp == 16))) {
245 transFn = transRGBFns[inPF.bpp/32][outPF.bpp/16];
246 (*initRGBTCtoTCFns[outPF.bpp/16]) (&table, inPF, outPF);
247 } else {
248 transFn = transSimpleFns[inPF.bpp/16][outPF.bpp/16];
249 (*initSimpleTCtoTCFns[outPF.bpp/16]) (&table, inPF, outPF);
250 }
251}
252
253void PixelTransformer::setColourMapEntries(int firstCol, int nCols)
254{
255 if (nCols == 0)
256 nCols = (1 << inPF.depth) - firstCol;
257
258 if (inPF.trueColour) return; // shouldn't be called in this case
259
260 if (outPF.trueColour) {
261 (*initSimpleCMtoTCFns[outPF.bpp/16]) (&table, inPF, inCM, outPF);
262 } else if (cube) {
263 (*initSimpleCMtoCubeFns[outPF.bpp/16]) (&table, inPF, inCM, cube);
264 } else {
265 if (!cmCallback)
266 throw Exception("PixelTransformer: Neither colour map callback nor colour cube provided");
267 cmCallback(firstCol, nCols, inCM, cbData);
268 }
269}
270
271void PixelTransformer::translatePixels(void* inPtr, void* outPtr,
272 int nPixels) const
273{
274 if (!transFn)
275 throw Exception("PixelTransformer: not initialised yet");
276
277 (*transFn)(table, inPF, inPtr, nPixels,
278 outPF, outPtr, nPixels, nPixels, 1);
279}
280
281void PixelTransformer::translateRect(void* inPtr, int inStride,
282 Rect inRect,
283 void* outPtr, int outStride,
284 Point outCoord) const
285{
286 char *in, *out;
287
288 if (!transFn)
289 throw Exception("PixelTransformer: not initialised yet");
290
291 in = (char*)inPtr;
292 in += inPF.bpp/8 * inRect.tl.x;
293 in += (inStride * inPF.bpp/8) * inRect.tl.y;
294
295 out = (char*)outPtr;
296 out += outPF.bpp/8 * outCoord.x;
297 out += (outStride * outPF.bpp/8) * outCoord.y;
298
299 (*transFn)(table, inPF, in, inStride,
300 outPF, out, outStride,
301 inRect.width(), inRect.height());
302}