10 #include <drawing_manager/drawing_manager.hpp>
11 #include <ST_util/string_util.hpp>
12 #include "main/metrics.hpp"
13 #include "main/timer.hpp"
15 static bool singleton_initialized =
false;
25 if (singleton_initialized) {
26 throw std::runtime_error(
"The drawing manager cannot be initialized more than once!");
28 singleton_initialized =
true;
32 fprintf(stderr,
"Failed to initialize SDL_TTF: %s\n", TTF_GetError());
37 gMessage_bus.
subscribe(VSYNC_STATE, &msg_sub);
38 gMessage_bus.
subscribe(SET_VSYNC, &msg_sub);
39 gMessage_bus.
subscribe(SHOW_COLLISIONS, &msg_sub);
40 gMessage_bus.
subscribe(SHOW_FPS, &msg_sub);
41 gMessage_bus.
subscribe(SHOW_METRICS, &msg_sub);
42 gMessage_bus.
subscribe(SET_DARKNESS, &msg_sub);
43 gMessage_bus.
subscribe(SURFACES_ASSETS, &msg_sub);
44 gMessage_bus.
subscribe(FONTS_ASSETS, &msg_sub);
45 gMessage_bus.
subscribe(ENABLE_LIGHTING, &msg_sub);
46 gMessage_bus.
subscribe(SET_INTERNAL_RESOLUTION, &msg_sub);
49 collisions_shown =
false;
56 default_font_normal = ST::hash_string(DEFAULT_FONT_NORMAL);
57 default_font_small = ST::hash_string(DEFAULT_FONT_SMALL);
61 uint32_t screen_width_height = w_width |
static_cast<uint32_t
>(w_height << 16U);
62 gMessage_bus.
send_msg(
new message(VIRTUAL_SCREEN_COORDINATES, screen_width_height));
76 ticks = SDL_GetTicks();
79 draw_background(temp.background, temp.parallax_speed);
81 std::vector<ST::entity> entities{};
82 std::copy_if(temp.entities.begin(), temp.entities.end(), std::back_inserter(entities), [
this](
ST::entity e) {
83 return is_onscreen(e);
86 draw_entities(entities);
88 temp.overlay_sprite_num);
89 draw_text_objects(temp.text_objects);
91 if (lighting_enabled) {
92 process_lights(temp.lights);
96 if (collisions_shown) {
97 draw_collisions(entities);
98 draw_coordinates(entities);
103 draw_metrics(metrics, temp, entities);
105 draw_console(gConsole);
116 void drawing_manager::draw_text_objects(
const std::vector<ST::text> &objects)
const {
117 for (
auto &i: objects) {
118 if (is_onscreen(i)) {
128 void drawing_manager::draw_fps(
float fps)
const {
130 SDL_Color color_font = {255, 0, 255, 255};
132 "fps:" + std::to_string(
static_cast<int32_t
>(
fps)), 0, 50,
142 const std::vector<ST::entity> &entities)
const {
144 SDL_Color color_font = {255, 0, 255, 255};
146 "game_logic_time:" + std::to_string(metrics.game_logic_time), 0, 100,
149 "physics_time:" + std::to_string(metrics.physics_time), 0, 130,
152 "render_time:" + std::to_string(metrics.render_time), 0, 160,
155 "frame_time:" + std::to_string(metrics.frame_time), 0, 190,
158 "entities_on_screen:" + std::to_string(entities.size()), 0, 220,
161 "physics_objects:" + std::to_string(level.physics_objects_count), 0,
164 "entities_total:" + std::to_string(level.entities.size()), 0, 280,
175 int pos = w_height / 2;
176 SDL_Color log_entry_color;
177 for (
auto i =
console.entries.rbegin(); i !=
console.entries.rend(); ++i) {
179 if (pos_offset > 0 && pos_offset <= w_height / 2 + 50 -
console.font_size * 2) {
181 case ST::log_type::ERROR:
182 log_entry_color =
console.color_error;
185 case ST::log_type::INFO:
186 log_entry_color =
console.color_info;
190 log_entry_color =
console.color_success;
200 int32_t cursor_draw_position;
203 "Input: " +
console.composition, 0,
204 w_height / 2,
console.color_text);
206 std::string to_cursor =
console.composition.substr(0,
console.cursor_position);
207 std::string after_cursor =
console.composition.substr(
console.cursor_position, INT_MAX);
209 w_height / 2,
console.color_text);
213 if (ticks -
console.cursor_timer < 250 ||
console.cursor_timer == 0) {
215 cursor_draw_position, w_height / 2 - 50 + 5, 3,
218 console.cursor_timer = (ticks -
console.cursor_timer >= 500) * ticks +
227 void drawing_manager::process_lights(
const std::vector<ST::light> &lights) {
228 memset(lightmap, darkness_level,
sizeof lightmap);
229 for (
const auto &light: lights) {
230 int x = !light.is_static * (light.origin_x - camera.x) + light.is_static * light.origin_x;
231 int y = !light.is_static * (light.origin_y - camera.y) + light.is_static * light.origin_y;
233 double step = darkness_level /
static_cast<double>(light.radius);
235 int radius = light.radius;
236 int intensity = light.intensity;
237 if (x - radius - intensity > w_width || y - radius - intensity > w_height) {
241 for (
int i = y; i < y + radius + intensity; ++i) {
242 for (
int j = x; j < x + radius + intensity; ++j) {
243 if (j > 0 && j < w_width && i > 0 && i < w_height) {
244 lightmap[j][i] = (uint8_t) light.brightness +
static_cast<uint8_t
>(count);
246 if (count + light.brightness < darkness_level && j > x + intensity) {
252 if (step2 + light.brightness < darkness_level && i > y + intensity)
257 for (
int i = y; i > y - radius - intensity; --i) {
258 for (
int j = x; j > x - radius - intensity; --j) {
259 if (j > 0 && j < w_width && i > 0 && i < w_height) {
260 lightmap[j][i] = light.brightness + (uint8_t) count;
262 if (count + light.brightness < darkness_level && j < x - intensity) {
268 if (step2 + light.brightness < darkness_level && i < y - intensity) {
274 for (
int i = y; i > y - radius - intensity; --i) {
275 for (
int j = x; j < x + radius + intensity; ++j) {
276 if (j > 0 && j < w_width && i > 0 && i < w_height) {
277 lightmap[j][i] = light.brightness + (uint8_t) count;
279 if (count + light.brightness < darkness_level && j > x + intensity) {
285 if (step2 + light.brightness < darkness_level && i < y - intensity) {
291 for (
int i = y; i < y + radius + intensity; ++i) {
292 for (
int j = x; j > x - radius - intensity; --j) {
293 if (j > 0 && j < w_width && i > 0 && i < w_height) {
294 lightmap[j][i] = light.brightness + (uint8_t) count;
296 if (count + light.brightness < darkness_level && j < x - intensity) {
302 if (step2 + light.brightness < darkness_level && i > y + intensity) {
312 void drawing_manager::draw_lights()
const {
314 SDL_Rect tempRect = {0, 0, lights_quality, lights_quality};
315 SDL_Color light_color;
317 for (
int i = 0; i <= w_width - lights_quality; i += lights_quality) {
320 for (
int j = 0; j <= w_height - lights_quality; j += lights_quality) {
321 if (lightmap[i][j] == lightmap[i][j + lights_quality] && j + lights_quality == w_height) {
322 tempRect.y = j - a * lights_quality;
323 tempRect.h = (a + 1) * lights_quality;
324 light_color = {0, 0, 0, lightmap[i][j]};
326 }
else if (lightmap[i][j] == lightmap[i][j + lights_quality]) {
329 tempRect.h = a * lights_quality;
330 tempRect.y = j - a * lights_quality;
331 light_color = {0, 0, 0, lightmap[i][j]};
343 void drawing_manager::handle_messages() {
345 while (temp !=
nullptr) {
346 switch (temp->msg_name) {
348 auto arg =
static_cast<bool>(temp->base_data0);
358 set_darkness(
static_cast<uint8_t
>(temp->base_data0));
360 case SHOW_COLLISIONS:
361 collisions_shown =
static_cast<bool>(temp->base_data0);
364 show_fps =
static_cast<bool>(temp->base_data0);
367 metrics_shown =
static_cast<bool>(temp->base_data0);
369 case ENABLE_LIGHTING:
370 lighting_enabled =
static_cast<bool>(temp->base_data0);
372 case SURFACES_ASSETS: {
373 auto surfaces = *
static_cast<ska::bytell_hash_map<uint16_t, SDL_Surface *> **
>(temp->
get_data());
378 auto fonts = *
static_cast<ska::bytell_hash_map<uint16_t, TTF_Font *> **
>(temp->
get_data());
382 case SET_INTERNAL_RESOLUTION: {
383 auto data = temp->base_data0;
384 w_width = data & 0x0000ffffU;
385 w_height = (data >> 16U) & 0x0000ffffU;
400 void drawing_manager::set_darkness(uint8_t arg) {
401 darkness_level = arg;
402 memset(lightmap, arg,
sizeof lightmap);
409 void drawing_manager::draw_entities(
const std::vector<ST::entity> &entities)
const {
410 uint32_t time = ticks >> 7U;
411 for (
auto &i: entities) {
412 int32_t camera_offset_x = (!i.is_static()) * camera.x;
413 int32_t camera_offset_y = (camera_offset_x != 0) * camera.y;
415 i.x - camera_offset_x,
416 i.y - camera_offset_y,
431 bool drawing_manager::is_onscreen(
const ST::entity &i)
const {
432 return i.is_visible() &&
434 (i.x - camera.x +
static_cast<int>(
static_cast<float>(i.tex_w) * i.tex_scale_x) >= 0 &&
435 i.x - camera.x <= w_width
445 bool drawing_manager::is_onscreen(
const ST::text &i)
const {
446 return i.is_visible && i.x < camera.x + w_width;
453 void drawing_manager::draw_collisions(
const std::vector<ST::entity> &entities)
const {
454 for (
auto &i: entities) {
455 int32_t x_offset = (!i.is_static()) * camera.x;
456 int32_t y_offset = (x_offset != 0) * camera.y;
457 uint8_t b = (!i.is_affected_by_physics()) * 220;
458 uint8_t r = (!b) * 240;
469 void drawing_manager::draw_coordinates(
const std::vector<ST::entity> &entities)
const {
470 for (
auto &i: entities) {
471 if (i.is_affected_by_physics()) {
472 int32_t x_offset = (!i.is_static()) * camera.x;
473 int32_t y_offset = (x_offset != 0) * camera.y;
474 SDL_Color colour_text = {255, 255, 0, 255};
476 i.y - y_offset - i.tex_h, colour_text);
478 i.y - y_offset - i.tex_h + 30, colour_text);
488 void drawing_manager::draw_background(
const uint16_t background[PARALLAX_BG_LAYERS],
489 const uint8_t parallax_speed[PARALLAX_BG_LAYERS])
const {
490 for (uint8_t i = 0; i < PARALLAX_BG_LAYERS; i++) {
492 (camera.x * (parallax_speed[i] << 3)) / (w_width >> 1) % w_width);
503 singleton_initialized =
false;
This class represents all static or dynamic objects in the game (excluding text, see ST::text)
int32_t get_col_y() const
int16_t get_col_x_offset() const
int16_t get_col_y_offset() const
int32_t get_col_x() const
This object contains all the data for a level and provides functions for loading and unloading a leve...
This object represents the console window.
drawing_manager(SDL_Window *window, message_bus &gMessageBus)
void update(const ST::level &temp, float fps, console &gConsole, ST::metrics metrics)
The central messaging system of the engine. All subsystem make extensive use of it.
void subscribe(uint8_t msg, subscriber *sub)
void send_msg(message *msg)
A message object passed around in the message bus. Holds anything created with make_data<>().
message * get_next_message()
uint16_t draw_text_lru_cached(uint16_t font, const std::string &arg2, int x, int y, SDL_Color color_font)
void upload_fonts(ska::bytell_hash_map< uint16_t, TTF_Font * > *fonts)
void upload_surfaces(ska::bytell_hash_map< uint16_t, SDL_Surface * > *surfaces)
void draw_overlay(uint16_t arg, uint8_t sprite, uint8_t sprite_num)
void draw_sprite_scaled(uint16_t arg, int32_t x, int32_t y, uint8_t sprite, uint8_t animation, uint8_t animation_num, uint8_t sprite_num, float scale_x, float scale_y)
void clear_screen(SDL_Color color)
uint16_t draw_text_cached_glyphs(uint16_t font, const std::string &text, int x, int y, SDL_Color color_font)
void draw_background_parallax(uint16_t arg, uint16_t offset)
int8_t initialize(SDL_Window *win, int16_t width, int16_t height)
void set_resolution(int16_t r_width, int16_t r_height)
void draw_rectangle_filled(int32_t x, int32_t y, int32_t w, int32_t h, SDL_Color color)
This struct represents text objects in the game.