WIP: settings, color picker and stuff

This commit is contained in:
2024-01-05 22:19:31 +02:00
parent b8d11050f8
commit bba2f8a189
10 changed files with 561 additions and 68 deletions
+171 -50
View File
@@ -64,29 +64,29 @@ void print_new_board() {
Color get_tile_color(u16 value) { Color get_tile_color(u16 value) {
switch (value) { switch (value) {
case 2: case 2:
return ColorRGBA(238, 228, 218, 255); return game.palette.tile_colors[0];
case 4: case 4:
return ColorRGBA(237, 224, 200, 255); return game.palette.tile_colors[1];
case 8: case 8:
return ColorRGBA(242, 177, 121, 255); return game.palette.tile_colors[2];
case 16: case 16:
return ColorRGBA(245, 149, 99, 255); return game.palette.tile_colors[3];
case 32: case 32:
return ColorRGBA(246, 124, 95, 255); return game.palette.tile_colors[4];
case 64: case 64:
return ColorRGBA(246, 94, 59, 255); return game.palette.tile_colors[5];
case 128: case 128:
return ColorRGBA(237, 207, 114, 255); return game.palette.tile_colors[6];
case 256: case 256:
return ColorRGBA(237, 204, 97, 255); return game.palette.tile_colors[7];
case 512: case 512:
return ColorRGBA(237, 200, 80, 255); return game.palette.tile_colors[8];
case 1024: case 1024:
return ColorRGBA(237, 197, 63, 255); return game.palette.tile_colors[9];
case 2048: case 2048:
return ColorRGBA(237, 194, 46, 255); return game.palette.tile_colors[10];
default: default:
return ColorRGBA(237, 194, 46, 255); return game.palette.tile_colors[10];
} }
} }
@@ -399,6 +399,7 @@ void reset_game(void) {
game.spawning_new_tile = false; game.spawning_new_tile = false;
game.quit_dialog = false; game.quit_dialog = false;
game.help_dialog = false; game.help_dialog = false;
game.settings_dialog = false;
game.has_lost = false; game.has_lost = false;
game.game_over_bg_opacity = 0; game.game_over_bg_opacity = 0;
game.game_over_opacity = 0; game.game_over_opacity = 0;
@@ -421,9 +422,29 @@ void reset_game(void) {
void game_attempt_quit(void) { void game_attempt_quit(void) {
game.help_dialog = false; game.help_dialog = false;
game.settings_dialog = false;
game.quit_dialog = true; game.quit_dialog = true;
} }
void reset_palette(void) {
game.palette = (ColorPalette){
.bg_color = ColorRGBA(248, 250, 230, 255),
.board_bg_color = ColorRGBA(140, 154, 147, 255),
.tile_colors[0] = ColorRGBA(238, 228, 218, 255), // 2
.tile_colors[1] = ColorRGBA(237, 224, 200, 255), // 4
.tile_colors[2] = ColorRGBA(242, 177, 121, 255), // 8
.tile_colors[3] = ColorRGBA(245, 149, 99, 255), // 16
.tile_colors[4] = ColorRGBA(246, 124, 95, 255), // 32
.tile_colors[5] = ColorRGBA(246, 94, 59, 255), // 64
.tile_colors[6] = ColorRGBA(237, 207, 114, 255), // 128
.tile_colors[7] = ColorRGBA(237, 204, 97, 255), // 256
.tile_colors[8] = ColorRGBA(237, 200, 80, 255), // 512
.tile_colors[9] = ColorRGBA(237, 197, 63, 255), // 1024
.tile_colors[10] = ColorRGBA(237, 194, 46, 255), // 2048
};
}
void game_init(void) { void game_init(void) {
srand(time(NULL)); srand(time(NULL));
@@ -431,6 +452,8 @@ void game_init(void) {
game.icon_textures[SETTINGS_ICON] = load_texture("assets/icons/settings.png"); game.icon_textures[SETTINGS_ICON] = load_texture("assets/icons/settings.png");
game.icon_textures[CLOSE_ICON] = load_texture("assets/icons/close.png"); game.icon_textures[CLOSE_ICON] = load_texture("assets/icons/close.png");
reset_palette();
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
spawn_random_tile(); spawn_random_tile();
} }
@@ -447,37 +470,39 @@ void game_init(void) {
void draw_bg(void) { void draw_bg(void) {
Size window_size = zephr_get_window_size(); Size window_size = zephr_get_window_size();
UIConstraints board_con = {0}; UIConstraints board_con = default_constraints;
set_width_constraint(&board_con, window_size.width, UI_CONSTRAINT_FIXED); set_width_constraint(&board_con, window_size.width, UI_CONSTRAINT_FIXED);
set_height_constraint(&board_con, window_size.height, UI_CONSTRAINT_FIXED); set_height_constraint(&board_con, window_size.height, UI_CONSTRAINT_FIXED);
// bg // bg
draw_quad(&board_con, ColorRGBA(248, 250, 230, 255), 0, ALIGN_TOP_LEFT); draw_quad(&board_con, game.palette.bg_color, 0, ALIGN_TOP_LEFT);
GlyphInstanceList batch;
new_glyph_instance_list(&batch, 32);
// 2048 text // 2048 text
UIConstraints text_con = {0}; UIConstraints text_con = default_constraints;
set_y_constraint(&text_con, 0.05f, UI_CONSTRAINT_RELATIVE); set_y_constraint(&text_con, 0.05f, UI_CONSTRAINT_RELATIVE);
set_width_constraint(&text_con, 1.5, UI_CONSTRAINT_RELATIVE_PIXELS); set_width_constraint(&text_con, 1.5, UI_CONSTRAINT_RELATIVE_PIXELS);
draw_text("2048", 100, text_con, ColorRGBA(34, 234, 82, 155), ALIGN_TOP_CENTER); add_text_instance(&batch, "2048", 100, text_con, ColorRGBA(34, 234, 82, 155), ALIGN_TOP_CENTER);
// score // score
char score[16]; char score[24];
sprintf(score, "%d", game.score); sprintf(score, "Score %d", game.score);
set_parent_constraint(&text_con, NULL); set_parent_constraint(&text_con, NULL);
set_x_constraint(&text_con, 0.05f, UI_CONSTRAINT_RELATIVE); set_x_constraint(&text_con, 0.05f, UI_CONSTRAINT_RELATIVE);
set_y_constraint(&text_con, 0.8f, UI_CONSTRAINT_RELATIVE); set_y_constraint(&text_con, 0.8f, UI_CONSTRAINT_RELATIVE);
draw_text("Score", 40, text_con, COLOR_BLACK, ALIGN_TOP_LEFT); add_text_instance(&batch, score, 40, text_con, COLOR_BLACK, ALIGN_TOP_LEFT);
set_x_constraint(&text_con, 0.15f, UI_CONSTRAINT_RELATIVE); draw_text_batch(&batch);
draw_text(score, 40, text_con, COLOR_BLACK, ALIGN_TOP_LEFT);
} }
void draw_quit_dialog(void) { void draw_quit_dialog(void) {
UIConstraints dialog_con = {0}; UIConstraints dialog_con = default_constraints;
set_x_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED); set_x_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED);
set_y_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED); set_y_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED);
set_width_constraint(&dialog_con, 1.f, UI_CONSTRAINT_RELATIVE); set_width_constraint(&dialog_con, 1.f, UI_CONSTRAINT_RELATIVE);
@@ -488,45 +513,45 @@ void draw_quit_dialog(void) {
set_height_constraint(&dialog_con, 0.2f, UI_CONSTRAINT_RELATIVE); set_height_constraint(&dialog_con, 0.2f, UI_CONSTRAINT_RELATIVE);
draw_quad(&dialog_con, ColorRGBA(135, 124, 124, 255), 8, ALIGN_CENTER); draw_quad(&dialog_con, ColorRGBA(135, 124, 124, 255), 8, ALIGN_CENTER);
UIConstraints text_con = {0}; UIConstraints text_con = default_constraints;
set_parent_constraint(&text_con, &dialog_con); set_parent_constraint(&text_con, &dialog_con);
set_x_constraint(&text_con, 0, UI_CONSTRAINT_FIXED); set_x_constraint(&text_con, 0, UI_CONSTRAINT_FIXED);
set_y_constraint(&text_con, -0.04f, UI_CONSTRAINT_RELATIVE); set_y_constraint(&text_con, -0.25f, UI_CONSTRAINT_RELATIVE);
set_width_constraint(&text_con, 1, UI_CONSTRAINT_RELATIVE_PIXELS); set_width_constraint(&text_con, 1, UI_CONSTRAINT_RELATIVE_PIXELS);
draw_text("Are you sure you want to quit?", 36.f, text_con, COLOR_WHITE, ALIGN_CENTER); draw_text("Are you sure you want to quit?", 36.f, text_con, COLOR_WHITE, ALIGN_CENTER);
UIConstraints btn_con = {0}; UIConstraints btn_con = default_constraints;
set_parent_constraint(&btn_con, &dialog_con); set_parent_constraint(&btn_con, &dialog_con);
set_width_constraint(&btn_con, 0.12f, UI_CONSTRAINT_RELATIVE); set_width_constraint(&btn_con, 0.25f, UI_CONSTRAINT_RELATIVE);
set_height_constraint(&btn_con, 0.05f, UI_CONSTRAINT_RELATIVE); set_height_constraint(&btn_con, 0.25f, UI_CONSTRAINT_RELATIVE);
set_y_constraint(&btn_con, -0.02f, UI_CONSTRAINT_RELATIVE); set_y_constraint(&btn_con, -0.10f, UI_CONSTRAINT_RELATIVE);
set_x_constraint(&btn_con, -0.07f, UI_CONSTRAINT_RELATIVE); set_x_constraint(&btn_con, -0.20f, UI_CONSTRAINT_RELATIVE);
if (draw_button(&btn_con, mult_color(COLOR_WHITE, 0.9f), "Yes", btn_con.height * 0.20f, ALIGN_BOTTOM_CENTER, BUTTON_STATE_ACTIVE)) { if (draw_button(&btn_con, mult_color(COLOR_WHITE, 0.9f), "Yes", btn_con.height * 0.20f, ALIGN_BOTTOM_CENTER, BUTTON_STATE_ACTIVE)) {
zephr_quit(); zephr_quit();
} }
set_y_constraint(&btn_con, -0.02f, UI_CONSTRAINT_RELATIVE); set_y_constraint(&btn_con, -0.10f, UI_CONSTRAINT_RELATIVE);
set_x_constraint(&btn_con, 0.07f, UI_CONSTRAINT_RELATIVE); set_x_constraint(&btn_con, 0.20f, UI_CONSTRAINT_RELATIVE);
if (draw_button(&btn_con, mult_color(COLOR_WHITE, 0.9f), "No", btn_con.height * 0.20f, ALIGN_BOTTOM_CENTER, BUTTON_STATE_ACTIVE)) { if (draw_button(&btn_con, mult_color(COLOR_WHITE, 0.9f), "No", btn_con.height * 0.20f, ALIGN_BOTTOM_CENTER, BUTTON_STATE_ACTIVE)) {
game.quit_dialog = false; game.quit_dialog = false;
} }
} }
void draw_help_dialog(void) { void draw_help_dialog(void) {
UIConstraints dialog_con = {0}; UIConstraints dialog_con = default_constraints;
set_width_constraint(&dialog_con, 1.f, UI_CONSTRAINT_RELATIVE); set_width_constraint(&dialog_con, 1.f, UI_CONSTRAINT_RELATIVE);
set_height_constraint(&dialog_con, 1.f, UI_CONSTRAINT_RELATIVE); set_height_constraint(&dialog_con, 1.f, UI_CONSTRAINT_RELATIVE);
set_x_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED); set_x_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED);
set_y_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED); set_y_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED);
draw_quad(&dialog_con, ColorRGBA(0, 0, 0, 200), 0, ALIGN_CENTER); draw_quad(&dialog_con, ColorRGBA(0, 0, 0, 200), 0, ALIGN_CENTER);
UIConstraints content_card_con = {0}; UIConstraints content_card_con = default_constraints;
set_parent_constraint(&content_card_con, &dialog_con); set_parent_constraint(&content_card_con, &dialog_con);
set_width_constraint(&content_card_con, 0.4f, UI_CONSTRAINT_RELATIVE); set_width_constraint(&content_card_con, 0.4f, UI_CONSTRAINT_RELATIVE);
set_height_constraint(&content_card_con, 0.3f, UI_CONSTRAINT_RELATIVE); set_height_constraint(&content_card_con, 0.33f, UI_CONSTRAINT_RELATIVE);
draw_quad(&content_card_con, ColorRGBA(135, 124, 124, 255), 8, ALIGN_CENTER); draw_quad(&content_card_con, ColorRGBA(135, 124, 124, 255), 8, ALIGN_CENTER);
UIConstraints text_con = {0}; UIConstraints text_con = default_constraints;
set_parent_constraint(&text_con, &content_card_con); set_parent_constraint(&text_con, &content_card_con);
set_width_constraint(&text_con, 1, UI_CONSTRAINT_RELATIVE_PIXELS); set_width_constraint(&text_con, 1, UI_CONSTRAINT_RELATIVE_PIXELS);
set_x_constraint(&text_con, 0, UI_CONSTRAINT_FIXED); set_x_constraint(&text_con, 0, UI_CONSTRAINT_FIXED);
@@ -539,7 +564,7 @@ void draw_help_dialog(void) {
"When two tiles with the same number touch, they\n" "When two tiles with the same number touch, they\n"
"merge into one!\n\nYour goal is to reach 2048 without filling all the tiles", 30.f, text_con, COLOR_WHITE, ALIGN_CENTER); "merge into one!\n\nYour goal is to reach 2048 without filling all the tiles", 30.f, text_con, COLOR_WHITE, ALIGN_CENTER);
UIConstraints btn_con = {0}; UIConstraints btn_con = default_constraints;
set_parent_constraint(&btn_con, &content_card_con); set_parent_constraint(&btn_con, &content_card_con);
set_width_constraint(&btn_con, 56, UI_CONSTRAINT_RELATIVE_PIXELS); set_width_constraint(&btn_con, 56, UI_CONSTRAINT_RELATIVE_PIXELS);
set_height_constraint(&btn_con, 1, UI_CONSTRAINT_ASPECT_RATIO); set_height_constraint(&btn_con, 1, UI_CONSTRAINT_ASPECT_RATIO);
@@ -550,33 +575,124 @@ void draw_help_dialog(void) {
} }
} }
void draw_settings_dialog(void) {
UIConstraints dialog_con = default_constraints;
set_width_constraint(&dialog_con, 1.f, UI_CONSTRAINT_RELATIVE);
set_height_constraint(&dialog_con, 1.f, UI_CONSTRAINT_RELATIVE);
set_x_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED);
set_y_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED);
draw_quad(&dialog_con, ColorRGBA(0, 0, 0, 200), 0, ALIGN_CENTER);
UIConstraints content_card_con = default_constraints;
set_parent_constraint(&content_card_con, &dialog_con);
set_width_constraint(&content_card_con, 0.55f, UI_CONSTRAINT_RELATIVE);
set_height_constraint(&content_card_con, 0.6f, UI_CONSTRAINT_RELATIVE);
draw_quad(&content_card_con, ColorRGBA(135, 124, 124, 255), 8, ALIGN_CENTER);
UIConstraints text_con = default_constraints;
set_parent_constraint(&text_con, &content_card_con);
set_width_constraint(&text_con, 1, UI_CONSTRAINT_RELATIVE_PIXELS);
set_x_constraint(&text_con, 0, UI_CONSTRAINT_FIXED);
set_y_constraint(&text_con, 40, UI_CONSTRAINT_RELATIVE_PIXELS);
draw_text("Settings", 64.f, text_con, COLOR_YELLOW, ALIGN_TOP_CENTER);
set_x_constraint(&text_con, 30, UI_CONSTRAINT_RELATIVE_PIXELS);
set_y_constraint(&text_con, 150, UI_CONSTRAINT_RELATIVE_PIXELS);
draw_text("Color Palette", 40.f, text_con, COLOR_WHITE, ALIGN_TOP_LEFT);
const char *bg_color_text = "Background: ";
const u8 font_size = 30.f;
set_x_constraint(&text_con, 30, UI_CONSTRAINT_RELATIVE_PIXELS);
set_y_constraint(&text_con, 220, UI_CONSTRAINT_RELATIVE_PIXELS);
set_height_constraint(&text_con, 0.9f, UI_CONSTRAINT_RELATIVE);
draw_text(bg_color_text, font_size, text_con, COLOR_WHITE, ALIGN_TOP_LEFT);
Sizef text_size = calculate_text_size(bg_color_text, font_size);
UIConstraints color_picker_con = default_constraints;
set_parent_constraint(&color_picker_con, &content_card_con);
set_x_constraint(&color_picker_con, 30 + text_size.width + 20, UI_CONSTRAINT_RELATIVE_PIXELS);
set_y_constraint(&color_picker_con, 220 - text_size.height / 2.f + 6, UI_CONSTRAINT_RELATIVE_PIXELS);
set_width_constraint(&color_picker_con, 100, UI_CONSTRAINT_RELATIVE_PIXELS);
set_height_constraint(&color_picker_con, 40, UI_CONSTRAINT_RELATIVE_PIXELS);
draw_color_picker(&color_picker_con, &game.palette.bg_color, ALIGN_TOP_LEFT, BUTTON_STATE_ACTIVE);
set_y_constraint(&text_con, 270, UI_CONSTRAINT_RELATIVE_PIXELS);
draw_text("Board: ", font_size, text_con, COLOR_WHITE, ALIGN_TOP_LEFT);
set_x_constraint(&color_picker_con, 30 + text_size.width + 20, UI_CONSTRAINT_RELATIVE_PIXELS);
set_y_constraint(&color_picker_con, 270 - text_size.height / 2.f + 6, UI_CONSTRAINT_RELATIVE_PIXELS);
set_width_constraint(&color_picker_con, 100, UI_CONSTRAINT_RELATIVE_PIXELS);
set_height_constraint(&color_picker_con, 40, UI_CONSTRAINT_RELATIVE_PIXELS);
draw_color_picker(&color_picker_con, &game.palette.board_bg_color, ALIGN_TOP_LEFT, BUTTON_STATE_ACTIVE);
set_y_constraint(&text_con, 320, UI_CONSTRAINT_RELATIVE_PIXELS);
draw_text("Tiles: ", font_size, text_con, COLOR_WHITE, ALIGN_TOP_LEFT);
const u8 tile_size = 60;
for (u8 i = 0; i < 11; i++) {
set_x_constraint(&color_picker_con, 30 + text_size.width + 20 + (i * (tile_size + 10)), UI_CONSTRAINT_RELATIVE_PIXELS);
set_y_constraint(&color_picker_con, 320 - text_size.height / 2.f + 6, UI_CONSTRAINT_RELATIVE_PIXELS);
set_width_constraint(&color_picker_con, tile_size, UI_CONSTRAINT_RELATIVE_PIXELS);
set_height_constraint(&color_picker_con, tile_size, UI_CONSTRAINT_RELATIVE_PIXELS);
draw_color_picker(&color_picker_con, &game.palette.tile_colors[i], ALIGN_TOP_LEFT, BUTTON_STATE_ACTIVE);
u16 tile_val = (u16)pow(2, i + 1);
char text[16];
sprintf(text, "%d", tile_val);
const f32 font_size = get_tile_font_size(tile_val) * 0.5f;
const Color tile_color = get_tile_color(tile_val);
set_parent_constraint(&text_con, &color_picker_con);
set_x_constraint(&text_con, 0, UI_CONSTRAINT_RELATIVE_PIXELS);
set_y_constraint(&text_con, 0, UI_CONSTRAINT_RELATIVE_PIXELS);
draw_text(text, (u8)font_size, text_con, mult_color(tile_color, 0.5f), ALIGN_CENTER);
}
UIConstraints btn_con = default_constraints;
set_parent_constraint(&btn_con, &content_card_con);
set_x_constraint(&btn_con, 0, UI_CONSTRAINT_RELATIVE_PIXELS);
set_y_constraint(&btn_con, 400, UI_CONSTRAINT_RELATIVE_PIXELS);
set_width_constraint(&btn_con, 150, UI_CONSTRAINT_RELATIVE_PIXELS);
set_height_constraint(&btn_con, 0.35f, UI_CONSTRAINT_ASPECT_RATIO);
if (draw_button(&btn_con, ColorRGBA(201, 146, 126, 255), "Reset", 8.f, ALIGN_TOP_CENTER, BUTTON_STATE_ACTIVE)) {
reset_palette();
}
set_width_constraint(&btn_con, 56, UI_CONSTRAINT_RELATIVE_PIXELS);
set_height_constraint(&btn_con, 1, UI_CONSTRAINT_ASPECT_RATIO);
set_y_constraint(&btn_con, -24, UI_CONSTRAINT_RELATIVE_PIXELS);
set_x_constraint(&btn_con, 24, UI_CONSTRAINT_RELATIVE_PIXELS);
if (draw_icon_button(&btn_con, mult_color(COLOR_WHITE, 0.8f), game.icon_textures[CLOSE_ICON], btn_con.height * 0.20f, ALIGN_TOP_RIGHT, BUTTON_STATE_ACTIVE)) {
game.settings_dialog = false;
}
}
void draw_game_over(void) { void draw_game_over(void) {
UIConstraints dialog_con = {0}; UIConstraints dialog_con = default_constraints;
set_width_constraint(&dialog_con, 1.f, UI_CONSTRAINT_RELATIVE); set_width_constraint(&dialog_con, 1.f, UI_CONSTRAINT_RELATIVE);
set_height_constraint(&dialog_con, 1.f, UI_CONSTRAINT_RELATIVE); set_height_constraint(&dialog_con, 1.f, UI_CONSTRAINT_RELATIVE);
set_x_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED); set_x_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED);
set_y_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED); set_y_constraint(&dialog_con, 0, UI_CONSTRAINT_FIXED);
draw_quad(&dialog_con, ColorRGBA(0, 0, 0, (u8)game.game_over_bg_opacity), 0, ALIGN_CENTER); draw_quad(&dialog_con, ColorRGBA(0, 0, 0, (u8)game.game_over_bg_opacity), 0, ALIGN_CENTER);
UIConstraints content_card_con = {0}; UIConstraints content_card_con = default_constraints;
set_parent_constraint(&content_card_con, &dialog_con); set_parent_constraint(&content_card_con, &dialog_con);
set_width_constraint(&content_card_con, 0.3f, UI_CONSTRAINT_RELATIVE); set_width_constraint(&content_card_con, 0.3f, UI_CONSTRAINT_RELATIVE);
set_height_constraint(&content_card_con, 0.2f, UI_CONSTRAINT_RELATIVE); set_height_constraint(&content_card_con, 0.2f, UI_CONSTRAINT_RELATIVE);
draw_quad(&content_card_con, ColorRGBA(135, 124, 124, (u8)game.game_over_opacity), 8, ALIGN_CENTER); draw_quad(&content_card_con, ColorRGBA(135, 124, 124, (u8)game.game_over_opacity), 8, ALIGN_CENTER);
UIConstraints text_con = {0}; UIConstraints text_con = default_constraints;
set_parent_constraint(&text_con, &content_card_con); set_parent_constraint(&text_con, &content_card_con);
set_width_constraint(&text_con, 1, UI_CONSTRAINT_RELATIVE_PIXELS); set_width_constraint(&text_con, 1, UI_CONSTRAINT_RELATIVE_PIXELS);
set_x_constraint(&text_con, 0, UI_CONSTRAINT_FIXED); set_x_constraint(&text_con, 0, UI_CONSTRAINT_FIXED);
set_y_constraint(&text_con, 40, UI_CONSTRAINT_RELATIVE_PIXELS); set_y_constraint(&text_con, 40, UI_CONSTRAINT_RELATIVE_PIXELS);
draw_text("Game Over!", 64.f, text_con, ColorRGBA(255, 255, 0, (u8)game.game_over_opacity), ALIGN_TOP_CENTER); draw_text("Game Over!", 64.f, text_con, ColorRGBA(255, 255, 0, (u8)game.game_over_opacity), ALIGN_TOP_CENTER);
UIConstraints btn_con = {0}; UIConstraints btn_con = default_constraints;
const ButtonState btn_state = game.quit_dialog ? BUTTON_STATE_INACTIVE : game.game_over_opacity > 0 ? BUTTON_STATE_ACTIVE : BUTTON_STATE_INACTIVE; const ButtonState btn_state = game.quit_dialog ? BUTTON_STATE_INACTIVE : game.game_over_opacity > 0 ? BUTTON_STATE_ACTIVE : BUTTON_STATE_INACTIVE;
set_parent_constraint(&btn_con, &content_card_con); set_parent_constraint(&btn_con, &content_card_con);
set_x_constraint(&btn_con, 0, UI_CONSTRAINT_RELATIVE_PIXELS); set_x_constraint(&btn_con, 0, UI_CONSTRAINT_RELATIVE_PIXELS);
set_y_constraint(&btn_con, -24, UI_CONSTRAINT_RELATIVE_PIXELS); set_y_constraint(&btn_con, -24, UI_CONSTRAINT_RELATIVE_PIXELS);
set_width_constraint(&btn_con, 0.10f, UI_CONSTRAINT_RELATIVE); set_width_constraint(&btn_con, 0.30f, UI_CONSTRAINT_RELATIVE);
set_height_constraint(&btn_con, 0.3f, UI_CONSTRAINT_ASPECT_RATIO); set_height_constraint(&btn_con, 0.3f, UI_CONSTRAINT_ASPECT_RATIO);
if (draw_button(&btn_con, ColorRGBA(201, 146, 126, (u8)game.game_over_opacity), "Try Again", 8.f, ALIGN_BOTTOM_CENTER, btn_state)) { if (draw_button(&btn_con, ColorRGBA(201, 146, 126, (u8)game.game_over_opacity), "Try Again", 8.f, ALIGN_BOTTOM_CENTER, btn_state)) {
reset_game(); reset_game();
@@ -584,14 +700,14 @@ void draw_game_over(void) {
} }
void draw_ui(void) { void draw_ui(void) {
ButtonState bg_btns_state = game.quit_dialog || game.help_dialog || game.has_lost ButtonState bg_btns_state = game.quit_dialog || game.help_dialog || game.settings_dialog || game.has_lost
? BUTTON_STATE_INACTIVE ? BUTTON_STATE_INACTIVE
: BUTTON_STATE_ACTIVE; : BUTTON_STATE_ACTIVE;
const int icon_btn_width = 80; const int icon_btn_width = 80;
const int icon_btn_offset = 8; const int icon_btn_offset = 8;
const int icon_btns_padding = 10; const int icon_btns_padding = 10;
UIConstraints btn_con = {0}; UIConstraints btn_con = default_constraints;
set_x_constraint(&btn_con, -icon_btn_offset, UI_CONSTRAINT_RELATIVE_PIXELS); set_x_constraint(&btn_con, -icon_btn_offset, UI_CONSTRAINT_RELATIVE_PIXELS);
set_y_constraint(&btn_con, icon_btn_offset, UI_CONSTRAINT_RELATIVE_PIXELS); set_y_constraint(&btn_con, icon_btn_offset, UI_CONSTRAINT_RELATIVE_PIXELS);
set_width_constraint(&btn_con, icon_btn_width, UI_CONSTRAINT_RELATIVE_PIXELS); set_width_constraint(&btn_con, icon_btn_width, UI_CONSTRAINT_RELATIVE_PIXELS);
@@ -603,7 +719,7 @@ void draw_ui(void) {
set_x_constraint(&btn_con, -icon_btn_offset - icon_btn_width - icon_btns_padding, UI_CONSTRAINT_RELATIVE_PIXELS); set_x_constraint(&btn_con, -icon_btn_offset - icon_btn_width - icon_btns_padding, UI_CONSTRAINT_RELATIVE_PIXELS);
if (draw_icon_button(&btn_con, ColorRGBA(201, 146, 126, 255), game.icon_textures[SETTINGS_ICON], btn_con.height * 0.15f, ALIGN_TOP_RIGHT, bg_btns_state)) { if (draw_icon_button(&btn_con, ColorRGBA(201, 146, 126, 255), game.icon_textures[SETTINGS_ICON], btn_con.height * 0.15f, ALIGN_TOP_RIGHT, bg_btns_state)) {
printf("TODO: settings\n"); game.settings_dialog = true;
} }
set_x_constraint(&btn_con, 0, UI_CONSTRAINT_RELATIVE_PIXELS); set_x_constraint(&btn_con, 0, UI_CONSTRAINT_RELATIVE_PIXELS);
@@ -614,6 +730,10 @@ void draw_ui(void) {
reset_game(); reset_game();
} }
if (game.settings_dialog) {
draw_settings_dialog();
}
if (game.help_dialog) { if (game.help_dialog) {
draw_help_dialog(); draw_help_dialog();
} }
@@ -629,19 +749,19 @@ void draw_ui(void) {
void draw_board(void) { void draw_board(void) {
// board // board
UIConstraints board_con = {0}; UIConstraints board_con = default_constraints;
set_y_constraint(&board_con, 0.05f, UI_CONSTRAINT_RELATIVE); set_y_constraint(&board_con, 0.05f, UI_CONSTRAINT_RELATIVE);
set_height_constraint(&board_con, 0.6f, UI_CONSTRAINT_RELATIVE); set_height_constraint(&board_con, 0.6f, UI_CONSTRAINT_RELATIVE);
set_width_constraint(&board_con, 1, UI_CONSTRAINT_ASPECT_RATIO); set_width_constraint(&board_con, 1, UI_CONSTRAINT_ASPECT_RATIO);
const float board_border_radius = board_con.width * 0.02f; const float board_border_radius = board_con.width * 0.02f;
draw_quad(&board_con, ColorRGBA(140, 154, 147, 255), board_border_radius, ALIGN_CENTER); draw_quad(&board_con, game.palette.board_bg_color, board_border_radius, ALIGN_CENTER);
// empty tiles // empty tiles
const float tile_padding = board_con.width * 0.02f; const float tile_padding = board_con.width * 0.02f;
const float tile_height = board_con.height * 0.225f; const float tile_height = board_con.height * 0.225f;
const float tile_board_radius = tile_height * 0.15f; const float tile_board_radius = tile_height * 0.15f;
UIConstraints empty_tile_con = {0}; UIConstraints empty_tile_con = default_constraints;
set_parent_constraint(&empty_tile_con, &board_con); set_parent_constraint(&empty_tile_con, &board_con);
set_height_constraint(&empty_tile_con, tile_height, UI_CONSTRAINT_FIXED); set_height_constraint(&empty_tile_con, tile_height, UI_CONSTRAINT_FIXED);
set_width_constraint(&empty_tile_con, 1, UI_CONSTRAINT_ASPECT_RATIO); set_width_constraint(&empty_tile_con, 1, UI_CONSTRAINT_ASPECT_RATIO);
@@ -650,14 +770,14 @@ void draw_board(void) {
set_y_constraint(&empty_tile_con, (tile_height + tile_padding) * i + tile_padding, UI_CONSTRAINT_FIXED); set_y_constraint(&empty_tile_con, (tile_height + tile_padding) * i + tile_padding, UI_CONSTRAINT_FIXED);
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
set_x_constraint(&empty_tile_con, (tile_height + tile_padding) * j + tile_padding, UI_CONSTRAINT_FIXED); set_x_constraint(&empty_tile_con, (tile_height + tile_padding) * j + tile_padding, UI_CONSTRAINT_FIXED);
draw_quad(&empty_tile_con, ColorRGBA(120, 133, 126, 255), tile_board_radius, ALIGN_TOP_LEFT); draw_quad(&empty_tile_con, mult_color(game.palette.board_bg_color, 0.85f), tile_board_radius, ALIGN_TOP_LEFT);
} }
} }
// filled tiles // filled tiles
UIConstraints text_con = {0}; UIConstraints text_con = default_constraints;
set_width_constraint(&text_con, 1.5, UI_CONSTRAINT_RELATIVE_PIXELS); set_width_constraint(&text_con, 1.5, UI_CONSTRAINT_RELATIVE_PIXELS);
UIConstraints tile_con = {0}; UIConstraints tile_con = default_constraints;
set_parent_constraint(&tile_con, &board_con); set_parent_constraint(&tile_con, &board_con);
set_height_constraint(&tile_con, tile_height, UI_CONSTRAINT_FIXED); set_height_constraint(&tile_con, tile_height, UI_CONSTRAINT_FIXED);
set_width_constraint(&tile_con, 1, UI_CONSTRAINT_ASPECT_RATIO); set_width_constraint(&tile_con, 1, UI_CONSTRAINT_ASPECT_RATIO);
@@ -863,6 +983,7 @@ void handle_keyboard_input(ZephrEvent e) {
} else if (e.key.code == ZEPHR_KEYCODE_ESCAPE) { } else if (e.key.code == ZEPHR_KEYCODE_ESCAPE) {
game.quit_dialog = false; game.quit_dialog = false;
game.help_dialog = false; game.help_dialog = false;
game.settings_dialog = false;
} else if (e.key.code == ZEPHR_KEYCODE_F11) { } else if (e.key.code == ZEPHR_KEYCODE_F11) {
zephr_toggle_fullscreen(); zephr_toggle_fullscreen();
} else if (e.key.code == ZEPHR_KEYCODE_UP) { } else if (e.key.code == ZEPHR_KEYCODE_UP) {
+10 -1
View File
@@ -18,6 +18,12 @@ typedef enum IconTexture {
ICON_TEXTURE_COUNT, ICON_TEXTURE_COUNT,
} IconTexture; } IconTexture;
typedef struct ColorPalette {
Color bg_color;
Color board_bg_color;
Color tile_colors[11];
} ColorPalette;
typedef struct Tile { typedef struct Tile {
u16 value; u16 value;
u16 new_value; u16 new_value;
@@ -41,9 +47,12 @@ typedef struct Game {
Vec2 spawning_tile_coords; Vec2 spawning_tile_coords;
u16 spawning_tile_value; u16 spawning_tile_value;
TextureId icon_textures[ICON_TEXTURE_COUNT];
bool quit_dialog; bool quit_dialog;
bool help_dialog; bool help_dialog;
bool settings_dialog;
TextureId icon_textures[ICON_TEXTURE_COUNT];
ColorPalette palette;
} Game; } Game;
void draw_board(void); void draw_board(void);
+32
View File
@@ -0,0 +1,32 @@
#version 330 core
in vec2 v_TexCoords;
out vec4 FragColor;
uniform bool isSlider;
uniform float sliderPercentage;
//vec3 rgb2hsv(vec3 c){
// vec4 K = vec4(0.0,-1.0 / 3.0,2.0 / 3.0,-1.0);
// vec4 p = mix(vec4(c.bg,K.wz),vec4(c.gb,K.xy),step(c.b,c.g));
// vec4 q = mix(vec4(p.xyw,c.r),vec4(c.r,p.yzx),step(p.x,c.r));
// float d = q.x - min(q.w,q.y);
// float e = 1.0e-10;
// return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)),d / (q.x + e),q.x);
//}
vec3 hsv2rgb(vec3 color){
vec3 rgb = clamp(abs(mod(color.r * 6.0 + vec3(0.0, 4.0, 2.0), 6.0) - 3.0) - 1.0, 0.0, 1.0);
rgb = rgb * rgb * (3.0 - 2.0 * rgb);
return color.b * mix(vec3(1.0), rgb, color.g);
}
void main() {
if (isSlider) {
vec3 color = hsv2rgb(vec3(v_TexCoords.y, 1.0, 1.0));
FragColor = vec4(color, 1.0);
} else {
vec3 color = hsv2rgb(vec3(sliderPercentage, v_TexCoords.x, 1.0 - v_TexCoords.y));
FragColor = vec4(color, 1.0);
}
}
+2 -2
View File
@@ -10,7 +10,7 @@
#include "text.h" #include "text.h"
#include "zephr.h" #include "zephr.h"
#define FONT_PIXEL_SIZE 128 #define FONT_PIXEL_SIZE 100
#define LINE_HEIGHT 2.0f #define LINE_HEIGHT 2.0f
Shader font_shader; Shader font_shader;
@@ -100,7 +100,7 @@ int init_freetype(const char* font_path) {
tex_height = CORE_MAX(tex_height, face->glyph->bitmap.rows); tex_height = CORE_MAX(tex_height, face->glyph->bitmap.rows);
} }
char *pixels = (char *)calloc(tex_width * tex_height, 1); char *pixels = (char *)malloc(tex_width * tex_height);
for (u32 i = 32; i < 128; i++) { for (u32 i = 32; i < 128; i++) {
/* while (glyph_idx) { */ /* while (glyph_idx) { */
+288 -8
View File
@@ -1,3 +1,4 @@
#include <math.h>
#include <stdio.h> #include <stdio.h>
#include <glad/glx.h> #include <glad/glx.h>
@@ -7,9 +8,14 @@
#include "zephr.h" #include "zephr.h"
Shader ui_shader; Shader ui_shader;
Shader color_chooser_shader;
unsigned int ui_vao; unsigned int ui_vao;
unsigned int ui_vbo; unsigned int ui_vbo;
const UIConstraints default_constraints = {
.scale = {.height = 1, .width = 1},
};
int init_ui(const char* font_path) { int init_ui(const char* font_path) {
int res = init_fonts(font_path); int res = init_fonts(font_path);
if (res == -1) { if (res == -1) {
@@ -21,6 +27,7 @@ int init_ui(const char* font_path) {
} }
ui_shader = create_shader("shaders/ui.vert", "shaders/ui.frag"); ui_shader = create_shader("shaders/ui.vert", "shaders/ui.frag");
color_chooser_shader = create_shader("shaders/ui.vert", "shaders/color_chooser.frag");
glGenVertexArrays(1, &ui_vao); glGenVertexArrays(1, &ui_vao);
glGenBuffers(1, &ui_vbo); glGenBuffers(1, &ui_vbo);
@@ -49,7 +56,11 @@ void set_x_constraint(UIConstraints *constraints, float value, UIConstraint type
constraints->x = value; constraints->x = value;
break; break;
case UI_CONSTRAINT_RELATIVE: case UI_CONSTRAINT_RELATIVE:
constraints->x = (value * zephr_ctx->window.size.width); if (constraints->parent) {
constraints->x = (value * constraints->parent->width);
} else {
constraints->x = (value * zephr_ctx->window.size.width);
}
break; break;
case UI_CONSTRAINT_RELATIVE_PIXELS: case UI_CONSTRAINT_RELATIVE_PIXELS:
constraints->x = zephr_ctx->window.size.width / (float)zephr_ctx->screen_size.width * value; constraints->x = zephr_ctx->window.size.width / (float)zephr_ctx->screen_size.width * value;
@@ -69,7 +80,11 @@ void set_y_constraint(UIConstraints *constraints, float value, UIConstraint type
constraints->y = value; constraints->y = value;
break; break;
case UI_CONSTRAINT_RELATIVE: case UI_CONSTRAINT_RELATIVE:
constraints->y = (value * zephr_ctx->window.size.height); if (constraints->parent) {
constraints->y = (value * constraints->parent->height);
} else {
constraints->y = (value * zephr_ctx->window.size.height);
}
break; break;
case UI_CONSTRAINT_RELATIVE_PIXELS: case UI_CONSTRAINT_RELATIVE_PIXELS:
constraints->y = zephr_ctx->window.size.height / (float)zephr_ctx->screen_size.height * value; constraints->y = zephr_ctx->window.size.height / (float)zephr_ctx->screen_size.height * value;
@@ -87,7 +102,11 @@ void set_width_constraint(UIConstraints *constraints, float value, UIConstraint
constraints->width = value; constraints->width = value;
break; break;
case UI_CONSTRAINT_RELATIVE: case UI_CONSTRAINT_RELATIVE:
constraints->width = (value * zephr_ctx->window.size.width); if (constraints->parent) {
constraints->width = (value * constraints->parent->width);
} else {
constraints->width = (value * zephr_ctx->window.size.width);
}
break; break;
case UI_CONSTRAINT_RELATIVE_PIXELS: case UI_CONSTRAINT_RELATIVE_PIXELS:
constraints->width = zephr_ctx->window.size.width / (float)zephr_ctx->screen_size.width * value; constraints->width = zephr_ctx->window.size.width / (float)zephr_ctx->screen_size.width * value;
@@ -104,7 +123,11 @@ void set_height_constraint(UIConstraints *constraints, float value, UIConstraint
constraints->height = value; constraints->height = value;
break; break;
case UI_CONSTRAINT_RELATIVE: case UI_CONSTRAINT_RELATIVE:
constraints->height = (value * zephr_ctx->window.size.height); if (constraints->parent) {
constraints->height = (value * constraints->parent->height);
} else {
constraints->height = (value * zephr_ctx->window.size.height);
}
break; break;
case UI_CONSTRAINT_RELATIVE_PIXELS: case UI_CONSTRAINT_RELATIVE_PIXELS:
constraints->height = zephr_ctx->window.size.height / (float)zephr_ctx->screen_size.height * value; constraints->height = zephr_ctx->window.size.height / (float)zephr_ctx->screen_size.height * value;
@@ -177,8 +200,15 @@ void apply_alignment(Alignment align, UIConstraints *constraints, Vec2f *pos, Si
} }
bool inside_rect(Rect *rect, Vec2 *point) { bool inside_rect(Rect *rect, Vec2 *point) {
if (point->x >= rect->pos.x && point->x <= rect->pos.x + rect->size.width && /* bool outside_popup = true; */
point->y >= rect->pos.y && point->y <= rect->pos.y + rect->size.height) { /* if (rect != &zephr_ctx->ui.popup_rect) { */
/* outside_popup = !inside_rect(&zephr_ctx->ui.popup_rect, point); */
/* } else { */
/* outside_popup = false; */
/* } */
if ((point->x >= rect->pos.x && point->x <= rect->pos.x + rect->size.width &&
point->y >= rect->pos.y && point->y <= rect->pos.y + rect->size.height)) {
return true; return true;
} }
return false; return false;
@@ -204,6 +234,10 @@ void draw_quad(UIConstraints *constraints, const Color color, float border_radiu
constraints->y = pos.y; constraints->y = pos.y;
Matrix4x4 model = identity(); Matrix4x4 model = identity();
apply_translation(&model, (Vec2f){-size.width / 2.f, -size.height / 2.f});
apply_scale(&model, constraints->scale);
apply_translation(&model, (Vec2f){size.width / 2.f, size.height / 2.f});
apply_translation(&model, (Vec2f){-size.width / 2.f, -size.height / 2.f}); apply_translation(&model, (Vec2f){-size.width / 2.f, -size.height / 2.f});
apply_rotation(&model, to_radians(constraints->rotation)); apply_rotation(&model, to_radians(constraints->rotation));
apply_translation(&model, (Vec2f){size.width / 2.f, size.height / 2.f}); apply_translation(&model, (Vec2f){size.width / 2.f, size.height / 2.f});
@@ -250,6 +284,7 @@ void draw_triangle(UIConstraints *constraints, const Color color, Alignment alig
use_shader(ui_shader); use_shader(ui_shader);
set_vec4f(ui_shader, "aColor", color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f); set_vec4f(ui_shader, "aColor", color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
set_float(ui_shader, "borderRadius", 0.f);
set_mat4f(ui_shader, "projection", (float *)zephr_ctx->projection.m); set_mat4f(ui_shader, "projection", (float *)zephr_ctx->projection.m);
Vec2f pos = { 0.f, 0.f }; Vec2f pos = { 0.f, 0.f };
@@ -263,6 +298,10 @@ void draw_triangle(UIConstraints *constraints, const Color color, Alignment alig
constraints->y = pos.y; constraints->y = pos.y;
Matrix4x4 model = identity(); Matrix4x4 model = identity();
apply_translation(&model, (Vec2f){-size.width / 2.f, -size.height / 2.f});
apply_scale(&model, constraints->scale);
apply_translation(&model, (Vec2f){size.width / 2.f, size.height / 2.f});
apply_translation(&model, (Vec2f){-size.width / 2.f, -size.height / 2.f}); apply_translation(&model, (Vec2f){-size.width / 2.f, -size.height / 2.f});
apply_rotation(&model, to_radians(constraints->rotation)); apply_rotation(&model, to_radians(constraints->rotation));
apply_translation(&model, (Vec2f){size.width / 2.f, size.height / 2.f}); apply_translation(&model, (Vec2f){size.width / 2.f, size.height / 2.f});
@@ -310,6 +349,10 @@ void draw_texture(UIConstraints *constraints, const TextureId texture_id, const
constraints->y = pos.y; constraints->y = pos.y;
Matrix4x4 model = identity(); Matrix4x4 model = identity();
apply_translation(&model, (Vec2f){-size.width / 2.f, -size.height / 2.f});
apply_scale(&model, constraints->scale);
apply_translation(&model, (Vec2f){size.width / 2.f, size.height / 2.f});
apply_translation(&model, (Vec2f){-size.width / 2.f, -size.height / 2.f}); apply_translation(&model, (Vec2f){-size.width / 2.f, -size.height / 2.f});
apply_rotation(&model, to_radians(constraints->rotation)); apply_rotation(&model, to_radians(constraints->rotation));
apply_translation(&model, (Vec2f){size.width / 2.f, size.height / 2.f}); apply_translation(&model, (Vec2f){size.width / 2.f, size.height / 2.f});
@@ -380,7 +423,7 @@ bool draw_button(UIConstraints *constraints, const Color color, const char *text
} }
if (text) { if (text) {
UIConstraints text_constraints = {0}; UIConstraints text_constraints = default_constraints;
set_parent_constraint(&text_constraints, constraints); set_parent_constraint(&text_constraints, constraints);
set_x_constraint(&text_constraints, 0, UI_CONSTRAINT_RELATIVE_PIXELS); set_x_constraint(&text_constraints, 0, UI_CONSTRAINT_RELATIVE_PIXELS);
@@ -434,7 +477,7 @@ bool draw_icon_button(UIConstraints *constraints, Color btn_color, const Texture
draw_quad(constraints, btn_color, radius, align); draw_quad(constraints, btn_color, radius, align);
UIConstraints icon_constraints = {0}; UIConstraints icon_constraints = default_constraints;
set_parent_constraint(&icon_constraints, constraints); set_parent_constraint(&icon_constraints, constraints);
set_x_constraint(&icon_constraints, 0, UI_CONSTRAINT_RELATIVE_PIXELS); set_x_constraint(&icon_constraints, 0, UI_CONSTRAINT_RELATIVE_PIXELS);
@@ -450,6 +493,243 @@ bool draw_icon_button(UIConstraints *constraints, Color btn_color, const Texture
return false; return false;
} }
void draw_color_picker_slider(UIConstraints *constraints, Alignment align) {
use_shader(color_chooser_shader);
set_bool(color_chooser_shader, "isSlider", true);
set_mat4f(color_chooser_shader, "projection", (float *)zephr_ctx->projection.m);
Vec2f pos = { 0.f, 0.f };
Sizef size = { 0.f, 0.f };
apply_constraints(constraints, &pos, &size);
apply_alignment(align, constraints, &pos, size);
// set the positions after applying alignment so children can use them
constraints->x = pos.x;
constraints->y = pos.y;
Matrix4x4 model = identity();
apply_translation(&model, pos);
set_mat4f(color_chooser_shader, "model", (float *)model.m);
glBindVertexArray(ui_vao);
float vertices[6][4] = {
// bottom left tri
{0, 0 + size.height, 0.0, 1.0},
{0, 0, 0.0, 0.0},
{0 + size.width, 0, 1.0, 0.0},
// top right tri
{0, 0 + size.height, 0.0, 1.0},
{0 + size.width, 0, 1.0, 0.0},
{0 + size.width, 0 + size.height, 1.0, 1.0},
};
glBindBuffer(GL_ARRAY_BUFFER, ui_vbo);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
set_bool(color_chooser_shader, "isSlider", false);
}
void draw_color_picker_canvas(UIConstraints *constraints, f32 slider_percentage, Alignment align) {
use_shader(color_chooser_shader);
set_bool(color_chooser_shader, "isSlider", false);
set_float(color_chooser_shader, "sliderPercentage", slider_percentage);
set_mat4f(color_chooser_shader, "projection", (float *)zephr_ctx->projection.m);
Vec2f pos = { 0.f, 0.f };
Sizef size = { 0.f, 0.f };
apply_constraints(constraints, &pos, &size);
apply_alignment(align, constraints, &pos, size);
// set the positions after applying alignment so children can use them
constraints->x = pos.x;
constraints->y = pos.y;
Matrix4x4 model = identity();
apply_translation(&model, pos);
set_mat4f(color_chooser_shader, "model", (float *)model.m);
glBindVertexArray(ui_vao);
float vertices[6][4] = {
// bottom left tri
{0, 0 + size.height, 0.0, 1.0},
{0, 0, 0.0, 0.0},
{0 + size.width, 0, 1.0, 0.0},
// top right tri
{0, 0 + size.height, 0.0, 1.0},
{0 + size.width, 0, 1.0, 0.0},
{0 + size.width, 0 + size.height, 1.0, 1.0},
};
glBindBuffer(GL_ARRAY_BUFFER, ui_vbo);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
// TODO: consume mouse events on the popup
void draw_color_picker_popup(UIConstraints *picker_button_con) {
UIConstraints popup_con = default_constraints;
set_parent_constraint(&popup_con, picker_button_con);
set_x_constraint(&popup_con, 0, UI_CONSTRAINT_FIXED);
set_y_constraint(&popup_con, picker_button_con->height + 20, UI_CONSTRAINT_FIXED);
set_width_constraint(&popup_con, 450, UI_CONSTRAINT_RELATIVE_PIXELS);
set_height_constraint(&popup_con, 480, UI_CONSTRAINT_RELATIVE_PIXELS);
draw_quad(&popup_con, mult_color(COLOR_WHITE, 0.94f), 8, ALIGN_TOP_LEFT);
UIConstraints color_slider_con = default_constraints;
set_parent_constraint(&color_slider_con, &popup_con);
set_x_constraint(&color_slider_con, -0.04f, UI_CONSTRAINT_RELATIVE);
set_y_constraint(&color_slider_con, 0.05f, UI_CONSTRAINT_RELATIVE);
set_height_constraint(&color_slider_con, 400 * 0.9f, UI_CONSTRAINT_RELATIVE_PIXELS);
set_width_constraint(&color_slider_con, 0.1f, UI_CONSTRAINT_ASPECT_RATIO);
draw_color_picker_slider(&color_slider_con, ALIGN_TOP_RIGHT);
static f32 slider_selection = 0;
static Vec2f canvas_pos = {0};
if (inside_rect(&(Rect){{color_slider_con.x, color_slider_con.y}, {color_slider_con.width, color_slider_con.height}}, &zephr_ctx->mouse.pos) &&
zephr_ctx->mouse.pressed && zephr_ctx->mouse.button == ZEPHR_MOUSE_BUTTON_LEFT) {
slider_selection = (zephr_ctx->mouse.pos.y - color_slider_con.y) / color_slider_con.height;
}
UIConstraints triangle_con = default_constraints;
set_parent_constraint(&triangle_con, &color_slider_con);
set_x_constraint(&triangle_con, -11, UI_CONSTRAINT_RELATIVE_PIXELS);
set_y_constraint(&triangle_con, slider_selection, UI_CONSTRAINT_RELATIVE);
set_rotation_constraint(&triangle_con, -90);
set_width_constraint(&triangle_con, 14, UI_CONSTRAINT_RELATIVE_PIXELS);
set_height_constraint(&triangle_con, 0.5f, UI_CONSTRAINT_ASPECT_RATIO);
triangle_con.y += -(triangle_con.height / 2.f);
draw_triangle(&triangle_con, COLOR_BLACK, ALIGN_TOP_LEFT);
set_x_constraint(&triangle_con, 1, UI_CONSTRAINT_RELATIVE);
triangle_con.x -= triangle_con.height / 2;
set_rotation_constraint(&triangle_con, 90);
draw_triangle(&triangle_con, COLOR_BLACK, ALIGN_TOP_LEFT);
set_x_constraint(&color_slider_con, 0.04f, UI_CONSTRAINT_RELATIVE);
set_y_constraint(&color_slider_con, 0.05f, UI_CONSTRAINT_RELATIVE);
set_width_constraint(&color_slider_con, popup_con.width * 0.8f, UI_CONSTRAINT_FIXED);
draw_color_picker_canvas(&color_slider_con, slider_selection, ALIGN_TOP_LEFT);
if (inside_rect(&(Rect){{color_slider_con.x, color_slider_con.y}, {color_slider_con.width, color_slider_con.height}}, &zephr_ctx->mouse.pos) &&
zephr_ctx->mouse.pressed && zephr_ctx->mouse.button == ZEPHR_MOUSE_BUTTON_LEFT) {
f32 x = (zephr_ctx->mouse.pos.x - color_slider_con.x) / color_slider_con.width;
f32 y = (zephr_ctx->mouse.pos.y - color_slider_con.y) / color_slider_con.height;
canvas_pos.x = x;
canvas_pos.y = y;
}
set_parent_constraint(&triangle_con, &color_slider_con);
set_x_constraint(&triangle_con, canvas_pos.x, UI_CONSTRAINT_RELATIVE);
set_y_constraint(&triangle_con, canvas_pos.y, UI_CONSTRAINT_RELATIVE);
triangle_con.x -= triangle_con.height;
triangle_con.y -= triangle_con.height * 2;
set_rotation_constraint(&triangle_con, 0);
draw_triangle(&triangle_con, COLOR_WHITE, ALIGN_TOP_LEFT);
triangle_con.x += triangle_con.height * 2;
triangle_con.y += triangle_con.height * 2;
set_rotation_constraint(&triangle_con, 90);
draw_triangle(&triangle_con, COLOR_WHITE, ALIGN_TOP_LEFT);
triangle_con.x -= triangle_con.height * 2;
triangle_con.y += triangle_con.height * 2;
set_rotation_constraint(&triangle_con, 180);
draw_triangle(&triangle_con, COLOR_WHITE, ALIGN_TOP_LEFT);
triangle_con.x -= triangle_con.height * 2;
triangle_con.y -= triangle_con.height * 2;
set_rotation_constraint(&triangle_con, 270);
draw_triangle(&triangle_con, COLOR_WHITE, ALIGN_TOP_LEFT);
UIConstraints button_con = default_constraints;
set_parent_constraint(&button_con, &popup_con);
set_x_constraint(&button_con, 0.04f, UI_CONSTRAINT_RELATIVE);
set_y_constraint(&button_con, -0.05f, UI_CONSTRAINT_RELATIVE);
set_width_constraint(&button_con, 0.43f, UI_CONSTRAINT_RELATIVE);
set_height_constraint(&button_con, 0.3f, UI_CONSTRAINT_ASPECT_RATIO);
if (draw_button(&button_con, *zephr_ctx->ui.popup_revert_color, "Revert", 4, ALIGN_BOTTOM_LEFT, BUTTON_STATE_ACTIVE)) {
zephr_ctx->ui.popup_open = false;
}
Color selected_color = hsv2rgb(slider_selection * 360.f, canvas_pos.x, 1.0f - canvas_pos.y);
set_x_constraint(&button_con, -0.04f, UI_CONSTRAINT_RELATIVE);
set_y_constraint(&button_con, -0.05f, UI_CONSTRAINT_RELATIVE);
if (draw_button(&button_con, selected_color, "Apply", 4, ALIGN_BOTTOM_RIGHT, BUTTON_STATE_ACTIVE)) {
*zephr_ctx->ui.popup_revert_color = selected_color;
zephr_ctx->ui.popup_open = false;
}
zephr_ctx->ui.popup_rect = (Rect){{popup_con.x, popup_con.y}, {popup_con.width, popup_con.height}};
}
void draw_color_picker(UIConstraints *constraints, Color *color, Alignment align, ButtonState state) {
Rect rect = {0};
Color display_color = *color;
UIConstraints con = *constraints;
apply_constraints(&con, &rect.pos, &rect.size);
apply_alignment(align, &con, &rect.pos, rect.size);
bool is_hovered = inside_rect(&rect, &zephr_ctx->mouse.pos);
bool left_mouse_pressed = zephr_ctx->mouse.pressed && zephr_ctx->mouse.button == ZEPHR_MOUSE_BUTTON_LEFT;
if (is_hovered && state == BUTTON_STATE_ACTIVE) {
zephr_set_cursor(ZEPHR_CURSOR_HAND);
con.scale.height *= 1.08f;
con.scale.width *= 1.08f;
if (left_mouse_pressed) {
display_color = mult_color(display_color, 0.8f);
} else {
display_color = mult_color(display_color, 0.9f);
}
} else if (state == BUTTON_STATE_DISABLED) {
if (is_hovered) {
zephr_set_cursor(ZEPHR_CURSOR_DISABLED);
}
display_color.a = 100;
}
draw_quad(&con, display_color, con.width * 0.08f, align);
if (is_hovered && state == BUTTON_STATE_ACTIVE && zephr_ctx->mouse.released && zephr_ctx->mouse.button == ZEPHR_MOUSE_BUTTON_LEFT) {
zephr_ctx->ui.popup_open = true;
zephr_ctx->ui.popup_parent_constraints = con;
zephr_ctx->ui.popup_revert_color = color;
/* zephr_ctx->ui.popup_rect = (Rect){rect.pos, rect.size}; */
/* draw_color_picker_overlay(constraints); */
}
/* if (is_hovered && state == BUTTON_STATE_ACTIVE && zephr_ctx->mouse.released && zephr_ctx->mouse.button == ZEPHR_MOUSE_BUTTON_LEFT) { */
/* return true; */
/* } */
/* return false; */
}
/* enum Element { */ /* enum Element { */
/* Rect, */ /* Rect, */
+18 -5
View File
@@ -3,11 +3,6 @@
#include "texture.h" #include "texture.h"
#include "zephr_math.h" #include "zephr_math.h"
typedef struct Rect {
Vec2f pos;
Sizef size;
} Rect;
typedef enum Alignment { typedef enum Alignment {
ALIGN_TOP_LEFT, ALIGN_TOP_LEFT,
ALIGN_TOP_CENTER, ALIGN_TOP_CENTER,
@@ -33,9 +28,24 @@ typedef struct UIConstraints {
float width; float width;
float height; float height;
float rotation; float rotation;
Sizef scale;
struct UIConstraints *parent; struct UIConstraints *parent;
} UIConstraints; } UIConstraints;
extern const UIConstraints default_constraints;
typedef struct Rect {
Vec2f pos;
Sizef size;
} Rect;
typedef struct UI {
bool popup_open;
Rect popup_rect;
UIConstraints popup_parent_constraints;
Color *popup_revert_color;
} UI;
typedef enum ButtonState { typedef enum ButtonState {
BUTTON_STATE_ACTIVE, BUTTON_STATE_ACTIVE,
BUTTON_STATE_INACTIVE, BUTTON_STATE_INACTIVE,
@@ -51,8 +61,11 @@ void set_height_constraint(UIConstraints *constraints, float value, UIConstraint
void set_rotation_constraint(UIConstraints *constraints, float angle_d); void set_rotation_constraint(UIConstraints *constraints, float angle_d);
void apply_constraints(UIConstraints *constraints, Vec2f *pos, Sizef *size); void apply_constraints(UIConstraints *constraints, Vec2f *pos, Sizef *size);
void apply_alignment(Alignment align, UIConstraints *constraints, Vec2f *pos, Sizef size); void apply_alignment(Alignment align, UIConstraints *constraints, Vec2f *pos, Sizef size);
bool inside_rect(Rect *rect, Vec2 *point);
void draw_quad(UIConstraints *constraints, const Color color, float border_radius, Alignment align); void draw_quad(UIConstraints *constraints, const Color color, float border_radius, Alignment align);
void draw_circle(UIConstraints *constraints, const Color color, Alignment align); void draw_circle(UIConstraints *constraints, const Color color, Alignment align);
void draw_triangle(UIConstraints *constraints, const Color color, Alignment align); void draw_triangle(UIConstraints *constraints, const Color color, Alignment align);
bool draw_button(UIConstraints *constraints, Color color, const char *text, f32 radius, Alignment align, ButtonState state); bool draw_button(UIConstraints *constraints, Color color, const char *text, f32 radius, Alignment align, ButtonState state);
bool draw_icon_button(UIConstraints *constraints, Color color, const TextureId icon_tex_id, f32 radius, Alignment align, ButtonState state); bool draw_icon_button(UIConstraints *constraints, Color color, const TextureId icon_tex_id, f32 radius, Alignment align, ButtonState state);
void draw_color_picker_popup(UIConstraints *picker_button_con);
void draw_color_picker(UIConstraints *constraints, Color *color, Alignment align, ButtonState state);
+14 -2
View File
@@ -539,7 +539,7 @@ void x11_assign_window_icon(const char *icon_path) {
u32 target_size = 2 + icon_width * icon_height; u32 target_size = 2 + icon_width * icon_height;
u64 *data = malloc(target_size * sizeof(u64)); u64 *data = alloca(target_size * sizeof(u64));
u64 *target = data; u64 *target = data;
// first two elements are width and height // first two elements are width and height
@@ -554,7 +554,6 @@ void x11_assign_window_icon(const char *icon_path) {
XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)data, target_size); XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)data, target_size);
free(data);
stbi_image_free(icon_data); stbi_image_free(icon_data);
} }
@@ -809,6 +808,10 @@ bool zephr_should_quit(void) {
void zephr_swap_buffers(void) { void zephr_swap_buffers(void) {
CORE_DEBUG_ASSERT(zephr_ctx, "Zephr context not initialized"); CORE_DEBUG_ASSERT(zephr_ctx, "Zephr context not initialized");
if (zephr_ctx->ui.popup_open) {
draw_color_picker_popup(&zephr_ctx->ui.popup_parent_constraints);
}
glXSwapBuffers(x11_display, x11_window); glXSwapBuffers(x11_display, x11_window);
XDefineCursor(x11_display, x11_window, zephr_ctx->cursors[zephr_ctx->cursor]); XDefineCursor(x11_display, x11_window, zephr_ctx->cursors[zephr_ctx->cursor]);
} }
@@ -1016,12 +1019,21 @@ bool zephr_iter_events(ZephrEvent *event_out) {
switch (xev.xbutton.button) { switch (xev.xbutton.button) {
case Button1: case Button1:
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_LEFT; event_out->mouse.button = ZEPHR_MOUSE_BUTTON_LEFT;
if (!inside_rect(&zephr_ctx->ui.popup_rect, &event_out->mouse.position)) {
zephr_ctx->ui.popup_open = false;
}
break; break;
case Button2: case Button2:
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_MIDDLE; event_out->mouse.button = ZEPHR_MOUSE_BUTTON_MIDDLE;
if (!inside_rect(&zephr_ctx->ui.popup_rect, &event_out->mouse.position)) {
zephr_ctx->ui.popup_open = false;
}
break; break;
case Button3: case Button3:
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_RIGHT; event_out->mouse.button = ZEPHR_MOUSE_BUTTON_RIGHT;
if (!inside_rect(&zephr_ctx->ui.popup_rect, &event_out->mouse.position)) {
zephr_ctx->ui.popup_open = false;
}
break; break;
} }
+2
View File
@@ -380,6 +380,8 @@ typedef struct ZephrContext {
ZephrMouse mouse; ZephrMouse mouse;
ZephrCursor cursor; ZephrCursor cursor;
ZephrCursor cursors[ZEPHR_CURSOR_COUNT]; ZephrCursor cursors[ZEPHR_CURSOR_COUNT];
UI ui;
/* ZephrKeyboard keyboard; */ /* ZephrKeyboard keyboard; */
/* XkbDescPtr xkb; */ /* XkbDescPtr xkb; */
/* XIM xim; */ /* XIM xim; */
+23
View File
@@ -84,3 +84,26 @@ Color mult_color(Color color, float amount) {
return result; return result;
} }
Color hsv2rgb(float h, float s, float v) {
float c = v * s;
float x = (float)(c * (1 - fabs(fmod(h / 60.0, 2) - 1)));
float m = v - c;
float r, g, b;
if (h >= 0 && h < 60) {
r = c, g = x, b = 0;
} else if (h >= 60 && h < 120) {
r = x, g = c, b = 0;
} else if (h >= 120 && h < 180) {
r = 0, g = c, b = x;
} else if (h >= 180 && h < 240) {
r = 0, g = x, b = c;
} else if (h >= 240 && h < 300) {
r = x, g = 0, b = c;
} else {
r = c, g = 0, b = x;
}
return (Color){(u8)((r + m) * 255), (u8)((g + m) * 255), (u8)((b + m) * 255), 255};
}
+1
View File
@@ -55,3 +55,4 @@ void apply_rotation(Matrix4x4 *model, float angle);
void apply_translation(Matrix4x4 *matrix, Vec2f pos); void apply_translation(Matrix4x4 *matrix, Vec2f pos);
Matrix4x4 orthographic_projection_2d(float left, float right, float bottom, float top); Matrix4x4 orthographic_projection_2d(float left, float right, float bottom, float top);
Color mult_color(Color color, float amount); Color mult_color(Color color, float amount);
Color hsv2rgb(float h, float s, float v);