Wizard Engine
2D cross-platform game engine built around SDL2
 
Loading...
Searching...
No Matches
renderer.cpp
1/*
2 Wizard Engine
3 Copyright (C) 2023-2024 Zana Domán
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
23#define __WIZARD_ENGINE_INTERNAL__
24
30
31float wze::renderer::_origo_x = {};
32float wze::renderer::_origo_y = {};
33SDL_Renderer* wze::renderer::_base = {};
34uint8_t wze::renderer::_background_color_r = {};
35uint8_t wze::renderer::_background_color_g = {};
36uint8_t wze::renderer::_background_color_b = {};
37std::shared_ptr<wze::texture> wze::renderer::_background_texture = {};
38std::unique_ptr<wze::texture, std::function<void(wze::texture*)>>
39 wze::renderer::_space = {};
40uint8_t wze::renderer::_space_color_r = {};
41uint8_t wze::renderer::_space_color_g = {};
42uint8_t wze::renderer::_space_color_b = {};
43uint8_t wze::renderer::_space_color_a = {};
44std::shared_ptr<wze::texture> wze::renderer::_space_texture = {};
45SDL_FRect wze::renderer::_space_area = {};
46std::unique_ptr<wze::texture, std::function<void(wze::texture*)>>
47 wze::renderer::_plane = {};
48uint8_t wze::renderer::_plane_color_r = {};
49uint8_t wze::renderer::_plane_color_g = {};
50uint8_t wze::renderer::_plane_color_b = {};
51uint8_t wze::renderer::_plane_color_a = {};
52
53void wze::renderer::open_frame() {
54 if ((bool)SDL_SetRenderTarget(base(), nullptr) ||
55 (bool)SDL_SetRenderDrawColor(base(), background_color_r(),
56 background_color_g(), background_color_b(),
57 std::numeric_limits<uint8_t>::max()) ||
58 (bool)SDL_RenderClear(base()) ||
59 (background_texture() &&
60 ((bool)SDL_SetTextureColorMod(
61 background_texture().get(), background_color_r(),
62 background_color_g(), background_color_b()) ||
63 (bool)SDL_RenderCopy(base(), background_texture().get(), nullptr,
64 nullptr)))) {
65 throw exception(SDL_GetError());
66 }
67}
68
69void wze::renderer::open_space() {
70 if ((bool)SDL_SetRenderTarget(base(), _space.get()) ||
71 (bool)SDL_SetRenderDrawColor(base(), 0, 0, 0, 0) ||
72 (bool)SDL_RenderClear(base()) ||
73 (space_texture() &&
74 ((bool)SDL_SetTextureColorMod(space_texture().get(), space_color_r(),
75 space_color_g(), space_color_b()) ||
76 (bool)SDL_SetTextureAlphaMod(space_texture().get(),
77 space_color_a()) ||
78 (bool)SDL_RenderCopyExF(base(), space_texture().get(), nullptr,
79 &_space_area,
80 (double)math::to_degrees(-camera::angle()),
81 nullptr, SDL_FLIP_NONE)))) {
82 throw exception(SDL_GetError());
83 }
84}
85
86void wze::renderer::open_plane() {
87 if ((bool)SDL_SetRenderTarget(base(), _plane.get()) ||
88 (bool)SDL_SetRenderDrawColor(base(), 0, 0, 0, 0) ||
89 (bool)SDL_RenderClear(base())) {
90 throw exception(SDL_GetError());
91 }
92}
93
94bool wze::renderer::invisible(renderable const& instance) {
95 return !instance.visible() ||
96 (instance.spatial() && instance.z() <= camera::z()) ||
97 !(bool)instance.color_a() || !instance.texture() ||
98 !(bool)instance.width() || !(bool)instance.height();
99}
100
101void wze::renderer::transform(renderable& instance) {
102 instance.set_screen_area(
103 {origo_x() + instance.screen_area().x - instance.screen_area().w / 2,
104 origo_y() + instance.screen_area().y - instance.screen_area().h / 2,
105 instance.screen_area().w, instance.screen_area().h});
106}
107
108bool wze::renderer::offscreen(renderable const& instance) {
109 return instance.screen_area().x + instance.screen_area().w < 0 ||
110 (float)window::width() <= instance.screen_area().x ||
111 instance.screen_area().y + instance.screen_area().h < 0 ||
112 (float)window::height() <= instance.screen_area().y;
113}
114
115void wze::renderer::render(renderable const& instance) {
116 if ((bool)SDL_SetTextureColorMod(instance.texture().get(),
117 instance.color_r(), instance.color_g(),
118 instance.color_b()) ||
119 (bool)SDL_SetTextureAlphaMod(instance.texture().get(),
120 instance.color_a()) ||
121 (bool)SDL_RenderCopyExF(
122 base(), instance.texture().get(), nullptr, &instance.screen_area(),
123 (double)math::to_degrees(instance.screen_angle()), nullptr,
124 (SDL_RendererFlip)instance.flip())) {
125 throw exception(SDL_GetError());
126 }
127}
128
129void wze::renderer::close_frame() {
130 if ((bool)SDL_SetRenderTarget(base(), nullptr) ||
131 (bool)SDL_SetTextureColorMod(_space.get(), space_color_r(),
132 space_color_g(), space_color_b()) ||
133 (bool)SDL_SetTextureAlphaMod(_space.get(), space_color_a()) ||
134 (bool)SDL_RenderCopy(base(), _space.get(), nullptr, nullptr) ||
135 (bool)SDL_SetTextureColorMod(_plane.get(), plane_color_r(),
136 plane_color_g(), plane_color_b()) ||
137 (bool)SDL_SetTextureAlphaMod(_plane.get(), plane_color_a()) ||
138 (bool)SDL_RenderCopy(base(), _plane.get(), nullptr, nullptr)) {
139 throw exception(SDL_GetError());
140 }
141 SDL_RenderPresent(base());
142}
143
144float wze::renderer::origo_x() {
145 return _origo_x;
146}
147
148void wze::renderer::set_origo_x(float origo_x) {
149 _origo_x = origo_x;
150}
151
152float wze::renderer::origo_y() {
153 return _origo_y;
154}
155
156void wze::renderer::set_origo_y(float origo_y) {
157 _origo_y = origo_y;
158}
159
160SDL_Renderer* wze::renderer::base() {
161 return _base;
162}
163
164uint8_t wze::renderer::background_color_r() {
165 return _background_color_r;
166}
167
168void wze::renderer::set_background_color_r(uint8_t background_color_r) {
169 _background_color_r = background_color_r;
170}
171
172uint8_t wze::renderer::background_color_g() {
173 return _background_color_g;
174}
175
176void wze::renderer::set_background_color_g(uint8_t background_color_g) {
177 _background_color_g = background_color_g;
178}
179
180uint8_t wze::renderer::background_color_b() {
181 return _background_color_b;
182}
183
184void wze::renderer::set_background_color_b(uint8_t background_color_b) {
185 _background_color_b = background_color_b;
186}
187
188std::shared_ptr<wze::texture> const& wze::renderer::background_texture() {
189 return _background_texture;
190}
191
192void wze::renderer::set_background_texture(
193 std::shared_ptr<texture> const& background_texture) {
194 _background_texture = background_texture;
195}
196
197uint8_t wze::renderer::space_color_r() {
198 return _space_color_r;
199}
200
201void wze::renderer::set_space_color_r(uint8_t space_color_r) {
202 _space_color_r = space_color_r;
203}
204
205uint8_t wze::renderer::space_color_g() {
206 return _space_color_g;
207}
208
209void wze::renderer::set_space_color_g(uint8_t space_color_g) {
210 _space_color_g = space_color_g;
211}
212
213uint8_t wze::renderer::space_color_b() {
214 return _space_color_b;
215}
216
217void wze::renderer::set_space_color_b(uint8_t space_color_b) {
218 _space_color_b = space_color_b;
219}
220
221uint8_t wze::renderer::space_color_a() {
222 return _space_color_a;
223}
224
225void wze::renderer::set_space_color_a(uint8_t space_color_a) {
226 _space_color_a = space_color_a;
227}
228
229std::shared_ptr<wze::texture> const& wze::renderer::space_texture() {
230 return _space_texture;
231}
232
233void wze::renderer::set_space_texture(
234 std::shared_ptr<texture> const& space_texture) {
235 _space_texture = space_texture;
236}
237
238uint8_t wze::renderer::plane_color_r() {
239 return _plane_color_r;
240}
241
242void wze::renderer::set_plane_color_r(uint8_t plane_color_r) {
243 _plane_color_r = plane_color_r;
244}
245
246uint8_t wze::renderer::plane_color_g() {
247 return _plane_color_g;
248}
249
250void wze::renderer::set_plane_color_g(uint8_t plane_color_g) {
251 _plane_color_g = plane_color_g;
252}
253
254uint8_t wze::renderer::plane_color_b() {
255 return _plane_color_b;
256}
257
258void wze::renderer::set_plane_color_b(uint8_t plane_color_b) {
259 _plane_color_b = plane_color_b;
260}
261
262uint8_t wze::renderer::plane_color_a() {
263 return _plane_color_a;
264}
265
266void wze::renderer::set_plane_color_a(uint8_t plane_color_a) {
267 _plane_color_a = plane_color_a;
268}
269
270void wze::renderer::initialize() {
271 set_origo_x((float)window::width() / 2);
272 set_origo_y((float)window::height() / 2);
273 _base = SDL_CreateRenderer(window::base(), -1, SDL_RENDERER_ACCELERATED);
274 if (!(bool)base() || (bool)SDL_RenderSetLogicalSize(base(), window::width(),
275 window::height())) {
276 throw exception(SDL_GetError());
277 }
278 set_background_color_r(0);
279 set_background_color_g(0);
280 set_background_color_b(0);
281 set_background_texture({});
282 _space = {SDL_CreateTexture(base(), SDL_PIXELFORMAT_RGBA8888,
283 SDL_TEXTUREACCESS_TARGET, window::width(),
284 window::height()),
285 SDL_DestroyTexture};
286 if (!_space ||
287 (bool)SDL_SetTextureBlendMode(_space.get(), SDL_BLENDMODE_BLEND)) {
288 throw exception(SDL_GetError());
289 }
290 set_space_color_r(std::numeric_limits<uint8_t>::max());
291 set_space_color_g(std::numeric_limits<uint8_t>::max());
292 set_space_color_b(std::numeric_limits<uint8_t>::max());
293 set_space_color_a(std::numeric_limits<uint8_t>::max());
294 set_space_texture({});
295 _space_area.w = _space_area.h =
296 math::length(window::width(), window::height());
297 _space_area.x = origo_x() - _space_area.w / 2;
298 _space_area.y = origo_y() - _space_area.h / 2;
299 _plane = {SDL_CreateTexture(base(), SDL_PIXELFORMAT_RGBA8888,
300 SDL_TEXTUREACCESS_TARGET, window::width(),
301 window::height()),
302 SDL_DestroyTexture};
303 if (!_plane ||
304 (bool)SDL_SetTextureBlendMode(_plane.get(), SDL_BLENDMODE_BLEND)) {
305 throw exception(SDL_GetError());
306 }
307 set_plane_color_r(std::numeric_limits<uint8_t>::max());
308 set_plane_color_g(std::numeric_limits<uint8_t>::max());
309 set_plane_color_b(std::numeric_limits<uint8_t>::max());
310 set_plane_color_a(std::numeric_limits<uint8_t>::max());
311}
312
313void wze::renderer::update() {
314 std::vector<renderable const*> space;
315 std::vector<renderable const*> plane;
316
317 std::for_each(renderable::instances().begin(),
318 renderable::instances().end(),
319 [&](renderable* instance) -> void {
320 if (invisible(*instance)) {
321 return;
322 }
323 camera::project(*instance);
324 transform(*instance);
325 if (offscreen(*instance)) {
326 return;
327 }
328 if (instance->spatial()) {
329 space.push_back(instance);
330 } else {
331 plane.push_back(instance);
332 }
333 });
334
335 std::stable_sort(
336 space.begin(), space.end(),
337 [](renderable const* instance1, renderable const* instance2) -> bool {
338 return instance1->z() != instance2->z()
339 ? instance2->z() < instance1->z()
340 : instance1->priority() < instance2->priority();
341 });
342 std::stable_sort(
343 plane.begin(), plane.end(),
344 [](renderable const* instance1, renderable const* instance2) -> bool {
345 return instance1->priority() < instance2->priority();
346 });
347
348 open_frame();
349 open_space();
350 std::for_each(space.begin(), space.end(),
351 [](renderable const* instance) -> void {
352 render(*instance);
353 });
354 open_plane();
355 std::for_each(plane.begin(), plane.end(),
356 [](renderable const* instance) -> void {
357 render(*instance);
358 });
359 close_frame();
360}
361
362std::pair<float, float> wze::renderer::detransform(float x, float y) {
363 return {x - origo_x(), y - origo_y()};
364}
Subsystem to handle transformations and spatial projections.
static constexpr float to_degrees(float radians)
Converts radians to degrees.
Definition math.hpp:75
static float length(float x, float y)
Returns the length of a vector.
Definition math.cpp:33
Generic exception.
Math modul.
Subsystem to handle graphics.
Subsystem to handle game window.