]> git.localhorst.tv Git - blobs.git/blob - src/app/app.cpp
fun with resources
[blobs.git] / src / app / app.cpp
1 #include "Application.hpp"
2 #include "Assets.hpp"
3 #include "State.hpp"
4
5 #include "init.hpp"
6 #include "../graphics/Viewport.hpp"
7
8 #include <SDL.h>
9 #include <SDL_image.h>
10
11
12 namespace blobs {
13 namespace app {
14
15 Application::Application(Window &win, graphics::Viewport &vp)
16 : window(win)
17 , viewport(vp)
18 , states() {
19 }
20
21 Application::~Application() {
22 }
23
24
25 void Application::PushState(State *s) {
26         s->app = this;
27         if (!states.empty()) {
28                 states.top()->OnPause();
29         }
30         states.emplace(s);
31         ++s->ref_count;
32         if (s->ref_count == 1) {
33                 s->OnEnter();
34         }
35         s->OnResume();
36 }
37
38 State *Application::PopState() {
39         State *s = states.top();
40         states.pop();
41         s->OnPause();
42         s->OnExit();
43         if (!states.empty()) {
44                 states.top()->OnResume();
45         }
46         return s;
47 }
48
49 State *Application::SwitchState(State *s_new) {
50         s_new->app = this;
51         State *s_old = states.top();
52         states.top() = s_new;
53         --s_old->ref_count;
54         ++s_new->ref_count;
55         s_old->OnPause();
56         if (s_old->ref_count == 0) {
57                 s_old->OnExit();
58         }
59         if (s_new->ref_count == 1) {
60                 s_new->OnEnter();
61         }
62         s_new->OnResume();
63         return s_old;
64 }
65
66 State &Application::GetState() {
67         return *states.top();
68 }
69
70 bool Application::HasState() const noexcept {
71         return !states.empty();
72 }
73
74
75 void Application::Run() {
76         Uint32 last = SDL_GetTicks();
77         while (HasState()) {
78                 Uint32 now = SDL_GetTicks();
79                 int delta = now - last;
80                 Loop(delta);
81                 last = now;
82         }
83 }
84
85 void Application::Loop(int dt) {
86         HandleEvents();
87         if (!HasState()) return;
88         GetState().Update(dt);
89         if (!HasState()) return;
90         viewport.Clear();
91         GetState().Render(viewport);
92         window.Flip();
93 }
94
95 void Application::HandleEvents() {
96         SDL_Event event;
97         while (HasState() && SDL_PollEvent(&event)) {
98                 if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) {
99                         viewport.Resize(event.window.data1, event.window.data2);
100                 }
101                 GetState().Handle(event);
102         }
103 }
104
105 void State::Handle(const SDL_Event &event) {
106         switch (event.type) {
107                 case SDL_KEYDOWN:
108                         OnKeyDown(event.key);
109                         break;
110                 case SDL_KEYUP:
111                         OnKeyUp(event.key);
112                         break;
113                 case SDL_MOUSEBUTTONDOWN:
114                         OnMouseDown(event.button);
115                         break;
116                 case SDL_MOUSEBUTTONUP:
117                         OnMouseUp(event.button);
118                         break;
119                 case SDL_MOUSEMOTION:
120                         OnMouseMotion(event.motion);
121                         break;
122                 case SDL_MOUSEWHEEL:
123                         OnMouseWheel(event.wheel);
124                         break;
125                 case SDL_QUIT:
126                         OnQuit();
127                         break;
128                 case SDL_WINDOWEVENT:
129                         Handle(event.window);
130                         break;
131                 default:
132                         // ignore
133                         break;
134         }
135 }
136
137 void State::Handle(const SDL_WindowEvent &event) {
138         switch (event.event) {
139                 case SDL_WINDOWEVENT_FOCUS_GAINED:
140                         OnFocus();
141                         break;
142                 case SDL_WINDOWEVENT_FOCUS_LOST:
143                         OnBlur();
144                         break;
145                 case SDL_WINDOWEVENT_RESIZED:
146                         OnResize(event.data1, event.data2);
147                         break;
148                 default:
149                         break;
150         }
151 }
152
153 void State::Update(int dt) {
154         OnUpdate(dt);
155 }
156
157 void State::Render(graphics::Viewport &viewport) {
158         OnRender(viewport);
159 }
160
161 void State::OnQuit() {
162         while (App().HasState()) {
163                 App().PopState();
164         }
165 }
166
167
168 Assets::Assets()
169 : path("assets/")
170 , tile_path(path + "tiles/")
171 , skin_path(path + "skins/") {
172         data.resources.Add({ "air", "Air", 0 });
173         data.resources.Add({ "biomass", "Biomass", 0 });
174         data.resources.Add({ "dirt", "Dirt", 0 });
175         data.resources.Add({ "ice", "Ice", 0 });
176         data.resources.Add({ "rock", "Rock", 0 });
177         data.resources.Add({ "sand", "Sand", 0 });
178         data.resources.Add({ "water", "Water", 0 });
179         data.resources.Add({ "wood", "Wood", 0 });
180
181         data.tiles.Add({ "algae",    "Algae",    0,  0 });
182         data.tiles.Add({ "desert",   "Desert",   0,  1 });
183         data.tiles.Add({ "forest",   "Forest",   0,  2 });
184         data.tiles.Add({ "grass",    "Grass",    0,  3 });
185         data.tiles.Add({ "ice",      "Ice",      0,  4 });
186         data.tiles.Add({ "jungle",   "Jungle",   0,  5 });
187         data.tiles.Add({ "mountain", "Mountain", 0,  6 });
188         data.tiles.Add({ "ocean",    "Ocean",    0,  7 });
189         data.tiles.Add({ "rock",     "Rock",     0,  8 });
190         data.tiles.Add({ "sand",     "Sand",     0,  9 });
191         data.tiles.Add({ "taiga",    "Taiga",    0, 10 });
192         data.tiles.Add({ "tundra",   "Tundra",   0, 11 });
193         data.tiles.Add({ "water",    "Water",    0, 12 });
194         data.tiles.Add({ "wheat",    "Wheat",    0, 13 });
195
196         data.tiles["algae"]   .resources.push_back({ data.resources["water"].id,   1.0  });
197         data.tiles["algae"]   .resources.push_back({ data.resources["biomass"].id, 0.5  });
198         data.tiles["desert"]  .resources.push_back({ data.resources["sand"].id,    1.0  });
199         data.tiles["forest"]  .resources.push_back({ data.resources["wood"].id,    1.0  });
200         data.tiles["forest"]  .resources.push_back({ data.resources["dirt"].id,    0.5  });
201         data.tiles["grass"]   .resources.push_back({ data.resources["dirt"].id,    0.5  });
202         data.tiles["grass"]   .resources.push_back({ data.resources["biomass"].id, 0.25 });
203         data.tiles["grass"]   .resources.push_back({ data.resources["water"].id,   0.25 });
204         data.tiles["ice"]     .resources.push_back({ data.resources["ice"].id,     1.0  });
205         data.tiles["ice"]     .resources.push_back({ data.resources["water"].id,   0.25 });
206         data.tiles["jungle"]  .resources.push_back({ data.resources["wood"].id,    0.5  });
207         data.tiles["jungle"]  .resources.push_back({ data.resources["biomass"].id, 0.5  });
208         data.tiles["mountain"].resources.push_back({ data.resources["rock"].id,    1.0  });
209         data.tiles["ocean"]   .resources.push_back({ data.resources["water"].id,   1.0  });
210         data.tiles["rock"]    .resources.push_back({ data.resources["rock"].id,    1.0  });
211         data.tiles["sand"]    .resources.push_back({ data.resources["sand"].id,    1.0  });
212         data.tiles["taiga"]   .resources.push_back({ data.resources["wood"].id,    1.0  });
213         data.tiles["taiga"]   .resources.push_back({ data.resources["water"].id,   0.5  });
214         data.tiles["tundra"]  .resources.push_back({ data.resources["rock"].id,    1.0  });
215         data.tiles["tundra"]  .resources.push_back({ data.resources["ice"].id,     0.5  });
216         data.tiles["water"]   .resources.push_back({ data.resources["water"].id,   1.0  });
217         data.tiles["water"]   .resources.push_back({ data.resources["biomass"].id, 0.25 });
218         data.tiles["wheat"]   .resources.push_back({ data.resources["biomass"].id, 1.0  });
219         data.tiles["wheat"]   .resources.push_back({ data.resources["water"].id,   0.25 });
220
221         graphics::Format format;
222         textures.tiles.Bind();
223         textures.tiles.Reserve(256, 256, 14, format);
224         LoadTileTexture("algae",    textures.tiles,  0);
225         LoadTileTexture("desert",   textures.tiles,  1);
226         LoadTileTexture("forest",   textures.tiles,  2);
227         LoadTileTexture("grass",    textures.tiles,  3);
228         LoadTileTexture("ice",      textures.tiles,  4);
229         LoadTileTexture("jungle",   textures.tiles,  5);
230         LoadTileTexture("mountain", textures.tiles,  6);
231         LoadTileTexture("ocean",    textures.tiles,  7);
232         LoadTileTexture("rock",     textures.tiles,  8);
233         LoadTileTexture("sand",     textures.tiles,  9);
234         LoadTileTexture("taiga",    textures.tiles, 10);
235         LoadTileTexture("tundra",   textures.tiles, 11);
236         LoadTileTexture("water",    textures.tiles, 12);
237         LoadTileTexture("wheat",    textures.tiles, 13);
238
239         textures.skins.Bind();
240         textures.skins.Reserve(256, 256, 9, format);
241         LoadSkinTexture("1", textures.skins, 0);
242         LoadSkinTexture("2", textures.skins, 1);
243         LoadSkinTexture("3", textures.skins, 2);
244         LoadSkinTexture("4", textures.skins, 3);
245         LoadSkinTexture("5", textures.skins, 4);
246         LoadSkinTexture("6", textures.skins, 5);
247         LoadSkinTexture("7", textures.skins, 6);
248         LoadSkinTexture("8", textures.skins, 7);
249         LoadSkinTexture("9", textures.skins, 8);
250 }
251
252 Assets::~Assets() {
253 }
254
255 void Assets::LoadTileTexture(const std::string &name, graphics::ArrayTexture &tex, int layer) const {
256         std::string path = tile_path + name + ".png";
257         SDL_Surface *srf = IMG_Load(path.c_str());
258         if (!srf) {
259                 throw SDLError("IMG_Load");
260         }
261         try {
262                 tex.Data(layer, *srf);
263         } catch (...) {
264                 SDL_FreeSurface(srf);
265                 throw;
266         }
267         SDL_FreeSurface(srf);
268 }
269
270 void Assets::LoadSkinTexture(const std::string &name, graphics::ArrayTexture &tex, int layer) const {
271         std::string path = skin_path + name + ".png";
272         SDL_Surface *srf = IMG_Load(path.c_str());
273         if (!srf) {
274                 throw SDLError("IMG_Load");
275         }
276         try {
277                 tex.Data(layer, *srf);
278         } catch (...) {
279                 SDL_FreeSurface(srf);
280                 throw;
281         }
282         SDL_FreeSurface(srf);
283 }
284
285 }
286 }