diff --git a/src/core/config.c b/src/core/config.c index f89b3fa24a..66cd934041 100644 --- a/src/core/config.c +++ b/src/core/config.c @@ -26,7 +26,8 @@ static const char *ini_keys[] = { "ui_show_water_structure_range", "ui_show_construction_size", "ui_highlight_legions", - "ui_show_military_sidebar" + "ui_show_military_sidebar", + "timelapse_screenshot" }; static const char *ini_string_keys[] = { diff --git a/src/core/config.h b/src/core/config.h index 66af79ab43..5474288872 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -19,6 +19,7 @@ typedef enum { CONFIG_UI_SHOW_CONSTRUCTION_SIZE, CONFIG_UI_HIGHLIGHT_LEGIONS, CONFIG_UI_SHOW_MILITARY_SIDEBAR, + CONFIG_TIMELAPSE_SCREENSHOT, CONFIG_MAX_ENTRIES } config_key; diff --git a/src/game/tick.c b/src/game/tick.c index 29e7bbff2f..415bec3e02 100644 --- a/src/game/tick.c +++ b/src/game/tick.c @@ -26,6 +26,7 @@ #include "city/sentiment.h" #include "city/trade.h" #include "city/victory.h" +#include "core/config.h" #include "core/random.h" #include "editor/editor.h" #include "empire/city.h" @@ -36,6 +37,7 @@ #include "game/time.h" #include "game/tutorial.h" #include "game/undo.h" +#include "graphics/screenshot.h" #include "map/desirability.h" #include "map/natives.h" #include "map/road_network.h" @@ -101,6 +103,9 @@ static void advance_month(void) if (setting_monthly_autosave()) { game_file_write_saved_game("autosave.sav"); } + if (config_get(CONFIG_TIMELAPSE_SCREENSHOT)) { + graphics_save_screenshot(2); + } } static void advance_day(void) diff --git a/src/graphics/screenshot.c b/src/graphics/screenshot.c index 68ee77eaf1..94684f0e2d 100644 --- a/src/graphics/screenshot.c +++ b/src/graphics/screenshot.c @@ -4,6 +4,7 @@ #include "city/warning.h" #include "core/buffer.h" #include "core/config.h" +#include "core/direction.h" #include "core/file.h" #include "core/log.h" #include "core/string.h" @@ -12,6 +13,7 @@ #include "graphics/menu.h" #include "graphics/window.h" #include "map/grid.h" +#include "map/orientation.h" #include "translation/translation.h" #include "widget/city_without_overlay.h" @@ -30,12 +32,14 @@ enum { FULL_CITY_SCREENSHOT = 0, DISPLAY_SCREENSHOT = 1, - MAX_SCREENSHOT_TYPES = 2 + TIMELAPSE_SCREENSHOT = 2, + MAX_SCREENSHOT_TYPES = 3 }; static const char filename_formats[MAX_SCREENSHOT_TYPES][32] = { "full city %Y-%m-%d %H.%M.%S.png", "city %Y-%m-%d %H.%M.%S.png", + "timelapse %Y-%m-%d %H.%M.%S.png", }; static struct { @@ -95,12 +99,12 @@ static int image_create(int width, int height, int rows_in_memory) return 1; } -static const char *generate_filename(int city_screenshot) +static const char *generate_filename(int screenshot_mode) { static char filename[FILE_NAME_MAX]; time_t curtime = time(NULL); struct tm *loctime = localtime(&curtime); - strftime(filename, FILE_NAME_MAX, filename_formats[city_screenshot], loctime); + strftime(filename, FILE_NAME_MAX, filename_formats[screenshot_mode], loctime); return filename; } @@ -277,11 +281,97 @@ static void create_full_city_screenshot(void) image_free(); } -void graphics_save_screenshot(int full_city) +static void create_timelapse_screenshot(void) { - if (full_city) { - create_full_city_screenshot(); - } else { - create_window_screenshot(); + pixel_offset original_camera_pixels; + city_view_get_camera_in_pixels(&original_camera_pixels.x, &original_camera_pixels.y); + int original_camera_orientation = city_view_orientation(); + int width = screen_width(); + int height = screen_height(); + + int city_width_pixels = map_grid_width() * TILE_X_SIZE; + int city_height_pixels = map_grid_height() * TILE_Y_SIZE; + + if (!image_create(city_width_pixels, city_height_pixels + TILE_Y_SIZE, IMAGE_HEIGHT_CHUNK)) { + log_error("Unable to set memory for full city screenshot", 0, 0); + return; + } + const char *filename = generate_filename(TIMELAPSE_SCREENSHOT); + if (!image_begin_io(filename) || !image_write_header()) { + log_error("Unable to write screenshot to:", filename, 0); + image_free(); + return; + } + + switch (original_camera_orientation) { + case DIR_2_RIGHT: + city_view_rotate_right(); + map_orientation_change(1); + break; + case DIR_4_BOTTOM: + city_view_rotate_left(); + map_orientation_change(0); + // fallthrough + case DIR_6_LEFT: + city_view_rotate_left(); + map_orientation_change(0); + break; + default: // already north + break; + } + int canvas_width = city_width_pixels + (city_view_is_sidebar_collapsed() ? 40 : 160); + screen_set_resolution(canvas_width, TOP_MENU_HEIGHT + IMAGE_HEIGHT_CHUNK); + graphics_set_clip_rectangle(0, TOP_MENU_HEIGHT, city_width_pixels, IMAGE_HEIGHT_CHUNK); + + int base_width = (GRID_SIZE * TILE_X_SIZE - city_width_pixels) / 2 + TILE_X_SIZE; + int max_height = (GRID_SIZE * TILE_Y_SIZE + city_height_pixels) / 2; + int min_height = max_height - city_height_pixels - TILE_Y_SIZE; + map_tile dummy_tile = {0, 0, 0}; + int error = 0; + int current_height = image_set_loop_height_limits(min_height, max_height); + int size; + const color_t *canvas = (color_t *) graphics_canvas() + TOP_MENU_HEIGHT * canvas_width; + while ((size = image_request_rows())) { + city_view_set_camera_from_pixel_position(base_width, current_height); + city_without_overlay_draw(0, 0, &dummy_tile); + if (!image_write_rows(canvas, canvas_width)) { + log_error("Error writing image", 0, 0); + error = 1; + break; + } + current_height += size; + } + graphics_reset_clip_rectangle(); + screen_set_resolution(width, height); + switch (original_camera_orientation) { + case DIR_2_RIGHT: + city_view_rotate_left(); + map_orientation_change(0); + break; + case DIR_4_BOTTOM: + city_view_rotate_right(); + map_orientation_change(1); + // fallthrough + case DIR_6_LEFT: + city_view_rotate_right(); + map_orientation_change(1); + break; + default: // already north + break; + } + city_view_set_camera_from_pixel_position(original_camera_pixels.x, original_camera_pixels.y); + if (!error) { + image_finish(); + log_info("Saved full city screenshot:", filename, 0); + } + image_free(); +} + +void graphics_save_screenshot(int mode) +{ + switch (mode) { + case 2: create_timelapse_screenshot(); break; + case 1: create_full_city_screenshot(); break; + case 0: create_window_screenshot(); break; } } diff --git a/src/graphics/screenshot.h b/src/graphics/screenshot.h index c9c4ba57e2..dcbadf52cd 100644 --- a/src/graphics/screenshot.h +++ b/src/graphics/screenshot.h @@ -1,6 +1,6 @@ #ifndef GRAPHICS_SCREENSHOT_H #define GRAPHICS_SCREENSHOT_H -void graphics_save_screenshot(int full_city); +void graphics_save_screenshot(int mode); #endif // GRAPHICS_SCREENSHOT_H diff --git a/src/translation/english.c b/src/translation/english.c index 0f6d3fcde5..764fa37224 100644 --- a/src/translation/english.c +++ b/src/translation/english.c @@ -47,6 +47,7 @@ static translation_string all_strings[] = { {TR_CONFIG_SHOW_MILITARY_SIDEBAR, "Enable military sidebar"}, {TR_CONFIG_FIX_IMMIGRATION_BUG, "Fix immigration bug on very hard"}, {TR_CONFIG_FIX_100_YEAR_GHOSTS, "Fix 100-year-old ghosts"}, + {TR_CONFIG_TIMELAPSE_SCREENSHOT, "Timelapse screenshots"}, {TR_HOTKEY_TITLE, "Julius hotkey configuration"}, {TR_HOTKEY_LABEL, "Hotkey"}, {TR_HOTKEY_ALTERNATIVE_LABEL, "Alternative"}, diff --git a/src/translation/translation.h b/src/translation/translation.h index 20207aad4a..9af84c46ab 100644 --- a/src/translation/translation.h +++ b/src/translation/translation.h @@ -39,6 +39,7 @@ typedef enum { TR_CONFIG_SHOW_MILITARY_SIDEBAR, TR_CONFIG_FIX_IMMIGRATION_BUG, TR_CONFIG_FIX_100_YEAR_GHOSTS, + TR_CONFIG_TIMELAPSE_SCREENSHOT, TR_HOTKEY_TITLE, TR_HOTKEY_LABEL, TR_HOTKEY_ALTERNATIVE_LABEL, diff --git a/src/window/config.c b/src/window/config.c index 7ba2553cfc..b54505e38b 100644 --- a/src/window/config.c +++ b/src/window/config.c @@ -116,7 +116,8 @@ static config_widget all_widgets[MAX_WIDGETS] = { {TYPE_SPACE}, {TYPE_HEADER, 0, TR_CONFIG_HEADER_GAMEPLAY_CHANGES}, {TYPE_CHECKBOX, CONFIG_GP_FIX_IMMIGRATION_BUG, TR_CONFIG_FIX_IMMIGRATION_BUG}, - {TYPE_CHECKBOX, CONFIG_GP_FIX_100_YEAR_GHOSTS, TR_CONFIG_FIX_100_YEAR_GHOSTS} + {TYPE_CHECKBOX, CONFIG_GP_FIX_100_YEAR_GHOSTS, TR_CONFIG_FIX_100_YEAR_GHOSTS}, + {TYPE_CHECKBOX, CONFIG_TIMELAPSE_SCREENSHOT, TR_CONFIG_TIMELAPSE_SCREENSHOT} }; static generic_button select_buttons[] = {