Work on OpenGL rendering environment.

This commit is contained in:
2017-10-19 15:39:15 +02:00
parent 289b6dce63
commit 501a59d00b
6 changed files with 270 additions and 23 deletions

View File

@@ -48,3 +48,13 @@ target_link_libraries(fmri ${png++_LIBRARIES})
find_package(GLUT REQUIRED)
include_directories(${GLUT_INCLUDE_DIRS})
target_link_libraries(fmri ${GLUT_LIBRARIES})
# Require OpenGL (visualisation)
find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIRS})
target_link_libraries(fmri ${OPENGL_LIBRARIES})
# Require GLEW (visulalisation)
find_package(GLEW REQUIRED)
include_directories(${GLEW_INCLUDE_DIRS})
target_link_libraries(fmri ${GLEW_LIBRARIES})

104
src/glutils.cpp Normal file
View File

@@ -0,0 +1,104 @@
#include <cstdint>
#include <memory>
#include <vector>
#include <GL/glew.h>
#include <cstring>
#include <glog/logging.h>
#include "glutils.hpp"
using namespace fmri;
using namespace std;
/**
* Utility function to send OpenGL info dumps to the log
*
* @param object The GLObject to get info for
* @param glGet__iv The function to query log length with
* @param glGet__InfoLog The function to get the log with
*/
static void show_info_log(
GLuint object,
PFNGLGETSHADERIVPROC glGet__iv,
PFNGLGETSHADERINFOLOGPROC glGet__InfoLog
)
{
GLint log_length;
glGet__iv(object, GL_INFO_LOG_LENGTH, &log_length);
unique_ptr<char[]> log(new char[log_length]);
glGet__InfoLog(object, log_length, nullptr, log.get());
LOG(INFO) << log.get() << endl;
}
GLuint fmri::loadTexture(DType const *data, unsigned int width, unsigned int height)
{
// Load and scale texture
vector<DType> textureBuffer(data, data + (width * height));
rescale(textureBuffer.begin(), textureBuffer.end(), 0, 1);
const float color[] = {0, 0, 0}; // Background color for textures.
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// Set up (lack of) repetition
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
static_assert(sizeof(DType) == 4); // verify data type for texture.
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 2, 2, 0, GL_R32F, GL_FLOAT, textureBuffer.data());
// Set up texture scaling
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Use mipmapping for scaling down
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // Use nearest pixel when scaling up.
glGenerateMipmap(GL_TEXTURE_2D);
return texture;
}
void fmri::changeWindowSize(int w, int h)
{
// Prevent a divide by zero, when window is too short
// (you cant make a window of zero width).
if (h == 0)
h = 1;
float ratio = w * 1.0f / h;
// Use the Projection Matrix
glMatrixMode(GL_PROJECTION);
// Reset Matrix
glLoadIdentity();
// Set the viewport to be the entire window
glViewport(0, 0, w, h);
// Set the correct perspective.
gluPerspective(45.0f, ratio, 0.1f, 100.0f);
// Get Back to the Modelview
glMatrixMode(GL_MODELVIEW);
}
GLuint fmri::compileShader(GLenum type, char const *source)
{
GLuint shader = glCreateShader(type);
auto length = static_cast<GLint>(strlen(source));
GLint compileOK;
glShaderSource(shader, 1, &source, &length);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileOK);
if (!compileOK) {
LOG(WARNING) << "Failed to compile " << source << endl;
show_info_log(shader, glGetShaderiv, glGetShaderInfoLog);
glDeleteShader(shader);
abort();
}
}

36
src/glutils.hpp Normal file
View File

@@ -0,0 +1,36 @@
#pragma once
#include "LayerData.hpp"
#include "utils.hpp"
#include <GL/glut.h>
namespace fmri {
/**
* Create a texture from an array of data.
*
* @param data
* @param width
* @param height
* @return A texture reference.
*/
GLuint loadTexture(DType const * data, unsigned int width, unsigned int height);
/**
*
* @param type
* @param source
* @return
*/
GLuint compileShader(GLenum type, char const * source);
/**
* Callback handler to handle resizing windows.
*
* This function resizes the rendering viewport so everything still
* looks proportional.
*
* @param w new Width
* @param h new Height.
*/
void changeWindowSize(int w, int h);
}

View File

@@ -1,44 +1,135 @@
#include <algorithm>
#include <iostream>
#include <glog/logging.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include <map>
#include <tuple>
#include "LayerData.hpp"
#include "Options.hpp"
#include "Simulator.hpp"
#include "glutils.hpp"
using namespace std;
using namespace fmri;
int main(int argc, char *const argv[]) {
google::InitGoogleLogging(argv[0]);
struct {
optional<vector<string>> labels;
vector<vector<LayerData>> data;
float angle = 0;
map<tuple<string, int, int>, GLuint> textureMap;
} rendererData;
Options options = Options::parse(argc, argv);
auto labels = options.labels();
static vector<vector<LayerData>> getSimulationData(const Options& options)
{
vector<vector<LayerData>> results;
auto dumper = options.imageDumper();
Simulator simulator(options.model(), options.weights(), options.means());
for (const auto &image : options.inputs()) {
const auto res = simulator.simulate(image);
LOG(INFO) << "Result for " << image << ":" << endl;
for (const auto& image : options.inputs()) {
results.emplace_back(simulator.simulate(image));
}
const auto& resultRow = res[res.size() - 1];
if (labels) {
vector<DType> weights(resultRow.data(), resultRow.data() + resultRow.numEntries());
auto scores = combine(weights, *labels);
sort(scores.begin(), scores.end(), greater<>());
for (unsigned int i = 0; i < scores.size() && i < 5; ++i) {
LOG(INFO) << scores[i].first << " " << scores[i].second << endl;
}
} else {
LOG(INFO) << "Best result: " << *(resultRow.data(), resultRow.data() + resultRow.numEntries()) << endl;
}
CHECK_GT(results.size(), 0) << "Should have some results" << endl;
if (dumper) {
for (const auto& layer : res) {
dumper->dump(layer);
if (dumper) {
for (auto& layer : *results.begin()) {
dumper->dump(layer);
}
}
return results;
}
static void render()
{
// Clear Color and Depth Buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset transformations
glLoadIdentity();
// Set the camera
gluLookAt( 0.0f, 0.0f, 10.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);
glRotatef(rendererData.angle, 0.0f, 1.0f, 0.0f);
glBegin(GL_TRIANGLES);
glVertex3f(-2.0f,-2.0f, 0.0f);
glVertex3f( 2.0f, 0.0f, 0.0);
glVertex3f( 0.0f, 2.0f, 0.0);
glEnd();
rendererData.angle+=0.1f;
glutSwapBuffers();
}
static void reloadTextures(unsigned dataIndex)
{
// First, release any existing textures
for (auto& entry : rendererData.textureMap) {
glDeleteTextures(0, &entry.second);
}
rendererData.textureMap.clear();
const auto& dataSet = rendererData.data[dataIndex];
for (auto& layer : dataSet) {
auto dimensions = layer.shape();
if (dimensions.size() != 4) {
continue;
}
const auto images = dimensions[0],
channels = dimensions[1],
width = dimensions[2],
height = dimensions[3];
auto dataPtr = layer.data();
for (auto i = 0; i < images; ++i) {
for (auto j = 0; j < channels; ++j) {
rendererData.textureMap[make_tuple(layer.name(), i, j)] = loadTexture(dataPtr, width, height);
dataPtr += width * height;
}
}
}
}
}
int main(int argc, char * argv[]) {
google::InitGoogleLogging(argv[0]);
google::InstallFailureSignalHandler();
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutCreateWindow(argv[0]);
// Prepare data for simulations
Options options = Options::parse(argc, argv);
rendererData.labels = options.labels();
rendererData.data = getSimulationData(options);
// Register callbacks
glutDisplayFunc(render);
glutIdleFunc(render);
glutReshapeFunc(changeWindowSize);
glewInit();
if (!GLEW_VERSION_2_0) {
cerr << "OpenGL 2.0 not available" << endl;
return 2;
}
reloadTextures(0);
// Start visualisation
glutMainLoop();
google::ShutdownGoogleLogging();

1
src/shaders.cpp Normal file
View File

@@ -0,0 +1 @@
#include "shaders.hpp"

5
src/shaders.hpp Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
#include <GL/glut.h>
extern const char * GRAYSCALE_TEXTURE_SHADER;