diff --git a/CMakeLists.txt b/CMakeLists.txt index c8f36d3..ad9e4c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,9 +29,11 @@ include("${DEVKITPRO}/cmake/3DS.cmake") # LVGL # ----------------------------------------------------------------------------- -set(LV_CONF_INCLUDE_SIMPLE ON) -set(LV_BUILD_CONF_DIR include) - +cmake_policy(SET CMP0077 NEW) +#set(LV_CONF_INCLUDE_SIMPLE ON) +#set(LV_BUILD_CONF_PATH ./include/lv_conf.h) +set(CONFIG_LV_BUILD_EXAMPLES OFF) +set(CONFIG_LV_BUILD_DEMOS OFF) add_subdirectory(libraries/lvgl) # ----------------------------------------------------------------------------- @@ -40,6 +42,7 @@ add_subdirectory(libraries/lvgl) add_executable(${PROJECT_NAME} source/main.c source/lv_ctr_disp.c + source/lv_ctr_indev.c ) target_include_directories(${PROJECT_NAME} PRIVATE diff --git a/include/lv_ctr_disp.h b/include/lv_ctr_disp.h index 8fdfc81..4f28920 100644 --- a/include/lv_ctr_disp.h +++ b/include/lv_ctr_disp.h @@ -25,6 +25,13 @@ extern "C" { * DEFINES *********************/ +// TODO: make it configurable for RGB888/RGB565 +// (currently hardcoded to ARGB888, otherwise I was getting only white screen) +#define CTR_LV_COLOR_FORMAT LV_COLOR_FORMAT_ARGB8888 +#define CTR_TEX_COLOR_FORMAT GPU_RGBA8 +#define CTR_TR_IN_COLOR_FORMAT GX_TRANSFER_FMT_RGBA8 +#define CTR_TR_OUT_COLOR_FORMAT GX_TRANSFER_FMT_RGBA8 + /********************** * TYPEDEFS **********************/ diff --git a/include/lv_ctr_indev.h b/include/lv_ctr_indev.h new file mode 100644 index 0000000..d997b3c --- /dev/null +++ b/include/lv_ctr_indev.h @@ -0,0 +1,48 @@ + +/** + * @file lv_ctr_indev.h + * + */ + +#if 1 + +#ifndef LV_CTR_INDEV_H +#define LV_CTR_INDEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#if defined(LV_LVGL_H_INCLUDE_SIMPLE) +#include "lvgl.h" +#else +#include "lvgl/lvgl.h" +#endif + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * GLOBAL PROTOTYPES + **********************/ +void lv_ctr_indev_init(void); + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_CTR_INDEV_H*/ + +#endif /*Disable/Enable content*/ diff --git a/include/lv_conf.h b/lv_conf.h similarity index 65% rename from include/lv_conf.h rename to lv_conf.h index bdf80c1..c0d1df8 100644 --- a/include/lv_conf.h +++ b/lv_conf.h @@ -1,11 +1,14 @@ #ifndef LV_CONF_H #define LV_CONF_H -#define LV_COLOR_DEPTH 16 +#define LV_COLOR_DEPTH 32 +#define LV_USE_OS 0 #define LV_MEM_SIZE (256U * 1024U) -#define LV_USE_LOG 0 +#define LV_USE_LOG 1 +//#define LV_LOG_LEVEL LV_LOG_LEVEL_TRACE +#define LV_LOG_PRINTF 1 #define LV_USE_ASSERT_NULL 1 diff --git a/source/lv_ctr_disp.c b/source/lv_ctr_disp.c index d03cb81..77533d7 100644 --- a/source/lv_ctr_disp.c +++ b/source/lv_ctr_disp.c @@ -22,7 +22,9 @@ #define BOTTOM_TEX_HOR_RES 512 #define BOTTOM_TEX_VER_RES 256 -#define BYTE_PER_PIXEL (LV_COLOR_FORMAT_GET_SIZE(LV_COLOR_FORMAT_ARGB8888)) +#define BYTE_PER_PIXEL (LV_COLOR_FORMAT_GET_SIZE(CTR_LV_COLOR_FORMAT)) +#define BOTTOM_DISP_STRIDE (BOTTOM_TEX_HOR_RES * BYTE_PER_PIXEL) +#define BOTTOM_DISP_BUF_SIZE BOTTOM_DISP_STRIDE * BOTTOM_DISP_VER_RES /********************** * TYPEDEFS @@ -48,6 +50,8 @@ __attribute__ ((const)) static inline u32 tex_pot(u32 x) { C3D_RenderTarget *bottom_screen; C3D_Tex tex; Tex3DS_SubTexture subt3x; +LV_ATTRIBUTE_MEM_ALIGN static uint8_t * buf_1 = NULL; +LV_ATTRIBUTE_MEM_ALIGN static uint8_t * buf_2 = NULL; /********************** * MACROS @@ -68,13 +72,14 @@ void lv_ctr_disp_init(void) * Create a display and set a flush_cb * -----------------------------------*/ lv_display_t * bottom_disp = lv_display_create(BOTTOM_DISP_HOR_RES, BOTTOM_DISP_VER_RES); + lv_display_set_color_format(bottom_disp, CTR_LV_COLOR_FORMAT); lv_display_set_flush_cb(bottom_disp, disp_flush); + lv_display_set_default(bottom_disp); /* Two buffers for double buffering. */ -#define BOTTOM_TEX_STRIDE (BOTTOM_TEX_HOR_RES * BYTE_PER_PIXEL) - LV_ATTRIBUTE_MEM_ALIGN static uint8_t buf_1[BOTTOM_TEX_STRIDE * BOTTOM_DISP_VER_RES]; - LV_ATTRIBUTE_MEM_ALIGN static uint8_t buf_2[BOTTOM_TEX_STRIDE * BOTTOM_DISP_VER_RES]; - lv_display_set_buffers_with_stride(bottom_disp, buf_1, buf_2, sizeof(buf_1), BOTTOM_TEX_STRIDE, LV_DISPLAY_RENDER_MODE_FULL); + buf_1 = linearAlloc(BOTTOM_DISP_BUF_SIZE); + buf_2 = linearAlloc(BOTTOM_DISP_BUF_SIZE); + lv_display_set_buffers_with_stride(bottom_disp, buf_1, buf_2, BOTTOM_DISP_BUF_SIZE, BOTTOM_DISP_STRIDE, LV_DISPLAY_RENDER_MODE_FULL); } @@ -85,17 +90,14 @@ void lv_ctr_disp_init(void) /*Initialize your display and the required peripherals.*/ static void disp_init(void) { - gfxInitDefault(); - - ptmuInit(); - C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); C2D_Init(C2D_DEFAULT_MAX_OBJECTS); C2D_Prepare(); bottom_screen = C2D_CreateScreenTarget(GFX_BOTTOM, GFX_LEFT); - if(0 == C3D_TexInit(&tex, BOTTOM_TEX_HOR_RES, BOTTOM_TEX_VER_RES, GPU_RGB8)) puts("Could not create main texture."); - memset(tex.data, 0, tex.size); + if(0 == C3D_TexInit(&tex, BOTTOM_TEX_HOR_RES, BOTTOM_TEX_VER_RES, CTR_TEX_COLOR_FORMAT)) puts("Could not create main texture."); + memset(tex.data, 0xFF, tex.size); + C3D_TexFlush(&tex); tex.border = 0xFFFFFFFF; C3D_TexSetWrap(&tex, GPU_CLAMP_TO_BORDER, GPU_CLAMP_TO_BORDER); @@ -134,21 +136,25 @@ static void disp_flush(lv_display_t * disp_drv, const lv_area_t * area, uint8_t if (lv_display_flush_is_last(disp_drv)) { GSPGPU_FlushDataCache(px_map, tex.width * tex.height * 4); - u32 dim = GX_BUFFER_DIM(tex.width, tex.height); - C3D_SyncDisplayTransfer((u32 *)px_map, dim, (u32*)tex.data, dim, - (GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | - GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | - GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) - ); + u32 dim = GX_BUFFER_DIM(tex.width, tex.height); + C3D_SyncDisplayTransfer((u32 *)px_map, dim, (u32*)tex.data, dim, + (GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | + GX_TRANSFER_IN_FORMAT(CTR_TR_IN_COLOR_FORMAT) | GX_TRANSFER_OUT_FORMAT(CTR_TR_OUT_COLOR_FORMAT) | + GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) + ); - // start frame, clear targets - C3D_FrameBegin(C3D_FRAME_SYNCDRAW); - C2D_TargetClear(bottom_screen, C2D_Color32f(0, 0, 0, 1)); + // start frame, clear targets + C3D_FrameBegin(C3D_FRAME_SYNCDRAW); + C2D_TargetClear(bottom_screen, C2D_Color32f(0, 0, 0, 1)); + C2D_ImageTint tint; + C2D_PlainImageTint(&tint, C2D_Color32(255,255,255,255), 1.0f); - C2D_SceneBegin(bottom_screen); + gspWaitForVBlank(); + + C2D_SceneBegin(bottom_screen); - C2D_Image img = { &tex, &subt3x }; - C2D_DrawImageAt(img, 0, 0, 0.6f, NULL, 1.0f, 1.0f); + C2D_Image img = { &tex, &subt3x }; + C2D_DrawImageAt(img, 0, 0, 0.6f, &tint, 1.f, 1.f); C3D_FrameEnd(0); } diff --git a/source/lv_ctr_indev.c b/source/lv_ctr_indev.c new file mode 100644 index 0000000..9f3791b --- /dev/null +++ b/source/lv_ctr_indev.c @@ -0,0 +1,90 @@ +/** + * @file lv_ctr_indev.c + * + */ + +#if 1 + +/********************* + * INCLUDES + *********************/ +#include "lv_ctr_indev.h" +#include <3ds.h> + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +static void touchpad_read(lv_indev_t * indev, lv_indev_data_t * data); + +/********************** + * STATIC VARIABLES + **********************/ +lv_indev_t * indev_touchpad; + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_ctr_indev_init(void) +{ + /*Register a touch screen input device*/ + indev_touchpad = lv_indev_create(); + lv_indev_set_type(indev_touchpad, LV_INDEV_TYPE_POINTER); + lv_indev_set_read_cb(indev_touchpad, touchpad_read); + + /*Later you should create group(s) with `lv_group_t * group = lv_group_create()`, + *add objects to the group with `lv_group_add_obj(group, obj)` + *and assign this input device to group to navigate in it: + *`lv_indev_set_group(indev_keypad, group);`*/ +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +/*------------------ + * Touchpad + * -----------------*/ + +static void touchpad_read(lv_indev_t * indev_drv, lv_indev_data_t * data) +{ + static int32_t last_x = 0; + static int32_t last_y = 0; + touchPosition touch; + + hidScanInput(); + + /*Save the pressed coordinates and the state*/ + if(hidKeysHeld() & KEY_TOUCH) { + hidTouchRead(&touch); + last_x = touch.px; + last_y = touch.py; + data->state = LV_INDEV_STATE_PRESSED; + } + else { + data->state = LV_INDEV_STATE_RELEASED; + } + + /*Set the last pressed coordinates*/ + data->point.x = last_x; + data->point.y = last_y; +} + +#else /*Enable this file at the top*/ + +/*This dummy typedef exists purely to silence -Wpedantic.*/ +typedef int keep_pedantic_happy; +#endif diff --git a/source/main.c b/source/main.c index eeeab5b..fe572b7 100644 --- a/source/main.c +++ b/source/main.c @@ -4,37 +4,171 @@ #include <3ds.h> #include "lvgl.h" #include "lv_ctr_disp.h" +#include "lv_ctr_indev.h" + + +static lv_obj_t * cursor; +static lv_obj_t * label; +static lv_obj_t * label2; +static lv_obj_t * fps_label; + -// ote: expected 'lv_tick_get_cb_t' {aka 'long unsigned int (*)(void)'} but argument is of type 'u64 (*)(void)' {aka 'long long unsigned int (*)(void)'} long unsigned int sys_tick(void) { - return (long unsigned int)svcGetSystemTick(); + long unsigned int tick = (long unsigned int)osGetTime(); + return tick; +} + +void sys_init(void) +{ + gfxInitDefault(); + consoleInit(GFX_TOP, NULL); +} + +void sys_free(void) +{ + gfxExit(); +} + +static void cursor_timer_cb(lv_timer_t * t) +{ + LV_UNUSED(t); + + lv_indev_t * indev = lv_indev_get_next(NULL); + + if (!indev) + return; + + lv_point_t p; + lv_indev_get_point(indev, &p); + + if (lv_indev_get_state(indev) == LV_INDEV_STATE_PRESSED) { + + lv_obj_set_pos(cursor, p.x - 5, p.y - 5); + lv_obj_clear_flag(cursor, LV_OBJ_FLAG_HIDDEN); + + lv_label_set_text_fmt(label2, + "x: %d\ny: %d", + p.x, + p.y); + } + else { + lv_obj_add_flag(cursor, LV_OBJ_FLAG_HIDDEN); + } +} + +static void switch_event_cb(lv_event_t * e) +{ + lv_obj_t * sw = lv_event_get_target(e); + + if (lv_obj_has_state(sw, LV_STATE_CHECKED)) + lv_label_set_text_fmt(label, "ON"); + else + lv_label_set_text_fmt(label, "OFF"); +} + +static void fps_tick(void) +{ + static u32 frames = 0; + static u64 last = 0; + + u64 now = osGetTime(); + + frames++; + + if (now - last >= 1000) { + + lv_label_set_text_fmt(fps_label, + "FPS: %lu", + frames); + + frames = 0; + last = now; + } +} + +static void ui_prepare(void) +{ + /* Container START */ + lv_obj_t * cont = lv_obj_create(lv_screen_active()); + + /* Container layout */ + lv_obj_set_size(cont, 220, 120); + lv_obj_center(cont); + + lv_obj_set_layout(cont, LV_LAYOUT_FLEX); + lv_obj_set_flex_flow(cont, LV_FLEX_FLOW_COLUMN); + lv_obj_set_flex_align(cont, + LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_CENTER, + LV_FLEX_ALIGN_CENTER); + + /* Optional cleaner look */ + lv_obj_set_style_pad_all(cont, 16, 0); + lv_obj_set_style_pad_row(cont, 12, 0); + + /* Label */ + label = lv_label_create(cont); + lv_label_set_text(label, "Hello world"); + + /* Switch */ + lv_obj_t * sw = lv_switch_create(cont); + lv_obj_center(sw); + lv_obj_add_event_cb(sw, + switch_event_cb, + LV_EVENT_VALUE_CHANGED, + NULL); + /* Container END */ + + /* Cursor */ + cursor = lv_obj_create(lv_screen_active()); + lv_obj_set_size(cursor, 10, 10); + lv_obj_set_style_radius(cursor, LV_RADIUS_CIRCLE, 0); + lv_obj_set_style_bg_color(cursor, lv_palette_main(LV_PALETTE_RED), 0); + lv_obj_set_style_border_width(cursor, 0, 0); + + /* Coord label */ + label2 = lv_label_create(lv_screen_active()); + lv_obj_align(label2, LV_ALIGN_TOP_LEFT, 4, 4); + + /* FPS label */ + fps_label = lv_label_create(lv_screen_active()); + lv_obj_align(fps_label, + LV_ALIGN_BOTTOM_LEFT, + 4, + -4); + + /* Main loop UI update timer */ + lv_timer_create(cursor_timer_cb, 16, NULL); + + lv_obj_invalidate(lv_screen_active()); } int main(int argc, char* argv[]) { - lv_ctr_disp_init(); + sys_init(); lv_init(); + lv_ctr_disp_init(); + lv_ctr_indev_init(); lv_tick_set_cb(sys_tick); - lv_obj_t * label = lv_label_create(lv_screen_active()); - lv_label_set_text(label, "Hello world"); - lv_obj_center(label); + ui_prepare(); - // Main loop - while (aptMainLoop()) - { - lv_timer_handler(); - gspWaitForVBlank(); - gfxSwapBuffers(); - hidScanInput(); + // Main loop + while (aptMainLoop()) + { + u64 start = osGetTime(); + lv_timer_handler(); + u64 end = osGetTime(); + lv_label_set_text_fmt(fps_label, "render: %llums", end - start); - // Your code goes here - u32 kDown = hidKeysDown(); - if (kDown & KEY_START) - break; // break in order to return to hbmenu - } + hidScanInput(); - gfxExit(); - return 0; + u32 kDown = hidKeysDown(); + if (kDown & KEY_START) + break; // break in order to return to hbmenu + } + + sys_free(); + return 0; }