#help_index "Graphics/Screen"

U0 GrSetUpTables()
{
        CDC *dc;
        I64  i, j, k, l, m, x, y, rr;
        U8  *dst;

        k = 0;
        for (i = 0; i < 256; i++)
                for (j = 0; j < 8; j++)
                        if (Bt(&i, j))
                                gr.to_8_bits(U8 *)[k++] = 0xFF;
                        else
                                gr.to_8_bits(U8 *)[k++] = 0x00;
        k = 0;
        for (i = 0; i < 256; i++)
                for (j = 0; j < 8; j++)
                        gr.to_8_colors(U8 *)[k++] = i;

        for (i = 0; i < GR_PEN_BRUSHES_NUM; i++)
        {
                k = i + 1;

                rr = k * k;
                for (y = 1; y < k; y++)
                        for (x = 1; x < k; x++)
                                if (SqrI64(y * 2 - k) + SqrI64(x * 2 - k) < rr)
                                {
                                        if (x - 1 - i >> 1 < gr.circle_lo[i][i - y])
                                                gr.circle_lo[i][i - y] = x - 1 - i >> 1;
                                        if (x - 1 - i >> 1 > gr.circle_hi[i][i - y])
                                                gr.circle_hi[i][i-y] = x - 1 - i >> 1;
                                }

                dc = DCNew(i, i);
                gr.pen_brushes[i] = dc;
                dc->color = COLOR_MONO;
                rr = k * k;
                for (y = 1; y < k; y++)
                        for (x = 1; x < k; x++)
                                if (SqrI64(y * 2 - k) + SqrI64(x * 2 - k) < rr)
                                        GrPlot0(dc, x - 1, y - 1);

                dc = DCNew(i, i);
                gr.collision_pen_brushes[i] = dc;
                dc->color = COLOR_INVALID;//Want color that never occurs.
                rr = k * k;
                for (y = 1; y < k; y++)
                        for (x = 1; x < k; x++)
                                if (SqrI64(y * 2 - k) + SqrI64(x * 2 - k) < rr)
                                        GrPlot0(dc, x - 1, y - 1);

                dc = DCNew(i, i);
                gr.even_pen_brushes[i] = dc;
                dc->color = COLOR_MONO;
                rr = k * k;
                for (y = 1;y < k; y++)
                        for (x = 1; x < k; x++)
                                if (!(((x - 1) ^ (y - 1)) & 1) && SqrI64(y * 2 - k) + SqrI64(x * 2 - k) < rr)
                                        GrPlot0(dc, x - 1, y - 1);

                dc = DCNew(i, i);
                gr.odd_pen_brushes[i] = dc;
                dc->color = COLOR_MONO;
                rr = k * k;
                for (y = 1; y < k; y++)
                        for (x = 1; x < k; x++)
                                if (((x - 1) ^ (y - 1)) & 1 && SqrI64(y * 2 - k) + SqrI64(x * 2 - k) < rr)
                                        GrPlot0(dc, x - 1, y - 1);
        }

        for (i = 1; i <= GR_SCREEN_ZOOM_MAX; i++)
        {
                dst = gr.screen_zoom_tables[i] = MAlloc(256 * i);
                for (j = 0; j < 256; j++)
                {
                        m = 0;
                        for (k = 0; k < 8; k++)
                        {
                                if (Bt(&j, k))
                                {
                                        for (l = 0; l < i; l++)
                                                Bts(&m, l + k * i);
                                }
                        }
                        for (l = 0; l < i; l++)
                                dst[j + l * 256] = m.u8[l];
                }
        }
}

#help_index "Graphics/Screen;Windows"

U0 WinZBufFill(CTask *task)
{//Not public
        I64 y, t, b, l, r, w;
        if (!Bt(&task->display_flags, DISPLAYf_NO_BORDER))
        {
                if (task->win_top - 1 > 0)
                        t = task->win_top - 1;
                else
                        t = 0;
                if (task->win_bottom + 1 < TEXT_ROWS)
                        b = task->win_bottom + 1;
                else
                        b = TEXT_ROWS - 1;
                if (task->win_left - 1 > 0)
                        l = task->win_left - 1;
                else
                        l = 0;
                if (task->win_right + 1 < TEXT_COLS)
                        r = task->win_right + 1;
                else
                        r = TEXT_COLS - 1;
        }
        else
        {
                if (task->win_top > 0)
                        t = task->win_top;
                else
                        t = 0;
                if (task->win_bottom < TEXT_ROWS)
                        b = task->win_bottom;
                else
                        b = TEXT_ROWS - 1;
                if (task->win_left > 0)
                        l = task->win_left;
                else
                        l = 0;
                if (task->win_right < TEXT_COLS)
                        r = task->win_right;
                else
                        r = TEXT_COLS - 1;
        }
        t = ClampI64(t, 0, TEXT_ROWS - 1);
        b = ClampI64(b, t, TEXT_ROWS - 1);
        l = ClampI64(l, 0, TEXT_COLS - 1);
        r = ClampI64(r, l, TEXT_COLS - 1);
        if (w = r - l + 1)
                for (y = t; y <= b; y++)
                        MemSetU16(gr.win_z_buf(U8 *) + (y * TEXT_COLS + l) * sizeof(U16), task->win_z_num, w);
}

public U0 WinZBufUpdate()
{//Might have to call if doing graphics outside winmgr callback routines.
//Call it if, for example, when a pop-up window closes and you need to refresh
        //before graphics.
        I64              i, z = 1;
        U16             *ptr;
        CTask   *task, *task1;

        if (gr.win_z_buf)
        {
                LBtr(&sys_semas[SEMA_UPDATE_WIN_Z_BUF], 0);
                task1 = task = sys_winmgr_task;
                do
                {
                        if (!TaskValidate(task))
                                break;
                        if (Bt(&task->display_flags, DISPLAYf_SHOW))
                        {
                                task->win_z_num = z++;
                                WinZBufFill(task);
                        }
                        task = task->next_task;
                }
                while (task != task1 && z < 0x10000);

                MemSet(gr.win_uncovered_bitmap, 0, (gr.highest_uncovered + 7) >> 3 + 1);
                gr.highest_uncovered = z - 1;
                for (ptr = gr.win_z_buf, i = TEXT_ROWS * TEXT_COLS; i; i--)
                        Bts(gr.win_uncovered_bitmap, *ptr++);
        }
}

#help_index "Graphics"
U0 GrInit2()
{
        MemSet(&gr, 0, sizeof(CGrGlobals));
        gr.sprite_hash = HashTableNew(512);
        HashDefineListAdd("ST_SPRITE_ELEM_CODES", SPHT_ELEM_CODE, gr.sprite_hash);
        gr.screen_zoom = 1;

        PaletteSetDark;

        gr.to_8_bits    = MAlloc(256 * sizeof(I64));
        gr.to_8_colors  = MAlloc(256 * sizeof(I64));

        gr.screen_cache = MAlloc(sys_vbe_mode.width * sys_vbe_mode.height);

        gr.text_base                    = CAlloc(TEXT_ROWS * TEXT_COLS * sizeof(U32));
        gr.win_uncovered_bitmap = CAlloc(65536 / 8);
        gr.highest_uncovered    = 0;
        gr.win_z_buf                    = MAlloc(TEXT_ROWS * TEXT_COLS * sizeof(U16));

        gr.dc2 = DCNew(GR_WIDTH, GR_HEIGHT);
        gr.dc2->flags |= DCF_SCREEN_BITMAP;
        gr.dc_cache = DCNew(GR_WIDTH, GR_HEIGHT);

        gr.dc = DCNew(GR_WIDTH, GR_HEIGHT);
        gr.dc->flags |= DCF_SCREEN_BITMAP | DCF_ON_TOP;
        DCFill;

        gr.dc1 = DCNew(GR_WIDTH, GR_HEIGHT);
        gr.dc1->flags |= DCF_SCREEN_BITMAP;

        gr.screen_image = DCNew(GR_WIDTH, GR_HEIGHT); //4-bit
        gr.zoomed_dc    = DCNew(GR_WIDTH, GR_HEIGHT); //4-bit
        gr.zoomed_dc->flags |= DCF_SCREEN_BITMAP;
}

GrInit2;