#pragma once
#include <list>
#include <memory>
#include "viewport.hpp"
template <class T>
class BufferView;
class XWin; // keep out X includes
class XFrame;
/**
* @brief Final anti-aliasing and scaling/sub-sampling pass.
*
* I.e., either 1:1, nearest neighbour, or bilinear interpolation.
*/
class Sampler {
private:
const res_t res;
std::unique_ptr<BufferView<vertex_t>> view; ///< concrete buffer accessor instance
static std::unique_ptr<BufferView<vertex_t>> make(res_t, bool); ///< actual view factory
public:
Sampler(res_t, bool subsample);
~Sampler();
BufferView<vertex_t>* get();
res_t resolution_in() const; ///< tracing dimension
res_t resolution_off() const; ///< offset if not square
res_t resolution_out() const; ///< output dimension
};
/** @brief Frame pipeline duration feedback for the main loop. */
template <class T>
class SlidingAverage {
private:
const size_t len;
size_t total_num{};
std::list<T> buf{};
T sum{}, total_sum{};
float avg{}, total_avg{}; // precomputed averages, as technically not really threadsafe
public:
SlidingAverage(size_t max_len) : len(max_len) {
assert(len > 0);
}
void push(T value);
size_t get_num() const {
return total_num;
}
size_t get_size() const {
return buf.size();
}
float get_avg() const {
return total_avg;
}
float get_sliding_avg() const {
return avg;
}
};
/**
* @brief Final stage, combining hit texture and light information to X raster image.
*
* Only interface to interact with X, thus also provides key input from window to main loop.
*/
class Renderer {
public:
struct input_t {
vertex_t offset{}; ///< movement as determined by keypress duration
union {
unsigned actions{};
struct {
unsigned move : 1; ///< move by offset
unsigned beam : 1; ///< move to offset
unsigned action : 1; ///< interact (drop/pick light)
unsigned restart : 1; ///< restart level
unsigned regen : 1; ///< start next level with new seed
unsigned quit : 1; ///< program exit
} action;
};
};
struct render_task_t { ///< aggregate as @ref ThreadPool callback argument
const context_t& context;
const BufferView<vertex_t>& view;
XFrame& frame;
};
private:
SlidingAverage<msec_t> frame_duration;
Sampler& sampler;
std::unique_ptr<XWin> xwin;
ThreadQueue<context_t> thread;
ThreadPool<render_task_t, 4> threads;
void draw(std::unique_ptr<context_t>&&);
public:
Renderer(ContextFactory&, Sampler&);
~Renderer();
ThreadQueue<context_t>& queue();
input_t get_input(fcoord_t sensitivity); ///< pop key presses from @ref XKeyEvents thread
const SlidingAverage<msec_t>& duration_hint() const; ///< collect average duration until render
};