From fb38574083f79dd1e8acec0eaf9f9d8e272d1f6c Mon Sep 17 00:00:00 2001 From: namark <namark@disroot.org> Date: Tue, 4 Feb 2020 01:42:21 +0400 Subject: [PATCH] Basic recording functionality. --- source/main.cpp | 226 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 165 insertions(+), 61 deletions(-) diff --git a/source/main.cpp b/source/main.cpp index 66d6bd1..aa2b4cc 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -5,6 +5,8 @@ #include <tuple> #include <bitset> #include <random> +#include <vector> +#include <map> #include <iostream> #include "simple/graphical.hpp" @@ -12,6 +14,7 @@ #include "simple/support.hpp" #include "simple/geom/algorithm.hpp" +#include "recorder.h" #include "factors.hpp" #include "utils.hpp" @@ -51,8 +54,15 @@ void gol_advance(const cell_writer&, range<int2>); using supported_concurrencies = std::integer_sequence<size_t, 1,2,4,6,8,10,12,14,16,32>; constexpr auto split_range = prepare_splits(supported_concurrencies{}); -int main() try +int main(int argc, char** argv) try { + const char* recording_file = argc > 1 ? argv[1] : nullptr; + bool recording_started = false; + size_t recorded_frame_count = 0; + size_t current_recording_frame = 0; + std::map<size_t,std::vector<interactive::event>> event_record; + auto current_event_record = event_record.begin(); + std::optional<recorder> recorder; auto selected_concurrency = upper_bound(supported_concurrencies{}, std::thread::hardware_concurrency()); std::cout << "Hardware concurrency: " << std::thread::hardware_concurrency() << '\n'; @@ -88,7 +98,7 @@ int main() try std::fputs("Wow! index8 surface has no palette???", stderr); return -1; } - + surface world_snapshot(world); auto pixels = world.pixels(); if(!std::holds_alternative<cell_writer>(pixels)) @@ -96,7 +106,7 @@ int main() try std::fputs("Wow! Can't access index8 surface pixels as bytes???", stderr); return -2; } - auto cells = std::get<cell_writer>(world.pixels()); + auto cells = std::get<cell_writer>(pixels); surface intermediate(win.size(), win.surface().format()); @@ -111,74 +121,144 @@ int main() try bool live = false; bool live_once = false; size_t history = 0; - auto current_frame = steady_clock::now(); - while(!done) + auto cell_size_snapshot = cell_size; + bool live_snapshot = live; + size_t history_snapshot = history; + + using namespace simple::interactive; + auto quit_handler = [&done](quit_request) + { done = true; return false; }; + auto event_handler = support::overloaded { - current_frame = steady_clock::now(); - - using namespace simple::interactive; - while(auto event = next_event()) + quit_handler, + [&cells, &cell_size](mouse_down e) + { + if(e.data.button == mouse_button::left) + cells[e.data.position / *cell_size] ^= 1; + return true; + }, + [&cells, &cell_size](mouse_motion e) { - std::visit(support::overloaded + if(bool(e.data.button_state & mouse_button_mask::left)) { - [&done](quit_request){ done = true; }, - [&cells, &cell_size](mouse_down e) - { - if(e.data.button == mouse_button::left) - cells[e.data.position / *cell_size] ^= 1; - }, - [&cells, &cell_size](mouse_motion e) - { - if(bool(e.data.button_state & mouse_button_mask::left)) - { - auto start = e.data.position / *cell_size; - auto end = start - e.data.motion / *cell_size; - bresenham_line<int2>({start, end}, [&cells](int2 p) - { - cells[p] |= 1; - }); - } - }, - [&](key_pressed e) + auto start = e.data.position / *cell_size; + auto end = start - e.data.motion / *cell_size; + bresenham_line<int2>({start, end}, [&cells](int2 p) { - switch(e.data.scancode) - { + cells[p] |= 1; + }); + return true; + } + return false; + }, + [&](key_pressed e) + { + switch(e.data.scancode) + { - case scancode::enter: - live = !live; - break; + case scancode::enter: + live = !live; + break; - case scancode::right: - live_once = true; - live = false; - break; + case scancode::right: + live_once = true; + live = false; + break; - case scancode::left: - if(history > 1) + case scancode::left: + if(history > 1) + { + for(auto&& cell : cells.raw_range()) cell >>= 1; + --history; + } + live = false; + break; + + case scancode::equals: + case scancode::kp_plus: + if(cell_size < cell_sizes.end()-1) + ++cell_size; + break; + + case scancode::minus: + case scancode::kp_minus: + if(cell_size > cell_sizes.begin()) + --cell_size; + break; + + case scancode::r: + if(pressed(scancode::rshift) || pressed(scancode::lshift)) + { + if(recording_file) + { + recording_started = !recording_started; + if(recording_started) { - for(auto&& cell : cells.raw_range()) cell >>= 1; - --history; + std::cout << "Recording" << '\n'; + blit(world, world_snapshot); + live_snapshot = live; + history_snapshot = history; + cell_size_snapshot = cell_size; + recorded_frame_count = 0; } - live = false; - break; - - case scancode::equals: - case scancode::kp_plus: - if(cell_size < cell_sizes.end()-1) - ++cell_size; - break; - - case scancode::minus: - case scancode::kp_minus: - if(cell_size > cell_sizes.begin()) - --cell_size; - break; - - default: break; + else + { + std::cout << "Rendering" << '\n'; + recorder.emplace(recording_file, win.size()); + current_recording_frame = 0; + current_event_record = event_record.begin(); + blit(world_snapshot, world); + live = live_snapshot; + history = history_snapshot; + cell_size = cell_size_snapshot; + } + + } + return false; } - }, - [](auto&&){} - }, *event); + break; + + default: return false; + } + return true; + }, + [](auto&&){ return false; } + }; + auto recording_event_handler = support::overloaded + { + quit_handler, + [](auto&&){ return false; } + }; + + auto current_frame = steady_clock::now(); + while(!done) + { + current_frame = steady_clock::now(); + + if(recorder) + { + while(auto event = next_event()) + std::visit(recording_event_handler, *event); + + if(current_event_record != event_record.end()) + if(current_event_record->first < current_recording_frame) + ++current_event_record; + + // have to check this again?? come ooon...! + if(current_event_record != event_record.end()) + if(current_event_record->first == current_recording_frame) + for(auto&& event : current_event_record->second) + std::visit(event_handler, event); + } + else + { + while(auto event = next_event()) + { + auto record = std::visit(event_handler, *event); + + if(recording_started && record) + event_record[recorded_frame_count-1].push_back(*event); + } } const int2 active_size = world.size() / *cell_size; @@ -189,6 +269,7 @@ int main() try // technically UB? but should work fine for any sane arch // not too hard to un-UB with small performance hit + // also TODO: if the world is small(er than nproc * cacheline) don't split support::apply_for(selected_concurrency.index, [&](auto splitter) { @@ -232,6 +313,29 @@ int main() try win.update(); frametime_logger.log(steady_clock::now() - current_frame); + if(recording_started) + { + ++recorded_frame_count; + } + else if(recorder) + { + if(current_recording_frame < recorded_frame_count) + { + if(current_recording_frame == recorded_frame_count - 1 || done) + { + recorder->record(world, *cell_size, true); + recorder.reset(); + event_record.clear(); + } + else + recorder->record(world, *cell_size, false); + } + ++current_recording_frame; + std::cout << "rendered: " + << current_recording_frame << '/' + << recorded_frame_count << '\n'; + } + // this is not very precise, maybe busy wait for last millisecond(or less) std::this_thread::sleep_until(current_frame + frametime); } -- GitLab