Sprint game for GR-PEACH.

Dependencies:   GR-PEACH_video GraphicsFramework LCD_shield_config R_BSP


What is this ?

This is a sprint time trial game. In this game you move by swiping from left to right.
The faster you swipe, the faster your character moves.
You can change the language of the comment by USER_BUTTON0. (defalt :English)
It uses the high speed Renesas graphics drawing library and the 2D graphics hardware accelerator.

Composition

GR-PEACH and GR-PEACH 4.3inch LCD Shield. /media/uploads/dkato/swipe_runner.jpg

About image to be drawn

Image files that are used in the sample program is easily possible replacement by using the "Convert Image to Binary Table" tool below.
This tool generates "BinaryImage_RZ_A1H.c" and "BinaryImage_RZ_A1H.h" in the Images folder and converts each image file to binary. Then, this tool outputs the data to "RGA_Sample_BinaryImage" table of "BinaryImage_RZ_A1H.c" and defines the macro name indicating the offset position in the table to "BinaryImage_RZ_A1H.h".
The sample program executes with reference to this macro name for offset.
/media/uploads/dkato/cnv_img_to_bin_tbl_swipe_runner.zip


概要

ゴールまでの到着時間を競うゲームです。画面の左から右へスワイプすると走ります。
速くスワイプすると走るスピードがあがります。
USER_BUTTON0を押すと吹き出しコメントを日本語に変更できます。(初期状態では英語に設定されています)
アクセラレータハードウェア アクセラレーションを使って高速に描画。

構成

GR-PEACH、GR-PEACH 4.3inch LCD Shield。 /media/uploads/dkato/swipe_runner.jpg

描画する画像について

サンプルプログラムで使用している画像ファイルは、下記の"Convert Image to Binary Table"ツールを利用する事で、簡単に差し替えが可能です。
このツールは、Imagesフォルダ内にBinaryImage_RZ_A1H.c ファイルと BinaryImage_RZ_A1H.h ファイルを生成し、各画像ファイルをバイナリ変換します。そして、そのデータをBinaryImage_RZ_A1H.c ファイルのRGA_Sample_BinaryImageテーブルに出力し、BinaryImage_RZ_A1H.h ファイルにテーブル内のオフセット位置を示すマクロ名を定義します。
サンプルプログラムでは、オフセット用のマクロ名を参照して動作します。
/media/uploads/dkato/cnv_img_to_bin_tbl_swipe_runner.zip

main.cpp

Committer:
dkato
Date:
2016-11-25
Revision:
4:ee278c441f98
Parent:
2:9c5f0045c9df

File content as of revision 4:ee278c441f98:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include "mbed.h"
#include "DisplayBace.h"
#include "RGA.h"
#include "rtos.h"
#include "BinaryImage_RZ_A1H.h"
#include "LCD_shield_config_4_3inch.h"

#define GRAPHICS_FORMAT      (DisplayBase::GRAPHICS_FORMAT_RGB565)
#define WR_RD_WRSWA          (DisplayBase::WR_RD_WRSWA_32_16BIT)

/* FRAME BUFFER Parameter */
#define FRAME_BUFFER_BYTE_PER_PIXEL   (2)
#define FRAME_BUFFER_STRIDE           (((LCD_PIXEL_WIDTH * FRAME_BUFFER_BYTE_PER_PIXEL) + 31u) & ~31u)

#define GOAL_POINT                    (15000)
#define NO_IMAGE                      (0xFFFFFFFF)
#define LANGUAGE_NUM                  (2)

typedef struct {
    int now_pos;
    int tutorial_seq;
    int total_time;
    int record_time;
    int result_seq;
    int hito_ofs;
    int max_speed;
    int goal_seq;
    int hosi_seq;
    int speed;
    uint32_t hito_no;
    uint32_t comment_no;
    uint32_t ready_set_go;
    const graphics_image_t * p_hito;
    bool tutorial;
    bool swipe_on;
    bool goal_on;
    bool result_on;
    bool new_record;
    bool hosi;
    bool first_record;
    bool time_and_speed;
} disp_func_t;

static DisplayBase Display;
static Canvas2D_ContextClass canvas2d;
static DigitalOut lcd_pwon(P7_15);
static DigitalOut lcd_blon(P8_1);
static PwmOut     lcd_cntrst(P8_15);
static Serial     pc(USBTX, USBRX);
static Semaphore  sem_touch_int(0);
static TouckKey_LCD_shield touch(P4_0, P2_13, I2C_SDA, I2C_SCL);
static Timer  stop_watch;
static InterruptIn button(USER_BUTTON0);
static disp_func_t disp_info;
static bool  touch_click = false;
static bool touch_start = false;
static bool race_start = false;
static int total_move_x = 0;
static int wk_wait = 0;
static int pic_idx = 0;
static int tukare = 0;
static int table_no = 0;
static int language = 0;  /* 0:English */

#if defined(__ICCARM__)
#pragma data_alignment=32
static uint8_t user_frame_buffer1[FRAME_BUFFER_STRIDE * LCD_PIXEL_HEIGHT];
#pragma data_alignment=32
static uint8_t user_frame_buffer2[FRAME_BUFFER_STRIDE * LCD_PIXEL_HEIGHT];
#else
static uint8_t user_frame_buffer1[FRAME_BUFFER_STRIDE * LCD_PIXEL_HEIGHT]__attribute((aligned(32))); /* 32 bytes aligned */
static uint8_t user_frame_buffer2[FRAME_BUFFER_STRIDE * LCD_PIXEL_HEIGHT]__attribute((aligned(32))); /* 32 bytes aligned */
#endif
static frame_buffer_t frame_buffer_info;
static volatile int32_t vsync_count = 0;

static const graphics_image_t * hito_tukare[]  = {tukare1_File, tukare2_File};
static const graphics_image_t * hito_speed_1[] = {run1_File, run2_File, run3_File, run4_File, run5_File, run6_File, run7_File, run6_File, run5_File, run4_File, run3_File, run2_File};
static const graphics_image_t * hito_speed_2[] = {dash1_File, dash2_File, dash3_File, dash4_File, dash3_File, dash2_File};
static const graphics_image_t * hito_speed_3[] = {sdash1_File, sdash2_File, sdash3_File, sdash2_File};
static const graphics_image_t * comment_tbl[LANGUAGE_NUM][5]  = {
  {comment1_en_File, comment2_en_File, comment3_en_File, comment4_en_File, comment5_en_File},  /* English */
  {comment1_jp_File, comment2_jp_File, comment3_jp_File, comment4_jp_File, comment5_jp_File}   /* Japanese */
};
static const graphics_image_t * ready_set_go_tbl[] = {go_File, start1_File, start2_File, start3_File};
static const graphics_image_t * num_tbl[]      = {num_0_File, num_1_File, num_2_File, num_3_File, num_4_File, num_5_File, num_6_File, num_7_File, num_8_File, num_9_File};

static void IntCallbackFunc_LoVsync(DisplayBase::int_type_t int_type) {
    /* Interrupt callback function for Vsync interruption */
    if (vsync_count > 0) {
        vsync_count--;
    }
}

static void Wait_Vsync(const int32_t wait_count) {
    /* Wait for the specified number of times Vsync occurs */
    vsync_count = wait_count;
    while (vsync_count > 0) {
        /* Do nothing */
    }
}

static void Init_LCD_Display(void) {
    DisplayBase::graphics_error_t error;
    DisplayBase::lcd_config_t lcd_config;
    PinName lvds_pin[8] = {
        /* data pin */
        P5_7, P5_6, P5_5, P5_4, P5_3, P5_2, P5_1, P5_0
    };

    lcd_pwon = 0;
    lcd_blon = 0;
    Thread::wait(100);
    lcd_pwon = 1;
    lcd_blon = 1;

    Display.Graphics_Lvds_Port_Init(lvds_pin, 8);

    /* Graphics initialization process */
    lcd_config = LcdCfgTbl_LCD_shield;
    error = Display.Graphics_init(&lcd_config);
    if (error != DisplayBase::GRAPHICS_OK) {
        printf("Line %d, error %d\n", __LINE__, error);
        mbed_die();
    }

#if(1) /* When needing LCD Vsync interrupt, please make it effective. */
    /* Interrupt callback function setting (Vsync signal output from scaler 0) */
    error = Display.Graphics_Irq_Handler_Set(DisplayBase::INT_TYPE_S0_LO_VSYNC, 0, IntCallbackFunc_LoVsync);
    if (error != DisplayBase::GRAPHICS_OK) {
        printf("Line %d, error %d\n", __LINE__, error);
        mbed_die();
    }
#endif
}

static void Start_LCD_Display(uint8_t * p_buf) {
    DisplayBase::rect_t rect;

    rect.vs = 0;
    rect.vw = LCD_PIXEL_HEIGHT;
    rect.hs = 0;
    rect.hw = LCD_PIXEL_WIDTH;
    Display.Graphics_Read_Setting(
        DisplayBase::GRAPHICS_LAYER_0,
        (void *)p_buf,
        FRAME_BUFFER_STRIDE,
        GRAPHICS_FORMAT,
        WR_RD_WRSWA,
        &rect
    );
    Display.Graphics_Start(DisplayBase::GRAPHICS_LAYER_0);
}

static void Update_LCD_Display(frame_buffer_t * frmbuf_info) {
    Display.Graphics_Read_Change(DisplayBase::GRAPHICS_LAYER_0,
     (void *)frmbuf_info->buffer_address[frmbuf_info->draw_buffer_index]);
    Wait_Vsync(1);
}

static void Swap_FrameBuffer(frame_buffer_t * frmbuf_info) {
    if (frmbuf_info->draw_buffer_index == 1) {
        frmbuf_info->draw_buffer_index = 0;
    } else {
        frmbuf_info->draw_buffer_index = 1;
    }
}

static void draw_time(int time_num, int pos_x, int pos_y, int disp_flg) {
    int wk_num;

    wk_num = (time_num / 100) % 10;
    if ((wk_num != 0) || (disp_flg != false)) {
        canvas2d.drawImage(num_tbl[wk_num], pos_x + 17 * 0, pos_y);  /* 400x42 */
        R_OSPL_CLEAR_ERROR();
        disp_flg = true;
    }
    wk_num = (time_num / 10) % 10;
    if ((wk_num != 0) || (disp_flg != false)) {
        canvas2d.drawImage(num_tbl[wk_num], pos_x + 17 * 1, pos_y);  /* 400x42 */
        R_OSPL_CLEAR_ERROR();
    }
    wk_num = time_num % 10;
    canvas2d.drawImage(num_tbl[wk_num], pos_x + 17 * 2, pos_y);      /* 400x42 */
    R_OSPL_CLEAR_ERROR();
}

static void draw_total_time(int time_ms, int x, int y) {
    int wk_time_sec = time_ms / 1000;   /* sec */
    int wk_time_ms  = time_ms % 1000;   /* ms */

    if (wk_time_sec > 999) {
        wk_time_sec = 999;
        wk_time_ms = 999;
    }
    draw_time(wk_time_sec, x, y, false);
    draw_time(wk_time_ms,  x + 61, y, true);
}

static void touch_int_callback(void) {
    sem_touch_int.release();
}

void touch_task(void const *) {
    TouchKey::touch_pos_t touch_pos;
    int touch_num = 0;
    int touch_num_last = 0;
    int move_x = 0;
    uint32_t last_x = 0;

    /* Callback setting */
    touch.SetCallback(&touch_int_callback);

    /* Reset touch IC */
    touch.Reset();

    while (1) {
        /* Wait touch event */
        sem_touch_int.wait();

        /* Get touch coordinates */
        touch_num = touch.GetCoordinates(1, &touch_pos);

        if (touch_num != 0) {
            if (touch_num_last == 0) {
                /* key On */
            } else {
                /* Move */
                if (touch_start) {
                    move_x = (int)touch_pos.x - (int)last_x;
                    if (move_x > 0) {
                        total_move_x += move_x;
                    }
                }
            }
        } else {
            /* key Off */
            touch_click = true;
        }

        touch_num_last = touch_num;
        last_x = touch_pos.x;
    }
}

static void display_func(frame_buffer_t* frmbuf_info) {
    int wk_osf;
    int wk_pos;

    Swap_FrameBuffer(frmbuf_info);

    /* Clear */
    canvas2d.clearRect(0, 0, frmbuf_info->width, frmbuf_info->height);

    /* Distant background */
    wk_osf = ((disp_info.now_pos / 8) % 1000) + LCD_PIXEL_WIDTH - 1000;
    canvas2d.globalAlpha = 0.6f;
    if (wk_osf > 0) {
        canvas2d.drawImage(haikei_File, -1000 + wk_osf, 40);            /* 1000x173 */
        R_OSPL_CLEAR_ERROR();
    }
    canvas2d.drawImage(haikei_File, wk_osf, 40);
    R_OSPL_CLEAR_ERROR();

    /* Nearby background */
    wk_osf = ((disp_info.now_pos / 2) % 500) + LCD_PIXEL_WIDTH - 500;
    canvas2d.globalAlpha = 1.0f;
    if (wk_osf > 0) {
        canvas2d.drawImage(haikei_temae_File, -500 + wk_osf, 91);       /* 500x130 */
        R_OSPL_CLEAR_ERROR();
    }
    canvas2d.drawImage(haikei_temae_File, wk_osf, 91);                  /* 500x130 */
    R_OSPL_CLEAR_ERROR();

    /* Progress */
    canvas2d.globalAlpha = 1.0f;
    canvas2d.drawImage(logo_goal_File,  10, 5);                         /* 23x20 */
    R_OSPL_CLEAR_ERROR();
    canvas2d.drawImage(logo_start_File, LCD_PIXEL_WIDTH - 23 - 10, 5);  /* 23x20 */
    R_OSPL_CLEAR_ERROR();

    wk_pos = disp_info.now_pos;

    if (wk_pos > GOAL_POINT) {
        wk_pos = GOAL_POINT;
    }
    canvas2d.drawImage(logo_genzai_File,
                       (int)(((float_t)LCD_PIXEL_WIDTH - 75) * ((float_t)(GOAL_POINT - wk_pos) / GOAL_POINT) + 26), 5);
    R_OSPL_CLEAR_ERROR();

    /* Human */
    if (disp_info.p_hito != NULL) {
        canvas2d.globalAlpha = 1.0f;
        canvas2d.drawImage(disp_info.p_hito, (LCD_PIXEL_WIDTH - 143) / 2 + disp_info.hito_ofs, LCD_PIXEL_HEIGHT - 210);
        R_OSPL_CLEAR_ERROR();
    }

    /* Serif */
    canvas2d.globalAlpha = 1.0f;
    if (disp_info.tutorial) {
        canvas2d.drawImage(comment_tbl[language][0], 43, 50);
        R_OSPL_CLEAR_ERROR();
        canvas2d.drawImage(comment_tbl[language][1], 275, 50);
        R_OSPL_CLEAR_ERROR();
    }
    if (disp_info.comment_no != NO_IMAGE) {
        canvas2d.drawImage(comment_tbl[language][disp_info.comment_no], 265, 50);
        R_OSPL_CLEAR_ERROR();
    }

    /* Swipe */
    if (disp_info.swipe_on) {
        canvas2d.globalAlpha = 0.9f;
        canvas2d.drawImage(swipe_File, disp_info.tutorial_seq * 6, (LCD_PIXEL_HEIGHT / 2) - 10);
        disp_info.tutorial_seq++;
        if ((disp_info.tutorial_seq * 6) >= LCD_PIXEL_WIDTH) {
            disp_info.tutorial_seq = 0;
        }
    }

    /* Ready Set Go! */
    if (disp_info.ready_set_go != NO_IMAGE) {
        canvas2d.globalAlpha = 0.82f;
        canvas2d.drawImage(ready_set_go_tbl[disp_info.ready_set_go], (LCD_PIXEL_WIDTH - 100) / 2,
                           (LCD_PIXEL_HEIGHT - 100) / 2);
        R_OSPL_CLEAR_ERROR();
    }

    /* Goooal! */
    if (disp_info.goal_on) {
        canvas2d.globalAlpha = (0.04f * disp_info.goal_seq);
        canvas2d.drawImage(goooal_File,
                            (LCD_PIXEL_WIDTH - 260 * (2.0 - (float_t)disp_info.goal_seq / 25)) / 2,
                            (LCD_PIXEL_HEIGHT - 53 * (2.0 - (float_t)disp_info.goal_seq / 25)) / 2,
                            260 * (2.0 - (float_t)disp_info.goal_seq / 25),
                            53 * (2.0 - (float_t)disp_info.goal_seq / 25));    /* 260x53 */
        R_OSPL_CLEAR_ERROR();
    }

    /* Result */
    if (disp_info.result_on) {
        /* record */
        canvas2d.globalAlpha = (0.025f * disp_info.result_seq);
        canvas2d.drawImage(result_File, (LCD_PIXEL_WIDTH - 400) / 2,
                           LCD_PIXEL_HEIGHT / 2 + 32 - disp_info.result_seq);  /* 400x68 */
        R_OSPL_CLEAR_ERROR();
        draw_total_time(disp_info.total_time, (LCD_PIXEL_WIDTH / 2 - 200 + 185),
                        (LCD_PIXEL_HEIGHT / 2 + 9) + 32 - disp_info.result_seq);
        draw_time(disp_info.max_speed, (LCD_PIXEL_WIDTH / 2 - 200 + 185 + 34),
                  (LCD_PIXEL_HEIGHT / 2 + 20 + 9) + 32 - disp_info.result_seq, false);
    }

    /* 1st record */
    if (disp_info.first_record) {
        canvas2d.drawImage(record_1st_File, 145, 201);
        R_OSPL_CLEAR_ERROR();
        draw_total_time(disp_info.record_time, 145 + 20, 201);
        canvas2d.drawImage(dot_File, 145 + 20 + 52, 201 + 11); /* . */
        R_OSPL_CLEAR_ERROR();
        canvas2d.drawImage(sec_File, 145 + 20 + 115, 201);     /* sec */
        R_OSPL_CLEAR_ERROR();
    }

    /* New Record */
    if (disp_info.new_record) {
        canvas2d.globalAlpha = 1.0f;
        canvas2d.drawImage(new_record_File, (LCD_PIXEL_WIDTH - 194) / 2, 20);
        R_OSPL_CLEAR_ERROR();
    }

    /* Star */
    if (disp_info.hosi) {
        int wk_seq;

        if (disp_info.hosi_seq < 25) {
            wk_seq = disp_info.hosi_seq;
            canvas2d.globalAlpha = 1.0f - (0.04f * wk_seq);
            canvas2d.drawImage(hosi_File, 300, 60);
        } else if (disp_info.hosi_seq < 50) {
            wk_seq = disp_info.hosi_seq - 25;
            canvas2d.globalAlpha = 1.0f - (0.04f * wk_seq);
            canvas2d.drawImage(hosi_File, 70, 100);
        } else {
            wk_seq = disp_info.hosi_seq - 50;
            canvas2d.globalAlpha = 1.0f - (0.04f * wk_seq);
            canvas2d.drawImage(hosi_File, 270, 170);
        }
        R_OSPL_CLEAR_ERROR();
        disp_info.hosi_seq++;
        if (disp_info.hosi_seq >= 75) {
             disp_info.hosi_seq = 0;
        }
    }

    /* Speed and Time */
    if (disp_info.time_and_speed) {
        int wk_ofs;

        canvas2d.globalAlpha = 1.0f;

        /* Speed */
        if (disp_info.speed >= 100) {
            wk_ofs = 10;
        } else if (disp_info.speed >= 10) {
            wk_ofs = 10 - 17;
        } else {
            wk_ofs = 10 - 17 - 17;
        }
        draw_time(disp_info.speed, wk_ofs, LCD_PIXEL_HEIGHT - 19 - 5, false);
        /* Time */
        draw_total_time(stop_watch.read_ms(), LCD_PIXEL_WIDTH - 112 - 5, LCD_PIXEL_HEIGHT - 19 - 5);
        canvas2d.drawImage(dot_File, LCD_PIXEL_WIDTH - 112 - 5 + 52, LCD_PIXEL_HEIGHT - 19 - 5 + 11);  /* . */
        R_OSPL_CLEAR_ERROR();
    }

    /* Complete drawing */
    R_GRAPHICS_Finish(canvas2d.c_LanguageContext);
    Update_LCD_Display(frmbuf_info);
}

static void set_hito_pic(void) {
    int new_table_no = 0;
    int bonus;
    float_t bonu_rate;

    disp_info.speed = total_move_x / 50;
    bonu_rate = ((float_t)disp_info.speed / 100.00);
    if (bonu_rate > 0.70) {
        bonu_rate = 0.70;
    }
    bonus = (int)((float_t)disp_info.speed * bonu_rate);

    if (disp_info.speed > disp_info.max_speed) {
        disp_info.max_speed = disp_info.speed;
    }

    if (disp_info.speed >= 50) {
        disp_info.comment_no = NO_IMAGE;
        new_table_no = 3;
    } else if (disp_info.speed >= 30) {
        tukare = 8;
        if ((race_start != false) && (disp_info.comment_no == 3)) {
            disp_info.comment_no = 4;
        }
        new_table_no = 2;
    } else if (disp_info.speed >= 1) {
        if ((race_start != false) && (disp_info.comment_no == 2)) {
            disp_info.comment_no = 3;
        }
        new_table_no = 1;
    } else {
        if (race_start != false) {
            disp_info.comment_no = 2;
        }
        new_table_no = 0;
    }

    if (new_table_no != table_no) {
        table_no = new_table_no;
        pic_idx = 0;
    }

    if (wk_wait == 0) {
        switch (table_no) {
            case 0:
                if (tukare > 0) {
                    tukare--;
                    disp_info.p_hito = hito_tukare[pic_idx++];
                    if (pic_idx >= (sizeof(hito_tukare) / sizeof(graphics_image_t *))) {
                        pic_idx = 0;
                    }
                    wk_wait = 20;
                } else {
                    disp_info.p_hito = start_File;
                    pic_idx = 0;
                    wk_wait = 3;
                }
                break;
            case 1:
                disp_info.p_hito = hito_speed_1[pic_idx++];
                if (pic_idx >= (sizeof(hito_speed_1) / sizeof(graphics_image_t *))) {
                    pic_idx = 0;
                }
                if (disp_info.speed <= 1) {
                   wk_wait = 6;
                } else if (disp_info.speed <= 3) {
                   wk_wait = 5;
                } else if (disp_info.speed <= 6) {
                   wk_wait = 4;
                } else if (disp_info.speed <= 12) {
                   wk_wait = 3;
                } else if (disp_info.speed <= 20) {
                   wk_wait = 2;
                } else {
                   wk_wait = 1;
                }
                break;
            case 2:
                disp_info.p_hito = hito_speed_2[pic_idx++];
                if (pic_idx >= (sizeof(hito_speed_2) / sizeof(graphics_image_t *))) {
                    pic_idx = 0;
                }
                if (disp_info.speed <= 40) {
                     wk_wait = 1;
                } else {
                     wk_wait = 0;
                }
                break;
            case 3:
                disp_info.p_hito = hito_speed_3[pic_idx++];
                if (pic_idx >= (sizeof(hito_speed_3) / sizeof(graphics_image_t *))) {
                    pic_idx = 0;
                }
                wk_wait = 0;
                break;
            default:
                break;
        }
    } else {
        wk_wait--;
    }

    disp_info.now_pos += disp_info.speed;
    if (disp_info.now_pos > GOAL_POINT) {
        disp_info.now_pos = GOAL_POINT;
    }
    total_move_x -= (disp_info.speed - bonus);
}

static void button_fall(void) {
    if ((language + 1) < LANGUAGE_NUM) {
        language++;
    } else {
        language = 0;
    }
}

int main(void) {
    errnum_t err;
    Canvas2D_ContextConfigClass config;

    /* Change the baud rate of the printf() */
    pc.baud(921600);

    button.fall(&button_fall);

    /* Initialization of LCD */
    Init_LCD_Display();

    memset(user_frame_buffer1, 0, sizeof(user_frame_buffer1));
    memset(user_frame_buffer2, 0, sizeof(user_frame_buffer2));
    frame_buffer_info.buffer_address[0] = user_frame_buffer1;
    frame_buffer_info.buffer_address[1] = user_frame_buffer2;
    frame_buffer_info.buffer_count      = 2;
    frame_buffer_info.show_buffer_index = 0;
    frame_buffer_info.draw_buffer_index = 0;
    frame_buffer_info.width             = LCD_PIXEL_WIDTH;
    frame_buffer_info.byte_per_pixel    = FRAME_BUFFER_BYTE_PER_PIXEL;
    frame_buffer_info.stride            = LCD_PIXEL_WIDTH * FRAME_BUFFER_BYTE_PER_PIXEL;
    frame_buffer_info.height            = LCD_PIXEL_HEIGHT;
    frame_buffer_info.pixel_format      = PIXEL_FORMAT_RGB565;

    config.frame_buffer = &frame_buffer_info;
    canvas2d = R_RGA_New_Canvas2D_ContextClass(config);
    err = R_OSPL_GetErrNum();
    if (err != 0) {
        printf("Line %d, error %d\n", __LINE__, err);
        mbed_die();
    }

    /* Start of LCD */
    Start_LCD_Display(frame_buffer_info.buffer_address[0]);

    /* Backlight on */
    Thread::wait(200);
    lcd_cntrst.write(1.0);

    Thread touchTask(touch_task, NULL, osPriorityNormal, 1024 * 2);
    Timer  system_timer;

    disp_info.tutorial    = true;
    disp_info.record_time = 15000;
    stop_watch.reset();
    system_timer.reset();

    while (1) {
        if (disp_info.tutorial) {
            touch_start = false;
            stop_watch.reset();
            stop_watch.stop();
            disp_info.speed          = 0;
            disp_info.ready_set_go   = NO_IMAGE;
            disp_info.now_pos        = 0;
            disp_info.comment_no     = NO_IMAGE;
            disp_info.p_hito         = start_File;
            disp_info.hito_ofs       = 0;
            disp_info.max_speed      = 0;
            disp_info.swipe_on       = false;
            disp_info.goal_on        = false;
            disp_info.result_on      = false;
            disp_info.new_record     = false;
            disp_info.hosi           = false;
            disp_info.first_record   = true;
            disp_info.time_and_speed = false;
            disp_info.total_time     = 0;
            disp_info.swipe_on       = true;
            disp_info.tutorial_seq   = 0;
            total_move_x             = 0;
            race_start               = false;
            pic_idx                  = 0;
            wk_wait                  = 0;
            tukare                   = 0;
            touch_click              = false;
            while (touch_click == false) {
                display_func(&frame_buffer_info);
            }
            disp_info.swipe_on       = false;
            disp_info.tutorial       = false;

            /* Ready Go! */
            system_timer.reset();
            system_timer.start();
            disp_info.time_and_speed = true;
            disp_info.first_record   = false;
            disp_info.ready_set_go   = 3;
            disp_info.now_pos        = 0;
            disp_info.speed          = 0;
            total_move_x             = 0;
            pic_idx                  = 0;
            table_no                 = 0;
        }

        if (disp_info.ready_set_go != NO_IMAGE) {
            int wk_system_time = system_timer.read_ms();
            if (wk_system_time > 4000) {
                disp_info.ready_set_go = NO_IMAGE;
                if (disp_info.now_pos == 0) {
                    disp_info.swipe_on = true;
                    disp_info.tutorial_seq = 0;
                }
            } else if (wk_system_time > 3000) {
                if (disp_info.ready_set_go != 0) {
                    disp_info.ready_set_go = 0;
                    touch_start = true;
                    race_start = true;
                    stop_watch.start();
                    disp_info.comment_no = 0;
                }
            } else if (wk_system_time > 2000) {
                disp_info.ready_set_go = 1;
            } else if (wk_system_time > 1000) {
                disp_info.ready_set_go = 2;
            } else {
                /* do nothing */
            }
        }
        if (disp_info.now_pos != 0) {
            disp_info.swipe_on = false;
        }

        set_hito_pic();
        display_func(&frame_buffer_info);

        disp_info.total_time = stop_watch.read_ms();
        if ((disp_info.total_time > 35000) && (disp_info.speed == 0)) {
            disp_info.tutorial = true;
        }
        if (disp_info.now_pos >= GOAL_POINT) {
            int over_run = 0;
            int wk_ofs;
            int back_speed;
            int i;

            stop_watch.stop();
            race_start = false;
            disp_info.comment_no = NO_IMAGE;

            /* Through the goal */
            disp_info.goal_on = true;
            disp_info.goal_seq = 0;

            system_timer.reset();
            system_timer.start();

            while (system_timer.read_ms() < 1500) {
                total_move_x = total_move_x * 0.9;
                set_hito_pic();
                disp_info.comment_no = NO_IMAGE;
                disp_info.hito_ofs -= disp_info.speed;
                over_run += disp_info.speed;
                display_func(&frame_buffer_info);
                if (disp_info.goal_seq < 25) {
                     disp_info.goal_seq++;
                }
            }

            /* Catch up background */
            disp_info.time_and_speed = false;
            back_speed = over_run / 60 + 1;

            for (i = 0; i < 60; i++) {
                if (over_run > back_speed) {
                    wk_ofs = back_speed;
                    if (wk_wait == 0) {
                        disp_info.p_hito = hito_tukare[pic_idx++];
                        if (pic_idx >= (sizeof(hito_tukare) / sizeof(graphics_image_t *))) {
                            pic_idx = 0;
                        }
                        wk_wait = 20;
                    } else {
                        wk_wait--;
                    }
                } else {
                    wk_ofs = over_run;
                    disp_info.p_hito = goal_File;
                }
                if (over_run != 0) {
                    over_run -= wk_ofs;
                    disp_info.now_pos  += wk_ofs;
                    disp_info.hito_ofs += wk_ofs;
                }
                display_func(&frame_buffer_info);
                if (disp_info.goal_seq > 1) {
                     disp_info.goal_seq--;
                } else {
                    disp_info.goal_on = false;
                }
            }

            disp_info.result_on = true;
            disp_info.first_record = true;
            for (disp_info.result_seq = 1; disp_info.result_seq < 40; disp_info.result_seq++) {
                display_func(&frame_buffer_info);
            }

            if (disp_info.total_time < disp_info.record_time) {
                disp_info.record_time = disp_info.total_time;
                disp_info.new_record = true;
                disp_info.hosi = true;
                disp_info.hosi_seq = 0;
                touch_click = false;
            }

            touch_click = false;
            while (touch_click == false) {
                display_func(&frame_buffer_info);
            }
            disp_info.tutorial = true;
        }
    }
}