render_surfaces shows the use of mir to render some moving surfaces
main()
The main() function uses a RenderSurfacesServerConfiguration to initialize and run mir.
RenderSurfacesServerConfiguration conf{argc, argv};
{
conf.create_surfaces();
cursor = conf.the_cursor();
input_is_on = conf.input_is_on();
});
RenderSurfacesServerConfiguration
The configuration stubs out client connectivity and input.
std::shared_ptr<mf::Connector> the_connector() override
{
{
};
return std::make_shared<NullConnector>();
}
it also provides a bespoke buffer initializer
std::shared_ptr<mg::BufferInitializer> the_buffer_initializer() override
{
{
public:
RenderResourcesBufferInitializer()
{
}
{
mir_image.bytes_per_pixel};
brt.make_current();
img_renderer.render();
}
};
return std::make_shared<RenderResourcesBufferInitializer>();
}
and a bespoke display buffer compositor
std::shared_ptr<mc::DisplayBufferCompositorFactory> the_display_buffer_compositor_factory() override
{
{
public:
RenderSurfacesDisplayBufferCompositor(
std::unique_ptr<DisplayBufferCompositor> db_compositor,
std::vector<Moveable>& moveables)
: db_compositor{std::move(db_compositor)},
moveables(moveables),
frames{0}
{
}
{
animate_cursor();
stop_watch.stop();
if (stop_watch.elapsed_seconds_since_last_restart() >= 1)
{
std::cout << "FPS: " << frames << " Frame Time: " << 1.0 / frames << std::endl;
frames = 0;
stop_watch.restart();
}
glClearColor(0.0, 1.0, 0.0, 1.0);
db_compositor->composite();
for (auto& m : moveables)
m.step();
frames++;
}
private:
std::unique_ptr<DisplayBufferCompositor> const db_compositor;
StopWatch stop_watch;
std::vector<Moveable>& moveables;
uint32_t frames;
};
{
public:
RenderSurfacesDisplayBufferCompositorFactory(
std::shared_ptr<mc::Scene> const& scene,
std::shared_ptr<mc::RendererFactory> const& renderer_factory,
std::shared_ptr<mc::OverlayRenderer> const& overlay_renderer,
std::vector<Moveable>& moveables)
: DefaultDisplayBufferCompositorFactory{scene, renderer_factory, overlay_renderer},
moveables(moveables)
{
}
{
auto raw = new RenderSurfacesDisplayBufferCompositor(std::move(cs), moveables);
return std::unique_ptr<RenderSurfacesDisplayBufferCompositor>(raw);
}
std::vector<Moveable>& moveables;
};
return std::make_shared<RenderSurfacesDisplayBufferCompositorFactory>(
the_scene(),
the_renderer_factory(),
the_overlay_renderer(),
moveables);
}
Utility classes
For smooth animation we need to track time and move surfaces accordingly
StopWatch
class StopWatch
{
public:
StopWatch() : start(std::chrono::high_resolution_clock::now()),
last(start),
now(last)
{
}
void stop()
{
now = std::chrono::high_resolution_clock::now();
}
double elapsed_seconds_since_start()
{
auto elapsed = now - start;
float elapsed_sec = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count() / 1000000.0f;
return elapsed_sec;
}
double elapsed_seconds_since_last_restart()
{
auto elapsed = now - last;
float elapsed_sec = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count() / 1000000.0f;
return elapsed_sec;
}
void restart()
{
std::swap(last, now);
}
private:
std::chrono::high_resolution_clock::time_point start;
std::chrono::high_resolution_clock::time_point last;
std::chrono::high_resolution_clock::time_point now;
};
Moveable
class Moveable
{
public:
Moveable() {}
float dx,
float dy,
const glm::vec3& rotation_axis,
float alpha_offset)
: surface(&s), display_size(display_size),
dx{dx},
dy{dy},
rotation_axis{rotation_axis},
alpha_offset{alpha_offset}
{
}
void step()
{
stop_watch.stop();
float elapsed_sec = stop_watch.elapsed_seconds_since_last_restart();
float total_elapsed_sec = stop_watch.elapsed_seconds_since_start();
stop_watch.restart();
bool should_update = true;
float new_x =
x + elapsed_sec *
dx;
float new_y =
y + elapsed_sec *
dy;
{
should_update = false;
}
{
should_update = false;
}
if (should_update)
{
surface->move_to({new_x, new_y});
}
surface->set_rotation(total_elapsed_sec * 120.0f, rotation_axis);
surface->set_alpha(0.5 + 0.5 * sin(alpha_offset + 2 * M_PI * total_elapsed_sec / 3.0));
}
private:
float w;
float h;
StopWatch stop_watch;
glm::vec3 rotation_axis;
float alpha_offset;
};