//Practice tracing circles

//Giotto, a famous artist, drew a freehand circle to get a job.

RegDefault("ZealOS/CircleTrace", "F64 best_score=999;\n");
RegExe("ZealOS/CircleTrace");

I64 cx, cy;
F64 avg_error = 0, elapsed_time = 0, total_error = 0, score = 999;

U0 SongTask(I64)
{
        Fs->task_end_cb = &SoundTaskEndCB;
        MusicSettingsReset;
        while (TRUE)
                Play("5hEDC4A5RCDECR");
}

U0 DrawIt(CTask *task, CDC *dc)
{
        GrPrint(dc, 0, 0, "Error:%6.3f  Time:%6.3f  Score:%6.3f  Best:%8.3f", avg_error, elapsed_time, score, best_score);
}

#define CIRCLE_RADIUS   100
#define CIRCUMFERENCE   (2 * pi * CIRCLE_RADIUS)

Bool CTPlot(CDC *dc, I64 x, I64 y, I64)
{
        F64 rad = Sqrt(Sqr(x - cx) + Sqr(y - cy));

        GrPlot(dc, x, y);
        total_error += Abs(rad - CIRCLE_RADIUS);

        return TRUE;
}

U0 CircleTrace()
{
        I64  message_code, arg1, arg2, x1, y1;
        F64  rad, t0, total_distance;
        CDC *dc = DCAlias;

        SettingsPush; //See SettingsPush
        Fs->song_task = Spawn(&SongTask, NULL, "Song",, Fs);
        AutoComplete;
        WinBorder;
        WinMax;
        DocCursor;
        DocClear;

        cx = Fs->pix_width  / 2;
        cy = Fs->pix_height / 2;

        Fs->win_inhibit = WIG_TASK_DEFAULT - WIF_SELF_FOCUS - WIF_SELF_BORDER;
        Fs->draw_it             = &DrawIt;

        DCFill;
        dc->color = ROP_XOR + BLACK ^ TRANSPARENT;
        GrCircle(dc, cx, cy, CIRCLE_RADIUS);
        do
        {
                message_code = MessageGet(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN + 1 << MESSAGE_MS_L_DOWN);
                switch (message_code)
                {
                        case MESSAGE_KEY_UP:
                                break;

                        case MESSAGE_MS_L_DOWN:
                                DCFill;
                                dc->color = ROP_XOR + BLACK ^ TRANSPARENT;
                                GrCircle(dc, cx, cy, CIRCLE_RADIUS);
                                dc->color = ROP_XOR + RED ^ TRANSPARENT;
                                t0 = tS;
                                total_distance = 0.001;
                                total_error = 0;
                                x1 = arg1;
                                y1 = arg2;
                                do
                                {
                                        message_code = MessageScan(&arg1, &arg2, 1 << MESSAGE_MS_L_UP + 1 << MESSAGE_MS_MOVE);
                                        switch (message_code)
                                        {
                                                case MESSAGE_MS_L_UP:
                                                        break;

                                                case MESSAGE_MS_MOVE:
                                                        if (x1 != arg1 || y1 != arg2)
                                                        {
                                                                total_distance += Sqrt(Sqr(x1 - arg1) + Sqr(y1 - arg2));
                                                                Line(dc, x1, y1, 0, arg1, arg2, 0, &CTPlot);
                                                                x1 = arg1;
                                                                y1 = arg2;
                                                                //undo overlapping pixs on segments
                                                                GrPlot(dc, x1, y1);
                                                                rad = Sqrt(Sqr(x1 - cx) + Sqr(y1 - cy));
                                                                total_error -= Abs(rad - CIRCLE_RADIUS);
                                                        }
                                                        break;
                                        }
                                        elapsed_time = tS - t0;
                                        avg_error = total_error / total_distance;
                                        score = elapsed_time * avg_error;

                                        //Sleep()s until the next time the
                                        //window mgr task runs.  The
                                        //window mgr calls the UpdateWin() routine
                                        //and places messages in the que, so there's
                                        //no need to do anything until the window mgr runs.
                                        Refresh;

                                }
                                while (message_code != MESSAGE_MS_L_UP);

                                music.mute = TRUE;
                                Sleep(200);
                                if (total_distance > 0.95 * CIRCUMFERENCE)
                                {
                                        if (score < best_score)
                                        {
                                                Sound(86);
                                                Sleep(50);
                                                Sound;
                                                Sleep(50);
                                                Sound(86);
                                                Sleep(50);
                                                Sound;
                                                Sleep(50);
                                                Sound(86);
                                                Sleep(50);
                                                best_score = score;
                                        }
                                        else
                                        {
                                                Sound(62);
                                                Sleep(50);
                                        }
                                }
                                else
                                {
                                        Sound(34);
                                        Sleep(1000);
                                }
                                Sound;
                                Sleep(200);
                                music.mute = FALSE;
                                break;
                }
        }
        while (message_code != MESSAGE_KEY_DOWN || arg1 != CH_SHIFT_ESC && arg1 != CH_ESC);

        MessageGet(,, 1 << MESSAGE_KEY_UP);
        SettingsPop;
        DCFill;
        DCDel(dc);
        RegWrite("ZealOS/CircleTrace", "F64 best_score=%5.4f;\n", best_score);
}

CircleTrace;    //Execute when #included