]> git.localhorst.tv Git - blobs.git/blob - src/app/app.cpp
basic creature model
[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         graphics::Format format;
173         textures.tiles.Bind();
174         textures.tiles.Reserve(256, 256, 9, format);
175         LoadTileTexture("1", textures.tiles, 0);
176         LoadTileTexture("2", textures.tiles, 1);
177         LoadTileTexture("3", textures.tiles, 2);
178         LoadTileTexture("4", textures.tiles, 3);
179         LoadTileTexture("5", textures.tiles, 4);
180         LoadTileTexture("6", textures.tiles, 5);
181         LoadTileTexture("7", textures.tiles, 6);
182         LoadTileTexture("8", textures.tiles, 7);
183         LoadTileTexture("9", textures.tiles, 8);
184         textures.skins.Bind();
185         textures.skins.Reserve(256, 256, 9, format);
186         LoadSkinTexture("1", textures.skins, 0);
187         LoadSkinTexture("2", textures.skins, 1);
188         LoadSkinTexture("3", textures.skins, 2);
189         LoadSkinTexture("4", textures.skins, 3);
190         LoadSkinTexture("5", textures.skins, 4);
191         LoadSkinTexture("6", textures.skins, 5);
192         LoadSkinTexture("7", textures.skins, 6);
193         LoadSkinTexture("8", textures.skins, 7);
194         LoadSkinTexture("9", textures.skins, 8);
195 }
196
197 Assets::~Assets() {
198 }
199
200 void Assets::LoadTileTexture(const std::string &name, graphics::ArrayTexture &tex, int layer) const {
201         std::string path = tile_path + name + ".png";
202         SDL_Surface *srf = IMG_Load(path.c_str());
203         if (!srf) {
204                 throw SDLError("IMG_Load");
205         }
206         try {
207                 tex.Data(layer, *srf);
208         } catch (...) {
209                 SDL_FreeSurface(srf);
210                 throw;
211         }
212         SDL_FreeSurface(srf);
213 }
214
215 void Assets::LoadSkinTexture(const std::string &name, graphics::ArrayTexture &tex, int layer) const {
216         std::string path = skin_path + name + ".png";
217         SDL_Surface *srf = IMG_Load(path.c_str());
218         if (!srf) {
219                 throw SDLError("IMG_Load");
220         }
221         try {
222                 tex.Data(layer, *srf);
223         } catch (...) {
224                 SDL_FreeSurface(srf);
225                 throw;
226         }
227         SDL_FreeSurface(srf);
228 }
229
230 }
231 }