Move all rendering logic to a single RenderingState.
This commit is contained in:
@@ -3,32 +3,13 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "RenderingState.hpp"
|
#include "RenderingState.hpp"
|
||||||
#include "utils.hpp"
|
#include "visualisations.hpp"
|
||||||
|
#include "Range.hpp"
|
||||||
|
#include "glutils.hpp"
|
||||||
|
|
||||||
using namespace fmri;
|
using namespace fmri;
|
||||||
|
|
||||||
static RenderingState& state = RenderingState::instance();
|
static RenderingState &state = RenderingState::instance();
|
||||||
|
|
||||||
/**
|
|
||||||
* Static utility function to bind to GLUT.
|
|
||||||
*
|
|
||||||
* @param x
|
|
||||||
* @param y
|
|
||||||
*/
|
|
||||||
static void handleMouseMove(int x, int y)
|
|
||||||
{
|
|
||||||
state.handleMouseAt(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static utility function to bind to GLUT.
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
*/
|
|
||||||
static void handleKeys(unsigned char key, int, int)
|
|
||||||
{
|
|
||||||
state.handleKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
static float getFPS()
|
static float getFPS()
|
||||||
{
|
{
|
||||||
@@ -100,7 +81,7 @@ void RenderingState::handleKey(unsigned char x)
|
|||||||
glutPostRedisplay();
|
glutPostRedisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RenderingState::infoLine()
|
std::string RenderingState::infoLine()const
|
||||||
{
|
{
|
||||||
std::stringstream buffer;
|
std::stringstream buffer;
|
||||||
buffer << "Pos(x,y,z) = (" << pos[0] << ", " << pos[1] << ", " << pos[2] << ")\n";
|
buffer << "Pos(x,y,z) = (" << pos[0] << ", " << pos[1] << ", " << pos[2] << ")\n";
|
||||||
@@ -119,7 +100,7 @@ void RenderingState::reset()
|
|||||||
angle[1] = 0;
|
angle[1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingState::configureRenderingContext()
|
void RenderingState::configureRenderingContext()const
|
||||||
{
|
{
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glRotatef(angle[1], 1, 0, 0);
|
glRotatef(angle[1], 1, 0, 0);
|
||||||
@@ -136,8 +117,24 @@ RenderingState &RenderingState::instance()
|
|||||||
void RenderingState::registerControls()
|
void RenderingState::registerControls()
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
glutPassiveMotionFunc(handleMouseMove);
|
glutPassiveMotionFunc([](int x, int y) {
|
||||||
glutKeyboardFunc(handleKeys);
|
RenderingState::instance().handleMouseAt(x, y);
|
||||||
|
});
|
||||||
|
glutKeyboardFunc([](auto key, auto, auto) {
|
||||||
|
RenderingState::instance().handleKey(key);
|
||||||
|
});
|
||||||
|
glutDisplayFunc([]() {
|
||||||
|
float time = getAnimationStep(std::chrono::seconds(5));
|
||||||
|
RenderingState::instance().render(time);
|
||||||
|
});
|
||||||
|
glutIdleFunc([]() {
|
||||||
|
checkGLErrors();
|
||||||
|
throttleIdleFunc();
|
||||||
|
glutPostRedisplay();
|
||||||
|
});
|
||||||
|
glutSpecialFunc([](int key, int, int) {
|
||||||
|
RenderingState::instance().handleSpecialKey(key);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderingState::handleMouseAt(int x, int y)
|
void RenderingState::handleMouseAt(int x, int y)
|
||||||
@@ -150,3 +147,110 @@ void RenderingState::handleMouseAt(int x, int y)
|
|||||||
|
|
||||||
glutPostRedisplay();
|
glutPostRedisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderingState::loadSimulationData(const std::map<string, LayerInfo> &info, vector<vector<LayerData>> &&data)
|
||||||
|
{
|
||||||
|
layerInfo = std::move(info);
|
||||||
|
layerData = std::move(data);
|
||||||
|
currentData = layerData.begin();
|
||||||
|
|
||||||
|
updateVisualisers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderingState::updateVisualisers()
|
||||||
|
{
|
||||||
|
layerVisualisations.clear();
|
||||||
|
interactionAnimations.clear();
|
||||||
|
LayerData *prevState = nullptr;
|
||||||
|
LayerVisualisation *prevVisualisation = nullptr;
|
||||||
|
|
||||||
|
for (LayerData &layer : *currentData) {
|
||||||
|
LayerVisualisation *visualisation = getVisualisationForLayer(layer, layerInfo.at(layer.name()));
|
||||||
|
if (prevState && prevVisualisation && visualisation) {
|
||||||
|
auto interaction = getActivityAnimation(*prevState, layer, layerInfo.at(layer.name()),
|
||||||
|
prevVisualisation->nodePositions(), visualisation->nodePositions());
|
||||||
|
interactionAnimations.emplace_back(interaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
layerVisualisations.emplace_back(visualisation);
|
||||||
|
|
||||||
|
prevVisualisation = visualisation;
|
||||||
|
prevState = &layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
glutPostRedisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderingState::render(float time) const
|
||||||
|
{
|
||||||
|
// Clear Color and Depth Buffers
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
configureRenderingContext();
|
||||||
|
|
||||||
|
|
||||||
|
glPushMatrix();
|
||||||
|
glTranslatef(5 * currentData->size(), 0, 0);
|
||||||
|
|
||||||
|
for (auto i : Range(currentData->size())) {
|
||||||
|
glPushMatrix();
|
||||||
|
renderLayerName(currentData->at(i).name());
|
||||||
|
layerVisualisations[i]->render();
|
||||||
|
if (i < interactionAnimations.size() && interactionAnimations[i]) {
|
||||||
|
interactionAnimations[i]->draw(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
glTranslatef(LAYER_X_OFFSET, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
|
||||||
|
renderDebugInfo();
|
||||||
|
|
||||||
|
glutSwapBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderingState::renderDebugInfo() const
|
||||||
|
{
|
||||||
|
glLoadIdentity();
|
||||||
|
setOrthographicProjection();
|
||||||
|
glColor3f(1, 1, 0);
|
||||||
|
renderText(infoLine(), 2, 10);
|
||||||
|
restorePerspectiveProjection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderingState::renderLayerName(const std::string &name) const
|
||||||
|
{
|
||||||
|
glColor3f(0.5, 0.5, 0.5);
|
||||||
|
auto layerName = name;
|
||||||
|
layerName += ": ";
|
||||||
|
layerName += LayerInfo::nameByType(layerInfo.at(name).type());
|
||||||
|
renderText(layerName);
|
||||||
|
|
||||||
|
glTranslatef(0, 0, -10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderingState::handleSpecialKey(int key)
|
||||||
|
{
|
||||||
|
switch (key) {
|
||||||
|
case GLUT_KEY_LEFT:
|
||||||
|
if (currentData == layerData.begin()) {
|
||||||
|
currentData = layerData.end();
|
||||||
|
}
|
||||||
|
--currentData;
|
||||||
|
updateVisualisers();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLUT_KEY_RIGHT:
|
||||||
|
++currentData;
|
||||||
|
if (currentData == layerData.end()) {
|
||||||
|
currentData = layerData.begin();
|
||||||
|
}
|
||||||
|
updateVisualisers();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG(INFO) << "Received keystroke " << key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "LayerInfo.hpp"
|
||||||
|
#include "LayerData.hpp"
|
||||||
|
#include "LayerVisualisation.hpp"
|
||||||
|
#include "Animation.hpp"
|
||||||
|
|
||||||
namespace fmri
|
namespace fmri
|
||||||
{
|
{
|
||||||
@@ -15,7 +19,6 @@ namespace fmri
|
|||||||
* Reset the rendering state
|
* Reset the rendering state
|
||||||
*/
|
*/
|
||||||
void reset();
|
void reset();
|
||||||
void configureRenderingContext();
|
|
||||||
void registerControls();
|
void registerControls();
|
||||||
/**
|
/**
|
||||||
* GLUT mouse handler function
|
* GLUT mouse handler function
|
||||||
@@ -28,16 +31,35 @@ namespace fmri
|
|||||||
* @param x
|
* @param x
|
||||||
*/
|
*/
|
||||||
void handleKey(unsigned char x);
|
void handleKey(unsigned char x);
|
||||||
std::string infoLine();
|
/**
|
||||||
|
* GLUT special keyboard handler.
|
||||||
|
* @param key
|
||||||
|
*/
|
||||||
|
void handleSpecialKey(int key);
|
||||||
|
void render(float time) const;
|
||||||
|
|
||||||
|
void loadSimulationData(const std::map<string, LayerInfo> &info, std::vector<std::vector<LayerData>> &&data);
|
||||||
|
|
||||||
static RenderingState& instance();
|
static RenderingState& instance();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float pos[3];
|
std::array<float, 3> pos;
|
||||||
float angle[2];
|
std::array<float, 2> angle;
|
||||||
|
std::map<std::string, LayerInfo> layerInfo;
|
||||||
|
std::vector<std::vector<LayerData>> layerData;
|
||||||
|
std::vector<std::vector<LayerData>>::iterator currentData;
|
||||||
|
std::vector<std::unique_ptr<LayerVisualisation>> layerVisualisations;
|
||||||
|
std::vector<std::unique_ptr<Animation>> interactionAnimations;
|
||||||
|
|
||||||
RenderingState() noexcept = default;
|
RenderingState() noexcept = default;
|
||||||
|
|
||||||
|
void configureRenderingContext() const;
|
||||||
|
|
||||||
void move(unsigned char key);
|
void move(unsigned char key);
|
||||||
|
void updateVisualisers();
|
||||||
|
|
||||||
|
std::string infoLine()const;
|
||||||
|
void renderDebugInfo() const;
|
||||||
|
void renderLayerName(const std::string& name) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ namespace fmri {
|
|||||||
/**
|
/**
|
||||||
* Draw a bitmap string at the current location.
|
* Draw a bitmap string at the current location.
|
||||||
*
|
*
|
||||||
|
* This function wraps glutBitmapCharacter, because its nicer version
|
||||||
|
* (glutBitmapString) is an extension that is possibly unavailable.
|
||||||
|
*
|
||||||
* @param text The text to draw.
|
* @param text The text to draw.
|
||||||
*/
|
*/
|
||||||
void renderText(std::string_view text, int x = 0, int y = 0);
|
void renderText(std::string_view text, int x = 0, int y = 0);
|
||||||
|
|||||||
@@ -16,31 +16,19 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace fmri;
|
using namespace fmri;
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
optional<vector<string>> labels;
|
|
||||||
map<string, LayerInfo> layerInfo;
|
|
||||||
vector<vector<LayerData>> data;
|
|
||||||
vector<vector<LayerData>>::iterator currentData;
|
|
||||||
vector<unique_ptr<LayerVisualisation>> layerVisualisations;
|
|
||||||
vector<unique_ptr<Animation>> animations;
|
|
||||||
float animationStep = 0;
|
|
||||||
} rendererData;
|
|
||||||
|
|
||||||
static void loadSimulationData(const Options &options)
|
static void loadSimulationData(const Options &options)
|
||||||
{
|
{
|
||||||
vector<vector<LayerData>> &results = rendererData.data;
|
vector<vector<LayerData>> results;
|
||||||
results.clear();
|
|
||||||
|
|
||||||
auto dumper = options.imageDumper();
|
auto dumper = options.imageDumper();
|
||||||
Simulator simulator(options.model(), options.weights(), options.means());
|
Simulator simulator(options.model(), options.weights(), options.means());
|
||||||
rendererData.layerInfo = simulator.layerInfo();
|
|
||||||
|
|
||||||
for (const auto &image : options.inputs()) {
|
for (const auto &image : options.inputs()) {
|
||||||
results.emplace_back(simulator.simulate(image));
|
results.emplace_back(simulator.simulate(image));
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK_GT(results.size(), 0) << "Should have some results" << endl;
|
CHECK_GT(results.size(), 0) << "Should have some results" << endl;
|
||||||
|
RenderingState::instance().loadSimulationData(simulator.layerInfo(), std::move(results));
|
||||||
|
|
||||||
if (dumper) {
|
if (dumper) {
|
||||||
for (auto &layer : *results.begin()) {
|
for (auto &layer : *results.begin()) {
|
||||||
@@ -60,118 +48,6 @@ static void loadSimulationData(const Options &options)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void renderLayerName(const LayerData &data);
|
|
||||||
|
|
||||||
static void renderDebugInfo()
|
|
||||||
{
|
|
||||||
glLoadIdentity();
|
|
||||||
setOrthographicProjection();
|
|
||||||
glColor3f(1, 1, 0);
|
|
||||||
renderText(RenderingState::instance().infoLine(), 2, 10);
|
|
||||||
restorePerspectiveProjection();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void render()
|
|
||||||
{
|
|
||||||
// Clear Color and Depth Buffers
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
||||||
|
|
||||||
auto& camera = RenderingState::instance();
|
|
||||||
|
|
||||||
camera.configureRenderingContext();
|
|
||||||
|
|
||||||
const auto& dataSet = *rendererData.currentData;
|
|
||||||
|
|
||||||
glPushMatrix();
|
|
||||||
glTranslatef(5 * dataSet.size(), 0, 0);
|
|
||||||
|
|
||||||
for (auto i : Range(dataSet.size())) {
|
|
||||||
glPushMatrix();
|
|
||||||
renderLayerName(dataSet[i]);
|
|
||||||
rendererData.layerVisualisations[i]->render();
|
|
||||||
if (i < rendererData.animations.size() && rendererData.animations[i]) {
|
|
||||||
rendererData.animations[i]->draw(rendererData.animationStep);
|
|
||||||
}
|
|
||||||
|
|
||||||
glPopMatrix();
|
|
||||||
glTranslatef(LAYER_X_OFFSET, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
glPopMatrix();
|
|
||||||
|
|
||||||
renderDebugInfo();
|
|
||||||
|
|
||||||
glutSwapBuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void renderLayerName(const LayerData &data)
|
|
||||||
{
|
|
||||||
// Draw the name of the layer for reference.
|
|
||||||
glColor3f(0.5, 0.5, 0.5);
|
|
||||||
auto layerName = data.name();
|
|
||||||
layerName += ": ";
|
|
||||||
layerName += LayerInfo::nameByType(rendererData.layerInfo.at(data.name()).type());
|
|
||||||
renderText(layerName);
|
|
||||||
|
|
||||||
glTranslatef(0, 0, -10);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void updateVisualisers()
|
|
||||||
{
|
|
||||||
rendererData.layerVisualisations.clear();
|
|
||||||
rendererData.animations.clear();
|
|
||||||
LayerData* prevState = nullptr;
|
|
||||||
LayerVisualisation* prevVisualisation = nullptr;
|
|
||||||
|
|
||||||
for (LayerData &layer : *rendererData.currentData) {
|
|
||||||
LayerVisualisation* visualisation = getVisualisationForLayer(layer, rendererData.layerInfo.at(layer.name()));
|
|
||||||
if (prevState && prevVisualisation && visualisation) {
|
|
||||||
auto interaction = getActivityAnimation(*prevState, layer, rendererData.layerInfo.at(layer.name()), prevVisualisation->nodePositions(), visualisation->nodePositions());
|
|
||||||
rendererData.animations.emplace_back(interaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
rendererData.layerVisualisations.emplace_back(visualisation);
|
|
||||||
|
|
||||||
prevVisualisation = visualisation;
|
|
||||||
prevState = &layer;
|
|
||||||
}
|
|
||||||
|
|
||||||
glutPostRedisplay();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void specialKeyFunc(int key, int, int)
|
|
||||||
{
|
|
||||||
switch (key) {
|
|
||||||
case GLUT_KEY_LEFT:
|
|
||||||
if (rendererData.currentData == rendererData.data.begin()) {
|
|
||||||
rendererData.currentData = rendererData.data.end();
|
|
||||||
}
|
|
||||||
--rendererData.currentData;
|
|
||||||
updateVisualisers();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case GLUT_KEY_RIGHT:
|
|
||||||
++rendererData.currentData;
|
|
||||||
if (rendererData.currentData == rendererData.data.end()) {
|
|
||||||
rendererData.currentData = rendererData.data.begin();
|
|
||||||
}
|
|
||||||
updateVisualisers();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
LOG(INFO) << "Received keystroke " << key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void idleFunc()
|
|
||||||
{
|
|
||||||
checkGLErrors();
|
|
||||||
glutPostRedisplay();
|
|
||||||
throttleIdleFunc();
|
|
||||||
rendererData.animationStep = (1 - cos(M_PI * getAnimationStep(std::chrono::seconds(5)))) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
google::InitGoogleLogging(argv[0]);
|
google::InitGoogleLogging(argv[0]);
|
||||||
@@ -183,20 +59,13 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
// Prepare data for simulations
|
// Prepare data for simulations
|
||||||
Options options = Options::parse(argc, argv);
|
Options options = Options::parse(argc, argv);
|
||||||
rendererData.labels = options.labels();
|
|
||||||
loadSimulationData(options);
|
loadSimulationData(options);
|
||||||
|
|
||||||
// Register callbacks
|
// Register callbacks
|
||||||
glutDisplayFunc(render);
|
|
||||||
glutIdleFunc(idleFunc);
|
|
||||||
glutReshapeFunc(changeWindowSize);
|
glutReshapeFunc(changeWindowSize);
|
||||||
glutSpecialFunc(specialKeyFunc);
|
|
||||||
|
|
||||||
RenderingState::instance().registerControls();
|
RenderingState::instance().registerControls();
|
||||||
|
|
||||||
rendererData.currentData = rendererData.data.begin();
|
|
||||||
updateVisualisers();
|
|
||||||
|
|
||||||
// Enable depth test to fix objects behind you
|
// Enable depth test to fix objects behind you
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user