#pragma once
#include "object.hpp"
#include "renderer.hpp"
#include "tracer.hpp"
/**
* @file
* @brief First entrypoint of the main loop, processing user input and maintaining state for a new frame.
*/
typedef std::vector<std::unique_ptr<const Object>> scene_t;
typedef std::vector<std::pair<vertex_t, const PointLight*>> lights_t;
/** @brief Player can collect lights and drop them again. */
class LightStack {
public:
private:
std::list<lightbox_t> lightboxes{}; ///< active dynamic lights
std::vector<const PointLight*> stack{}; ///< picked and thus disabled lights
void push(const PointLight*, const vertex_t&, const scene_t&);
public:
LightStack(const scene_t& scene, const lights_t& lights);
bool push(const vertex_t&, const scene_t&); ///< place at given position, if any available
const PointLight* pop_nearest(const vertex_t&, fcoord_t); ///< take a light, if nearby
size_t size() const; ///< number of collected lights
const std::list<lightbox_t>& get() const; ///< all lights to be put into the current scene
};
/**
* @brief Main coordinator, getting user input and starting new frame pipeline.
*
* Sets up and holds the overall processing pipeline (@ref Tracer, @ref LightTracer, @ref Renderer).
* Update player position and preprocess an optimized scene.
* The result should only contain the subset of objects and lights that might contribute.
* A new frame render is triggered by pushing a @ref context_t to the @ref Tracer @ref ThreadQueue.
*/
class State {
private:
Sampler sampler; ///< final interpolation, i.e., when subsampling is enabled
ContextFactory contexts;
const scene_t& scene;
const lights_t& lights;
LightStack lightboxes;
vertex_t camera; ///< last position, moving along ticks
const fcoord_t sensitivity;
unsigned congestion_count{};
PointLight player;
Renderer renderer;
LightTracer light_tracer;
Tracer tracer;
vertex_t clip(const vertex_t& pos, const vertex_t& off) const; ///< intersect player movement with scene
public:
State(const scene_t& scene, const lights_t& lights, vertex_t raster, vertex_t viewport, vertex_t camera,
res_t resolution, bool subsample, fcoord_t sensitivity);
bool tick(const Renderer::input_t&); ///< process input, update state, enqueue new frame context
Renderer::input_t get_input(); ///< wait for pressed keys
unsigned congestion_hint(); ///< number of queue overflow events, reset counter afterwards
const SlidingAverage<msec_t>& duration_hint(); ///< overall frame pipeline delay, as observed by @ref Renderer
};