Stretchblitting 8->8 bpp implemented
[reactos.git] / reactos / subsys / win32k / dib / dib16bpp.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: dib16bpp.c,v 1.15 2003/12/18 18:30:48 fireball Exp $ */
20 #undef WIN32_LEAN_AND_MEAN
21 #include <windows.h>
22 #include <stdlib.h>
23 #include <math.h>
24 #include <win32k/bitmaps.h>
25 #include <win32k/debug.h>
26 #include <debug.h>
27 #include <ddk/winddi.h>
28 #include "../eng/objects.h"
29 #include "dib.h"
30
31 VOID
32 DIB_16BPP_PutPixel(PSURFOBJ SurfObj, LONG x, LONG y, ULONG c)
33 {
34 PBYTE byteaddr = SurfObj->pvScan0 + y * SurfObj->lDelta;
35 PWORD addr = (PWORD)byteaddr + x;
36
37 *addr = (WORD)c;
38 }
39
40 ULONG
41 DIB_16BPP_GetPixel(PSURFOBJ SurfObj, LONG x, LONG y)
42 {
43 PBYTE byteaddr = SurfObj->pvScan0 + y * SurfObj->lDelta;
44 PWORD addr = (PWORD)byteaddr + x;
45
46 return (ULONG)(*addr);
47 }
48
49 VOID
50 DIB_16BPP_HLine(PSURFOBJ SurfObj, LONG x1, LONG x2, LONG y, ULONG c)
51 {
52 PBYTE byteaddr = SurfObj->pvScan0 + y * SurfObj->lDelta;
53 PWORD addr = (PWORD)byteaddr + x1;
54 LONG cx = x1;
55
56 while(cx < x2) {
57 *addr = (WORD)c;
58 ++addr;
59 ++cx;
60 }
61 }
62
63 VOID
64 DIB_16BPP_VLine(PSURFOBJ SurfObj, LONG x, LONG y1, LONG y2, ULONG c)
65 {
66 PBYTE byteaddr = SurfObj->pvScan0 + y1 * SurfObj->lDelta;
67 PWORD addr = (PWORD)byteaddr + x;
68 LONG lDelta = SurfObj->lDelta;
69
70 byteaddr = (PBYTE)addr;
71 while(y1++ < y2) {
72 *addr = (WORD)c;
73
74 byteaddr += lDelta;
75 addr = (PWORD)byteaddr;
76 }
77 }
78
79 BOOLEAN STATIC
80 DIB_16BPP_BitBltSrcCopy(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
81 SURFGDI *DestGDI, SURFGDI *SourceGDI,
82 PRECTL DestRect, POINTL *SourcePoint,
83 XLATEOBJ *ColorTranslation)
84 {
85 LONG i, j, sx, sy, xColor, f1;
86 PBYTE SourceBits, DestBits, SourceLine, DestLine;
87 PBYTE SourceBits_4BPP, SourceLine_4BPP;
88 DestBits = DestSurf->pvScan0 + (DestRect->top * DestSurf->lDelta) + 2 * DestRect->left;
89
90 switch(SourceGDI->BitsPerPixel)
91 {
92 case 1:
93 sx = SourcePoint->x;
94 sy = SourcePoint->y;
95
96 for (j=DestRect->top; j<DestRect->bottom; j++)
97 {
98 sx = SourcePoint->x;
99 for (i=DestRect->left; i<DestRect->right; i++)
100 {
101 if(DIB_1BPP_GetPixel(SourceSurf, sx, sy) == 0)
102 {
103 DIB_16BPP_PutPixel(DestSurf, i, j, XLATEOBJ_iXlate(ColorTranslation, 0));
104 } else {
105 DIB_16BPP_PutPixel(DestSurf, i, j, XLATEOBJ_iXlate(ColorTranslation, 1));
106 }
107 sx++;
108 }
109 sy++;
110 }
111 break;
112
113 case 4:
114 SourceBits_4BPP = SourceSurf->pvScan0 + (SourcePoint->y * SourceSurf->lDelta) + (SourcePoint->x >> 1);
115
116 for (j=DestRect->top; j<DestRect->bottom; j++)
117 {
118 SourceLine_4BPP = SourceBits_4BPP;
119 sx = SourcePoint->x;
120 f1 = sx & 1;
121
122 for (i=DestRect->left; i<DestRect->right; i++)
123 {
124 xColor = XLATEOBJ_iXlate(ColorTranslation,
125 (*SourceLine_4BPP & altnotmask[sx&1]) >> (4 * (1-(sx & 1))));
126 DIB_16BPP_PutPixel(DestSurf, i, j, xColor);
127 if(f1 == 1) { SourceLine_4BPP++; f1 = 0; } else { f1 = 1; }
128 sx++;
129 }
130
131 SourceBits_4BPP += SourceSurf->lDelta;
132 }
133 break;
134
135 case 8:
136 SourceLine = SourceSurf->pvScan0 + (SourcePoint->y * SourceSurf->lDelta) + SourcePoint->x;
137 DestLine = DestBits;
138
139 for (j = DestRect->top; j < DestRect->bottom; j++)
140 {
141 SourceBits = SourceLine;
142 DestBits = DestLine;
143
144 for (i = DestRect->left; i < DestRect->right; i++)
145 {
146 *((WORD *)DestBits) = (WORD)XLATEOBJ_iXlate(ColorTranslation, *SourceBits);
147 SourceBits += 1;
148 DestBits += 2;
149 }
150
151 SourceLine += SourceSurf->lDelta;
152 DestLine += DestSurf->lDelta;
153 }
154 break;
155
156 case 16:
157 if (NULL == ColorTranslation || 0 != (ColorTranslation->flXlate & XO_TRIVIAL))
158 {
159 if (DestRect->top < SourcePoint->y)
160 {
161 SourceBits = SourceSurf->pvScan0 + (SourcePoint->y * SourceSurf->lDelta) + 2 * SourcePoint->x;
162 for (j = DestRect->top; j < DestRect->bottom; j++)
163 {
164 RtlMoveMemory(DestBits, SourceBits, 2 * (DestRect->right - DestRect->left));
165 SourceBits += SourceSurf->lDelta;
166 DestBits += DestSurf->lDelta;
167 }
168 }
169 else
170 {
171 SourceBits = SourceSurf->pvScan0 + ((SourcePoint->y + DestRect->bottom - DestRect->top - 1) * SourceSurf->lDelta) + 2 * SourcePoint->x;
172 DestBits = DestSurf->pvScan0 + ((DestRect->bottom - 1) * DestSurf->lDelta) + 2 * DestRect->left;
173 for (j = DestRect->bottom - 1; DestRect->top <= j; j--)
174 {
175 RtlMoveMemory(DestBits, SourceBits, 2 * (DestRect->right - DestRect->left));
176 SourceBits -= SourceSurf->lDelta;
177 DestBits -= DestSurf->lDelta;
178 }
179 }
180 }
181 else
182 {
183 if (DestRect->top < SourcePoint->y)
184 {
185 SourceLine = SourceSurf->pvScan0 + (SourcePoint->y * SourceSurf->lDelta) + 2 * SourcePoint->x;
186 DestLine = DestBits;
187 for (j = DestRect->top; j < DestRect->bottom; j++)
188 {
189 SourceBits = SourceLine;
190 DestBits = DestLine;
191 for (i = DestRect->left; i < DestRect->right; i++)
192 {
193 *((WORD *)DestBits) = (WORD)XLATEOBJ_iXlate(ColorTranslation, *((WORD *)SourceBits));
194 SourceBits += 2;
195 DestBits += 2;
196 }
197 SourceLine += SourceSurf->lDelta;
198 DestLine += DestSurf->lDelta;
199 }
200 }
201 else
202 {
203 SourceLine = SourceSurf->pvScan0 + ((SourcePoint->y + DestRect->bottom - DestRect->top - 1) * SourceSurf->lDelta) + 2 * SourcePoint->x;
204 DestLine = DestSurf->pvScan0 + ((DestRect->bottom - 1) * DestSurf->lDelta) + 2 * DestRect->left;
205 for (j = DestRect->bottom - 1; DestRect->top <= j; j--)
206 {
207 SourceBits = SourceLine;
208 DestBits = DestLine;
209 for (i = DestRect->left; i < DestRect->right; i++)
210 {
211 *((WORD *)DestBits) = (WORD)XLATEOBJ_iXlate(ColorTranslation, *((WORD *)SourceBits));
212 SourceBits += 2;
213 DestBits += 2;
214 }
215 SourceLine -= SourceSurf->lDelta;
216 DestLine -= DestSurf->lDelta;
217 }
218 }
219 }
220 break;
221
222 case 24:
223 SourceLine = SourceSurf->pvScan0 + (SourcePoint->y * SourceSurf->lDelta) + 3 * SourcePoint->x;
224 DestLine = DestBits;
225
226 for (j = DestRect->top; j < DestRect->bottom; j++)
227 {
228 SourceBits = SourceLine;
229 DestBits = DestLine;
230
231 for (i = DestRect->left; i < DestRect->right; i++)
232 {
233 xColor = (*(SourceBits + 2) << 0x10) +
234 (*(SourceBits + 1) << 0x08) +
235 (*(SourceBits));
236 *((WORD *)DestBits) = (WORD)XLATEOBJ_iXlate(ColorTranslation, xColor);
237 SourceBits += 3;
238 DestBits += 2;
239 }
240
241 SourceLine += SourceSurf->lDelta;
242 DestLine += DestSurf->lDelta;
243 }
244 break;
245
246 case 32:
247 SourceLine = SourceSurf->pvScan0 + (SourcePoint->y * SourceSurf->lDelta) + 4 * SourcePoint->x;
248 DestLine = DestBits;
249
250 for (j = DestRect->top; j < DestRect->bottom; j++)
251 {
252 SourceBits = SourceLine;
253 DestBits = DestLine;
254
255 for (i = DestRect->left; i < DestRect->right; i++)
256 {
257 *((WORD *)DestBits) = (WORD)XLATEOBJ_iXlate(ColorTranslation, *((PDWORD) SourceBits));
258 SourceBits += 4;
259 DestBits += 2;
260 }
261
262 SourceLine += SourceSurf->lDelta;
263 DestLine += DestSurf->lDelta;
264 }
265 break;
266
267 default:
268 DbgPrint("DIB_16BPP_Bitblt: Unhandled Source BPP: %u\n", SourceGDI->BitsPerPixel);
269 return FALSE;
270 }
271
272 return TRUE;
273 }
274
275 BOOLEAN
276 DIB_16BPP_BitBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
277 SURFGDI *DestGDI, SURFGDI *SourceGDI,
278 PRECTL DestRect, POINTL *SourcePoint,
279 PBRUSHOBJ Brush, PPOINTL BrushOrigin,
280 XLATEOBJ *ColorTranslation, ULONG Rop4)
281 {
282 LONG i, j, sx, sy;
283 ULONG Dest, Source, Pattern;
284 PULONG DestBits;
285 BOOL UsesSource = ((Rop4 & 0xCC0000) >> 2) != (Rop4 & 0x330000);
286 BOOL UsesPattern = ((Rop4 & 0xF00000) >> 4) != (Rop4 & 0x0F0000);
287 LONG RoundedRight = DestRect->right - ((DestRect->right - DestRect->left) & 0x1);
288
289 if (Rop4 == SRCCOPY)
290 {
291 return(DIB_16BPP_BitBltSrcCopy(DestSurf, SourceSurf, DestGDI, SourceGDI, DestRect, SourcePoint, ColorTranslation));
292 }
293 else
294 {
295 sy = SourcePoint->y;
296
297 for (j=DestRect->top; j<DestRect->bottom; j++)
298 {
299 sx = SourcePoint->x;
300 DestBits = (PULONG)(DestSurf->pvScan0 + 2 * DestRect->left + j * DestSurf->lDelta);
301 for (i=DestRect->left; i<RoundedRight; i+=2, DestBits++)
302 {
303 Dest = *DestBits;
304 if (UsesSource)
305 {
306 Source = DIB_GetSource(SourceSurf, SourceGDI, sx + (i - DestRect->left), sy, ColorTranslation);
307 Source |= DIB_GetSource(SourceSurf, SourceGDI, sx + (i - DestRect->left) + 1, sy, ColorTranslation) << 16;
308 }
309 if (UsesPattern)
310 {
311 /* FIXME: No support for pattern brushes. */
312 Pattern = (Brush->iSolidColor & 0xFFFF) |
313 ((Brush->iSolidColor & 0xFFFF) << 16);
314 }
315 *DestBits = DIB_DoRop(Rop4, Dest, Source, Pattern);
316 }
317 if (i < DestRect->right)
318 {
319 Dest = *DestBits;
320 for (; i < DestRect->right; i++)
321 {
322 if (UsesSource)
323 {
324 Source = DIB_GetSource(SourceSurf, SourceGDI, sx + (i - DestRect->left), sy, ColorTranslation);
325 }
326 if (UsesPattern)
327 {
328 /* FIXME: No support for pattern brushes. */
329 Pattern = (Brush->iSolidColor & 0xFFFF) |
330 ((Brush->iSolidColor & 0xFFFF) << 16);
331 }
332 DIB_16BPP_PutPixel(DestSurf, i, j, DIB_DoRop(Rop4, Dest, Source, Pattern) & 0xFFFF);
333 Dest >>= 16;
334 }
335 }
336 sy++;
337 }
338 }
339 return TRUE;
340 }
341
342
343 /*
344 =======================================
345 Stretching functions goes below
346 Some parts of code are based on an
347 article "Bresenhame image scaling"
348 Dr. Dobb Journal, May 2002
349 =======================================
350 */
351
352 typedef unsigned short PIXEL;
353
354 /* 16-bit HiColor (565 format) */
355 inline PIXEL average16(PIXEL a, PIXEL b)
356 {
357 // This one doesn't work
358 /*
359 if (a == b) {
360 return a;
361 } else {
362 unsigned short mask = ~ (((a | b) & 0x0410) << 1);
363 return ((a & mask) + (b & mask)) >> 1;
364 }*/ /* if */
365
366 // This one should be correct, but it's too long
367 /*
368 unsigned char r1, g1, b1, r2, g2, b2, rr, gr, br;
369 unsigned short res;
370
371 r1 = (a & 0xF800) >> 11;
372 g1 = (a & 0x7E0) >> 5;
373 b1 = (a & 0x1F);
374
375 r2 = (b & 0xF800) >> 11;
376 g2 = (b & 0x7E0) >> 5;
377 b2 = (b & 0x1F);
378
379 rr = (r1+r2) / 2;
380 gr = (g1+g2) / 2;
381 br = (b1+b2) / 2;
382
383 res = (rr << 11) + (gr << 5) + br;
384
385 return res;
386 */
387 return a; // FIXME: Depend on SetStretchMode
388 }
389
390 //NOTE: If you change something here, please do the same in other dibXXbpp.c files!
391 void ScaleLineAvg16(PIXEL *Target, PIXEL *Source, int SrcWidth, int TgtWidth)
392 {
393 int NumPixels = TgtWidth;
394 int IntPart = SrcWidth / TgtWidth;
395 int FractPart = SrcWidth % TgtWidth;
396 int Mid = TgtWidth / 2;
397 int E = 0;
398 int skip;
399 PIXEL p;
400
401 skip = (TgtWidth < SrcWidth) ? 0 : (TgtWidth / (2*SrcWidth) + 1);
402 NumPixels -= skip;
403
404 while (NumPixels-- > 0) {
405 p = *Source;
406 if (E >= Mid)
407 p = average16(p, *(Source+1));
408 *Target++ = p;
409 Source += IntPart;
410 E += FractPart;
411 if (E >= TgtWidth) {
412 E -= TgtWidth;
413 Source++;
414 } /* if */
415 } /* while */
416 while (skip-- > 0)
417 *Target++ = *Source;
418 }
419
420 //NOTE: If you change something here, please do the same in other dibXXbpp.c files!
421 void ScaleRectAvg16(PIXEL *Target, PIXEL *Source, int SrcWidth, int SrcHeight,
422 int TgtWidth, int TgtHeight, int srcPitch, int dstPitch)
423 {
424 int NumPixels = TgtHeight;
425 int IntPart = (SrcHeight / TgtHeight) * (SrcWidth+1);
426 int FractPart = SrcHeight % TgtHeight;
427 int Mid = TgtHeight / 2;
428 int E = 0;
429 int skip;
430 PIXEL *ScanLine, *ScanLineAhead;
431 PIXEL *PrevSource = NULL;
432 PIXEL *PrevSourceAhead = NULL;
433
434 skip = (TgtHeight < SrcHeight) ? 0 : (TgtHeight / (2*SrcHeight) + 1);
435 NumPixels -= skip;
436
437 ScanLine = (PIXEL*)ExAllocatePool(NonPagedPool, TgtWidth*sizeof(PIXEL)); // FIXME: Should we use PagedPool here?
438 ScanLineAhead = (PIXEL *)ExAllocatePool(NonPagedPool, TgtWidth*sizeof(PIXEL));
439
440 while (NumPixels-- > 0) {
441 if (Source != PrevSource) {
442 if (Source == PrevSourceAhead) {
443 /* the next scan line has already been scaled and stored in
444 * ScanLineAhead; swap the buffers that ScanLine and ScanLineAhead
445 * point to
446 */
447 PIXEL *tmp = ScanLine;
448 ScanLine = ScanLineAhead;
449 ScanLineAhead = tmp;
450 } else {
451 ScaleLineAvg16(ScanLine, Source, SrcWidth, TgtWidth);
452 } /* if */
453 PrevSource = Source;
454 } /* if */
455
456 if (E >= Mid && PrevSourceAhead != (PIXEL *)((BYTE *)Source + srcPitch)) {
457 int x;
458 ScaleLineAvg16(ScanLineAhead, (PIXEL *)((BYTE *)Source + srcPitch), SrcWidth, TgtWidth);
459 for (x = 0; x < TgtWidth; x++)
460 ScanLine[x] = average16(ScanLine[x], ScanLineAhead[x]);
461 PrevSourceAhead = (PIXEL *)((BYTE *)Source + srcPitch);
462 } /* if */
463
464 memcpy(Target, ScanLine, TgtWidth*sizeof(PIXEL));
465 Target = (PIXEL *)((BYTE *)Target + dstPitch);
466 Source += IntPart;
467 E += FractPart;
468 if (E >= TgtHeight) {
469 E -= TgtHeight;
470 Source = (PIXEL *)((BYTE *)Source + srcPitch);
471 } /* if */
472 } /* while */
473
474 if (skip > 0 && Source != PrevSource)
475 ScaleLineAvg16(ScanLine, Source, SrcWidth, TgtWidth);
476 while (skip-- > 0) {
477 memcpy(Target, ScanLine, TgtWidth*sizeof(PIXEL));
478 Target = (PIXEL *)((BYTE *)Target + dstPitch);
479 } /* while */
480
481 ExFreePool(ScanLine);
482 ExFreePool(ScanLineAhead);
483 }
484
485 //NOTE: If you change something here, please do the same in other dibXXbpp.c files!
486 BOOLEAN DIB_16BPP_StretchBlt(SURFOBJ *DestSurf, SURFOBJ *SourceSurf,
487 SURFGDI *DestGDI, SURFGDI *SourceGDI,
488 RECTL* DestRect, RECTL *SourceRect,
489 POINTL* MaskOrigin, POINTL* BrushOrigin,
490 XLATEOBJ *ColorTranslation, ULONG Mode)
491 {
492 BYTE *SourceLine, *DestLine;
493
494 DbgPrint("DIB_16BPP_StretchBlt: Source BPP: %u, srcRect: (%d,%d)-(%d,%d), dstRect: (%d,%d)-(%d,%d)\n",
495 SourceGDI->BitsPerPixel, SourceRect->left, SourceRect->top, SourceRect->right, SourceRect->bottom,
496 DestRect->left, DestRect->top, DestRect->right, DestRect->bottom);
497
498 switch(SourceGDI->BitsPerPixel)
499 {
500 case 1:
501 return FALSE;
502 break;
503
504 case 4:
505 return FALSE;
506 break;
507
508 case 8:
509 return FALSE;
510 break;
511
512 case 16:
513 SourceLine = SourceSurf->pvScan0 + (SourceRect->top * SourceSurf->lDelta) + 2 * SourceRect->left;
514 DestLine = DestSurf->pvScan0 + (DestRect->top * DestSurf->lDelta) + 2 * DestRect->left;
515
516 ScaleRectAvg16((PIXEL *)DestLine, (PIXEL *)SourceLine,
517 SourceRect->right-SourceRect->left, SourceRect->bottom-SourceRect->top,
518 DestRect->right-DestRect->left, DestRect->bottom-DestRect->top, SourceSurf->lDelta, DestSurf->lDelta);
519 break;
520
521 case 24:
522 return FALSE;
523 break;
524
525 case 32:
526 return FALSE;
527 break;
528
529 default:
530 DbgPrint("DIB_16BPP_StretchBlt: Unhandled Source BPP: %u\n", SourceGDI->BitsPerPixel);
531 return FALSE;
532 }
533
534
535
536 return TRUE;
537 }
538
539 /* EOF */