//#define SQUARE_SIZE       20
//#define SQUARE_GAP        5
//#define SQUARE_DELAY  5 // mS

// paint program globals
class CPaint
{
    // Image Framebuffer
    U32     *fb;

    // Brush
    CBGR24   color;
    U64      thick;
    U64      last_x;
    U64      last_y;
    U64      last_thick;

} paint;

U0 PaintGlobalsInit()
{
    paint.fb            = CAlloc(text.buffer_size);
    paint.thick         = 8;
    paint.color         = BLACK32;

    // last cursor position and size
    paint.last_x        = mouse.pos.x;
    paint.last_y        = mouse.pos.y;
    paint.last_thick    = paint.thick;
}


I0 DrawImagePixel(I64 x, I64 y, CBGR24 color)
{
    paint.fb[x + y * GR_WIDTH] = color;
}

I0 DrawScreenPixel(I64 x, I64 y, CBGR24 color)
{
    text.fb_alias[x + y * GR_WIDTH] = color;
}

I0 DrawScreenChar(I64 x, I64 y, I64 char)
{
    I64 i, j;

    for (i = 0; i < FONT_HEIGHT; i++)
        for (j = 0; j < FONT_WIDTH; j++)
            if ((text.font[char] >> (i * 8)) & (1 << j))
                DrawScreenPixel(x + j, y + i, BLACK32);
}

I0 DrawScreenStr(I64 x, I64 y, U8 *str)
{
    I64 c, i = 0;

    while (c = *str++)
    {
        DrawScreenChar(x + (FONT_WIDTH * i++), y, c);
    }
}

I0 DrawImageBrush(I64 x, I64 y, CBGR24 color, I64 thick)
{
    I64 i, j;

    for (i = x; i < x + thick; i++)
        for (j = y; j < y + thick; j++)
            DrawImagePixel(i, j, color);
}

I0 DrawScreenBrush(I64 x, I64 y, CBGR24 color, I64 thick)
{
    I64 i, j;

    for (i = x; i < x + thick; i++)
        for (j = y; j < y + thick; j++)
            DrawScreenPixel(i, j, color);

    paint.last_x        = x;
    paint.last_y        = y;
    paint.last_thick    = thick;

}

U0 PaintSaveImage()
{
    U8          *filename, *tmp;

    text.is_fb_busy = FALSE;
    LFBFlush;

    tmp = PopUpFileName("~/");
    filename = ExtChange(tmp, "GR32");// make sure file ends in .GR32
    Free(tmp);
    FileWrite(filename, paint.fb, text.buffer_size);
    Free(filename);

    text.is_fb_busy = TRUE;
    MemCopy(text.fb_alias, paint.fb, text.buffer_size);

}

U0 PaintLoadImage()
{
    U8   ext[STR_LEN],
        *file,
         filename[STR_LEN],
        *file_image;

    text.is_fb_busy = FALSE;
    LFBFlush;

    PopUpOk("Pick a .GR32 file to load.\n\n"
            "(Double-click / ESC to pick.)");

    do
    {
        file = PopUpPickFile("~/");
        FileExtRemove(file, ext);
    }
    while (StrCompare(ext, "GR32"));

    StrCopy(filename, file);
    Free(file);
    file = ExtDefault(filename, "GR32");

    file_image = FileRead(file);
    Free(file);

    text.is_fb_busy = TRUE;
    MemCopy(paint.fb, file_image, text.buffer_size);
    Free(file_image);
    MemCopy(text.fb_alias, paint.fb, text.buffer_size);
}

U32 PaintImagePeek(I64 x, I64 y)
{
    return paint.fb[x + y * GR_WIDTH];
}

I0 Paint32()
{
    I64     sc, ch, i, j, sc_space = Char2ScanCode(CH_SPACE);
    U8      str_r[STR_LEN],
            str_g[STR_LEN],
            str_b[STR_LEN];

    SettingsPush; //See SettingsPush
    AutoComplete;
    WinBorder;
    WinMax;
    DocCursor;
    DocClear;
    MenuPush("");

    PopUpOk("\n"
            "$GREEN$0-9$FG$ to get colors from current palette.\n"
            "$GREEN$R, G, or B$FG$ to increase color values.\n"
            "$GREEN$Shift-R, Shift-G, or Shift-B$FG$ to decrease.\n"
            "$GREEN$+ or -$FG$ to change brush size.\n"
            "$GREEN$Alt$FG$ to peek (eyedropper) color under brush.\n\n"
            "$BLUE$Ctrl-S$FG$ to save image.\n"
            "$BLUE$Ctrl-L$FG$ to load image.\n\n"
            "$GREEN$Left-click or SPACE$FG$ to draw.\n\n"
            "$RED$END$FG$ to clear image.\n"
            "$RED$Shift-Esc or Double Right-Click$FG$ to exit.");
    Sleep(250); // help ensure SPACE press doesn't draw early

    text.is_fb_busy = TRUE;
    MemSet(text.fb_alias,   WHITE32, text.buffer_size);
    MemSet(paint.fb,        WHITE32, text.buffer_size);

    while (TRUE)
    {
        // draw the image where the brush was last covering it
        for (i = paint.last_x; i < paint.last_x + paint.last_thick; i++)
            for (j = paint.last_y; j < paint.last_y + paint.last_thick; j++)
                DrawScreenPixel(i, j, paint.fb[i + j * GR_WIDTH]);

        // draw the brush on the screen
        DrawScreenBrush(mouse.pos.x, mouse.pos.y, paint.color, paint.thick);

        // if clicked, draw brush on the image
        if (mouse.lb || Bt(kbd.down_bitmap, sc_space))
            DrawImageBrush(mouse.pos.x, mouse.pos.y, paint.color, paint.thick);

        // build the color strings (U8[], no MAlloc)
        StrPrint(str_r, "Red:   %d", paint.color.r);
        StrPrint(str_g, "Green: %d", paint.color.g);
        StrPrint(str_b, "Blue:  %d", paint.color.b);

        // draw the image where the color strings where covering it 
        for (i = 0; i < 3 * FONT_HEIGHT; i++)
            for (j = 0; j < 12 * FONT_WIDTH; j++)
                DrawScreenPixel(j, i, paint.fb[j + i * GR_WIDTH]);

        // draw the color strings on screen
        DrawScreenStr(0, 0 * FONT_HEIGHT, str_r);
        DrawScreenStr(0, 1 * FONT_HEIGHT, str_g);
        DrawScreenStr(0, 2 * FONT_HEIGHT, str_b);

        // 60fps wait
        Refresh;

        // Get key, process
        KeyScan(&ch, &sc);
        switch (ch)
        {
            case 0:
                switch (sc.u8[0])
                {
                    case SC_ALT:
                        paint.color = PaintImagePeek(mouse.pos.x, mouse.pos.y);
                        break;

                    case SC_CURSOR_LEFT:
                        mouse.pos.x--;
                        break;

                    case SC_CURSOR_RIGHT:
                        mouse.pos.x++;
                        break;

                    case SC_CURSOR_UP:
                        mouse.pos.y--;
                        break;

                    case SC_CURSOR_DOWN:
                        mouse.pos.y++;
                        break;

                    case SC_END:
                        MemSet(paint.fb,        WHITE32, text.buffer_size);
                        MemSet(text.fb_alias,   WHITE32, text.buffer_size);
                        break;
                }
                break;

            case '+':
                paint.thick++;
                break;
            case '-':
                paint.thick--;
                break;

            case 'r':
                paint.color.r++;
                break;
            case 'g':
                paint.color.g++;
                break;
            case 'b':
                paint.color.b++;
                break;

            case 'R':
                paint.color.r--;
                break;
            case 'G':
                paint.color.g--;
                break;
            case 'B':
                paint.color.b--;
                break;

            case '0'...'9':
                paint.color = gr_palette[ch - '0'];
                break;

            case CH_CTRLS:
                PaintSaveImage;
                break;

            case CH_CTRLL:
                PaintLoadImage;
                break;

            case CH_SHIFT_ESC:
                goto paint_done;
        }
    }

paint_done:
    text.is_fb_busy = FALSE;
    LFBFlush;
    SettingsPop;
    MenuPop;
}

PaintGlobalsInit;
Paint32;