diff --git a/src/MultiImageVisualisation.cpp b/src/MultiImageVisualisation.cpp index 0d6e9fb..fb84795 100644 --- a/src/MultiImageVisualisation.cpp +++ b/src/MultiImageVisualisation.cpp @@ -19,19 +19,16 @@ MultiImageVisualisation::MultiImageVisualisation(const fmri::LayerData &layer) CHECK_EQ(1, images) << "Only single input image is supported" << endl; nodePositions_.resize(channels * 3); - auto dataPtr = layer.data(); const int columns = numCols(channels); - textureReferences.resize(channels); + texture = loadTexture(layer.data(), width, channels * height, channels); for (auto i : Range(channels)) { - textureReferences[i] = loadTexture(dataPtr, width, height); - dataPtr += width * height; - nodePositions_[3 * i + 0] = 0; nodePositions_[3 * i + 1] = 3 * (i / columns); nodePositions_[3 * i + 2] = -3 * (i % columns); } vertexBuffer = std::make_unique(channels * BASE_VERTICES.size()); + texCoordBuffer = std::make_unique(channels * 2u * BASE_VERTICES.size() / 3); auto v = 0; @@ -40,35 +37,33 @@ MultiImageVisualisation::MultiImageVisualisation(const fmri::LayerData &layer) for (auto j : Range(BASE_VERTICES.size())) { vertexBuffer[v++] = nodePos[j % 3] + BASE_VERTICES[j]; } + + const float textureCoords[] = { + 1, (i + 1) / (float) channels, + 1, i / (float) channels, + 0, i / (float) channels, + 0, (i + 1) / (float) channels, + }; + + memcpy(texCoordBuffer.get() + 8 * i, textureCoords, sizeof(textureCoords)); } } MultiImageVisualisation::~MultiImageVisualisation() { - for (auto entry : textureReferences) { - glDeleteTextures(0, &entry); - } + glDeleteTextures(0, &texture); } void MultiImageVisualisation::render() { - static const float textureCoords[] = { - 1, 1, - 1, 0, - 0, 0, - 0, 1, - }; - glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glEnable(GL_TEXTURE_2D); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - for (auto i : Range(textureReferences.size())) { - glBindTexture(GL_TEXTURE_2D, textureReferences[i]); - glTexCoordPointer(2, GL_FLOAT, 0, textureCoords); - glVertexPointer(3, GL_FLOAT, 0, vertexBuffer.get() + i * BASE_VERTICES.size()); - glDrawArrays(GL_QUADS, 0, 4); - } + glBindTexture(GL_TEXTURE_2D, texture); + glTexCoordPointer(2, GL_FLOAT, 0, texCoordBuffer.get()); + glVertexPointer(3, GL_FLOAT, 0, vertexBuffer.get()); + glDrawArrays(GL_QUADS, 0, nodePositions_.size() / 3 * 4); glDisable(GL_TEXTURE_2D); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); diff --git a/src/MultiImageVisualisation.hpp b/src/MultiImageVisualisation.hpp index 70eb7d1..6ebf0dd 100644 --- a/src/MultiImageVisualisation.hpp +++ b/src/MultiImageVisualisation.hpp @@ -23,7 +23,8 @@ namespace fmri 0, 1, 1, 0, -1, 1, }; - std::vector textureReferences; + GLuint texture; std::unique_ptr vertexBuffer; + std::unique_ptr texCoordBuffer; }; } diff --git a/src/glutils.cpp b/src/glutils.cpp index 7ad62d5..d86e3e5 100644 --- a/src/glutils.cpp +++ b/src/glutils.cpp @@ -7,6 +7,7 @@ #include #include #include "glutils.hpp" +#include "Range.hpp" using namespace fmri; using namespace std; @@ -21,11 +22,21 @@ static void handleGLError(GLenum error) { } } -GLuint fmri::loadTexture(DType const *data, int width, int height) +static void rescaleSubImages(vector& textureBuffer, int subImages) { + auto cur = textureBuffer.begin(); + const auto increment = textureBuffer.size() / subImages; + + while (cur != textureBuffer.end()) { + rescale(cur, cur + increment, 0, 1); + advance(cur, increment); + } +} + +GLuint fmri::loadTexture(DType const *data, int width, int height, int subImages) { // Load and scale texture vector textureBuffer(data, data + (width * height)); - rescale(textureBuffer.begin(), textureBuffer.end(), 0, 1); + rescaleSubImages(textureBuffer, subImages); const float color[] = {1, 1, 1}; // Background color for textures. GLuint texture; diff --git a/src/glutils.hpp b/src/glutils.hpp index fa28a00..a42e29a 100644 --- a/src/glutils.hpp +++ b/src/glutils.hpp @@ -12,9 +12,10 @@ namespace fmri { * @param data * @param width * @param height + * @param subImages Number of subimages in the original image. Sub images are rescaled individually to preserve contrast. Optional, default 1. * @return A texture reference. */ - GLuint loadTexture(DType const * data, int width, int height); + GLuint loadTexture(DType const *data, int width, int height, int subImages = 1); /** * Callback handler to handle resizing windows.