2022-08-14 16:31:09 +02:00
|
|
|
#include <vhex/display.h>
|
|
|
|
#include <vhex/display/draw/circle.h>
|
|
|
|
#include <vhex/display/draw/pixel.h>
|
|
|
|
#include <vhex/display/image.h>
|
|
|
|
#include <vhex/timer.h>
|
|
|
|
#include <vhex/timer/fps.h>
|
|
|
|
#include <vhex/timer/profiling.h>
|
|
|
|
#include <vhex/keyboard.h>
|
|
|
|
|
|
|
|
#define BG_COLOR 0x869c
|
|
|
|
#define CIRCLE_COLOR 0xcf1c
|
|
|
|
#define NB_CIRCLE 9
|
|
|
|
#define NB_BUTTON_ROW 8
|
|
|
|
#define NB_BUTTON_COL 5
|
|
|
|
#define NB_BUTTON_TOTAL (NB_BUTTON_ROW * NB_BUTTON_COL)
|
|
|
|
|
|
|
|
/* define internal circle information structure */
|
|
|
|
struct circle {
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
int size;
|
|
|
|
} circle[NB_CIRCLE] = {
|
|
|
|
{ .x = 42, .y = 163, .size = 35 },
|
|
|
|
{ .x = 72, .y = 31, .size = 55 },
|
|
|
|
{ .x = 223, .y = 239, .size = 60 },
|
|
|
|
{ .x = 265, .y = 109, .size = 51 },
|
|
|
|
{ .x = 358, .y = 0, .size = 34 },
|
|
|
|
{ .x = 396, .y = 185, .size = 50 },
|
|
|
|
{ .x = 506, .y = 83, .size = 65 },
|
|
|
|
{ .x = 587, .y = 230, .size = 53 },
|
|
|
|
{ .x = 606, .y = 38, .size = 27 },
|
|
|
|
};
|
|
|
|
|
|
|
|
//---
|
|
|
|
// Internal functions
|
|
|
|
//---
|
|
|
|
|
|
|
|
/* menu_background() : update and draw circle */
|
|
|
|
static void menu_background(void)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < NB_CIRCLE; ++i) {
|
|
|
|
circle[i].x += 1;
|
|
|
|
if ((circle[i].x - circle[i].size) >= (int)dwidth())
|
|
|
|
circle[i].x -= (dwidth() + (circle[i].size << 1));
|
|
|
|
dcircle_filled(
|
|
|
|
circle[i].x,
|
|
|
|
circle[i].y,
|
|
|
|
circle[i].size,
|
|
|
|
DCIRCLE_CENTER | DCIRCLE_MIDDLE,
|
|
|
|
CIRCLE_COLOR
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* title menu */
|
|
|
|
|
|
|
|
/* menu_title_background() : display circle */
|
|
|
|
static void menu_title_background(void)
|
|
|
|
{
|
|
|
|
menu_background();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* menu_icon() : display the game icon */
|
|
|
|
static void menu_title_icon(void)
|
|
|
|
{
|
|
|
|
extern const image_t gduck_menu_title;
|
|
|
|
did_t did;
|
|
|
|
|
|
|
|
did = dimage(
|
|
|
|
&gduck_menu_title,
|
|
|
|
dwidth() / 2,
|
|
|
|
(dheight() / 2) - (dheight() / 8),
|
|
|
|
DIMAGE_CENTER | DIMAGE_MIDDLE
|
|
|
|
);
|
|
|
|
dimage_shader_shadow(did, -4, 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* menu_hub() : display HUD information */
|
|
|
|
static void menu_title_hud(fps_t *fps, int trigger)
|
|
|
|
{
|
|
|
|
dprint(0, 0, C_WHITE, "FPS: %d", fps->fps);
|
|
|
|
if (trigger != 0) {
|
|
|
|
dtext_opt(
|
|
|
|
dwidth() / 2,
|
|
|
|
(dheight() / 2) + (dheight() / 4),
|
|
|
|
C_WHITE,
|
|
|
|
C_NONE,
|
|
|
|
DTEXT_CENTER | DTEXT_MIDDLE,
|
|
|
|
"Press [SHIFT] to start !",
|
|
|
|
-1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* menu_text_blink() : change trigger status each 500ms */
|
|
|
|
static int menu_title_text_blink(volatile int *trigger)
|
|
|
|
{
|
|
|
|
*trigger ^= 1;
|
|
|
|
return TIMER_CONTINUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* selection menu */
|
|
|
|
|
|
|
|
/* menu_select_background() : display circle */
|
|
|
|
static void menu_select_background(void)
|
|
|
|
{
|
|
|
|
menu_background();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* menu_select_ui() : display button selection */
|
|
|
|
static void menu_select_ui(int max_level, int cursor)
|
|
|
|
{
|
|
|
|
extern const image_t gduck_menu_select_title;
|
|
|
|
extern const image_t gduck_menu_select_button_bg;
|
|
|
|
extern const image_t gduck_menu_select_button_0;
|
|
|
|
extern const image_t gduck_menu_select_button_1;
|
|
|
|
extern const image_t gduck_menu_select_button_2;
|
|
|
|
const image_t *image;
|
|
|
|
int counter;
|
|
|
|
int imgx;
|
|
|
|
int imgy;
|
|
|
|
int imgs;
|
|
|
|
|
|
|
|
dimage(
|
|
|
|
&gduck_menu_select_title,
|
|
|
|
dwidth() / 2,
|
|
|
|
dheight() / 6,
|
|
|
|
DIMAGE_CENTER | DIMAGE_MIDDLE
|
|
|
|
);
|
|
|
|
dimage(
|
|
|
|
&gduck_menu_select_button_bg,
|
|
|
|
dwidth() / 2,
|
|
|
|
(dheight() / 2) + (dheight() / 8),
|
|
|
|
DIMAGE_CENTER | DIMAGE_MIDDLE
|
|
|
|
);
|
|
|
|
|
|
|
|
imgx = (NB_BUTTON_ROW * gduck_menu_select_button_0.width);
|
|
|
|
imgx += (NB_BUTTON_ROW - 1);
|
|
|
|
imgx = (dwidth() / 2) - (imgx / 2);
|
|
|
|
imgx += (gduck_menu_select_button_0.width / 2);
|
|
|
|
|
|
|
|
imgy = (NB_BUTTON_COL * gduck_menu_select_button_0.height);
|
|
|
|
imgy += (NB_BUTTON_COL - 1);
|
|
|
|
imgy = ((dheight() / 2) + (dheight() / 8)) - (imgy / 2);
|
|
|
|
imgy += (gduck_menu_select_button_0.height / 2);
|
|
|
|
|
|
|
|
imgs = imgx;
|
|
|
|
counter = 0;
|
|
|
|
for (int y = 0; y < NB_BUTTON_COL; ++y)
|
|
|
|
{
|
|
|
|
imgx = imgs;
|
|
|
|
for (int x = 0; x < NB_BUTTON_ROW; ++x)
|
|
|
|
{
|
|
|
|
image = &gduck_menu_select_button_0;
|
|
|
|
if (counter == cursor)
|
|
|
|
image = &gduck_menu_select_button_1;
|
|
|
|
if (counter >= max_level)
|
|
|
|
image = &gduck_menu_select_button_2;
|
|
|
|
|
|
|
|
dimage(
|
|
|
|
image,
|
|
|
|
imgx,
|
|
|
|
imgy,
|
|
|
|
DIMAGE_CENTER | DIMAGE_MIDDLE
|
|
|
|
);
|
|
|
|
|
|
|
|
if (image != &gduck_menu_select_button_2) {
|
|
|
|
dprint_opt(
|
|
|
|
imgx - 1,
|
|
|
|
imgy + 1,
|
|
|
|
C_WHITE,
|
|
|
|
C_NONE,
|
|
|
|
DTEXT_CENTER | DTEXT_MIDDLE,
|
|
|
|
"%d",
|
|
|
|
counter + 1
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
imgx += image->width + 1;
|
|
|
|
counter += 1;
|
|
|
|
}
|
|
|
|
imgy += image->height + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* menu_select_hud() : display HUB information */
|
|
|
|
static void menu_select_hud(fps_t *fps)
|
|
|
|
{
|
|
|
|
dprint(0, 0, C_WHITE, "FPS: %d (%d us)", fps->fps, fps->render);
|
|
|
|
}
|
|
|
|
|
|
|
|
//---
|
|
|
|
// Public function
|
|
|
|
//----
|
|
|
|
|
|
|
|
/* menu_title() : display logo/animation and wait user interaction */
|
|
|
|
void menu_title(void)
|
|
|
|
{
|
|
|
|
volatile int trigger;
|
2022-12-04 18:33:46 +01:00
|
|
|
vkey_event_t e;
|
2022-08-14 16:31:09 +02:00
|
|
|
fps_t fps;
|
|
|
|
int exit;
|
|
|
|
int timer;
|
|
|
|
|
|
|
|
trigger = 1;
|
|
|
|
timer = timer_configure(
|
|
|
|
TIMER_DELAY_MS(500),
|
|
|
|
VHEX_CALL(&menu_title_text_blink, &trigger)
|
|
|
|
);
|
|
|
|
timer_start(timer);
|
|
|
|
|
|
|
|
uint32_t cache_us = 0;
|
|
|
|
uint32_t render_us = 0;
|
|
|
|
uint32_t key_us = 0;
|
|
|
|
|
|
|
|
exit = 1;
|
2023-01-17 22:05:09 +01:00
|
|
|
timer_fps_init(&fps, 30);
|
2022-08-14 16:31:09 +02:00
|
|
|
while (exit)
|
|
|
|
{
|
|
|
|
cache_us = timer_prof_exec({
|
|
|
|
dclear(BG_COLOR);
|
|
|
|
menu_title_background();
|
|
|
|
menu_title_icon();
|
|
|
|
menu_title_hud(&fps, trigger);
|
|
|
|
dprint(0, 20, C_WHITE,
|
|
|
|
"cache = %d us\nrender = %d us\nkey = %d us",
|
|
|
|
cache_us, render_us, key_us
|
|
|
|
);
|
|
|
|
});
|
|
|
|
render_us = timer_prof_exec({ dupdate(); });
|
|
|
|
|
2023-01-17 22:05:09 +01:00
|
|
|
timer_fps_sync(&fps);
|
2022-08-14 16:31:09 +02:00
|
|
|
|
|
|
|
key_us = timer_prof_exec({
|
2022-12-04 18:33:46 +01:00
|
|
|
while (keyvent_poll(&e)) {
|
|
|
|
if (e.type == VKEYEV_NONE)
|
2022-08-14 16:31:09 +02:00
|
|
|
break;
|
2022-12-04 18:33:46 +01:00
|
|
|
if (e.type != VKEYEV_UP)
|
2022-08-14 16:31:09 +02:00
|
|
|
continue;
|
2022-12-04 18:33:46 +01:00
|
|
|
if (e.key == VKEY_SHIFT)
|
2022-08-14 16:31:09 +02:00
|
|
|
exit = 0;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
timer_fps_quit(&fps);
|
|
|
|
timer_stop(timer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* menu_select() : level selection */
|
|
|
|
int menu_select(int max_level)
|
|
|
|
{
|
2022-12-04 18:33:46 +01:00
|
|
|
vkey_event_t e;
|
2022-08-14 16:31:09 +02:00
|
|
|
fps_t fps;
|
|
|
|
int cursor;
|
|
|
|
int exit;
|
|
|
|
|
|
|
|
exit = -1;
|
|
|
|
cursor = 0;
|
2023-01-17 22:05:09 +01:00
|
|
|
timer_fps_init(&fps, 30);
|
2022-08-14 16:31:09 +02:00
|
|
|
while (exit < 0)
|
|
|
|
{
|
|
|
|
dclear(BG_COLOR);
|
|
|
|
menu_select_background();
|
|
|
|
menu_select_ui(max_level, cursor);
|
|
|
|
menu_select_hud(&fps);
|
|
|
|
dupdate();
|
|
|
|
|
2023-01-17 22:05:09 +01:00
|
|
|
timer_fps_sync(&fps);
|
2022-08-14 16:31:09 +02:00
|
|
|
|
2022-12-04 18:33:46 +01:00
|
|
|
while (keyvent_poll(&e)) {
|
|
|
|
if (e.type != VKEYEV_UP)
|
2022-08-14 16:31:09 +02:00
|
|
|
continue;
|
2022-12-04 18:33:46 +01:00
|
|
|
if (e.key == VKEY_LEFT) cursor -= 1;
|
|
|
|
if (e.key == VKEY_RIGHT) cursor += 1;
|
|
|
|
if (e.key == VKEY_DOWN) cursor += NB_BUTTON_ROW;
|
|
|
|
if (e.key == VKEY_UP) cursor -= NB_BUTTON_ROW;
|
2022-08-14 16:31:09 +02:00
|
|
|
|
|
|
|
if (cursor < 0) cursor = 0;
|
|
|
|
if (cursor >= max_level) cursor = max_level - 1;
|
|
|
|
|
2022-12-04 18:33:46 +01:00
|
|
|
if (e.key == VKEY_SHIFT) exit = cursor;
|
2022-08-14 16:31:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
timer_fps_quit(&fps);
|
|
|
|
return (cursor);
|
|
|
|
}
|