Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timelapse: Automatically take screenshots every month, if enabled #647

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/core/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = {
Expand Down
1 change: 1 addition & 0 deletions src/core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
5 changes: 5 additions & 0 deletions src/game/tick.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -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)
Expand Down
106 changes: 98 additions & 8 deletions src/graphics/screenshot.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"

Expand All @@ -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 {
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
}
2 changes: 1 addition & 1 deletion src/graphics/screenshot.h
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions src/translation/english.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"},
Expand Down
1 change: 1 addition & 0 deletions src/translation/translation.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion src/window/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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[] = {
Expand Down