#help_index "Graphics"

Option(OPTf_WARN_HEADER_MISMATCH, OFF);
public Bool GrPlot0(CDC *dc=gr.dc, I64 x, I64 y)
{//2D. No clipping or transformation or thick.
        U8                              *dst;
        I32                             *db;
        I64                              d, dist;
        CColorROPU32     c, color = dc->color, bkcolor = dc->bkcolor;
        Bool                     was_timer_rand = Bts(&Fs->task_flags, TASKf_NONTIMER_RAND);

        if (dc->flags & DCF_LOCATE_NEAREST)
        {
                dist = DistSqrI64(x, y, dc->cur_x, dc->cur_y);
                if (dist <= dc->nearest_dist)
                        dc->nearest_dist = dist;
        }
        if (dc->flags & DCF_RECORD_EXTENTS)
        {
                if (x < dc->min_x)
                        dc->min_x = x;

                if (x > dc->max_x)
                        dc->max_x = x;

                if (y < dc->min_y)
                        dc->min_y = y;

                if (y > dc->max_y)
                        dc->max_y = y;
        }
        if (dc->flags & DCF_DONT_DRAW)
                return TRUE;
        d = dc->width_internal * y + x;
        if (db = dc->depth_buf)
        {
                db += d;
                if (0 <= dc->db_z <= *db)
                        *db = dc->db_z;
                else
                        return TRUE;
        }
        if (color.c1.rop & (ROPBF_DITHER | ROPBF_PROBABILITY_DITHER))
        {
                if (color.c1.rop & ROPBF_PROBABILITY_DITHER)
                {
                        if (RandU16<dc->dither_probability_u16)
                        {
                                color.c1.rop = color.c0.rop;
                                color.c0         = color.c1;
                        }
                        BEqual(&Fs->task_flags, TASKf_NONTIMER_RAND, was_timer_rand);
                }
                else
                {
                        if ((x ^ y) & 1)
                        {
                                color.c1.rop = color.c0.rop;
                                color.c0         = color.c1;
                        }
                }
        }
        dst = dc->body + d;
        switch [color.c0.rop]
        {
                case ROPB_EQU:
                case ROPB_MONO:
                        *dst = color.c0.color;
                        break;

                case ROPB_COLLISION:
                        c = *dst;
                        if (c != TRANSPARENT && c != bkcolor.c0.color)
                                dc->collision_count++;
                        break;

                case ROPB_XOR:
                        *dst ^= color.c0.color;
                        break;
        }

        return TRUE;
}
Option(OPTf_WARN_HEADER_MISMATCH, ON);

public I64 GrPeek0(CDC *dc=gr.dc, I64 x, I64 y)
{//2D. No clipping or transformation.
        return dc->body[dc->width_internal * y + x];
}

#help_index "Graphics;Graphics/Device Contexts"

public I64 GrBlot(CDC *dc=gr.dc, I64 x, I64 y, CDC *img)
{//2D. Clipping but not transformation..
        I64                              i, j, k, k1, kk, kk1, w1, h1, w2, h2, dist, 
                                         leading_pixels, leading_pixel_mask, whole_I64s, 
                                         trailing_pixels, trailing_pixel_mask, 
                                reg  bit_shift, win_z_buf_line_inc, win_z_buf_line_dec, win_z_num, 
                                         color_mask;
        U8                      reg *dst, *src;
        I32                             *db;
        U16                     reg *win_z_buf_ptr;
        CColorROPU32     color, c, old_color;
        CTask                   *win_task;

        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                win_task = dc->win_task;
                x += win_task->scroll_x;
                y += win_task->scroll_y;
        }
        if (x < 0)
                w1 = -x;
        else
                w1 = 0;
        if (y < 0)
                h1 = -y;
        else
                h1 = 0;
        w2 = img->width;
        h2 = img->height;
        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                x += win_task->pix_left;
                y += win_task->pix_top;
        }
        if (dc->flags & DCF_LOCATE_NEAREST)
        {
                dist = DistSqrI64(x + img->width >> 1, y + img->height >> 1, dc->cur_x, dc->cur_y);
                if (dist <= dc->nearest_dist)
                        dc->nearest_dist = dist;
        }
        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                if (x + w1 < 0)
                        w1=-x;
                if (x + w2 > win_task->pix_right + 1)
                        w2 = win_task->pix_right + 1 - x;

                if (y + h1 < 0)
                        h1 = -y;
                if (y + h2 > win_task->pix_bottom + 1)
                        h2 = win_task->pix_bottom + 1 - y;
        }
        if (x + w2>dc->width)
                w2 = dc->width - x;
        if (y + h2 > dc->height)
                h2 = dc->height - y;
        if (w1 < w2 <= img->width && h1 < h2 <= img->height)
        {
                if (dc->flags & DCF_RECORD_EXTENTS)
                {
                        if (x + w1 < dc->min_x)
                                dc->min_x = x + w1;

                        if (x + w2 - 1 > dc->max_x)
                                dc->max_x = x + w2 - 1;

                        if (y + h1 < dc->min_y)
                                dc->min_y = y + h1;

                        if (y + h2 - 1 > dc->max_y)
                                dc->max_y = y + h2 - 1;
                }
                if (dc->flags & DCF_DONT_DRAW)
                        return 1;

                old_color = dc->color;
                db = dc->depth_buf;
                dc->depth_buf = NULL;
                dc->color &= ~ROPF_DITHER;
                color = dc->color;
                leading_pixels = -(w1 + x) & 7;
                leading_pixel_mask = gr.to_8_bits[0xFF >> leading_pixels];
                bit_shift = -x & 7;
                whole_I64s = (w2 - w1 - leading_pixels) >> 3;
                if (whole_I64s < 0)
                        whole_I64s = 0;
                trailing_pixels = (x + w2) & 7;
                trailing_pixel_mask = gr.to_8_bits[0xFF << trailing_pixels & 0xFF];
                if (leading_pixels + trailing_pixels > w2 - w1)
                {
                        leading_pixel_mask |= trailing_pixel_mask;
                        trailing_pixels = 0;
                }
                switch (color.c0.rop)
                {
                        case ROPB_COLLISION: //TODO: Might want to check win_z_buf
                                color = dc->bkcolor.c0.color;
                                k = h1 * img->width_internal;
                                k1 = (h1 + y) * dc->width_internal + x;
                                for (j = h2 - h1; j; j--)
                                {
                                        for (i = w1; i < w2; i++)
                                        {
                                                c = dc->body[k1 + i];
                                                if (c != TRANSPARENT && c != color && img->body[k + i] != TRANSPARENT)
                                                        dc->collision_count++;
                                        }
                                        k += img->width_internal;
                                        k1 += dc->width_internal;
                                }
                                break;

                        case ROPB_MONO:
                                color_mask = gr.to_8_colors[color.c0.color];
                                if (img->flags & DCF_NO_TRANSPARENTS)
                                {
                                        if (!(dc->flags & DCF_SCREEN_BITMAP) || dc->flags & DCF_ON_TOP)
                                                win_z_buf_ptr = NULL;
                                        else
                                        {
                                                win_z_num = win_task->win_z_num;
                                                win_z_buf_ptr = gr.win_z_buf(U8 *) +
                                                                                ((h1 + y) / FONT_HEIGHT * TEXT_COLS + (w1 + x) / FONT_WIDTH) * sizeof(U16);
                                                win_z_buf_line_dec = whole_I64s;
                                                if (leading_pixels)
                                                        win_z_buf_line_dec++;
                                                if (trailing_pixels)
                                                        win_z_buf_line_dec++;
                                                win_z_buf_line_dec *= sizeof(U16);
                                                win_z_buf_line_inc = TEXT_COLS * sizeof(U16) - win_z_buf_line_dec;
                                        }
                                        kk = h1 * img->width_internal + w1;
                                        kk1 = (h1 + y) * dc->width_internal + x + w1;
                                        kk = (kk - bit_shift) & ~7 + bit_shift;
                                        bit_shift *= 8;
                                        if (win_z_buf_ptr)
                                                for (j = h1; j < h2; j++)
                                                {
                                                        src = img->body + kk  & ~7;
                                                        dst = dc->body  + kk1 & ~7;
                                                        if (leading_pixels)
                                                        {
                                                                if (win_z_num >= *win_z_buf_ptr++)
                                                                {
                                                                        if (bit_shift)
                                                                                *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask |
                                                                                                           (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift)) &
                                                                                                                ~leading_pixel_mask & color_mask;
                                                                        else
                                                                                *dst(I64 *)++ = *dst(I64 *)   &  leading_pixel_mask |
                                                                                                                *src(I64 *)++ & ~leading_pixel_mask & color_mask;
                                                                }
                                                                else
                                                                {
                                                                        src(I64 *)++;
                                                                        dst(I64 *)++;
                                                                }
                                                        }
                                                        if (bit_shift)
                                                                for (i = 0; i < whole_I64s; i++)
                                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                                *dst(I64 *)++ = (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift)) &
                                                                                                                color_mask;
                                                                        else
                                                                        {
                                                                                src(I64 *)++;
                                                                                dst(I64 *)++;
                                                                        }
                                                        else
                                                                for (i = 0; i < whole_I64s; i++)
                                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                                *dst(I64 *)++ = *src(I64 *)++ & color_mask;
                                                                        else
                                                                        {
                                                                                src(I64 *)++;
                                                                                dst(I64 *)++;
                                                                        }
                                                        if (trailing_pixels && win_z_num >= *win_z_buf_ptr++)
                                                        {
                                                                if (bit_shift)
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                 (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift)) &
                                                                                                  ~trailing_pixel_mask & color_mask;
                                                                else
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                  *src(I64 *)++ & ~trailing_pixel_mask & color_mask;
                                                        }
                                                        kk  += img->width_internal;
                                                        kk1 += dc->width_internal;
                                                        if ((j + y) & 7 == 7)
                                                                win_z_buf_ptr(U8 *) += win_z_buf_line_inc;
                                                        else
                                                                win_z_buf_ptr(U8 *) -= win_z_buf_line_dec;
                                                }
                                        else
                                                for (j = h2 - h1; j; j--)
                                                {
                                                        src = img->body + kk  & ~7;
                                                        dst = dc->body  + kk1 & ~7;
                                                        if (leading_pixels)
                                                        {
                                                                if (bit_shift)
                                                                        *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask |
                                                                                                   (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift)) &
                                                                                                        ~leading_pixel_mask & color_mask;
                                                                else
                                                                        *dst(I64 *)++ = *dst(I64 *)   &  leading_pixel_mask |
                                                                                                        *src(I64 *)++ & ~leading_pixel_mask & color_mask;
                                                        }
                                                        if (bit_shift)
                                                                for (i = 0; i < whole_I64s; i++)
                                                                        *dst(I64 *)++ = (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift)) &
                                                                                                        color_mask;
                                                        else
                                                                for (i = 0; i < whole_I64s; i++)
                                                                        *dst(I64 *)++ = *src(I64 *)++ & color_mask;

                                                        if (trailing_pixels)
                                                        {
                                                                if (bit_shift)
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                 (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift)) &
                                                                                                  ~trailing_pixel_mask & color_mask;
                                                                else
                                                                        *dst(I64 *) = *dst(I64 *)   &  trailing_pixel_mask |
                                                                                                  *src(I64 *)++ & ~trailing_pixel_mask & color_mask;
                                                        }
                                                        kk  += img->width_internal;
                                                        kk1 += dc->width_internal;
                                                }
                                }
                                else
                                {
                                        k = h1 * img->width_internal;
                                        if (!(dc->flags & DCF_SCREEN_BITMAP) || dc->flags & DCF_ON_TOP)
                                        {
                                                for (j = h1; j < h2; j++)
                                                {
                                                        for (i = w1; i < w2; i++)
                                                                if (img->body[k + i])
                                                                        GrPlot0(dc, x + i, y + j);
                                                        k += img->width_internal;
                                                }
                                        }
                                        else
                                        {
                                                win_z_num = win_task->win_z_num;
                                                win_z_buf_ptr = gr.win_z_buf(U8 *) +
                                                                                ((h1 + y) / FONT_HEIGHT * TEXT_COLS + (w1 + x) / FONT_WIDTH) * sizeof(U16);
                                                win_z_buf_line_dec = whole_I64s;
                                                if (leading_pixels)
                                                        win_z_buf_line_dec++;
                                                if (trailing_pixels)
                                                        win_z_buf_line_dec++;
                                                win_z_buf_line_dec *= sizeof(U16);
                                                win_z_buf_line_inc = TEXT_COLS * sizeof(U16) - win_z_buf_line_dec;
                                                for (j = h1; j < h2; j++)
                                                {
                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                color_mask = TRUE;
                                                        else
                                                                color_mask = FALSE;
                                                        for (i = w1; i < w2;)
                                                        {
                                                                if (color_mask)
                                                                        if (img->body[k + i])
                                                                                GrPlot0(dc, x + i, y + j);
                                                                if (!((++i + x) & 7) && i < w2)
                                                                {
                                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                                color_mask = TRUE;
                                                                        else
                                                                                color_mask = FALSE;
                                                                }
                                                        }
                                                        if ((j + y) & 7 == 7)
                                                                win_z_buf_ptr(U8 *) += win_z_buf_line_inc;
                                                        else
                                                                win_z_buf_ptr(U8 *) -= win_z_buf_line_dec;
                                                        k += img->width_internal;
                                                }
                                        }
                                }
                                break;

                        case ROPB_EQU:
                                if (img->flags & DCF_NO_TRANSPARENTS)
                                {
                                        if (!(dc->flags & DCF_SCREEN_BITMAP) || dc->flags & DCF_ON_TOP)
                                                win_z_buf_ptr = NULL;
                                        else
                                        {
                                                win_z_num = win_task->win_z_num;
                                                win_z_buf_ptr = gr.win_z_buf(U8 *) +
                                                                                ((h1 + y) / FONT_HEIGHT * TEXT_COLS + (w1 + x) / FONT_WIDTH) * sizeof(U16);
                                                win_z_buf_line_dec = whole_I64s;
                                                if (leading_pixels)
                                                        win_z_buf_line_dec++;
                                                if (trailing_pixels)
                                                        win_z_buf_line_dec++;
                                                win_z_buf_line_dec *= sizeof(U16);
                                                win_z_buf_line_inc = TEXT_COLS * sizeof(U16) - win_z_buf_line_dec;
                                        }
                                        kk = h1 * img->width_internal + w1;
                                        kk1 = (h1 + y) * dc->width_internal + x + w1;
                                        kk = (kk - bit_shift) & ~7 + bit_shift;
                                        bit_shift *= 8;
                                        if (win_z_buf_ptr)
                                                for (j = h1; j < h2; j++)
                                                {
                                                        src = img->body + kk  & ~7;
                                                        dst = dc->body  + kk1 & ~7;
                                                        if (leading_pixels)
                                                        {
                                                                if (win_z_num >= *win_z_buf_ptr++)
                                                                {
                                                                        if (bit_shift)
                                                                                *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask |
                                                                                                           (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift)) &
                                                                                                                ~leading_pixel_mask;
                                                                        else
                                                                                *dst(I64 *)++ = *dst(I64 *)   &  leading_pixel_mask |
                                                                                                                *src(I64 *)++ & ~leading_pixel_mask;
                                                                }
                                                                else
                                                                {
                                                                        src(I64 *)++;
                                                                        dst(I64 *)++;
                                                                }
                                                        }
                                                        if (bit_shift)
                                                                for (i = 0; i < whole_I64s; i++)
                                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                                *dst(I64 *)++ = *src(U64 *)++ >> bit_shift |
                                                                                                                *src(I64 *) << (64 - bit_shift);
                                                                        else
                                                                        {
                                                                                src(I64 *)++;
                                                                                dst(I64 *)++;
                                                                        }
                                                        else
                                                                for (i = 0; i < whole_I64s; i++)
                                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                                *dst(I64 *)++ = *src(I64 *)++;
                                                                        else
                                                                        {
                                                                                src(I64 *)++;
                                                                                dst(I64 *)++;
                                                                        }
                                                        if (trailing_pixels && win_z_num >= *win_z_buf_ptr++)
                                                        {
                                                                if (bit_shift)
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                 (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift)) &
                                                                                                  ~trailing_pixel_mask;
                                                                else
                                                                        *dst(I64 *) = *dst(I64 *)   &  trailing_pixel_mask |
                                                                                                  *src(I64 *)++ & ~trailing_pixel_mask;
                                                        }
                                                        kk  += img->width_internal;
                                                        kk1 += dc->width_internal;
                                                        if ((j + y) & 7 == 7)
                                                                win_z_buf_ptr(U8 *) += win_z_buf_line_inc;
                                                        else
                                                                win_z_buf_ptr(U8 *) -= win_z_buf_line_dec;
                                                }
                                        else
                                                for (j = h2 - h1; j; j--)
                                                {
                                                        src = img->body + kk  & ~7;
                                                        dst = dc->body  + kk1 & ~7;
                                                        if (leading_pixels)
                                                        {
                                                                if (bit_shift)
                                                                        *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask |
                                                                                                   (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift)) &
                                                                                                        ~leading_pixel_mask;
                                                                else
                                                                        *dst(I64 *)++ = *dst(I64 *)   &  leading_pixel_mask |
                                                                                                        *src(I64 *)++ & ~leading_pixel_mask;
                                                        }
                                                        if (bit_shift)
                                                                for (i = 0; i < whole_I64s; i++)
                                                                        *dst(I64 *)++ = *src(U64 *)++ >> bit_shift |
                                                                                                        *src(I64 *) << (64 - bit_shift);
                                                        else
                                                                for (i = 0; i < whole_I64s; i++)
                                                                        *dst(I64 *)++ = *src(I64 *)++;

                                                        if (trailing_pixels)
                                                        {
                                                                if (bit_shift)
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                 (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift)) &
                                                                                                  ~trailing_pixel_mask;
                                                                else
                                                                        *dst(I64 *) = *dst(I64 *)   &  trailing_pixel_mask |
                                                                                                  *src(I64 *)++ & ~trailing_pixel_mask;
                                                        }
                                                        kk  += img->width_internal;
                                                        kk1 += dc->width_internal;
                                                }
                                }
                                else
                                {
here1a:
                                        k = h1 * img->width_internal;
                                        if (!(dc->flags & DCF_SCREEN_BITMAP) || dc->flags & DCF_ON_TOP)
                                        {
                                                for (j = h1; j < h2; j++)
                                                {
                                                        for (i = w1; i < w2; i++)
                                                        {
                                                                c = img->body[k + i];
                                                                if (c != TRANSPARENT)
                                                                {
                                                                        dc->color.c0.color = c;
                                                                        GrPlot0(dc, x + i, y + j);
                                                                }
                                                        }
                                                        k += img->width_internal;
                                                }
                                        }
                                        else
                                        {
                                                win_z_num = win_task->win_z_num;
                                                win_z_buf_ptr = gr.win_z_buf(U8 *) +
                                                                                ((h1 + y) / FONT_HEIGHT * TEXT_COLS + (w1 + x) / FONT_WIDTH) * sizeof(U16);
                                                win_z_buf_line_dec = whole_I64s;
                                                if (leading_pixels)
                                                        win_z_buf_line_dec++;
                                                if (trailing_pixels)
                                                        win_z_buf_line_dec++;
                                                win_z_buf_line_dec *= sizeof(U16);
                                                win_z_buf_line_inc = TEXT_COLS * sizeof(U16) - win_z_buf_line_dec;
                                                for (j = h1; j < h2; j++)
                                                {
                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                color_mask = TRUE;
                                                        else
                                                                color_mask = FALSE;
                                                        for (i = w1; i < w2;)
                                                        {
                                                                if (color_mask)
                                                                {
                                                                        c = img->body[k + i];
                                                                        if (c != TRANSPARENT)
                                                                        {
                                                                                dc->color.c0.color = c;
                                                                                GrPlot0(dc, x + i, y + j);
                                                                        }
                                                                }
                                                                if (!((++i + x) & 7) && i < w2)
                                                                {
                                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                                color_mask = TRUE;
                                                                        else
                                                                                color_mask = FALSE;
                                                                }
                                                        }
                                                        if ((j + y) & 7 == 7)
                                                                win_z_buf_ptr(U8 *) += win_z_buf_line_inc;
                                                        else
                                                                win_z_buf_ptr(U8 *) -= win_z_buf_line_dec;
                                                        k += img->width_internal;
                                                }
                                        }
                                        dc->color = color;
                                }
                                break;

                        case ROPB_XOR:
                                if (img->flags & DCF_NO_TRANSPARENTS)
                                {
                                        if (!(dc->flags & DCF_SCREEN_BITMAP) || dc->flags & DCF_ON_TOP)
                                                win_z_buf_ptr = NULL;
                                        else
                                        {
                                                win_z_num = win_task->win_z_num;
                                                win_z_buf_ptr = gr.win_z_buf(U8 *) +
                                                                                ((h1 + y) / FONT_HEIGHT * TEXT_COLS + (w1 + x) / FONT_WIDTH) * sizeof(U16);
                                                win_z_buf_line_dec = whole_I64s;
                                                if (leading_pixels)
                                                        win_z_buf_line_dec++;
                                                if (trailing_pixels)
                                                        win_z_buf_line_dec++;
                                                win_z_buf_line_dec *= sizeof(U16);
                                                win_z_buf_line_inc = TEXT_COLS * sizeof(U16) - win_z_buf_line_dec;
                                        }
                                        kk = h1 * img->width_internal + w1;
                                        kk1 = (h1 + y) * dc->width_internal + x + w1;
                                        kk = (kk - bit_shift) & ~7 + bit_shift;
                                        bit_shift *= 8;
                                        if (win_z_buf_ptr)
                                                for (j = h1; j < h2; j++)
                                                {
                                                        src = img->body + kk  & ~7;
                                                        dst = dc->body  + kk1 & ~7;
                                                        if (leading_pixels)
                                                        {
                                                                if (win_z_num >= *win_z_buf_ptr++)
                                                                {
                                                                        if (bit_shift)
                                                                                *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask |
                                                                                                           (*dst(I64 *) ^
                                                                                                                        (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift))) &
                                                                                                                ~leading_pixel_mask;
                                                                        else
                                                                                *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask |
                                                                                                           (*dst(I64 *) ^ *src(I64 *)++) & ~leading_pixel_mask;
                                                                }
                                                                else
                                                                {
                                                                        src(I64 *)++;
                                                                        dst(I64 *)++;
                                                                }
                                                        }
                                                        if (bit_shift)
                                                                for (i = 0; i < whole_I64s; i++)
                                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                                *dst(I64 *)++ ^= *src(U64 *)++ >> bit_shift |
                                                                                                                 *src(I64 *) << (64 - bit_shift);
                                                                        else
                                                                        {
                                                                                src(I64 *)++;
                                                                                dst(I64 *)++;
                                                                        }
                                                        else
                                                                for (i = 0; i < whole_I64s; i++)
                                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                                *dst(I64 *)++ ^= *src(I64 *)++;
                                                                        else
                                                                        {
                                                                                src(I64 *)++;
                                                                                dst(I64 *)++;
                                                                        }
                                                        if (trailing_pixels && win_z_num >= *win_z_buf_ptr++)
                                                        {
                                                                if (bit_shift)
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                 (*dst(I64 *) ^
                                                                                                        (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift))) &
                                                                                                  ~trailing_pixel_mask;
                                                                else
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                 (*dst(I64 *) ^ *src(I64 *)++) & ~trailing_pixel_mask;
                                                        }
                                                        kk  += img->width_internal;
                                                        kk1 += dc->width_internal;
                                                        if ((j + y) & 7 == 7)
                                                                win_z_buf_ptr(U8 *) += win_z_buf_line_inc;
                                                        else
                                                                win_z_buf_ptr(U8 *) -= win_z_buf_line_dec;
                                                }
                                        else
                                                for (j = h2 - h1; j; j--)
                                                {
                                                        src = img->body + kk  & ~7;
                                                        dst = dc->body  + kk1 & ~7;
                                                        if (leading_pixels)
                                                        {
                                                                if (bit_shift)
                                                                        *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask |
                                                                                                   (*dst(I64 *) ^
                                                                                                                (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift))) &
                                                                                                        ~leading_pixel_mask;
                                                                else
                                                                        *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask |
                                                                                                   (*dst(I64 *) ^ *src(I64 *)++) & ~leading_pixel_mask;
                                                        }
                                                        if (bit_shift)
                                                                for (i = 0; i < whole_I64s; i++)
                                                                        *dst(I64 *)++ ^= *src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift);
                                                        else
                                                                for (i = 0; i < whole_I64s; i++)
                                                                        *dst(I64 *)++ ^= *src(I64 *)++;
                                                        if (trailing_pixels)
                                                        {
                                                                if (bit_shift)
                                                                        *dst(I64 *) = *dst(I64 *)&trailing_pixel_mask |
                                                                                                 (*dst(I64 *) ^
                                                                                                        (*src(U64 *)++ >> bit_shift | *src(I64 *) << (64 - bit_shift))) &
                                                                                                  ~trailing_pixel_mask;
                                                                else
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                 (*dst(I64 *) ^ *src(I64 *)++) & ~trailing_pixel_mask;
                                                        }
                                                        kk  += img->width_internal;
                                                        kk1 += dc->width_internal;
                                                }
                                }
                                else
                                        goto here1a;
                                break;
                }
                dc->depth_buf   = db;
                dc->color               = old_color;
                return 1;
        }
        else
                return 0;
}

#help_index "Graphics/Device Contexts"

U8 *GrBitMap4ToBitMap8(U8 *dst, U8 *src, I64 src_size, I64 bkcolor)
{
        I64 c, k, i = src_size * 2, i1 = i >> 3;

        for (k = 0; k < i; k++)
        {
                c = 0;
                if (Bt(src,                      k)) c |= 1;
                if (Bt(src + i1,         k)) c |= 2;
                if (Bt(src + i1 * 2, k)) c |= 4;
                if (Bt(src + i1 * 3, k)) c |= 8;
                if (c == bkcolor)                c  = TRANSPARENT;
                *dst++ = c;
        }

        return dst;
}

U8 *GrBitMap1ToBitMap8(U8 *dst, U8 *src, I64 src_size, I64 bkcolor)
{
        I64 c, k, i = src_size * 8;

        for (k = 0; k < i; k++)
        {
                c = 0;
                if (Bt(src, k))   c = COLOR_MONO;
                if (c == bkcolor) c = TRANSPARENT;
                *dst++ = c;
        }

        return dst;
}

public CDC *DCExt(CDC *dc=gr.dc, I64 x1, I64 y1, I64 x2, I64 y2, CTask *task=NULL)
{//Extract new device context rect from device context.
        CDC       *res;
        CTask *win_task;

        if (x1 > x2)
                SwapI64(&x1, &x2);
        if (y1 > y2)
                SwapI64(&y1, &y2);
        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                win_task = dc->win_task;
                x1 += win_task->pix_left + win_task->scroll_x;
                y1 += win_task->pix_top  + win_task->scroll_y;
                x2 += win_task->pix_left + win_task->scroll_x;
                y2 += win_task->pix_top  + win_task->scroll_y;
        }
        res = DCNew(x2 - x1 + 1, y2 -y1 + 1, task);
        DCFill(res);
        GrBlot(res, -x1, -y1, dc);

        return res;
}

public CDC *DCDiff(CDC *base, CDC *update)
{//Trim to win of what has chged.
        I64  i, x1 = 0, y1 = 0, x2 = update->width - 1, y2 = update->height - 1; //inclusive
        U32 *ptr_base, *ptr_update;
        CDC *res;

        ptr_base   = base->body;
        ptr_update = update->body;
        while (y1 <= y2)
        {
                i = update->width >> 2;
                while (i--)
                        if (*ptr_base++ != *ptr_update++)
                                goto df_y2;
                i = update->width & 3;
                while (i--)
                        if (*ptr_base(U8 *)++ != *ptr_update(U8 *)++)
                                goto df_y2;
                y1++;
        }
        return NULL;
df_y2:
        ptr_base   = base->body   + base->width_internal        * base->height;
        ptr_update = update->body + update->width_internal      * update->height;
        while (y1 < y2)
        {
                i = update->width >> 2;
                while (i--)
                        if (*--ptr_base != *--ptr_update)
                                goto df_x1;
                i = update->width & 3;
                while (i--)
                        if (*--ptr_base(U8 *) != *--ptr_update(U8 *))
                                goto df_x1;
                y2--;
        }
df_x1:
        while (x1 < x2)
        {
                for (i = y1; i <= y2; i++)
                        if (GrPeek0(base, x1, i) != GrPeek0(update, x1, i))
                                 goto df_x2;
                x1++;
        }
df_x2:
        while (x1 < x2)
        {
                for (i = y1; i <= y2; i++)
                        if (GrPeek0(base, x2, i) != GrPeek0(update, x2, i))
                                 goto df_done;
                x2--;
        }
df_done:
        res = DCExt(update, x1, y1, x2, y2);
        res->x0 = x1;
        res->y0 = y1;

        return res;
}

#help_index "Graphics/Char;Char/Graphics"

public I64 GrPutChar(CDC *dc=gr.dc, I64 x, I64 y, U8 ch)
{//2D. Clipping but not transformation.
        U8                      reg *src, reg *dst, *font_ptr;
        I64                              i, m, leading_pixels, trailing_pixels, leading_pixel_mask, trailing_pixel_mask, 
                                         j, k1, kk1, w1, h1, w2, h2, reg bit_shift, reg color_mask, dist;
        CColorROPU32     color, c;
        CTask                   *win_task;

        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                win_task = dc->win_task;
                x += win_task->scroll_x;
                y += win_task->scroll_y;
        }

        if (x < 0)
                w1 = -x;
        else
                w1 = 0;
        if (y < 0)
                h1 = -y;
        else
                h1 = 0;
        w2 = FONT_WIDTH;
        h2 = FONT_HEIGHT;

        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                x += win_task->pix_left;
                y += win_task->pix_top;
        }
        if (dc->flags & DCF_LOCATE_NEAREST)
        {
                dist = DistSqrI64(x + w2 >> 1, y + h2 >> 1, dc->cur_x, dc->cur_y);
                if (dist <= dc->nearest_dist)
                        dc->nearest_dist = dist;
        }
        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                if (x + w1 < 0)
                        w1 = -x;
                if (x + w2 > win_task->pix_right + 1)
                        w2 = win_task->pix_right + 1 - x;

                if (y + h1 < 0)
                        h1 = -y;
                if (y + h2 > win_task->pix_bottom + 1)
                        h2 = win_task->pix_bottom + 1 - y;
        }
        if (x + w2 > dc->width)
                w2 = dc->width - x;
        if (y + h2>dc->height)
                h2 = dc->height - y;
        if (w1 < w2 <= FONT_WIDTH && h1 < h2 <= FONT_HEIGHT)
        {
                if (dc->flags & DCF_RECORD_EXTENTS)
                {
                        if (x + w1 < dc->min_x)
                                dc->min_x = x + w1;

                        if (x + w2 - 1 > dc->max_x)
                                dc->max_x = x + w2 - 1;

                        if (y + h1      < dc->min_y)
                                dc->min_y = y + h1;

                        if (y + h2 - 1 > dc->max_y)
                                dc->max_y = y + h2 - 1;
                }
                if (dc->flags & DCF_DONT_DRAW)
                        return 1;
                color = dc->color;
                leading_pixels = -(w1 + x) & 7;
                if (!leading_pixels)
                        leading_pixels = 8;
                leading_pixel_mask = gr.to_8_bits[0xFF >> leading_pixels];
                bit_shift = -x & 7;
                trailing_pixels = (x + w2) & 7;
                trailing_pixel_mask = gr.to_8_bits[0xFF << trailing_pixels & 0xFF];
                if (leading_pixels + trailing_pixels > w2 - w1)
                {
                        leading_pixel_mask |= trailing_pixel_mask;
                        trailing_pixels = 0;
                }
                font_ptr = &text.font(U8 *)[FONT_HEIGHT * ch + h1];
                if (color.c0.rop == ROPB_COLLISION)
                {
                        m = w1 & (FONT_WIDTH - 1);
#assert FONT_WIDTH == 8
                        color =dc->bkcolor.c0.color;
                        for (i = w1; i < w2; i++, m++)
                        {
                                k1 = (h1 + y) * dc->width_internal + x;
                                src = font_ptr;
                                for (j = h2 - h1; j; j--)
                                {
                                        c = dc->body[k1 + i];
                                        if (c != TRANSPARENT && c != color && Bt(src, m))
                                                dc->collision_count++;
                                        k1 += dc->width_internal;
                                        src++;
                                }
                        }
                }
                else
                {
                        color_mask = gr.to_8_colors[color.c0.color];
                        k1 = x + w1;
                        kk1 = (h1 + y) * dc->width_internal + k1;
                        if (!(dc->flags & DCF_SCREEN_BITMAP) || dc->flags & DCF_ON_TOP)
                        {
                                if (leading_pixels)
                                {
                                        dst = dc->body + kk1 & ~7;
                                        src = font_ptr;
                                        if (bit_shift)
                                                src--;
                                        switch [color.c0.rop]
                                        {
                                                case ROPB_EQU:
                                                case ROPB_MONO:
                                                        for (j = h2 - h1; j; j--)
                                                        {
                                                                m = gr.to_8_bits[*src(U16 *) >> bit_shift & 0xFF];
                                                                *dst(I64 *) = *dst(I64 *) & leading_pixel_mask |
                                                                                         (color_mask & m | *dst(I64 *) & ~m) & ~leading_pixel_mask;
                                                                src++;
                                                                dst += dc->width_internal;
                                                        }
                                                        break;

                                                case ROPB_XOR:
                                                        if (color_mask)
                                                        {
                                                                for (j = h2 - h1; j; j--)
                                                                {
                                                                        *dst(I64 *) = *dst(I64 *) & leading_pixel_mask |
                                                                                                 (*dst(I64 *) ^ gr.to_8_bits[*src(U16 *) >> bit_shift & 0xFF]) &
                                                                                                  ~leading_pixel_mask;
                                                                        src++;
                                                                        dst += dc->width_internal;
                                                                }
                                                        }
                                                        break;
                                        }
                                        kk1 += 8;
                                }
                                if (trailing_pixels)
                                {
                                        dst = dc->body + kk1 & ~7;
                                        src = font_ptr + 1;
                                        if (bit_shift)
                                                src--;
                                        switch [color.c0.rop]
                                        {
                                                case ROPB_EQU:
                                                case ROPB_MONO:
                                                        for (j = h2 - h1; j; j--)
                                                        {
                                                                m = gr.to_8_bits[*src(U16 *) >> bit_shift & 0xFF];
                                                                *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                         (color_mask & m | *dst(I64 *) & ~m) & ~trailing_pixel_mask;
                                                                src++;
                                                                dst += dc->width_internal;
                                                        }
                                                        break;

                                                case ROPB_XOR:
                                                        if (color_mask)
                                                                for (j = h2 - h1; j; j--)
                                                                {
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                 (*dst(I64 *) ^ gr.to_8_bits[*src(U16 *) >> bit_shift & 0xFF]) &
                                                                                                  ~trailing_pixel_mask;
                                                                        src++;
                                                                        dst += dc->width_internal;
                                                                }
                                                        break;
                                        }
                                }
                        }
                        else
                        {
                                if (leading_pixels)
                                {
                                        dst = dc->body + kk1 & ~7;
                                        src = font_ptr;
                                        if (bit_shift)
                                                src--;
                                        switch [color.c0.rop]
                                        {
                                                case ROPB_EQU:
                                                case ROPB_MONO:
                                                        for (j = h1; j < h2; j++)
                                                        {
                                                                if (!IsPixCovered0(win_task, k1, y + j))
                                                                {
                                                                        m = gr.to_8_bits[*src(U16 *) >> bit_shift & 0xFF];
                                                                        *dst(I64 *) = *dst(I64 *) & leading_pixel_mask |
                                                                                                 (color_mask & m | *dst(I64 *) & ~m) & ~leading_pixel_mask;
                                                                }
                                                                src++;
                                                                dst += dc->width_internal;
                                                        }
                                                        break;

                                                case ROPB_XOR:
                                                        if (color_mask)
                                                                for (j = h1; j < h2; j++)
                                                                {
                                                                        if (!IsPixCovered0(win_task, k1, y + j))
                                                                                *dst(I64 *) = *dst(I64 *) & leading_pixel_mask |
                                                                                                         (*dst(I64 *) ^ gr.to_8_bits[*src(U16 *) >> bit_shift & 0xFF]) &
                                                                                                          ~leading_pixel_mask;
                                                                        src++;
                                                                        dst += dc->width_internal;
                                                                }
                                                        break;
                                        }
                                        k1 += 8;
                                        kk1 += 8;
                                }
                                if (trailing_pixels)
                                {
                                        dst = dc->body + kk1 & ~7;
                                        src = font_ptr + 1;
                                        if (bit_shift)
                                                src--;
                                        switch [color.c0.rop]
                                        {
                                                case ROPB_EQU:
                                                case ROPB_MONO:
                                                        for (j = h1; j < h2; j++)
                                                        {
                                                                if (!IsPixCovered0(win_task, k1, y + j))
                                                                {
                                                                        m = gr.to_8_bits[*src(U16 *) >> bit_shift & 0xFF];
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                 (color_mask & m | *dst(I64 *) & ~m) & ~trailing_pixel_mask;
                                                                }
                                                                src++;
                                                                dst += dc->width_internal;
                                                        }
                                                        break;

                                                case ROPB_XOR:
                                                        if (color_mask)
                                                                for (j  =h1; j < h2; j++)
                                                                {
                                                                        if (!IsPixCovered0(win_task, k1, y + j))
                                                                                *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                         (*dst(I64 *) ^ gr.to_8_bits[*src(U16 *) >> bit_shift & 0xFF]) &
                                                                                                          ~trailing_pixel_mask;
                                                                        src++;
                                                                        dst += dc->width_internal;
                                                                }
                                                        break;
                                        }
                                }
                        }
                }
                return 1;
        }
        else
                return 0;
}

I64 GrPutS(CDC *dc=gr.dc, I64 x, I64 y, U8 *_s)
{//Use GrPrint()
        I64 x0, sx = 0, sy = 0, res;

        if (!_s)
                return 0;
        x0 = x;
        res = 0;
        while (*_s)
        {
                if (*_s == '\n')
                {
                        x = x0;
                        y += FONT_HEIGHT;
                        _s++;
                }
                else if (*_s == '\t')
                {
                        x = x0 + CeilU64(x - x0 + FONT_WIDTH, 8 * FONT_WIDTH);
                        _s++;
                }
                else if (*_s(U32 *) == '$SY,')
                {
                        if (_s[4] == '-')
                        {
                                _s++;
                                sy = '0' - _s[4];
                        }
                        else
                                sy = _s[4] - '0';
                        _s += 6;
                }
                else if (*_s(U32 *) == '$SX,')
                {
                        if (_s[4] == '-')
                        {
                                _s++;
                                sx = '0' - _s[4];
                        }
                        else
                                sx = _s[4] - '0';
                        _s += 6;
                }
                else
                {
                        res += GrPutChar(dc, x + sx, y + sy, *_s);
                        x += FONT_WIDTH;
                        _s++;
                }
        }

        return res;
}

I64 GrVPutS(CDC *dc=gr.dc, I64 x, I64 y, U8 *_s)
{//Vertical Text.  Use GrVPrint()
        I64 y0, sx = 0, sy = 0, res;
        U8  buf[2];

        if (!_s)
                return 0;
        y0 = y;
        res = 0;
        buf[1] = 0;
        while (*_s)
        {
                if (*_s == '\n')
                {
                        y = y0;
                        x += FONT_WIDTH;
                        _s++;
                }
                else if (*_s == '\t')
                {
                        y = y0 + CeilU64(y - y0 + FONT_HEIGHT, 8 * FONT_HEIGHT);
                        _s++;
                }
                else if (*_s(U32 *) == '$SY,')
                {
                        if (_s[4] == '-')
                        {
                                _s++;
                                sx = '0' - _s[4];
                        }
                        else
                                sx = _s[4] - '0';
                        _s += 6;
                }
                else if (*_s(U32 *) == '$SX,')
                {
                        if (_s[4] == '-')
                        {
                                _s++;
                                sy = '0' - _s[4];
                        }
                        else
                                sy = _s[4] - '0';
                        _s += 6;
                }
                else
                {
                        *buf = *_s++;
                        res += GrPutS(dc, x, y, buf);
                        y += FONT_HEIGHT;
                }
        }

        return res;
}

public I64 GrPrint(CDC *dc=gr.dc, I64 x, I64 y, U8 *format, ...)
{//2D. Clipping but not transformation.
        I64 res;
        U8 *buf = StrPrintJoin(NULL, format, argc, argv);

        res = GrPutS(dc, x, y, buf);
        Free(buf);

        return res;
}

public I64 GrVPrint(CDC *dc=gr.dc, I64 x, I64 y, U8 *format, ...)
{//2D. Vertical text. Clipping but not transformation.
        I64 res;
        U8 *buf = StrPrintJoin(NULL, format, argc, argv);

        res = GrVPutS(dc, x, y, buf);
        Free(buf);

        return res;
}

#help_index "Graphics"
public I64 GrRect(CDC *dc=gr.dc, I64 x, I64 y, I64 w, I64 h)
{//2D. Width Height. Clipping but not transformation.
//Returns count of pixs changed.
        I64                              i, res = 0, j, k1, kk1, w1, h1, w2, h2, dist, 
                                         leading_pixels, original_leading_pixels, whole_I64s, 
                                         trailing_pixels, leading_pixel_mask, trailing_pixel_mask, 
                                         win_z_buf_line_inc, win_z_buf_line_dec, win_z_num, color_mask;
        U8                      reg *dst;
        U16                     reg *win_z_buf_ptr;
        CColorROPU32     color, c, dither_colors;
        Bool                     dither, probability_dither, was_timer_rand = Bts(&Fs->task_flags, TASKf_NONTIMER_RAND);
        CTask                   *win_task;

        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                win_task = dc->win_task;
                x += win_task->scroll_x;
                y += win_task->scroll_y;
        }

        if (x < 0)
                w1 = -x;
        else
                w1 = 0;
        if (y < 0)
                h1 = -y;
        else
                h1 = 0;
        w2 = w;
        h2 = h;

        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                x += win_task->pix_left;
                y += win_task->pix_top;
        }
        if (dc->flags & DCF_LOCATE_NEAREST)
        {//TODO:Untested
                if (x <= dc->cur_x <= x + w && y <= dc->cur_y <= y + h)
                        dist = 0;
                else
                        dist = DistSqrI64(x + w >> 1, y + h >> 1, dc->cur_x, dc->cur_y);
                if (dist <= dc->nearest_dist)
                        dc->nearest_dist = dist;
        }
        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                if (x + w1 < 0)
                        w1 = -x;
                if (x + w2 > win_task->pix_right + 1)
                        w2 = win_task->pix_right + 1 - x;

                if (y + h1 < 0)
                        h1 = -y;
                if (y + h2 > win_task->pix_bottom + 1)
                        h2 = win_task->pix_bottom + 1 - y;
        }
        if (x + w2 > dc->width)
                w2 = dc->width - x;

        if (y + h2 > dc->height)
                h2 = dc->height - y;

        if (w1 < w2 <= w && h1 < h2 <= h)
        {
                if (dc->flags & DCF_RECORD_EXTENTS)
                {
                        if (x + w1      < dc->min_x)
                                dc->min_x = x + w1;

                        if (x + w2 - 1 > dc->max_x)
                                dc->max_x = x + w2 - 1;

                        if (y + h1      < dc->min_y)
                                dc->min_y = y + h1;

                        if (y + h2 - 1 > dc->max_y)
                                dc->max_y = y + h2 - 1;
                }
                if (dc->flags & DCF_DONT_DRAW)
                        return TRUE;
                color = dc->color;
                if (color.c1.rop & (ROPBF_DITHER | ROPBF_PROBABILITY_DITHER))
                {
                        dither = TRUE;
                        if (color.c1.rop & ROPBF_PROBABILITY_DITHER)
                        {
                                probability_dither = TRUE;
                                color.c1.rop = color.c0.rop;
                                dither_colors = color;
                        }
                        else
                        {
                                probability_dither = FALSE;
                                color.c1.rop = color.c0.rop;
                        }
                }
                else
                        dither = FALSE;
                original_leading_pixels = leading_pixels = -(w1 + x) & 7;
                leading_pixel_mask = gr.to_8_bits[0xFF >> leading_pixels];
                whole_I64s = (w2 - w1 - leading_pixels) >> 3;
                if (whole_I64s < 0)
                        whole_I64s = 0;
                trailing_pixels = (x + w2) & 7;
                trailing_pixel_mask = gr.to_8_bits[0xFF << trailing_pixels & 0xFF];
                if (leading_pixels + trailing_pixels > w2 - w1)
                {
                        leading_pixel_mask |= trailing_pixel_mask;
                        leading_pixels = w2 - w1; //Correct so it's right for res.
                        trailing_pixels = 0;
                }
                if (color.c0.rop == ROPB_COLLISION)
                {//TODO: Might want to check win_z_buf
                        color = dc->bkcolor.c0.color;
                        k1 = (h1 + y) * dc->width_internal + x;
                        res = -dc->collision_count;
                        for (j = h2 - h1; j; j--)
                        {
                                for (i = w1; i < w2; i++)
                                {
                                        c = dc->body[k1 + i];
                                        if (c != TRANSPARENT && c != color)
                                                dc->collision_count++;
                                }
                                k1 += dc->width_internal;
                        }
                        res += dc->collision_count;
                }
                else
                {
                        if (!(dc->flags & DCF_SCREEN_BITMAP) || dc->flags & DCF_ON_TOP)
                                win_z_buf_ptr = NULL;
                        else
                        {
                                win_z_num = win_task->win_z_num;
                                win_z_buf_ptr = gr.win_z_buf(U8 *) +
                                                                ((h1 + y) / FONT_HEIGHT * TEXT_COLS + (w1 + x) / FONT_WIDTH) * sizeof(U16);
                                win_z_buf_line_dec = whole_I64s;
                                if (leading_pixels)
                                        win_z_buf_line_dec++;
                                if (trailing_pixels)
                                        win_z_buf_line_dec++;
                                win_z_buf_line_dec *= sizeof(U16);
                                win_z_buf_line_inc = TEXT_COLS * sizeof(U16) - win_z_buf_line_dec;
                        }
                        kk1 = (h1 + y) * dc->width_internal + x + w1;
                        if (dither)
                        {
                                if (probability_dither)
                                {
                                        if (RandU16 < dc->dither_probability_u16)
                                                color.c0 = dither_colors.c1;
                                        else
                                                color.c0 = dither_colors.c0;
                                        switch [color.c0.rop]
                                        {
                                                case ROPB_EQU:
                                                case ROPB_MONO:
                                                        if (win_z_buf_ptr)
                                                        {
                                                                res = 0;
                                                                for (j = h1; j < h2; j++)
                                                                {
                                                                        color_mask = gr.to_8_colors[color.c0.color];
                                                                        dst = dc->body + kk1 & ~7;
                                                                        if (leading_pixels)
                                                                        {
                                                                                if (win_z_num >= *win_z_buf_ptr++)
                                                                                {
                                                                                        *dst(I64 *) = *dst(I64 *) & leading_pixel_mask | color_mask & ~leading_pixel_mask;
                                                                                        res += leading_pixels;
                                                                                }
                                                                                dst(I64 *)++;
                                                                        }
                                                                        for (i = 0; i < whole_I64s; i++, dst(I64 *)++)
                                                                                if (win_z_num >= *win_z_buf_ptr++)
                                                                                {
                                                                                        *dst(I64 *) = color_mask;
                                                                                        res += 8;
                                                                                }
                                                                        if (trailing_pixels && win_z_num >= *win_z_buf_ptr++)
                                                                        {
                                                                                *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask | color_mask & ~trailing_pixel_mask;
                                                                                res += trailing_pixels;
                                                                        }
                                                                        if ((j + y) & 7 == 7)
                                                                                win_z_buf_ptr(U8 *) += win_z_buf_line_inc;
                                                                        else
                                                                                win_z_buf_ptr(U8 *) -= win_z_buf_line_dec;
                                                                        kk1 += dc->width_internal;
                                                                        if (RandU16 < dc->dither_probability_u16)
                                                                                color.c0 = dither_colors.c1;
                                                                        else
                                                                                color.c0 = dither_colors.c0;
                                                                }
                                                        }
                                                        else
                                                        {
                                                                for (j = h2 - h1; j; j--)
                                                                {
                                                                        color_mask = gr.to_8_colors[color.c0.color];
                                                                        dst = dc->body + kk1 & ~7;
                                                                        if (leading_pixels)
                                                                                *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask | color_mask & ~leading_pixel_mask;
                                                                        for (i = 0; i < whole_I64s; i++, dst(I64 *)++)
                                                                                *dst(I64 *) = color_mask;
                                                                        if (trailing_pixels)
                                                                                *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask | color_mask & ~trailing_pixel_mask;
                                                                        kk1 += dc->width_internal;
                                                                        if (RandU16 < dc->dither_probability_u16)
                                                                                color.c0 = dither_colors.c1;
                                                                        else
                                                                                color.c0 = dither_colors.c0;
                                                                }
                                                                res = (h2 - h1) * (w2 - w1);
                                                        }
                                                        BEqual(&Fs->task_flags, TASKf_NONTIMER_RAND, was_timer_rand);

                                                        break;

                                                case ROPB_XOR:
                                                        if (win_z_buf_ptr)
                                                        {
                                                                res = 0;
                                                                for (j = h1; j < h2; j++)
                                                                {
                                                                        color_mask = gr.to_8_colors[color.c0.color];
                                                                        dst = dc->body + kk1 & ~7;
                                                                        if (leading_pixels)
                                                                        {
                                                                                if (win_z_num >= *win_z_buf_ptr++)
                                                                                {
                                                                                        *dst(I64 *) = *dst(I64 *) & leading_pixel_mask |
                                                                                                                  *dst(I64 *) ^ color_mask & ~leading_pixel_mask;
                                                                                        res += leading_pixels;
                                                                                }
                                                                                dst(I64 *)++;
                                                                        }
                                                                        for (i = 0; i < whole_I64s; i++, dst(I64 *)++)
                                                                                if (win_z_num >= *win_z_buf_ptr++)
                                                                                {
                                                                                        *dst(I64 *) ^= color_mask;
                                                                                        res += 8;
                                                                                }
                                                                        if (trailing_pixels && win_z_num >= *win_z_buf_ptr++)
                                                                        {
                                                                                *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                          *dst(I64 *) ^ color_mask & ~trailing_pixel_mask;
                                                                                res += trailing_pixels;
                                                                        }
                                                                        if ((j + y) & 7 == 7)
                                                                                win_z_buf_ptr(U8 *) += win_z_buf_line_inc;
                                                                        else
                                                                                win_z_buf_ptr(U8 *) -= win_z_buf_line_dec;
                                                                        kk1 += dc->width_internal;
                                                                        if (RandU16 < dc->dither_probability_u16)
                                                                                color.c0 = dither_colors.c1;
                                                                        else
                                                                                color.c0 = dither_colors.c0;
                                                                }
                                                        }
                                                        else
                                                        {
                                                                for (j = h2 - h1; j; j--)
                                                                {
                                                                        color_mask = gr.to_8_colors[color.c0.color];
                                                                        dst = dc->body + kk1 & ~7;
                                                                        if (leading_pixels)
                                                                                *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask |
                                                                                                                *dst(I64 *) ^ color_mask & ~leading_pixel_mask;
                                                                        for (i = 0; i < whole_I64s; i++, dst(I64 *)++)
                                                                                *dst(I64 *) ^= color_mask;
                                                                        if (trailing_pixels)
                                                                                *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                          *dst(I64 *) ^ color_mask & ~trailing_pixel_mask;
                                                                        kk1 += dc->width_internal;
                                                                        if (RandU16 < dc->dither_probability_u16)
                                                                                color.c0 = dither_colors.c1;
                                                                        else
                                                                                color.c0 = dither_colors.c0;
                                                                }
                                                                res = (h2 - h1) * (w2 - w1);
                                                        }
                                                        BEqual(&Fs->task_flags, TASKf_NONTIMER_RAND, was_timer_rand);

                                                        break;
                                        }
                                }
                                else
                                {
                                        BEqual(&Fs->task_flags, TASKf_NONTIMER_RAND, was_timer_rand);

                                        if (((x + w1 - original_leading_pixels) ^ (y + h1)) & 1)
                                                SwapU16(&color.c0, &color.c1);
                                        switch [color.c0.rop]
                                        {
                                                case ROPB_EQU:
                                                case ROPB_MONO:
                                                        if (win_z_buf_ptr)
                                                        {
                                                                res = 0;
                                                                for (j = h1; j < h2; j++)
                                                                {
                                                                        color_mask = gr.to_8_bits[0x55] & gr.to_8_colors[color.c0.color] |
                                                                                                 gr.to_8_bits[0xAA] & gr.to_8_colors[color.c1.color];
                                                                        dst = dc->body + kk1 & ~7;
                                                                        if (leading_pixels)
                                                                        {
                                                                                if (win_z_num >= *win_z_buf_ptr++)
                                                                                {
                                                                                        *dst(I64 *) = *dst(I64 *) & leading_pixel_mask | color_mask & ~leading_pixel_mask;
                                                                                        res += leading_pixels;
                                                                                }
                                                                                dst(I64 *)++;
                                                                        }
                                                                        for (i = 0; i < whole_I64s; i++, dst(I64 *)++)
                                                                                if (win_z_num >= *win_z_buf_ptr++)
                                                                                {
                                                                                        *dst(I64 *) = color_mask;
                                                                                        res += 8;
                                                                                }
                                                                        if (trailing_pixels && win_z_num >= *win_z_buf_ptr++)
                                                                        {
                                                                                *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask | color_mask & ~trailing_pixel_mask;
                                                                                res += trailing_pixels;
                                                                        }
                                                                        if ((j + y) & 7 == 7)
                                                                                win_z_buf_ptr(U8 *) += win_z_buf_line_inc;
                                                                        else
                                                                                win_z_buf_ptr(U8 *) -= win_z_buf_line_dec;
                                                                        kk1 += dc->width_internal;
                                                                        SwapU16(&color.c0, &color.c1);
                                                                }
                                                        }
                                                        else
                                                        {
                                                                for (j = h2 - h1; j; j--)
                                                                {
                                                                        color_mask = gr.to_8_bits[0x55] & gr.to_8_colors[color.c0.color] |
                                                                                                 gr.to_8_bits[0xAA] & gr.to_8_colors[color.c1.color];
                                                                        dst = dc->body + kk1 & ~7;
                                                                        if (leading_pixels)
                                                                                *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask | color_mask & ~leading_pixel_mask;
                                                                        for (i = 0; i < whole_I64s; i++, dst(I64 *)++)
                                                                                *dst(I64 *) = color_mask;
                                                                        if (trailing_pixels)
                                                                                *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask | color_mask & ~trailing_pixel_mask;
                                                                        kk1 += dc->width_internal;
                                                                        SwapU16(&color.c0, &color.c1);
                                                                }
                                                                res = (h2 - h1) * (w2 - w1);
                                                        }
                                                        break;

                                                case ROPB_XOR:
                                                        if (win_z_buf_ptr)
                                                        {
                                                                res = 0;
                                                                for (j = h1; j < h2; j++)
                                                                {
                                                                        color_mask = gr.to_8_bits[0x55] & gr.to_8_colors[color.c0.color] |
                                                                                                 gr.to_8_bits[0xAA] & gr.to_8_colors[color.c1.color];
                                                                        dst = dc->body + kk1 & ~7;
                                                                        if (leading_pixels)
                                                                        {
                                                                                if (win_z_num >= *win_z_buf_ptr++)
                                                                                {
                                                                                        *dst(I64 *) = *dst(I64 *) & leading_pixel_mask |
                                                                                                                  *dst(I64 *) ^ color_mask & ~leading_pixel_mask;
                                                                                        res += leading_pixels;
                                                                                }
                                                                                dst(I64 *)++;
                                                                        }
                                                                        for (i = 0; i < whole_I64s; i++, dst(I64 *)++)
                                                                                if (win_z_num >= *win_z_buf_ptr++)
                                                                                {
                                                                                        *dst(I64 *) ^= color_mask;
                                                                                        res += 8;
                                                                                }
                                                                        if (trailing_pixels && win_z_num >= *win_z_buf_ptr++)
                                                                        {
                                                                                *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                          *dst(I64 *) ^ color_mask & ~trailing_pixel_mask;
                                                                                res += trailing_pixels;
                                                                        }
                                                                        if ((j + y) & 7 == 7)
                                                                                win_z_buf_ptr(U8 *) += win_z_buf_line_inc;
                                                                        else
                                                                                win_z_buf_ptr(U8 *) -= win_z_buf_line_dec;
                                                                        kk1 += dc->width_internal;
                                                                        SwapU16(&color.c0, &color.c1);
                                                                }
                                                        }
                                                        else
                                                        {
                                                                for (j = h2 - h1; j; j--)
                                                                {
                                                                        color_mask = gr.to_8_bits[0x55] & gr.to_8_colors[color.c0.color] |
                                                                                                 gr.to_8_bits[0xAA] & gr.to_8_colors[color.c1.color];
                                                                        dst = dc->body + kk1 & ~7;
                                                                        if (leading_pixels)
                                                                                *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask |
                                                                                                                *dst(I64 *) ^ color_mask & ~leading_pixel_mask;
                                                                        for (i = 0; i < whole_I64s; i++, dst(I64 *)++)
                                                                                *dst(I64 *) ^= color_mask;
                                                                        if (trailing_pixels)
                                                                                *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                          *dst(I64 *) ^ color_mask & ~trailing_pixel_mask;
                                                                        kk1 += dc->width_internal;
                                                                        SwapU16(&color.c0, &color.c1);
                                                                }
                                                                res = (h2 - h1) * (w2 - w1);
                                                        }
                                                        break;
                                        }
                                }
                        }
                        else
                        {
                                BEqual(&Fs->task_flags, TASKf_NONTIMER_RAND, was_timer_rand);

                                color_mask = gr.to_8_colors[color.c0.color];
                                switch [color.c0.rop]
                                {
                                        case ROPB_EQU:
                                        case ROPB_MONO:
                                                if (win_z_buf_ptr)
                                                {
                                                        res = 0;
                                                        for (j = h1; j < h2; j++)
                                                        {
                                                                dst = dc->body + kk1 & ~7;
                                                                if (leading_pixels)
                                                                {
                                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                        {
                                                                                *dst(I64 *) = *dst(I64 *) & leading_pixel_mask | color_mask & ~leading_pixel_mask;
                                                                                res += leading_pixels;
                                                                        }
                                                                        dst(I64 *)++;
                                                                }
                                                                for (i = 0; i < whole_I64s; i++, dst(I64 *)++)
                                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                        {
                                                                                *dst(I64 *) = color_mask;
                                                                                res += 8;
                                                                        }
                                                                if (trailing_pixels && win_z_num >= *win_z_buf_ptr++)
                                                                {
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask | color_mask & ~trailing_pixel_mask;
                                                                        res += trailing_pixels;
                                                                }
                                                                if ((j + y) & 7 == 7)
                                                                        win_z_buf_ptr(U8 *) += win_z_buf_line_inc;
                                                                else
                                                                        win_z_buf_ptr(U8 *) -= win_z_buf_line_dec;
                                                                kk1 += dc->width_internal;
                                                        }
                                                }
                                                else
                                                {
                                                        for (j = h2 - h1; j; j--)
                                                        {
                                                                dst(I64 *) = dc->body + kk1 & ~7;
                                                                if (leading_pixels)
                                                                        *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask | color_mask & ~leading_pixel_mask;
                                                                for (i = 0; i < whole_I64s; i++, dst(I64 *)++)
                                                                        *dst(I64 *) = color_mask;
                                                                if (trailing_pixels)
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask | color_mask & ~trailing_pixel_mask;
                                                                kk1 += dc->width_internal;
                                                        }
                                                        res = (h2 - h1) * (w2 - w1);
                                                }
                                                break;

                                        case ROPB_XOR:
                                                if (win_z_buf_ptr)
                                                {
                                                        res = 0;
                                                        for (j = h1; j < h2; j++)
                                                        {
                                                                dst = dc->body + kk1 & ~7;
                                                                if (leading_pixels)
                                                                {
                                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                        {
                                                                                *dst(I64 *) = *dst(I64 *) & leading_pixel_mask |
                                                                                                          *dst(I64 *) ^ color_mask & ~leading_pixel_mask;
                                                                                res += leading_pixels;
                                                                        }
                                                                        dst(I64 *)++;
                                                                }
                                                                for (i = 0; i < whole_I64s; i++, dst(I64 *)++)
                                                                        if (win_z_num >= *win_z_buf_ptr++)
                                                                        {
                                                                                *dst(I64 *) ^= color_mask;
                                                                                res += 8;
                                                                        }
                                                                if (trailing_pixels && win_z_num >= *win_z_buf_ptr++)
                                                                {
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                  *dst(I64 *) ^ color_mask & ~trailing_pixel_mask;
                                                                        res += trailing_pixels;
                                                                }
                                                                if ((j + y) & 7 == 7)
                                                                        win_z_buf_ptr(U8 *) += win_z_buf_line_inc;
                                                                else
                                                                        win_z_buf_ptr(U8 *) -= win_z_buf_line_dec;
                                                                kk1 += dc->width_internal;
                                                        }
                                                }
                                                else
                                                {
                                                        for (j = h2 - h1; j; j--)
                                                        {
                                                                dst = dc->body + kk1 & ~7;
                                                                if (leading_pixels)
                                                                        *dst(I64 *)++ = *dst(I64 *) & leading_pixel_mask |
                                                                                                        *dst(I64 *) ^ color_mask & ~leading_pixel_mask;
                                                                for (i = 0; i < whole_I64s; i++, dst(I64 *)++)
                                                                        *dst(I64 *) ^= color_mask;
                                                                if (trailing_pixels)
                                                                        *dst(I64 *) = *dst(I64 *) & trailing_pixel_mask |
                                                                                                  *dst(I64 *) ^ color_mask & ~trailing_pixel_mask;
                                                                kk1 += dc->width_internal;
                                                        }
                                                        res = (h2 - h1) * (w2 - w1);
                                                }
                                                break;
                                }
                        }
                }
        }

        return res;
}

I64 GrRayLenMinus(CDC *dc, I64 x, I64 y)
{//Returns count of pixs changed
        I64              res = 0, c, x3, y3, d;
        U8              *dst, *dst2;
        Bool     not_color = ToBool(dc->flags & DCF_FILL_NOT_COLOR);
        CTask   *win_task;

        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                win_task = dc->win_task;
                x += win_task->scroll_x;
                y += win_task->scroll_y;
        }
        x3 = x;
        y3 = y;
        if (x3 < 0 || y3 < 0)
                goto gr_done;
        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                x3 += win_task->pix_left;
                y3 += win_task->pix_top;
                if (    !(0 <= x3 <= win_task->pix_right)  ||
                                !(0 <= y3 <= win_task->pix_bottom) ||
                                !(dc->flags & DCF_ON_TOP) && IsPixCovered0(win_task, x3, y3))
                        goto gr_done;
        }
        if (x3 >= dc->width || y3 >= dc->height)
                goto gr_done;

        d = y3 * dc->width_internal;
        dst2 = dc->body + d;
        while (TRUE)
        {
                x3 = x;
                if (x3 & (FONT_WIDTH - 1) == FONT_WIDTH - 1)
                {
                        if (dc->flags & DCF_SCREEN_BITMAP)
                        {
                                if (x3 < 0)
                                        break;
                                x3 += win_task->pix_left;
                                if (    !(0 <= x3 <= win_task->pix_right) || x3 >= dc->width ||
                                                !(dc->flags & DCF_ON_TOP) && IsPixCovered0(win_task, x3, y3))
                                        break;
                        }
                        else
                                if (!(0 <= x3 < dc->width))
                                        break;
                }
                else if (dc->flags & DCF_SCREEN_BITMAP)
                        x3 += win_task->pix_left;
                dst = dst2 + x3;
                c = *dst;
                if (not_color)
                {
                        if (c != dc->color2)
                        {
                                res++;
                                x--;
                        }
                        else
                                break;
                }
                else
                {
                        if (c == dc->color2)
                        {
                                res++;
                                x--;
                        }
                        else
                                break;
                }
        }

        return res;
gr_done:
        return 0;
}

I64 GrRayLen(CDC *dc, I64 *x1, I64 y, I64 z=0, I32 *db=NULL)
{
//Returns count of pixs changed
        I64                              res = 0, d, x = *x1, x2, x3, y3, dist;
        Bool                     plot, dither, probability_dither, 
                                         not_color = ToBool(dc->flags & DCF_FILL_NOT_COLOR), 
                                         was_timer_rand = Bts(&Fs->task_flags, TASKf_NONTIMER_RAND);
        U8                              *dst, *dst2;
        CColorROPU32     c, c2, color = dc->color, bkcolor = dc->bkcolor;
        I32                             *db2;
        CTask                   *win_task;


        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                win_task = dc->win_task;
                x += win_task->scroll_x;
                y += win_task->scroll_y;
                z += win_task->scroll_z;
        }
        x2 = x;
        x3 = x;
        y3 = y;
        if (x3 < 0 || y3 < 0)
                goto gr_done;
        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                x3 += win_task->pix_left;
                y3 += win_task->pix_top;
                if (    !(0 <= x3 <= win_task->pix_right)  ||
                                !(0 <= y3 <= win_task->pix_bottom) ||
                                !(dc->flags & DCF_ON_TOP) && IsPixCovered0(win_task, x3, y3))
                        goto gr_done;
        }
        if (x3 >= dc->width || y3 >= dc->height)
                goto gr_done;

        d = dc->width_internal * y3;
        if (db)
                db += d;

        color = dc->color;
        if (color.c1.rop & (ROPBF_DITHER | ROPBF_PROBABILITY_DITHER))
        {
                dither = TRUE;
                if (color.c1.rop & ROPBF_PROBABILITY_DITHER)
                {
                        probability_dither = TRUE;
                        color.c1.rop = color.c0.rop;
                }
                else
                {
                        probability_dither = FALSE;
                        color.c1.rop = color.c0.rop;
                }
        }
        else
                dither = FALSE;
        dst2 = dc->body + d;
        while (TRUE)
        {
                x3 = x;
                if (!(x3 & (FONT_WIDTH - 1)))
                {
                        if (dc->flags & DCF_SCREEN_BITMAP)
                        {
                                if (x3 < 0)
                                        break;
                                x3 += win_task->pix_left;
                                if (    !(0 <= x3 <= win_task->pix_right) || x3 >= dc->width ||
                                                !(dc->flags & DCF_ON_TOP) && IsPixCovered0(win_task, x3, y3))
                                        break;
                        }
                        else
                        {
                                if (!(0 <= x3 < dc->width))
                                        break;
                        }
                }
                else if (dc->flags & DCF_SCREEN_BITMAP)
                        x3 += win_task->pix_left;

                dst = dst2 + x3;

                c = *dst;
                if (db)
                {
                        db2 = db + x3;
                        if (0 <= z <= *db2)
                        {
                                *db2 = z;
                                plot = TRUE;
                        }
                        else
                                plot = FALSE;
                }
                else
                        plot = TRUE;

                if ((not_color && c != dc->color2 || !not_color && c == dc->color2) && plot)
                {
                        if (dc->flags & DCF_LOCATE_NEAREST)
                        {
                                dist = DistSqrI64(x3, y3, dc->cur_x, dc->cur_y);
                                if (dist <= dc->nearest_dist)
                                        dc->nearest_dist = dist;
                        }
                        if (dc->flags & DCF_RECORD_EXTENTS)
                        {
                                if (x3 < dc->min_x)
                                        dc->min_x = x3;

                                if (x3 > dc->max_x)
                                        dc->max_x = x3;

                                if (y3 < dc->min_y)
                                        dc->min_y = y3;

                                if (y3 > dc->max_y)
                                        dc->max_y = y3;
                        }
                        dst = dst2 + x3;

                        c = color.c0.color;
                        if (dither)
                        {
                                if (probability_dither)
                                {
                                        if (RandU16 < dc->dither_probability_u16)
                                                c = color.c1.color;
                                }
                                else
                                        if ((x3 ^ y3) & 1)
                                                c = color.c1.color;
                        }
                        switch [color.c0.rop]
                        {
                                case ROPB_EQU:
                                case ROPB_MONO:
                                        *dst = c;
                                        break;

                                case ROPB_COLLISION:
                                        c2 = *dst;
                                        if (c2 != TRANSPARENT && c2 != bkcolor.c0.color)
                                                dc->collision_count++;
                                        break;

                                case ROPB_XOR:
                                        *dst ^= c;
                                        break;
                        }
                        res++;
                        x++;
                }
                else
                        break;
        }
        if (dc->flags & DCF_SCREEN_BITMAP)
                *x1 = x - 1 - win_task->scroll_x;
        else
                *x1 = x - 1;
        x = x2 - 1;
        while (TRUE)
        {
                x3 = x;
                if (x3 & (FONT_WIDTH - 1) == FONT_WIDTH - 1)
                {
                        if (dc->flags & DCF_SCREEN_BITMAP)
                        {
                                if (x3 < 0)
                                        break;
                                x3 += win_task->pix_left;
                                if (    !(0 <= x3 <= win_task->pix_right) || x3 >= dc->width ||
                                                !(dc->flags & DCF_ON_TOP) && IsPixCovered0(win_task, x3, y3))
                                        break;
                        }
                        else
                                if (!(0 <= x3 < dc->width))
                                        break;
                }
                else if (dc->flags & DCF_SCREEN_BITMAP)
                        x3 += win_task->pix_left;

                dst = dst2 + x3;
                c = *dst;
                if (db)
                {
                        db2 = db + x3;
                        if (0 <= z <= *db2)
                        {
                                *db2 = z;
                                plot = TRUE;
                        }
                        else
                                plot = FALSE;
                }
                else
                        plot = TRUE;

                if ((not_color && c != dc->color2 || !not_color && c == dc->color2) && plot)
                {
                        if (dc->flags & DCF_LOCATE_NEAREST)
                        {
                                dist = DistSqrI64(x3, y3, dc->cur_x, dc->cur_y);
                                if (dist <= dc->nearest_dist)
                                        dc->nearest_dist = dist;
                        }
                        if (dc->flags & DCF_RECORD_EXTENTS)
                        {
                                if (x3 < dc->min_x)
                                        dc->min_x = x3;
                                if (x3 > dc->max_x)
                                        dc->max_x = x3;
                                if (y3 < dc->min_y)
                                        dc->min_y = y3;
                                if (y3 > dc->max_y)
                                        dc->max_y = y3;
                        }
                        dst = dst2 + x3;

                        c = color.c0.color;
                        if (dither)
                        {
                                if (probability_dither)
                                {
                                        if (RandU16 < dc->dither_probability_u16)
                                                c = color.c1.color;
                                }
                                else
                                        if ((x3 ^ y3) & 1)
                                                c = color.c1.color;
                        }
                        switch [color.c0.rop]
                        {
                                case ROPB_EQU:
                                case ROPB_MONO:
                                        *dst = c;
                                        break;

                                case ROPB_COLLISION:
                                        c2 = *dst;
                                        if (c2 != TRANSPARENT && c2 != bkcolor.c0.color)
                                                dc->collision_count++;
                                        break;

                                case ROPB_XOR:
                                        *dst ^= c;
                                        break;
                        }
                        res++;
                        x--;
                }
                else
                        break;
        }
        BEqual(&Fs->task_flags, TASKf_NONTIMER_RAND, was_timer_rand);

        return res;
gr_done:
        BEqual(&Fs->task_flags, TASKf_NONTIMER_RAND, was_timer_rand);

        return 0;
}

public I64 GrHLine(CDC *dc=gr.dc, I64 x1, I64 x2, I64 y, I64 z1=0, I64 z2=0)
{//3D. No transformation or thick.
//Returns count of pixs changed
        //Uses fixed-point.
        I64                              dist, dx, dz, z, res = 0, i, j, d;
        U8                              *dst;
        CColorROPU32     c, c2, color = dc->color, bkcolor = dc->bkcolor, dither_colors;
        I32                             *db;
        Bool                     plot = TRUE, char_clear, dither, probability_dither,
                                         was_timer_rand = Bts(&Fs->task_flags, TASKf_NONTIMER_RAND);
        CTask                   *win_task;


        if (!dc->depth_buf)
        {
                if (x2 < x1)
                        SwapI64(&x1, &x2);
                return GrRect(dc, x1, y, x2 - x1 + 1, 1);
        }

        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                win_task = dc->win_task;
                x1 += win_task->scroll_x;
                x2 += win_task->scroll_x;
                y  += win_task->scroll_y;
                z1 += win_task->scroll_z;
                z2 += win_task->scroll_z;
        }
        if (dc->flags & DCF_RECORD_EXTENTS)
        {
                if (x1 < dc->min_x)
                        dc->min_x = x1;

                if (x1 > dc->max_x)
                        dc->max_x = x1;

                if (x2 < dc->min_x)
                        dc->min_x = x2;

                if (x2 > dc->max_x)
                        dc->max_x = x2;

                if (y < dc->min_y)
                        dc->min_y = y;

                if (y > dc->max_y)
                        dc->max_y = y;
        }
        if (y < 0)
                goto gr_done;
        if (x2 < x1)
        {
                SwapI64(&x1, &x2);
                SwapI64(&z1, &z2);
        }
        if (x2 < 0)
                goto gr_done;
        if (x1 < 0)
        {
                i = -x1;
                x1 = 0;
        }
        else
                i = 0;
        j = 0;
        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                x1 += win_task->pix_left;
                x2 += win_task->pix_left;
                if (x1 > win_task->pix_right)
                        goto gr_done;
                if (x2 > win_task->pix_right)
                {
                        j = x2 - win_task->pix_right;
                        x2 = win_task->pix_right;
                }
                y += win_task->pix_top;
                if (!(0 <= y <= win_task->pix_bottom) || x2 < 0)
                        goto gr_done;
        }
        if (x1 >= dc->width || y >= dc->height)
                goto gr_done;
        dx = x2 + j - (x1 - i);
        d = dc->width_internal * y + x1;
        if (db = dc->depth_buf)
        {
                db += d;
                if (dx)
                        dz = (z2 - z1) << 32 / dx;
                else
                        dz = 0;
                z = z1 << 32;
        }
        if (i)
                z += i * dz;
        if (x2 >= dc->width)
                x2 = dc->width - 1;

        if (dc->flags & DCF_LOCATE_NEAREST)
        {
                if (x1 <= dc->cur_x <= x2)
                        dist = 0;
                else if (dc->cur_x < x1)
                        dist = SqrI64(x1 - dc->cur_x);
                else
                        dist = SqrI64(dc->cur_x - x2);
                dist += SqrI64(y - dc->cur_y);
                if (dist <= dc->nearest_dist)
                        dc->nearest_dist = dist;
        }
        if (dc->flags & DCF_DONT_DRAW)
                goto gr_done;

        if (    !(dc->flags & DCF_SCREEN_BITMAP) ||
                        win_task->next_task == sys_winmgr_task ||
                        dc->flags & DCF_ON_TOP || !IsPixCovered0(win_task, x1, y))
                char_clear = TRUE;
        else
                char_clear = FALSE;
        if (color.c1.rop & (ROPBF_DITHER | ROPBF_PROBABILITY_DITHER))
        {
                dither = TRUE;
                if (color.c1.rop & ROPBF_PROBABILITY_DITHER)
                {
                        probability_dither = TRUE;
                        color.c1.rop = color.c0.rop;
                        dither_colors = color;
                        if (RandU16 < dc->dither_probability_u16)
                                color.c0 = dither_colors.c1;
                        else
                                color.c0 = dither_colors.c0;
                }
                else
                {
                        probability_dither = FALSE;
                        color.c1.rop = color.c0.rop;
                        if ((x1 ^ y) & 1)
                                SwapU16(&color.c0, &color.c1);
                }
        }
        else
                dither = FALSE;
        while (x1 <= x2)
        {
                if (char_clear)
                {
                        if (db)
                        {
                                if (0 <= z.i32[1] <= *db)
                                {
                                        *db = z.i32[1];
                                        plot = TRUE;
                                }
                                else
                                        plot = FALSE;
                        }
                        if (plot)
                        {
                                dst = dc->body + d;
                                c = color.c0.color;
                                switch [color.c0.rop]
                                {
                                        case ROPB_EQU:
                                        case ROPB_MONO:
                                                *dst = c;
                                                break;

                                        case ROPB_COLLISION:
                                                c2 = *dst;
                                                if (c2 != TRANSPARENT && c2 != bkcolor.c0.color)
                                                        dc->collision_count++;
                                                break;

                                        case ROPB_XOR:
                                                *dst ^= c;
                                                break;
                                }
                                res++;
                        }
                }
                if (dither)
                {
                        if (probability_dither)
                        {
                                if (RandU16 < dc->dither_probability_u16)
                                        color.c0 = dither_colors.c1;
                                else
                                        color.c0 = dither_colors.c0;
                        }
                        else
                                SwapU16(&color.c0, &color.c1);
                }
                d++;
                x1++;
                if (db)
                        db++;
                z += dz;
                if (!(x1 & (FONT_WIDTH - 1)) && x1 <= x2)
                {
                        if (    !(dc->flags & DCF_SCREEN_BITMAP)||
                                        win_task->next_task == sys_winmgr_task ||
                                        dc->flags & DCF_ON_TOP || !IsPixCovered0(win_task, x1, y))
                                char_clear = TRUE;
                        else
                                char_clear = FALSE;
                }
        }
gr_done:
        BEqual(&Fs->task_flags, TASKf_NONTIMER_RAND, was_timer_rand);

        return res;
}

public I64 GrVLine(CDC *dc=gr.dc, I64 x, I64 y1, I64 y2, I64 z1=0, I64 z2=0)
{//3D. No transformation or thick.
//Returns count of pixs changed
        //Uses fixed-point.
        I64                              dist, dy, dz, z, res = 0, i, j, d;
        U8                              *dst;
        CColorROPU32     c, c2, color = dc->color, bkcolor = dc->bkcolor, dither_colors;
        I32                             *db;
        Bool                     plot = TRUE, char_clear, dither, probability_dither,
                                         was_timer_rand = Bts(&Fs->task_flags, TASKf_NONTIMER_RAND);
        CTask                   *win_task;


        if (!dc->depth_buf)
        {
                if (y2 < y1)
                        SwapI64(&y1, &y2);
                return GrRect(dc, x, y1, 1, y2 - y1 + 1);
        }

        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                win_task = dc->win_task;
                x  += win_task->scroll_x;
                y1 += win_task->scroll_y;
                y2 += win_task->scroll_y;
                z1 += win_task->scroll_z;
                z2 += win_task->scroll_z;
        }
        if (dc->flags & DCF_RECORD_EXTENTS)
        {
                if (x < dc->min_x)
                        dc->min_x = x;

                if (x > dc->max_x)
                        dc->max_x = x;

                if (y1 < dc->min_y)
                        dc->min_y = y1;

                if (y1 > dc->max_y)
                        dc->max_y = y1;

                if (y2 < dc->min_y)
                        dc->min_y = y2;

                if (y2 > dc->max_y)
                        dc->max_y = y2;
        }
        if (x < 0)
                goto gr_done;
        if (y2 < y1)
        {
                SwapI64(&y1, &y2);
                SwapI64(&z1, &z2);
        }
        if (y2 < 0)
                goto gr_done;
        if (y1 < 0)
        {
                i = -y1;
                y1 = 0;
        }
        else
                i = 0;
        j = 0;
        if (dc->flags & DCF_SCREEN_BITMAP)
        {
                y1 += win_task->pix_top;
                y2 += win_task->pix_top;
                if (y1 > win_task->pix_bottom)
                        goto gr_done;
                if (y2 > win_task->pix_bottom)
                {
                        j = y2 - win_task->pix_bottom;
                        y2 = win_task->pix_bottom;
                }
                x += win_task->pix_left;
                if (!(0 <= x <= win_task->pix_right) || y2 < 0)
                        goto gr_done;
        }
        if (y1 >= dc->height || x >= dc->width)
                goto gr_done;
        dy = y2 + j - (y1 - i);
        d = dc->width_internal * y1 + x;
        if (db = dc->depth_buf)
        {
                db += d;
                if (dy)
                        dz = (z2 - z1) << 32 / dy;
                else
                        dz = 0;
                z = z1 << 32;
        }
        if (i)
                z += i * dz;
        if (y2 >= dc->height)
                y2 = dc->height - 1;

        if (dc->flags & DCF_LOCATE_NEAREST)
        {
                if (y1 <= dc->cur_y <= y2)
                        dist = 0;
                else if (dc->cur_y < y1)
                        dist = SqrI64(y1 - dc->cur_y);
                else
                        dist = SqrI64(dc->cur_y - y2);
                dist += SqrI64(x - dc->cur_x);
                if (dist <= dc->nearest_dist)
                        dc->nearest_dist = dist;
        }
        if (dc->flags & DCF_DONT_DRAW)
                goto gr_done;

        if (    !(dc->flags & DCF_SCREEN_BITMAP) ||
                        win_task->next_task == sys_winmgr_task ||
                        dc->flags & DCF_ON_TOP || !IsPixCovered0(win_task, x, y1))
                char_clear = TRUE;
        else
                char_clear = FALSE;
        if (color.c1.rop & (ROPBF_DITHER | ROPBF_PROBABILITY_DITHER))
        {
                dither = TRUE;
                if (color.c1.rop & ROPBF_PROBABILITY_DITHER)
                {
                        probability_dither = TRUE;
                        color.c1.rop = color.c0.rop;
                        dither_colors = color;
                        if (RandU16 < dc->dither_probability_u16)
                                color.c0 = dither_colors.c1;
                        else
                                color.c0 = dither_colors.c0;
                }
                else
                {
                        probability_dither = FALSE;
                        color.c1.rop = color.c0.rop;
                        if ((x ^ y1) & 1)
                                SwapU16(&color.c0, &color.c1);
                }
        }
        else
                dither = FALSE;
        while (y1 <= y2)
        {
                if (char_clear)
                {
                        if (db)
                        {
                                if (0 <= z.i32[1] <= *db)
                                {
                                        *db = z.i32[1];
                                        plot = TRUE;
                                }
                                else
                                        plot = FALSE;
                        }
                        if (plot)
                        {
                                dst = dc->body + d;
                                c = color.c0.color;
                                switch [color.c0.rop]
                                {
                                        case ROPB_EQU:
                                        case ROPB_MONO:
                                                *dst = c;
                                                break;

                                        case ROPB_COLLISION:
                                                c2 = *dst;
                                                if (c2 != TRANSPARENT && c2 != bkcolor.c0.color)
                                                        dc->collision_count++;
                                                break;

                                        case ROPB_XOR:
                                                *dst ^= c;
                                                break;
                                }
                                res++;
                        }
                }
                if (dither)
                {
                        if (probability_dither)
                        {
                                if (RandU16 < dc->dither_probability_u16)
                                        color.c0 = dither_colors.c1;
                                else
                                        color.c0 = dither_colors.c0;
                        }
                        else
                                SwapU16(&color.c0, &color.c1);
                }
                d += dc->width_internal;
                y1++;
                if (db)
                        db += dc->width_internal;
                z += dz;
                if (!(y1 & (FONT_HEIGHT - 1)) && y1 <= y2)
                {
                        if (    !(dc->flags & DCF_SCREEN_BITMAP) ||
                                        win_task->next_task == sys_winmgr_task ||
                                        dc->flags & DCF_ON_TOP || !IsPixCovered0(win_task, x, y1))
                                char_clear = TRUE;
                        else
                                char_clear = FALSE;
                }
        }
gr_done:
        BEqual(&Fs->task_flags, TASKf_NONTIMER_RAND, was_timer_rand);

        return res;
}