xref: /reactos/base/applications/mstsc/bsops.c (revision c2c66aff)
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
bs_do_rop(int rop,int src,int dst)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
bs_get_pixel(int x,int y)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
bs_set_pixel(int x,int y,int pixel,int rop,int use_clip)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 *
get_bs_ptr(int x,int y)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
bs_init(int width,int height,int bpp)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
bs_exit(void)179 bs_exit(void)
180 {
181   if (g_bs != 0)
182   {
183     free(g_bs);
184   }
185 }
186 
187 /*****************************************************************************/
188 void
bs_set_clip(int x,int y,int cx,int cy)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
bs_reset_clip(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
bs_is_pixel_on(char * data,int x,int y,int width,int bpp)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 == 15 || bpp == 16)
227   {
228     return data[(y * 2) * width + (x * 2)] != 0 ||
229            data[(y * 2) * width + (x * 2) + 1] != 0;
230   }
231   else if (bpp == 24 || bpp == 32)
232   {
233     return data[(y * 4) * width + (x * 4)] != 0 ||
234            data[(y * 4) * width + (x * 4) + 1] != 0 ||
235            data[(y * 4) * width + (x * 4) + 2] != 0 ||
236            data[(y * 4) * width + (x * 4) + 3] != 0;
237   }
238   else
239   {
240     return 0;
241   }
242 }
243 
244 /*****************************************************************************/
245 void
bs_set_pixel_on(char * data,int x,int y,int width,int bpp,int pixel)246 bs_set_pixel_on(char * data, int x, int y, int width, int bpp,
247                 int pixel)
248 {
249   int start;
250   int shift;
251 
252   if (bpp == 1)
253   {
254     width = (width + 7) / 8;
255     start = (y * width) + x / 8;
256     shift = x % 8;
257     if (pixel != 0)
258     {
259       data[start] = data[start] | (0x80 >> shift);
260     }
261     else
262     {
263       data[start] = data[start] & ~(0x80 >> shift);
264     }
265   }
266   else if (bpp == 8)
267   {
268     data[y * width + x] = pixel;
269   }
270   else if (bpp == 15 || bpp == 16)
271   {
272     ((unsigned short *) data)[y * width + x] = pixel;
273   }
274   else if (bpp == 24 || bpp == 32)
275   {
276     ((unsigned int *) data)[y * width + x] = (unsigned int) pixel;
277   }
278 }
279 
280 /*****************************************************************************/
281 void
bs_copy_mem(char * d,char * s,int n)282 bs_copy_mem(char * d, char * s, int n)
283 {
284   while (n & (~7))
285   {
286     *(d++) = *(s++);
287     *(d++) = *(s++);
288     *(d++) = *(s++);
289     *(d++) = *(s++);
290     *(d++) = *(s++);
291     *(d++) = *(s++);
292     *(d++) = *(s++);
293     *(d++) = *(s++);
294     n = n - 8;
295   }
296   while (n > 0)
297   {
298     *(d++) = *(s++);
299     n--;
300   }
301 }
302 
303 /*****************************************************************************/
304 void
bs_copy_memb(char * d,char * s,int n)305 bs_copy_memb(char * d, char * s, int n)
306 {
307   d = (d + n) - 1;
308   s = (s + n) - 1;
309   while (n & (~7))
310   {
311     *(d--) = *(s--);
312     *(d--) = *(s--);
313     *(d--) = *(s--);
314     *(d--) = *(s--);
315     *(d--) = *(s--);
316     *(d--) = *(s--);
317     *(d--) = *(s--);
318     *(d--) = *(s--);
319     n = n - 8;
320   }
321   while (n > 0)
322   {
323     *(d--) = *(s--);
324     n--;
325   }
326 }
327 
328 /*****************************************************************************/
329 /* return true is the is something to draw */
330 int
bs_warp_coords(int * x,int * y,int * cx,int * cy,int * srcx,int * srcy)331 bs_warp_coords(int * x, int * y, int * cx, int * cy,
332                int * srcx, int * srcy)
333 {
334   int dx;
335   int dy;
336 
337   if (g_clip_left1 > *x)
338   {
339     dx = g_clip_left1 - *x;
340   }
341   else
342   {
343     dx = 0;
344   }
345   if (g_clip_top1 > *y)
346   {
347     dy = g_clip_top1 - *y;
348   }
349   else
350   {
351     dy = 0;
352   }
353   if (*x + *cx > g_clip_right1)
354   {
355     *cx = (*cx - ((*x + *cx) - g_clip_right1));
356   }
357   if (*y + *cy > g_clip_bottom1)
358   {
359     *cy = (*cy - ((*y + *cy) - g_clip_bottom1));
360   }
361   *cx = *cx - dx;
362   *cy = *cy - dy;
363   if (*cx <= 0)
364   {
365     return 0;
366   }
367   if (*cy <= 0)
368   {
369     return 0;
370   }
371   *x = *x + dx;
372   *y = *y + dy;
373   if (srcx != 0)
374   {
375     *srcx = *srcx + dx;
376   }
377   if (srcy != 0)
378   {
379     *srcy = *srcy + dy;
380   }
381   return 1;
382 }
383 
384 /*****************************************************************************/
385 void
bs_rect(int x,int y,int cx,int cy,int colour,int rop)386 bs_rect(int x, int y, int cx, int cy, int colour, int rop)
387 {
388   int i;
389   int j;
390   unsigned char * p8;
391   unsigned short * p16;
392   unsigned int * p32;
393 
394   if (bs_warp_coords(&x, &y, &cx, &cy, 0, 0))
395   {
396     if (rop == 0) /* black */
397     {
398       rop = 12;
399       colour = 0;
400     }
401     else if (rop == 15) /* white */
402     {
403       rop = 12;
404       colour = 0xffffff;
405     }
406     if (rop == 12) /* copy */
407     {
408       if (g_Bpp == 1)
409       {
410         for (i = 0; i < cy; i++)
411         {
412           p8 = (unsigned char *) get_bs_ptr(x, y + i);
413           if (p8 != 0)
414           {
415             for (j = 0; j < cx; j++)
416             {
417               *p8 = colour;
418               p8++;
419             }
420           }
421         }
422       }
423       else if (g_Bpp == 2)
424       {
425         for (i = 0; i < cy; i++)
426         {
427           p16 = (unsigned short *) get_bs_ptr(x, y + i);
428           if (p16 != 0)
429           {
430             for (j = 0; j < cx; j++)
431             {
432               *p16 = colour;
433               p16++;
434             }
435           }
436         }
437       }
438       else
439       {
440         for (i = 0; i < cy; i++)
441         {
442           p32 = (unsigned int *) get_bs_ptr(x, y + i);
443           if (p32 != 0)
444           {
445             for (j = 0; j < cx; j++)
446             {
447               *p32 = colour;
448               p32++;
449             }
450           }
451         }
452       }
453     }
454     else /* slow */
455     {
456       for (i = 0; i < cy; i++)
457       {
458         for (j = 0; j < cx; j++)
459         {
460           bs_set_pixel(j + x, i + y, colour, rop, 0);
461         }
462       }
463     }
464   }
465 }
466 
467 /*****************************************************************************/
468 void
bs_screenblt(int rop,int x,int y,int cx,int cy,int srcx,int srcy)469 bs_screenblt(int rop, int x, int y, int cx, int cy,
470              int srcx, int srcy)
471 {
472   int p;
473   int i;
474   int j;
475   char * src;
476   char * dst;
477 
478   if (bs_warp_coords(&x, &y, &cx, &cy, &srcx, &srcy))
479   {
480     if (rop == 12) /* copy */
481     {
482       if (srcy < y) /* copy down - bottom to top */
483       {
484         for (i = cy - 1; i >= 0; i--)
485         {
486           src = get_bs_ptr(srcx, srcy + i);
487           dst = get_bs_ptr(x, y + i);
488           if (src != 0 && dst != 0)
489           {
490             bs_copy_mem(dst, src, cx * g_Bpp);
491           }
492         }
493       }
494       else if (srcy > y || srcx > x) /* copy up or left - top to bottom */
495       {
496         for (i = 0; i < cy; i++)
497         {
498           src = get_bs_ptr(srcx, srcy + i);
499           dst = get_bs_ptr(x, y + i);
500           if (src != 0 && dst != 0)
501           {
502             bs_copy_mem(dst, src, cx * g_Bpp);
503           }
504         }
505       }
506       else /* copy straight right */
507       {
508         for (i = 0; i < cy; i++)
509         {
510           src = get_bs_ptr(srcx, srcy + i);
511           dst = get_bs_ptr(x, y + i);
512           if (src != 0 && dst != 0)
513           {
514             bs_copy_memb(dst, src, cx * g_Bpp);
515           }
516         }
517       }
518     }
519     else /* slow */
520     {
521       if (srcy < y) /* copy down - bottom to top */
522       {
523         for (i = cy - 1; i >= 0; i--)
524         {
525           for (j = 0; j < cx; j++)
526           {
527             p = bs_get_pixel(srcx + j, srcy + i);
528             bs_set_pixel(x + j, y + i, p, rop, 0);
529           }
530         }
531       }
532       else if (srcy > y || srcx > x) /* copy up or left - top to bottom */
533       {
534         for (i = 0; i < cy; i++)
535         {
536           for (j = 0; j < cx; j++)
537           {
538             p = bs_get_pixel(srcx + j, srcy + i);
539             bs_set_pixel(x + j, y + i, p, rop, 0);
540           }
541         }
542       }
543       else /* copy straight right */
544       {
545         for (i = 0; i < cy; i++)
546         {
547           for (j = cx - 1; j >= 0; j--)
548           {
549             p = bs_get_pixel(srcx + j, srcy + i);
550             bs_set_pixel(x + j, y + i, p, rop, 0);
551           }
552         }
553       }
554     }
555   }
556 }
557 
558 /*****************************************************************************/
559 void
bs_memblt(int opcode,int x,int y,int cx,int cy,void * srcdata,int srcwidth,int srcheight,int srcx,int srcy)560 bs_memblt(int opcode, int x, int y, int cx, int cy,
561           void * srcdata, int srcwidth, int srcheight,
562           int srcx, int srcy)
563 {
564   int i;
565   int j;
566   int p;
567   char * dst;
568   char * src;
569 
570   if (bs_warp_coords(&x, &y, &cx, &cy, &srcx, &srcy))
571   {
572     if (opcode == 12) /* copy */
573     {
574       if (g_Bpp == 1)
575       {
576         src = (char *) (((unsigned char *) srcdata) + srcy * srcwidth + srcx);
577       }
578       else if (g_Bpp == 2)
579       {
580         src = (char *) (((unsigned short *) srcdata) + srcy * srcwidth + srcx);
581       }
582       else
583       {
584         src = (char *) (((unsigned int *) srcdata) + srcy * srcwidth + srcx);
585       }
586       for (i = 0; i < cy; i++)
587       {
588         dst = get_bs_ptr(x, y + i);
589         if (dst != 0)
590         {
591           bs_copy_mem(dst, src, cx * g_Bpp);
592           src += srcwidth * g_Bpp;
593         }
594       }
595     }
596     else /* slow */
597     {
598       if (g_Bpp == 1)
599       {
600         for (i = 0; i < cy; i++)
601         {
602           for (j = 0; j < cx; j++)
603           {
604             p = *(((unsigned char *) srcdata) +
605                          ((i + srcy) * srcwidth + (j + srcx)));
606             bs_set_pixel(x + j, y + i, p, opcode, 0);
607           }
608         }
609       }
610       else if (g_Bpp == 2)
611       {
612         for (i = 0; i < cy; i++)
613         {
614           for (j = 0; j < cx; j++)
615           {
616             p = *(((unsigned short *) srcdata) +
617                          ((i + srcy) * srcwidth + (j + srcx)));
618             bs_set_pixel(x + j, y + i, p, opcode, 0);
619           }
620         }
621       }
622       else
623       {
624         for (i = 0; i < cy; i++)
625         {
626           for (j = 0; j < cx; j++)
627           {
628             p = *(((unsigned int *) srcdata) +
629                          ((i + srcy) * srcwidth + (j + srcx)));
630             bs_set_pixel(x + j, y + i, p, opcode, 0);
631           }
632         }
633       }
634     }
635   }
636 }
637 
638 /*****************************************************************************/
639 void
bs_draw_glyph(int x,int y,char * glyph_data,int glyph_width,int glyph_height,int fgcolour)640 bs_draw_glyph(int x, int y, char * glyph_data, int glyph_width,
641               int glyph_height, int fgcolour)
642 {
643   int i;
644   int j;
645 
646   for (i = 0; i < glyph_height; i++)
647   {
648     for (j = 0; j < glyph_width; j++)
649     {
650       if (bs_is_pixel_on(glyph_data, j, i, glyph_width, 8))
651       {
652         bs_set_pixel(x + j, y + i, fgcolour, 12, 1);
653       }
654     }
655   }
656 }
657 
658 /*****************************************************************************/
659 /* Bresenham's line drawing algorithm */
660 void
bs_line(int opcode,int startx,int starty,int endx,int endy,int pen_width,int pen_style,int pen_colour)661 bs_line(int opcode, int startx, int starty, int endx, int endy,
662         int pen_width, int pen_style, int pen_colour)
663 {
664   int dx;
665   int dy;
666   int incx;
667   int incy;
668   int dpr;
669   int dpru;
670   int p;
671 
672   if (startx > endx)
673   {
674     dx = startx - endx;
675     incx = -1;
676   }
677   else
678   {
679     dx = endx - startx;
680     incx = 1;
681   }
682   if (starty > endy)
683   {
684     dy = starty - endy;
685     incy = -1;
686   }
687   else
688   {
689     dy = endy - starty;
690     incy = 1;
691   }
692   if (dx >= dy)
693   {
694     dpr = dy << 1;
695     dpru = dpr - (dx << 1);
696     p = dpr - dx;
697     for (; dx >= 0; dx--)
698     {
699       if (startx != endx || starty != endy)
700       {
701         bs_set_pixel(startx, starty, pen_colour, opcode, 1);
702       }
703       if (p > 0)
704       {
705         startx += incx;
706         starty += incy;
707         p += dpru;
708       }
709       else
710       {
711         startx += incx;
712         p += dpr;
713       }
714     }
715   }
716   else
717   {
718     dpr = dx << 1;
719     dpru = dpr - (dy << 1);
720     p = dpr - dy;
721     for (; dy >= 0; dy--)
722     {
723       if (startx != endx || starty != endy)
724       {
725         bs_set_pixel(startx, starty, pen_colour, opcode, 1);
726       }
727       if (p > 0)
728       {
729         startx += incx;
730         starty += incy;
731         p += dpru;
732       }
733       else
734       {
735         starty += incy;
736         p += dpr;
737       }
738     }
739   }
740 }
741 
742 /*****************************************************************************/
743 void
bs_patblt(int opcode,int x,int y,int cx,int cy,int brush_style,char * brush_pattern,int brush_x_org,int brush_y_org,int bgcolour,int fgcolour)744 bs_patblt(int opcode, int x, int y, int cx, int cy,
745           int brush_style, char * brush_pattern,
746           int brush_x_org, int brush_y_org,
747           int bgcolour, int fgcolour)
748 {
749   int i;
750   int j;
751   char ipattern[8];
752   char * b;
753 
754   b = 0;
755   switch (brush_style)
756   {
757     case 0:
758       bs_rect(x, y, cx, cy, fgcolour, opcode);
759       break;
760     case 2: /* Hatch */
761       b = g_hatch_patterns + brush_pattern[0] * 8;
762       break;
763     case 3:
764       for (i = 0; i < 8; i++)
765       {
766         ipattern[i] = ~brush_pattern[7 - i];
767       }
768       b = ipattern;
769       break;
770   }
771   if (b != 0)
772   {
773     for (i = 0; i < cy; i++)
774     {
775       for (j = 0; j < cx; j++)
776       {
777         if (bs_is_pixel_on(b, (x + j + brush_x_org) % 8,
778                            (y + i + brush_y_org) % 8, 8, 1))
779         {
780           bs_set_pixel(x + j, y + i, fgcolour, opcode, 1);
781         }
782         else
783         {
784           bs_set_pixel(x + j, y + i, bgcolour, opcode, 1);
785         }
786       }
787     }
788   }
789 }
790 
791 /*****************************************************************************/
792 void
bs_copy_box(char * dst,int x,int y,int cx,int cy,int line_size)793 bs_copy_box(char * dst, int x, int y, int cx, int cy, int line_size)
794 {
795   char * src;
796   int i;
797 
798   /* shouldn't happen */
799   if (cx < 1 || cy < 1)
800   {
801     return;
802   }
803   /* nothing to draw, memset and leave */
804   if (x + cx < 0 || y + cy < 0 || x >= g_width1 || y >= g_height1)
805   {
806     memset(dst, 0, cx * cy * g_Bpp);
807     return;
808   }
809   /* check if it goes over an edge */
810   if (x < 0 || y < 0 || x + cx > g_width1 || y + cy > g_height1)
811   {
812     memset(dst, 0, cx * cy * g_Bpp);
813     if (x < 0)
814     {
815       cx += x;
816       dst += -x * g_Bpp;
817       x = 0;
818     }
819     if (x + cx > g_width1)
820     {
821       cx = g_width1 - x;
822     }
823     for (i = 0; i < cy; i++)
824     {
825       src = get_bs_ptr(x, y + i);
826       if (src != 0)
827       {
828         bs_copy_mem(dst, src, cx * g_Bpp);
829       }
830       dst += line_size;
831     }
832   }
833   else /* whole box is within */
834   {
835     for (i = 0; i < cy; i++)
836     {
837       src = get_bs_ptr(x, y + i);
838       if (src != 0)
839       {
840         bs_copy_mem(dst, src, cx * g_Bpp);
841       }
842       dst += line_size;
843     }
844   }
845 }
846