-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMenuMode.cpp
160 lines (137 loc) · 4.55 KB
/
MenuMode.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include "MenuMode.hpp"
//for the GL_ERRORS() macro:
#include "gl_errors.hpp"
//for easy sprite drawing:
#include "DrawSprites.hpp"
//for playing movement sounds:
#include "Sound.hpp"
//for loading:
#include "Load.hpp"
#include <random>
Load< Sound::Sample > sound_click(LoadTagDefault, []() -> Sound::Sample *{
std::vector< float > data(size_t(48000 * 0.2f), 0.0f);
for (uint32_t i = 0; i < data.size(); ++i) {
float t = i / float(48000);
//phase-modulated sine wave (creates some metal-like sound):
data[i] = std::sin(3.1415926f * 2.0f * 440.0f * t + std::sin(3.1415926f * 2.0f * 450.0f * t));
//quadratic falloff:
data[i] *= 0.3f * std::pow(std::max(0.0f, (1.0f - t / 0.2f)), 2.0f);
}
return new Sound::Sample(data);
});
Load< Sound::Sample > sound_clonk(LoadTagDefault, []() -> Sound::Sample *{
std::vector< float > data(size_t(48000 * 0.2f), 0.0f);
for (uint32_t i = 0; i < data.size(); ++i) {
float t = i / float(48000);
//phase-modulated sine wave (creates some metal-like sound):
data[i] = std::sin(3.1415926f * 2.0f * 220.0f * t + std::sin(3.1415926f * 2.0f * 200.0f * t));
//quadratic falloff:
data[i] *= 0.3f * std::pow(std::max(0.0f, (1.0f - t / 0.2f)), 2.0f);
}
return new Sound::Sample(data);
});
MenuMode::MenuMode(std::vector< Item > const &items_) : items(items_) {
//select first item which can be selected:
for (uint32_t i = 0; i < items.size(); ++i) {
if (items[i].on_select) {
selected = i;
break;
}
}
}
MenuMode::~MenuMode() {
}
bool MenuMode::handle_event(SDL_Event const &evt, glm::uvec2 const &window_size) {
if (evt.type == SDL_KEYDOWN) {
if (evt.key.keysym.sym == SDLK_UP) {
//skip non-selectable items:
for (uint32_t i = selected - 1; i < items.size(); --i) {
if (items[i].on_select) {
selected = i;
Sound::play(*sound_click);
break;
}
}
return true;
} else if (evt.key.keysym.sym == SDLK_DOWN) {
//note: skips non-selectable items:
for (uint32_t i = selected + 1; i < items.size(); ++i) {
if (items[i].on_select) {
selected = i;
Sound::play(*sound_click);
break;
}
}
return true;
} else if (evt.key.keysym.sym == SDLK_RETURN) {
if (selected < items.size() && items[selected].on_select) {
Sound::play(*sound_clonk);
items[selected].on_select(items[selected]);
return true;
}
}
}
if (background) {
return background->handle_event(evt, window_size);
} else {
return false;
}
}
void MenuMode::update(float elapsed) {
select_bounce_acc = select_bounce_acc + elapsed / 0.7f;
select_bounce_acc -= std::floor(select_bounce_acc);
if (background) {
background->update(elapsed);
}
}
void MenuMode::draw(glm::uvec2 const &drawable_size) {
if (background) {
std::shared_ptr< Mode > hold_me = shared_from_this();
background->draw(drawable_size);
//it is an error to remove the last reference to this object in background->draw():
assert(hold_me.use_count() > 1);
} else {
glClearColor(0.5f, 0.5f, 0.5f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
//use alpha blending:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//don't use the depth test:
glDisable(GL_DEPTH_TEST);
float bounce = (0.25f - (select_bounce_acc - 0.5f) * (select_bounce_acc - 0.5f)) / 0.25f * select_bounce_amount;
{ //draw the menu using DrawSprites:
assert(atlas && "it is an error to try to draw a menu without an atlas");
DrawSprites draw_sprites(*atlas, view_min, view_max, drawable_size, DrawSprites::AlignPixelPerfect);
for (auto const &item : items) {
bool is_selected = (&item == &items[0] + selected);
glm::u8vec4 color = (is_selected ? item.selected_tint : item.tint);
float left, right;
if (!item.sprite) {
//draw item.name as text:
draw_sprites.draw_text(
item.name, item.at, item.scale, color
);
glm::vec2 min,max;
draw_sprites.get_text_extents(
item.name, item.at, item.scale, &min, &max
);
left = min.x;
right = max.x;
} else {
draw_sprites.draw(*item.sprite, item.at, item.scale, color);
left = item.at.x + item.scale * (item.sprite->min_px.x - item.sprite->anchor_px.x);
right = item.at.x + item.scale * (item.sprite->max_px.x - item.sprite->anchor_px.x);
}
if (is_selected) {
if (left_select) {
draw_sprites.draw(*left_select, glm::vec2(left - bounce, item.at.y), item.scale, left_select_tint);
}
if (right_select) {
draw_sprites.draw(*right_select, glm::vec2(right + bounce, item.at.y), item.scale, right_select_tint);
}
}
}
} //<-- gets drawn here!
GL_ERRORS(); //PARANOIA: print errors just in case we did something wrong.
}