Support for VMware video drivers
[reactos.git] / reactos / subsys / win32k / eng / xlate.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI Color Translation Functions
5 * FILE: subsys/win32k/eng/xlate.c
6 * PROGRAMER: Jason Filby
7 * REVISION HISTORY:
8 * 8/20/1999: Created
9 */
10
11 // TODO: Cache XLATEOBJs that are created by EngCreateXlate by checking if the given palettes match a cached list
12
13 #include <ddk/ntddk.h>
14 #include <ddk/winddi.h>
15 #include <ddk/ntddvid.h>
16
17 #include <include/object.h>
18 #include "handle.h"
19
20 #define NDEBUG
21 #include <win32k/debug1.h>
22
23 ULONG CCMLastSourceColor = 0, CCMLastColorMatch = 0;
24
25 ULONG RGBtoULONG(BYTE Red, BYTE Green, BYTE Blue)
26 {
27 return ((Red & 0xff) << 16) | ((Green & 0xff) << 8) | (Blue & 0xff);
28 }
29
30 ULONG BGRtoULONG(BYTE Blue, BYTE Green, BYTE Red)
31 {
32 return ((Blue & 0xff) << 16) | ((Green & 0xff) << 8) | (Red & 0xff);
33 }
34
35
36 // FIXME: If the caller knows that the destinations are indexed and not RGB
37 // then we should cache more than one value. Same with the source.
38
39 // Takes indexed palette and a
40 ULONG ClosestColorMatch(ULONG SourceColor, ULONG *DestColors,
41 ULONG NumColors)
42 {
43 PVIDEO_CLUTDATA cSourceColor;
44 PVIDEO_CLUTDATA cDestColors;
45 LONG idx = 0, i, rt;
46 ULONG cxRed, cxGreen, cxBlue, BestMatch = 16777215;
47
48 // Simple cache -- only one value because we don't want to waste time
49 // if the colors aren't very sequential
50
51 if(SourceColor == CCMLastSourceColor)
52 {
53 return CCMLastColorMatch;
54 }
55
56 cSourceColor = (PVIDEO_CLUTDATA)&SourceColor;
57 for (i=0; i<NumColors; i++)
58 {
59 cDestColors = (PVIDEO_CLUTDATA)&DestColors[i];
60
61 cxRed = (cSourceColor->Red - cDestColors->Red);
62 cxRed *= cxRed; //compute cxRed squared
63 cxGreen = (cSourceColor->Green - cDestColors->Green);
64 cxGreen *= cxGreen;
65 cxBlue = (cSourceColor->Blue - cDestColors->Blue);
66 cxBlue *= cxBlue;
67
68 rt = /* sqrt */ (cxRed + cxGreen + cxBlue);
69
70 if(rt<=BestMatch)
71 {
72 idx = i;
73 BestMatch = rt;
74 }
75 }
76
77 CCMLastSourceColor = SourceColor;
78 CCMLastColorMatch = idx;
79
80 return idx;
81 }
82
83 VOID IndexedToIndexedTranslationTable(ULONG *TranslationTable,
84 PALGDI *PalDest, PALGDI *PalSource)
85 {
86 ULONG i;
87
88 for(i=0; i<PalSource->NumColors; i++)
89 {
90 TranslationTable[i] = ClosestColorMatch(PalSource->IndexedColors[i], PalDest->IndexedColors, PalDest->NumColors);
91 }
92 }
93
94 static VOID BitMasksFromPal(USHORT PalType, PPALGDI Palette,
95 PULONG RedMask, PULONG BlueMask, PULONG GreenMask)
96 {
97 switch(PalType)
98 {
99 case PAL_RGB:
100 *RedMask = RGB(255, 0, 0);
101 *GreenMask = RGB(0, 255, 0);
102 *BlueMask = RGB(0, 0, 255);
103 break;
104 case PAL_BGR:
105 *RedMask = RGB(0, 0, 255);
106 *GreenMask = RGB(0, 255, 0);
107 *BlueMask = RGB(255, 0, 0);
108 break;
109 case PAL_BITFIELDS:
110 *RedMask = Palette->RedMask;
111 *BlueMask = Palette->BlueMask;
112 *GreenMask = Palette->GreenMask;
113 break;
114 }
115 }
116
117 /*
118 * Calculate the number of bits Mask must be shift to the left to get a
119 * 1 in the most significant bit position
120 */
121 static INT CalculateShift(ULONG Mask)
122 {
123 INT Shift = 0;
124 ULONG LeftmostBit = 1 << (8 * sizeof(ULONG) - 1);
125
126 while (0 == (Mask & LeftmostBit) && Shift < 8 * sizeof(ULONG))
127 {
128 Mask = Mask << 1;
129 Shift++;
130 }
131
132 return Shift;
133 }
134
135 static ULONG ShiftAndMask(XLATEGDI *XlateGDI, ULONG Color)
136 {
137 ULONG TranslatedColor;
138
139 TranslatedColor = 0;
140 if (XlateGDI->RedShift < 0)
141 {
142 TranslatedColor = (Color >> -(XlateGDI->RedShift)) & XlateGDI->RedMask;
143 } else
144 TranslatedColor = (Color << XlateGDI->RedShift) & XlateGDI->RedMask;
145 if (XlateGDI->GreenShift < 0)
146 {
147 TranslatedColor |= (Color >> -(XlateGDI->GreenShift)) & XlateGDI->GreenMask;
148 } else
149 TranslatedColor |= (Color << XlateGDI->GreenShift) & XlateGDI->GreenMask;
150 if (XlateGDI->BlueShift < 0)
151 {
152 TranslatedColor |= (Color >> -(XlateGDI->BlueShift)) & XlateGDI->BlueMask;
153 } else
154 TranslatedColor |= (Color << XlateGDI->BlueShift) & XlateGDI->BlueMask;
155
156 return TranslatedColor;
157 }
158
159 XLATEOBJ *EngCreateXlate(USHORT DestPalType, USHORT SourcePalType,
160 HPALETTE PaletteDest, HPALETTE PaletteSource)
161 {
162 // FIXME: Add support for BGR conversions
163
164 HPALETTE NewXlate;
165 XLATEOBJ *XlateObj;
166 XLATEGDI *XlateGDI;
167 PALGDI *SourcePalGDI, *DestPalGDI;
168 ULONG IndexedColors;
169 ULONG SourceRedMask, SourceGreenMask, SourceBlueMask;
170 ULONG DestRedMask, DestGreenMask, DestBlueMask;
171 UINT i;
172
173 NewXlate = (HPALETTE)CreateGDIHandle(sizeof( XLATEGDI ), sizeof( XLATEOBJ ));
174 if( !ValidEngHandle( NewXlate ) )
175 return NULL;
176
177 XlateObj = (XLATEOBJ*) AccessUserObject( (ULONG) NewXlate );
178 XlateGDI = (XLATEGDI*) AccessInternalObject( (ULONG) NewXlate );
179 ASSERT( XlateObj );
180 ASSERT( XlateGDI );
181
182 SourcePalGDI = (PALGDI*)AccessInternalObject((ULONG)PaletteSource);
183 DestPalGDI = (PALGDI*)AccessInternalObject((ULONG)PaletteDest);
184
185 XlateObj->iSrcType = SourcePalType;
186 XlateObj->iDstType = DestPalType;
187
188 // Store handles of palettes in internal Xlate GDI object (or NULLs)
189 XlateGDI->DestPal = PaletteDest;
190 XlateGDI->SourcePal = PaletteSource;
191
192 XlateObj->flXlate = 0;
193
194 XlateGDI->UseShiftAndMask = FALSE;
195
196 /* Compute bit fiddeling constants unless both palettes are indexed, then we don't need them */
197 if (PAL_INDEXED != SourcePalType || PAL_INDEXED != DestPalType)
198 {
199 BitMasksFromPal(PAL_INDEXED == SourcePalType ? PAL_RGB : SourcePalType,
200 SourcePalGDI, &SourceRedMask, &SourceBlueMask, &SourceGreenMask);
201 BitMasksFromPal(PAL_INDEXED == DestPalType ? PAL_RGB : DestPalType,
202 DestPalGDI, &DestRedMask, &DestBlueMask, &DestGreenMask);
203 XlateGDI->RedShift = CalculateShift(SourceRedMask) - CalculateShift(DestRedMask);
204 XlateGDI->RedMask = DestRedMask;
205 XlateGDI->GreenShift = CalculateShift(SourceGreenMask) - CalculateShift(DestGreenMask);
206 XlateGDI->GreenMask = DestGreenMask;
207 XlateGDI->BlueShift = CalculateShift(SourceBlueMask) - CalculateShift(DestBlueMask);
208 XlateGDI->BlueMask = DestBlueMask;
209 }
210
211 // If source and destination palettes are the same or if they're RGB/BGR
212 if( (PaletteDest == PaletteSource) ||
213 ((DestPalType == PAL_RGB) && (SourcePalType == PAL_RGB)) ||
214 ((DestPalType == PAL_BGR) && (SourcePalType == PAL_BGR)) )
215 {
216 XlateObj->flXlate |= XO_TRIVIAL;
217 return XlateObj;
218 }
219
220 /* If source and destination are bitfield based (RGB and BGR are just special bitfields) */
221 if ((PAL_RGB == DestPalType || PAL_BGR == DestPalType || PAL_BITFIELDS == DestPalType) &&
222 (PAL_RGB == SourcePalType || PAL_BGR == SourcePalType || PAL_BITFIELDS == SourcePalType))
223 {
224 if (SourceRedMask == DestRedMask &&
225 SourceBlueMask == DestBlueMask &&
226 SourceGreenMask == DestGreenMask)
227 {
228 XlateObj->flXlate |= XO_TRIVIAL;
229 }
230 XlateGDI->UseShiftAndMask = TRUE;
231 return XlateObj;
232 }
233
234 // Prepare the translation table
235 if( (SourcePalType == PAL_INDEXED) || (SourcePalType == PAL_RGB) )
236 {
237 XlateObj->flXlate |= XO_TABLE;
238 if ((SourcePalType == PAL_INDEXED) && (DestPalType == PAL_INDEXED))
239 {
240 if(SourcePalGDI->NumColors > DestPalGDI->NumColors)
241 {
242 IndexedColors = SourcePalGDI->NumColors;
243 } else
244 IndexedColors = DestPalGDI->NumColors;
245 }
246 else if (SourcePalType == PAL_INDEXED) { IndexedColors = SourcePalGDI->NumColors; }
247 else if (DestPalType == PAL_INDEXED) { IndexedColors = DestPalGDI->NumColors; }
248
249 XlateGDI->translationTable = EngAllocMem(FL_ZERO_MEMORY, sizeof(ULONG)*IndexedColors, 0);
250 }
251
252 // Source palette is indexed
253 if(XlateObj->iSrcType == PAL_INDEXED)
254 {
255 if(XlateObj->iDstType == PAL_INDEXED)
256 {
257 // Converting from indexed to indexed
258 IndexedToIndexedTranslationTable(XlateGDI->translationTable, DestPalGDI, SourcePalGDI);
259 } else
260 if (PAL_RGB == XlateObj->iDstType || PAL_BITFIELDS == XlateObj->iDstType )
261 {
262 // FIXME: Is this necessary? I think the driver has to call this
263 // function anyways if pulXlate is NULL and Source is PAL_INDEXED
264
265 // Converting from indexed to RGB
266
267 XLATEOBJ_cGetPalette(XlateObj, XO_SRCPALETTE,
268 SourcePalGDI->NumColors,
269 XlateGDI->translationTable);
270 if (PAL_BITFIELDS == XlateObj->iDstType)
271 {
272 for (i = 0; i < SourcePalGDI->NumColors; i++)
273 {
274 XlateGDI->translationTable[i] = ShiftAndMask(XlateGDI, XlateGDI->translationTable[i]);
275 }
276 }
277 }
278
279 XlateObj->pulXlate = XlateGDI->translationTable;
280 }
281
282 // Source palette is RGB
283 if(XlateObj->iSrcType == PAL_RGB)
284 {
285 if(XlateObj->iDstType == PAL_INDEXED)
286 {
287 // FIXME: Is this necessary? I think the driver has to call this
288 // function anyways if pulXlate is NULL and Dest is PAL_INDEXED
289
290 // Converting from RGB to indexed
291 XLATEOBJ_cGetPalette(XlateObj, XO_DESTPALETTE, DestPalGDI->NumColors, XlateGDI->translationTable);
292 }
293 }
294
295 // FIXME: Add support for XO_TO_MONO
296 return XlateObj;
297 }
298
299 VOID EngDeleteXlate(XLATEOBJ *XlateObj)
300 {
301 HPALETTE HXlate = (HPALETTE)AccessHandleFromUserObject(XlateObj);
302 XLATEGDI *XlateGDI = (XLATEGDI*)AccessInternalObject((ULONG)HXlate);
303
304 if(XlateGDI->translationTable!=NULL)
305 {
306 EngFreeMem(XlateGDI->translationTable);
307 }
308
309 FreeGDIHandle((ULONG)HXlate);
310 }
311
312 ULONG * STDCALL
313 XLATEOBJ_piVector(XLATEOBJ *XlateObj)
314 {
315 XLATEGDI *XlateGDI = (XLATEGDI*)AccessInternalObjectFromUserObject(XlateObj);
316
317 if(XlateObj->iSrcType == PAL_INDEXED)
318 {
319 return XlateGDI->translationTable;
320 }
321
322 return NULL;
323 }
324
325 ULONG STDCALL
326 XLATEOBJ_iXlate(XLATEOBJ *XlateObj,
327 ULONG Color)
328 {
329 PALGDI *PalGDI;
330 XLATEGDI *XlateGDI = (XLATEGDI*)AccessInternalObjectFromUserObject(XlateObj);
331
332 // Return the original color if there's no color translation object
333 if(!XlateObj) return Color;
334
335 if(XlateObj->flXlate & XO_TRIVIAL)
336 {
337 return Color;
338 } else
339 if(XlateGDI->UseShiftAndMask)
340 {
341 return ShiftAndMask(XlateGDI, Color);
342 } else
343 if(XlateObj->iSrcType == PAL_RGB)
344 {
345 // FIXME: should we cache colors used often?
346 // FIXME: won't work if destination isn't indexed
347
348 // Extract the destination palette
349 PalGDI = (PALGDI*)AccessInternalObject((ULONG)XlateGDI->DestPal);
350
351 // Return closest match for the given RGB color
352 return ClosestColorMatch(Color, PalGDI->IndexedColors, PalGDI->NumColors);
353 } else
354 if(XlateObj->iSrcType == PAL_INDEXED)
355 {
356 return XlateGDI->translationTable[Color];
357 }
358
359 return 0;
360 }
361
362 ULONG STDCALL
363 XLATEOBJ_cGetPalette(XLATEOBJ *XlateObj,
364 ULONG PalOutType,
365 ULONG cPal,
366 ULONG *OutPal)
367 {
368 ULONG i;
369 HPALETTE HPal;
370 XLATEGDI *XlateGDI;
371 PALGDI *PalGDI;
372
373 XlateGDI = (XLATEGDI*)AccessInternalObjectFromUserObject(XlateObj);
374
375 if(PalOutType == XO_SRCPALETTE)
376 {
377 HPal = XlateGDI->SourcePal;
378 } else
379 if(PalOutType == XO_DESTPALETTE)
380 {
381 HPal = XlateGDI->DestPal;
382 }
383
384 PalGDI = (PALGDI*)AccessInternalObject((ULONG)HPal);
385 RtlCopyMemory(OutPal, PalGDI->IndexedColors, sizeof(ULONG)*cPal);
386
387 return i;
388 }