Sync up with trunk r61578.
[reactos.git] / base / applications / mstsc / bsops.c
1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Generics backingstore operations
4 Copyright (C) Jay Sorg 2005-2006
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "precomp.h"
22
23 /* globals */
24 static char * g_bs = 0;
25 static int g_bs_size = 0;
26
27 static int g_width1 = 800;
28 static int g_height1 = 600;
29 static int g_bpp = 8;
30 static int g_Bpp = 1;
31
32 static int g_clip_left1 = 0;
33 static int g_clip_top1 = 0;
34 static int g_clip_right1 = 800;
35 static int g_clip_bottom1 = 600;
36
37 /* for bs_patblt */
38 static char g_hatch_patterns[] =
39 {
40 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, /* 0 - bsHorizontal */
41 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 1 - bsVertical */
42 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, /* 2 - bsFDiagonal */
43 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, /* 3 - bsBDiagonal */
44 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, /* 4 - bsCross */
45 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 /* 5 - bsDiagCross */
46 };
47
48
49 /*****************************************************************************/
50 /* do a raster op */
51 int
52 bs_do_rop(int rop, int src, int dst)
53 {
54 switch (rop)
55 {
56 case 0x0: return 0;
57 case 0x1: return ~(src | dst);
58 case 0x2: return (~src) & dst;
59 case 0x3: return ~src;
60 case 0x4: return src & (~dst);
61 case 0x5: return ~(dst);
62 case 0x6: return src ^ dst;
63 case 0x7: return ~(src & dst);
64 case 0x8: return src & dst;
65 case 0x9: return ~(src) ^ dst;
66 case 0xa: return dst;
67 case 0xb: return (~src) | dst;
68 case 0xc: return src;
69 case 0xd: return src | (~dst);
70 case 0xe: return src | dst;
71 case 0xf: return ~0;
72 }
73 return dst;
74 }
75
76 /*****************************************************************************/
77 /* get a pixel from the in memory copy of whats on the screen */
78 int
79 bs_get_pixel(int x, int y)
80 {
81 char * p;
82
83 if (x >= 0 && x < g_width1 && y >= 0 && y < g_height1)
84 {
85 p = g_bs + (y * g_width1 * g_Bpp) + (x * g_Bpp);
86 if (g_Bpp == 1)
87 {
88 return *((unsigned char *) p);
89 }
90 else if (g_Bpp == 2)
91 {
92 return *((unsigned short *) p);
93 }
94 else
95 {
96 return *((unsigned int *) p);
97 }
98 }
99 else
100 {
101 return 0;
102 }
103 }
104
105 /*****************************************************************************/
106 /* set a pixel on the screen using the clip */
107 void
108 bs_set_pixel(int x, int y, int pixel, int rop, int use_clip)
109 {
110 char * p;
111
112 if (!use_clip ||
113 (x >= g_clip_left1 && x < g_clip_right1 &&
114 y >= g_clip_top1 && y < g_clip_bottom1))
115 {
116 if (x >= 0 && x < g_width1 && y >= 0 && y < g_height1)
117 {
118 p = g_bs + (y * g_width1 * g_Bpp) + (x * g_Bpp);
119 if (rop != 12)
120 {
121 pixel = bs_do_rop(rop, pixel, bs_get_pixel(x, y));
122 }
123 if (g_Bpp == 1)
124 {
125 *((unsigned char *) p) = pixel;
126 }
127 else if (g_Bpp == 2)
128 {
129 *((unsigned short *) p) = pixel;
130 }
131 else
132 {
133 *((unsigned int *) p) = pixel;
134 }
135 }
136 }
137 }
138
139 /*****************************************************************************/
140 static char *
141 get_bs_ptr(int x, int y)
142 {
143 char * p;
144
145 if (x >= 0 && x < g_width1 && y >= 0 && y < g_height1)
146 {
147 p = g_bs + (y * g_width1 * g_Bpp) + (x * g_Bpp);
148 return p;
149 }
150 else
151 {
152 return 0;
153 }
154 }
155
156 /*****************************************************************************/
157 void
158 bs_init(int width, int height, int bpp)
159 {
160 if (g_bs != 0)
161 {
162 free(g_bs);
163 }
164 g_width1 = width;
165 g_height1 = height;
166 g_bpp = bpp;
167 g_Bpp = (bpp + 7) / 8;
168 g_bs_size = width * height * g_Bpp;
169 g_bs = malloc(g_bs_size);
170 memset(g_bs, 0, g_bs_size);
171 g_clip_left1 = 0;
172 g_clip_top1 = 0;
173 g_clip_right1 = width;
174 g_clip_bottom1 = height;
175 }
176
177 /*****************************************************************************/
178 void
179 bs_exit(void)
180 {
181 if (g_bs != 0)
182 {
183 free(g_bs);
184 }
185 }
186
187 /*****************************************************************************/
188 void
189 bs_set_clip(int x, int y, int cx, int cy)
190 {
191 g_clip_left1 = x;
192 g_clip_top1 = y;
193 g_clip_right1 = x + cx;
194 g_clip_bottom1 = y + cy;
195 }
196
197 /*****************************************************************************/
198 void
199 bs_reset_clip(void)
200 {
201 g_clip_left1 = 0;
202 g_clip_top1 = 0;
203 g_clip_right1 = g_width1;
204 g_clip_bottom1 = g_height1;
205 }
206
207 /*****************************************************************************/
208 /* check if a certain pixel is set in a bitmap */
209 int
210 bs_is_pixel_on(char * data, int x, int y, int width, int bpp)
211 {
212 int start;
213 int shift;
214
215 if (bpp == 1)
216 {
217 width = (width + 7) / 8;
218 start = (y * width) + x / 8;
219 shift = x % 8;
220 return (data[start] & (0x80 >> shift)) != 0;
221 }
222 else if (bpp == 8)
223 {
224 return data[y * width + x] != 0;
225 }
226 else if (bpp == 24)
227 {
228 return data[(y * 3) * width + (x * 3)] != 0 &&
229 data[(y * 3) * width + (x * 3) + 1] != 0 &&
230 data[(y * 3) * width + (x * 3) + 2] != 0;
231 }
232 else
233 {
234 return 0;
235 }
236 }
237
238 /*****************************************************************************/
239 void
240 bs_set_pixel_on(char * data, int x, int y, int width, int bpp,
241 int pixel)
242 {
243 int start;
244 int shift;
245
246 if (bpp == 1)
247 {
248 width = (width + 7) / 8;
249 start = (y * width) + x / 8;
250 shift = x % 8;
251 if (pixel != 0)
252 {
253 data[start] = data[start] | (0x80 >> shift);
254 }
255 else
256 {
257 data[start] = data[start] & ~(0x80 >> shift);
258 }
259 }
260 else if (bpp == 8)
261 {
262 data[y * width + x] = pixel;
263 }
264 else if (bpp == 15 || bpp == 16)
265 {
266 ((unsigned short *) data)[y * width + x] = pixel;
267 }
268 }
269
270 /*****************************************************************************/
271 void
272 bs_copy_mem(char * d, char * s, int n)
273 {
274 while (n & (~7))
275 {
276 *(d++) = *(s++);
277 *(d++) = *(s++);
278 *(d++) = *(s++);
279 *(d++) = *(s++);
280 *(d++) = *(s++);
281 *(d++) = *(s++);
282 *(d++) = *(s++);
283 *(d++) = *(s++);
284 n = n - 8;
285 }
286 while (n > 0)
287 {
288 *(d++) = *(s++);
289 n--;
290 }
291 }
292
293 /*****************************************************************************/
294 void
295 bs_copy_memb(char * d, char * s, int n)
296 {
297 d = (d + n) - 1;
298 s = (s + n) - 1;
299 while (n & (~7))
300 {
301 *(d--) = *(s--);
302 *(d--) = *(s--);
303 *(d--) = *(s--);
304 *(d--) = *(s--);
305 *(d--) = *(s--);
306 *(d--) = *(s--);
307 *(d--) = *(s--);
308 *(d--) = *(s--);
309 n = n - 8;
310 }
311 while (n > 0)
312 {
313 *(d--) = *(s--);
314 n--;
315 }
316 }
317
318 /*****************************************************************************/
319 /* return true is the is something to draw */
320 int
321 bs_warp_coords(int * x, int * y, int * cx, int * cy,
322 int * srcx, int * srcy)
323 {
324 int dx;
325 int dy;
326
327 if (g_clip_left1 > *x)
328 {
329 dx = g_clip_left1 - *x;
330 }
331 else
332 {
333 dx = 0;
334 }
335 if (g_clip_top1 > *y)
336 {
337 dy = g_clip_top1 - *y;
338 }
339 else
340 {
341 dy = 0;
342 }
343 if (*x + *cx > g_clip_right1)
344 {
345 *cx = (*cx - ((*x + *cx) - g_clip_right1));
346 }
347 if (*y + *cy > g_clip_bottom1)
348 {
349 *cy = (*cy - ((*y + *cy) - g_clip_bottom1));
350 }
351 *cx = *cx - dx;
352 *cy = *cy - dy;
353 if (*cx <= 0)
354 {
355 return 0;
356 }
357 if (*cy <= 0)
358 {
359 return 0;
360 }
361 *x = *x + dx;
362 *y = *y + dy;
363 if (srcx != 0)
364 {
365 *srcx = *srcx + dx;
366 }
367 if (srcy != 0)
368 {
369 *srcy = *srcy + dy;
370 }
371 return 1;
372 }
373
374 /*****************************************************************************/
375 void
376 bs_rect(int x, int y, int cx, int cy, int colour, int rop)
377 {
378 int i;
379 int j;
380 unsigned char * p8;
381 unsigned short * p16;
382 unsigned int * p32;
383
384 if (bs_warp_coords(&x, &y, &cx, &cy, 0, 0))
385 {
386 if (rop == 0) /* black */
387 {
388 rop = 12;
389 colour = 0;
390 }
391 else if (rop == 15) /* white */
392 {
393 rop = 12;
394 colour = 0xffffff;
395 }
396 if (rop == 12) /* copy */
397 {
398 if (g_Bpp == 1)
399 {
400 for (i = 0; i < cy; i++)
401 {
402 p8 = (unsigned char *) get_bs_ptr(x, y + i);
403 if (p8 != 0)
404 {
405 for (j = 0; j < cx; j++)
406 {
407 *p8 = colour;
408 p8++;
409 }
410 }
411 }
412 }
413 else if (g_Bpp == 2)
414 {
415 for (i = 0; i < cy; i++)
416 {
417 p16 = (unsigned short *) get_bs_ptr(x, y + i);
418 if (p16 != 0)
419 {
420 for (j = 0; j < cx; j++)
421 {
422 *p16 = colour;
423 p16++;
424 }
425 }
426 }
427 }
428 else
429 {
430 for (i = 0; i < cy; i++)
431 {
432 p32 = (unsigned int *) get_bs_ptr(x, y + i);
433 if (p32 != 0)
434 {
435 for (j = 0; j < cx; j++)
436 {
437 *p32 = colour;
438 p32++;
439 }
440 }
441 }
442 }
443 }
444 else /* slow */
445 {
446 for (i = 0; i < cy; i++)
447 {
448 for (j = 0; j < cx; j++)
449 {
450 bs_set_pixel(j + x, i + y, colour, rop, 0);
451 }
452 }
453 }
454 }
455 }
456
457 /*****************************************************************************/
458 void
459 bs_screenblt(int rop, int x, int y, int cx, int cy,
460 int srcx, int srcy)
461 {
462 int p;
463 int i;
464 int j;
465 char * src;
466 char * dst;
467
468 if (bs_warp_coords(&x, &y, &cx, &cy, &srcx, &srcy))
469 {
470 if (rop == 12) /* copy */
471 {
472 if (srcy < y) /* copy down - bottom to top */
473 {
474 for (i = cy - 1; i >= 0; i--)
475 {
476 src = get_bs_ptr(srcx, srcy + i);
477 dst = get_bs_ptr(x, y + i);
478 if (src != 0 && dst != 0)
479 {
480 bs_copy_mem(dst, src, cx * g_Bpp);
481 }
482 }
483 }
484 else if (srcy > y || srcx > x) /* copy up or left - top to bottom */
485 {
486 for (i = 0; i < cy; i++)
487 {
488 src = get_bs_ptr(srcx, srcy + i);
489 dst = get_bs_ptr(x, y + i);
490 if (src != 0 && dst != 0)
491 {
492 bs_copy_mem(dst, src, cx * g_Bpp);
493 }
494 }
495 }
496 else /* copy straight right */
497 {
498 for (i = 0; i < cy; i++)
499 {
500 src = get_bs_ptr(srcx, srcy + i);
501 dst = get_bs_ptr(x, y + i);
502 if (src != 0 && dst != 0)
503 {
504 bs_copy_memb(dst, src, cx * g_Bpp);
505 }
506 }
507 }
508 }
509 else /* slow */
510 {
511 if (srcy < y) /* copy down - bottom to top */
512 {
513 for (i = cy - 1; i >= 0; i--)
514 {
515 for (j = 0; j < cx; j++)
516 {
517 p = bs_get_pixel(srcx + j, srcy + i);
518 bs_set_pixel(x + j, y + i, p, rop, 0);
519 }
520 }
521 }
522 else if (srcy > y || srcx > x) /* copy up or left - top to bottom */
523 {
524 for (i = 0; i < cy; i++)
525 {
526 for (j = 0; j < cx; j++)
527 {
528 p = bs_get_pixel(srcx + j, srcy + i);
529 bs_set_pixel(x + j, y + i, p, rop, 0);
530 }
531 }
532 }
533 else /* copy straight right */
534 {
535 for (i = 0; i < cy; i++)
536 {
537 for (j = cx - 1; j >= 0; j--)
538 {
539 p = bs_get_pixel(srcx + j, srcy + i);
540 bs_set_pixel(x + j, y + i, p, rop, 0);
541 }
542 }
543 }
544 }
545 }
546 }
547
548 /*****************************************************************************/
549 void
550 bs_memblt(int opcode, int x, int y, int cx, int cy,
551 void * srcdata, int srcwidth, int srcheight,
552 int srcx, int srcy)
553 {
554 int i;
555 int j;
556 int p;
557 char * dst;
558 char * src;
559
560 if (bs_warp_coords(&x, &y, &cx, &cy, &srcx, &srcy))
561 {
562 if (opcode == 12) /* copy */
563 {
564 if (g_Bpp == 1)
565 {
566 src = (char *) (((unsigned char *) srcdata) + srcy * srcwidth + srcx);
567 }
568 else if (g_Bpp == 2)
569 {
570 src = (char *) (((unsigned short *) srcdata) + srcy * srcwidth + srcx);
571 }
572 else
573 {
574 src = (char *) (((unsigned int *) srcdata) + srcy * srcwidth + srcx);
575 }
576 for (i = 0; i < cy; i++)
577 {
578 dst = get_bs_ptr(x, y + i);
579 if (dst != 0)
580 {
581 bs_copy_mem(dst, src, cx * g_Bpp);
582 src += srcwidth * g_Bpp;
583 }
584 }
585 }
586 else /* slow */
587 {
588 if (g_Bpp == 1)
589 {
590 for (i = 0; i < cy; i++)
591 {
592 for (j = 0; j < cx; j++)
593 {
594 p = *(((unsigned char *) srcdata) +
595 ((i + srcy) * srcwidth + (j + srcx)));
596 bs_set_pixel(x + j, y + i, p, opcode, 0);
597 }
598 }
599 }
600 else if (g_Bpp == 2)
601 {
602 for (i = 0; i < cy; i++)
603 {
604 for (j = 0; j < cx; j++)
605 {
606 p = *(((unsigned short *) srcdata) +
607 ((i + srcy) * srcwidth + (j + srcx)));
608 bs_set_pixel(x + j, y + i, p, opcode, 0);
609 }
610 }
611 }
612 else
613 {
614 for (i = 0; i < cy; i++)
615 {
616 for (j = 0; j < cx; j++)
617 {
618 p = *(((unsigned int *) srcdata) +
619 ((i + srcy) * srcwidth + (j + srcx)));
620 bs_set_pixel(x + j, y + i, p, opcode, 0);
621 }
622 }
623 }
624 }
625 }
626 }
627
628 /*****************************************************************************/
629 void
630 bs_draw_glyph(int x, int y, char * glyph_data, int glyph_width,
631 int glyph_height, int fgcolour)
632 {
633 int i;
634 int j;
635
636 for (i = 0; i < glyph_height; i++)
637 {
638 for (j = 0; j < glyph_width; j++)
639 {
640 if (bs_is_pixel_on(glyph_data, j, i, glyph_width, 8))
641 {
642 bs_set_pixel(x + j, y + i, fgcolour, 12, 1);
643 }
644 }
645 }
646 }
647
648 /*****************************************************************************/
649 /* Bresenham's line drawing algorithm */
650 void
651 bs_line(int opcode, int startx, int starty, int endx, int endy,
652 int pen_width, int pen_style, int pen_colour)
653 {
654 int dx;
655 int dy;
656 int incx;
657 int incy;
658 int dpr;
659 int dpru;
660 int p;
661
662 if (startx > endx)
663 {
664 dx = startx - endx;
665 incx = -1;
666 }
667 else
668 {
669 dx = endx - startx;
670 incx = 1;
671 }
672 if (starty > endy)
673 {
674 dy = starty - endy;
675 incy = -1;
676 }
677 else
678 {
679 dy = endy - starty;
680 incy = 1;
681 }
682 if (dx >= dy)
683 {
684 dpr = dy << 1;
685 dpru = dpr - (dx << 1);
686 p = dpr - dx;
687 for (; dx >= 0; dx--)
688 {
689 if (startx != endx || starty != endy)
690 {
691 bs_set_pixel(startx, starty, pen_colour, opcode, 1);
692 }
693 if (p > 0)
694 {
695 startx += incx;
696 starty += incy;
697 p += dpru;
698 }
699 else
700 {
701 startx += incx;
702 p += dpr;
703 }
704 }
705 }
706 else
707 {
708 dpr = dx << 1;
709 dpru = dpr - (dy << 1);
710 p = dpr - dy;
711 for (; dy >= 0; dy--)
712 {
713 if (startx != endx || starty != endy)
714 {
715 bs_set_pixel(startx, starty, pen_colour, opcode, 1);
716 }
717 if (p > 0)
718 {
719 startx += incx;
720 starty += incy;
721 p += dpru;
722 }
723 else
724 {
725 starty += incy;
726 p += dpr;
727 }
728 }
729 }
730 }
731
732 /*****************************************************************************/
733 void
734 bs_patblt(int opcode, int x, int y, int cx, int cy,
735 int brush_style, char * brush_pattern,
736 int brush_x_org, int brush_y_org,
737 int bgcolour, int fgcolour)
738 {
739 int i;
740 int j;
741 char ipattern[8];
742 char * b;
743
744 b = 0;
745 switch (brush_style)
746 {
747 case 0:
748 bs_rect(x, y, cx, cy, fgcolour, opcode);
749 break;
750 case 2: /* Hatch */
751 b = g_hatch_patterns + brush_pattern[0] * 8;
752 break;
753 case 3:
754 for (i = 0; i < 8; i++)
755 {
756 ipattern[i] = ~brush_pattern[7 - i];
757 }
758 b = ipattern;
759 break;
760 }
761 if (b != 0)
762 {
763 for (i = 0; i < cy; i++)
764 {
765 for (j = 0; j < cx; j++)
766 {
767 if (bs_is_pixel_on(b, (x + j + brush_x_org) % 8,
768 (y + i + brush_y_org) % 8, 8, 1))
769 {
770 bs_set_pixel(x + j, y + i, fgcolour, opcode, 1);
771 }
772 else
773 {
774 bs_set_pixel(x + j, y + i, bgcolour, opcode, 1);
775 }
776 }
777 }
778 }
779 }
780
781 /*****************************************************************************/
782 void
783 bs_copy_box(char * dst, int x, int y, int cx, int cy, int line_size)
784 {
785 char * src;
786 int i;
787
788 /* shouldn't happen */
789 if (cx < 1 || cy < 1)
790 {
791 return;
792 }
793 /* nothing to draw, memset and leave */
794 if (x + cx < 0 || y + cy < 0 || x >= g_width1 || y >= g_height1)
795 {
796 memset(dst, 0, cx * cy * g_Bpp);
797 return;
798 }
799 /* check if it goes over an edge */
800 if (x < 0 || y < 0 || x + cx > g_width1 || y + cy > g_height1)
801 {
802 memset(dst, 0, cx * cy * g_Bpp);
803 if (x < 0)
804 {
805 cx += x;
806 dst += -x * g_Bpp;
807 x = 0;
808 }
809 if (x + cx > g_width1)
810 {
811 cx = g_width1 - x;
812 }
813 for (i = 0; i < cy; i++)
814 {
815 src = get_bs_ptr(x, y + i);
816 if (src != 0)
817 {
818 bs_copy_mem(dst, src, cx * g_Bpp);
819 }
820 dst += line_size;
821 }
822 }
823 else /* whole box is within */
824 {
825 for (i = 0; i < cy; i++)
826 {
827 src = get_bs_ptr(x, y + i);
828 if (src != 0)
829 {
830 bs_copy_mem(dst, src, cx * g_Bpp);
831 }
832 dst += line_size;
833 }
834 }
835 }