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