changeset 591:b66ced2c43d4

OpenGLTextureProgram
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 26 Apr 2019 12:05:38 +0200
parents 5430bcffba57
children bbe29efd3d1c
files Framework/OpenGL/TextOpenGLProgram.cpp Framework/OpenGL/TextOpenGLProgram.h Framework/Scene2D/Internals/ColorTextureOpenGLProgram.cpp Framework/Scene2D/Internals/ColorTextureOpenGLProgram.h Framework/Scene2D/Internals/OpenGLColorTextureProgram.cpp Framework/Scene2D/Internals/OpenGLColorTextureProgram.h Framework/Scene2D/Internals/OpenGLFloatTextureProgram.cpp Framework/Scene2D/Internals/OpenGLFloatTextureProgram.h Framework/Scene2D/Internals/OpenGLTextureProgram.cpp Framework/Scene2D/Internals/OpenGLTextureProgram.h Resources/CMake/OrthancStoneConfiguration.cmake
diffstat 11 files changed, 527 insertions(+), 507 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/OpenGL/TextOpenGLProgram.cpp	Fri Apr 26 11:33:57 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,185 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "TextOpenGLProgram.h"
-
-#include "../Fonts/OpenGLTextCoordinates.h"
-
-#include <Core/OrthancException.h>
-
-
-namespace OrthancStone
-{
-  namespace OpenGL
-  {
-    TextOpenGLProgram::TextOpenGLProgram(IOpenGLContext&  context) :
-      context_(context)
-    {
-      static const char* VERTEX_SHADER = 
-        "attribute vec2 a_texcoord;    \n"
-        "attribute vec4 a_position;    \n"
-        "uniform mat4 u_matrix;        \n"
-        "varying vec2 v_texcoord;      \n"
-        "void main()                   \n"
-        "{                             \n"
-        "  gl_Position = u_matrix * a_position; \n"
-        "  v_texcoord = a_texcoord;             \n"
-        "}";
-
-      static const char* FRAGMENT_SHADER = 
-        "uniform sampler2D u_texture;  \n"
-        "uniform vec3 u_color;         \n"
-        "varying vec2 v_texcoord;      \n"
-        "void main()                   \n"
-        "{                             \n"
-        "  vec4 v = texture2D(u_texture, v_texcoord);  \n"
-        "  gl_FragColor = vec4(u_color * v.w, v.w);    \n"   // Premultiplied alpha
-        "}";
-
-      context_.MakeCurrent();
-
-      program_.reset(new OpenGLProgram);
-      program_->CompileShaders(VERTEX_SHADER, FRAGMENT_SHADER);
-
-      positionLocation_ = program_->GetAttributeLocation("a_position");
-      textureLocation_ = program_->GetAttributeLocation("a_texcoord");
-    }
-
-
-    TextOpenGLProgram::Data::Data(IOpenGLContext& context,
-                                  const GlyphTextureAlphabet& alphabet,
-                                  const TextSceneLayer& layer) :
-      context_(context),
-      red_(layer.GetRedAsFloat()),
-      green_(layer.GetGreenAsFloat()),
-      blue_(layer.GetBlueAsFloat()),
-      x_(layer.GetX()),
-      y_(layer.GetY()),
-      border_(layer.GetBorder()),
-      anchor_(layer.GetAnchor())
-    {
-      OpenGLTextCoordinates coordinates(alphabet, layer.GetText());
-      textWidth_ = coordinates.GetTextWidth();
-      textHeight_ = coordinates.GetTextHeight();
-
-      if (coordinates.IsEmpty())
-      {
-        coordinatesCount_ = 0;
-      }
-      else
-      {
-        coordinatesCount_ = coordinates.GetRenderingCoords().size();
-
-        context_.MakeCurrent();
-        glGenBuffers(2, buffers_);
-
-        glBindBuffer(GL_ARRAY_BUFFER, buffers_[0]);
-        glBufferData(GL_ARRAY_BUFFER, sizeof(float) * coordinatesCount_,
-                     &coordinates.GetRenderingCoords() [0], GL_STATIC_DRAW);
-
-        glBindBuffer(GL_ARRAY_BUFFER, buffers_[1]);
-        glBufferData(GL_ARRAY_BUFFER, sizeof(float) * coordinatesCount_,
-                     &coordinates.GetTextureCoords() [0], GL_STATIC_DRAW);
-      }
-    }
-        
-
-    TextOpenGLProgram::Data::~Data()
-    {
-      if (!IsEmpty())
-      {
-        context_.MakeCurrent();
-        glDeleteBuffers(2, buffers_);
-      }
-    }
-
-
-    GLuint TextOpenGLProgram::Data::GetSceneLocationsBuffer() const
-    {
-      if (IsEmpty())
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-      else
-      {
-        return buffers_[0];
-      }
-    }
-
-
-    GLuint TextOpenGLProgram::Data::GetTextureLocationsBuffer() const
-    {
-      if (IsEmpty())
-      {
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
-      }
-      else
-      {
-        return buffers_[1];
-      }
-    }
-
-
-    void TextOpenGLProgram::Apply(OpenGLTexture& fontTexture,
-                                  const Data& data,
-                                  const AffineTransform2D& transform)
-    {
-      if (!data.IsEmpty())
-      {
-        context_.MakeCurrent();
-        program_->Use();
-
-        double dx, dy;  // In pixels
-        ComputeAnchorTranslation(dx, dy, data.GetAnchor(), data.GetTextWidth(), data.GetTextHeight(), data.GetBorder());
-      
-        double x = data.GetX();
-        double y = data.GetY();
-        transform.Apply(x, y);
-
-        const AffineTransform2D t = AffineTransform2D::CreateOffset(x + dx, y + dy);
-
-        float m[16];
-        t.ConvertToOpenGLMatrix(m, context_.GetCanvasWidth(), context_.GetCanvasHeight());
-
-        fontTexture.Bind(program_->GetUniformLocation("u_texture"));
-        glUniformMatrix4fv(program_->GetUniformLocation("u_matrix"), 1, GL_FALSE, m);
-        glUniform3f(program_->GetUniformLocation("u_color"), 
-                    data.GetRed(), data.GetGreen(), data.GetBlue());
-
-        glBindBuffer(GL_ARRAY_BUFFER, data.GetSceneLocationsBuffer());
-        glEnableVertexAttribArray(positionLocation_);
-        glVertexAttribPointer(positionLocation_, COMPONENTS, GL_FLOAT, GL_FALSE, 0, 0);
-
-        glBindBuffer(GL_ARRAY_BUFFER, data.GetTextureLocationsBuffer());
-        glEnableVertexAttribArray(textureLocation_);
-        glVertexAttribPointer(textureLocation_, COMPONENTS, GL_FLOAT, GL_FALSE, 0, 0);
-
-        glEnable(GL_BLEND);
-        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-        glDrawArrays(GL_TRIANGLES, 0, data.GetCoordinatesCount() / COMPONENTS);
-        glDisable(GL_BLEND);
-
-        glDisableVertexAttribArray(positionLocation_);
-        glDisableVertexAttribArray(textureLocation_);
-      }
-    }
-  }
-}
--- a/Framework/OpenGL/TextOpenGLProgram.h	Fri Apr 26 11:33:57 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,138 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "IOpenGLContext.h"
-#include "OpenGLProgram.h"
-#include "OpenGLTexture.h"
-
-#include "../Fonts/GlyphTextureAlphabet.h"
-#include "../Scene2D/TextSceneLayer.h"
-#include "../Toolbox/AffineTransform2D.h"
-
-namespace OrthancStone
-{
-  namespace OpenGL
-  {
-    class TextOpenGLProgram : public boost::noncopyable
-    {
-    public:
-      class Data : public boost::noncopyable
-      {
-      private:
-        IOpenGLContext&  context_;
-        size_t           coordinatesCount_;
-        GLuint           buffers_[2];
-        float            red_;
-        float            green_;
-        float            blue_;
-        double           x_;
-        double           y_;
-        double           border_;
-        unsigned int     textWidth_;
-        unsigned int     textHeight_;
-        BitmapAnchor     anchor_;
-
-      public:
-        Data(IOpenGLContext& context,
-             const GlyphTextureAlphabet& alphabet,
-             const TextSceneLayer& layer);
-
-        ~Data();
-        
-        bool IsEmpty() const
-        {
-          return coordinatesCount_ == 0;
-        }
-
-        size_t GetCoordinatesCount() const
-        {
-          return coordinatesCount_;
-        }
-
-        GLuint GetSceneLocationsBuffer() const;
-
-        GLuint GetTextureLocationsBuffer() const;
-
-        float GetRed() const
-        {
-          return red_;
-        }
-
-        float GetGreen() const
-        {
-          return green_;
-        }
-
-        float GetBlue() const
-        {
-          return blue_;
-        }
-
-        double GetX() const
-        {
-          return x_;
-        }
-
-        double GetY() const
-        {
-          return y_;
-        }
-
-        double GetBorder() const
-        {
-          return border_;
-        }
-
-        unsigned int GetTextWidth() const
-        {
-          return textWidth_;
-        }
-
-        unsigned int GetTextHeight() const
-        {
-          return textHeight_;
-        }
-
-        BitmapAnchor GetAnchor() const
-        {
-          return anchor_;
-        }
-      };
-      
-    private:
-      static const unsigned int COMPONENTS = 2;
-
-      IOpenGLContext&               context_;
-      std::auto_ptr<OpenGLProgram>  program_;
-      GLint                         positionLocation_;
-      GLint                         textureLocation_;
-
-    public:
-      TextOpenGLProgram(IOpenGLContext&  context);
-
-      void Apply(OpenGLTexture& fontTexture,
-                 const Data& data,
-                 const AffineTransform2D& transform);
-    };
-  }
-}
--- a/Framework/Scene2D/Internals/ColorTextureOpenGLProgram.cpp	Fri Apr 26 11:33:57 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "ColorTextureOpenGLProgram.h"
-
-namespace OrthancStone
-{
-  namespace Internals
-  {
-    ColorTextureOpenGLProgram::ColorTextureOpenGLProgram(OpenGL::IOpenGLContext&  context) :
-      context_(context)
-    {
-      static const char* VERTEX_SHADER = 
-        "attribute vec2 a_texcoord;    \n"
-        "attribute vec4 a_position;    \n"
-        "uniform mat4 u_matrix;        \n"
-        "varying vec2 v_texcoord;      \n"
-        "void main()                   \n"
-        "{                             \n"
-        "  gl_Position = u_matrix * a_position; \n"
-        "  v_texcoord = a_texcoord;             \n"
-        "}";
-
-      static const char* FRAGMENT_SHADER = 
-        "uniform sampler2D u_texture;  \n"
-        "varying vec2 v_texcoord;      \n"
-        "void main()                   \n"
-        "{                             \n"
-        "  gl_FragColor = texture2D(u_texture, v_texcoord); \n"
-        "}";
-
-      static const float POSITIONS[COMPONENTS * COUNT] = {
-        0, 0,
-        0, 1,
-        1, 0,
-        1, 0,
-        0, 1,
-        1, 1
-      };
-        
-      context_.MakeCurrent();
-
-      program_.reset(new OpenGL::OpenGLProgram);
-      program_->CompileShaders(VERTEX_SHADER, FRAGMENT_SHADER);
-
-      positionLocation_ = program_->GetAttributeLocation("a_position");
-      textureLocation_ = program_->GetAttributeLocation("a_texcoord");
-
-      glGenBuffers(2, buffers_);
-
-      glBindBuffer(GL_ARRAY_BUFFER, buffers_[0]);
-      glBufferData(GL_ARRAY_BUFFER, sizeof(float) * COMPONENTS * COUNT, POSITIONS, GL_STATIC_DRAW);
-
-      glBindBuffer(GL_ARRAY_BUFFER, buffers_[1]);
-      glBufferData(GL_ARRAY_BUFFER, sizeof(float) * COMPONENTS * COUNT, POSITIONS, GL_STATIC_DRAW);
-    }
-
-      
-    ColorTextureOpenGLProgram::~ColorTextureOpenGLProgram()
-    {
-      context_.MakeCurrent();
-      glDeleteBuffers(2, buffers_);
-    }
-
-    
-    void ColorTextureOpenGLProgram::Apply(OpenGL::OpenGLTexture& texture,
-                                          const AffineTransform2D& transform,
-                                          bool useAlpha)
-    {
-      context_.MakeCurrent();
-      program_->Use();
-
-      AffineTransform2D scale = AffineTransform2D::CreateScaling
-        (texture.GetWidth(), texture.GetHeight());
-
-      AffineTransform2D t = AffineTransform2D::Combine(transform, scale);
-
-      float m[16];
-      t.ConvertToOpenGLMatrix(m, context_.GetCanvasWidth(), context_.GetCanvasHeight());
-
-      texture.Bind(program_->GetUniformLocation("u_texture"));
-      glUniformMatrix4fv(program_->GetUniformLocation("u_matrix"), 1, GL_FALSE, m);
-
-      glBindBuffer(GL_ARRAY_BUFFER, buffers_[0]);
-      glEnableVertexAttribArray(positionLocation_);
-      glVertexAttribPointer(positionLocation_, COMPONENTS, GL_FLOAT, GL_FALSE, 0, 0);
-
-      glBindBuffer(GL_ARRAY_BUFFER, buffers_[1]);
-      glEnableVertexAttribArray(textureLocation_);
-      glVertexAttribPointer(textureLocation_, COMPONENTS, GL_FLOAT, GL_FALSE, 0, 0);
-
-      if (useAlpha)
-      {
-        glEnable(GL_BLEND);
-        //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-        glDrawArrays(GL_TRIANGLES, 0, COUNT);
-        glDisable(GL_BLEND);
-      }
-      else
-      {
-        glDrawArrays(GL_TRIANGLES, 0, COUNT);
-      }
-
-      glDisableVertexAttribArray(positionLocation_);
-      glDisableVertexAttribArray(textureLocation_);
-    }
-  }
-}
--- a/Framework/Scene2D/Internals/ColorTextureOpenGLProgram.h	Fri Apr 26 11:33:57 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/**
- * Stone of Orthanc
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- * Copyright (C) 2017-2019 Osimis S.A., Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU Affero General Public License
- * as published by the Free Software Foundation, either version 3 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Affero General Public License for more details.
- * 
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#pragma once
-
-#include "../../OpenGL/IOpenGLContext.h"
-#include "../../OpenGL/OpenGLProgram.h"
-#include "../../OpenGL/OpenGLTexture.h"
-#include "../../Toolbox/AffineTransform2D.h"
-
-namespace OrthancStone
-{
-  namespace Internals
-  {
-    class ColorTextureOpenGLProgram : public boost::noncopyable
-    {
-    private:
-      static const unsigned int COMPONENTS = 2;
-      static const unsigned int COUNT = 6;  // 2 triangles in 2D
-
-      OpenGL::IOpenGLContext&               context_;
-      std::auto_ptr<OpenGL::OpenGLProgram>  program_;
-      GLint                                 positionLocation_;
-      GLint                                 textureLocation_;
-      GLuint                                buffers_[2];
-
-    public:
-      ColorTextureOpenGLProgram(OpenGL::IOpenGLContext&  context);
-
-      ~ColorTextureOpenGLProgram();
-
-      void Apply(OpenGL::OpenGLTexture& texture,
-                 const AffineTransform2D& transform,
-                 bool useAlpha);
-    };
-  }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2D/Internals/OpenGLColorTextureProgram.cpp	Fri Apr 26 12:05:38 2019 +0200
@@ -0,0 +1,63 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "OpenGLColorTextureProgram.h"
+
+
+static const char* FRAGMENT_SHADER = 
+  "uniform sampler2D u_texture;                       \n"
+  "varying vec2 v_texcoord;                           \n"
+  "void main()                                        \n"
+  "{                                                  \n"
+  "  gl_FragColor = texture2D(u_texture, v_texcoord); \n"
+  "}";
+
+
+namespace OrthancStone
+{
+  namespace Internals
+  {
+    OpenGLColorTextureProgram::OpenGLColorTextureProgram(OpenGL::IOpenGLContext&  context) :
+      program_(context, FRAGMENT_SHADER)
+    {
+    }
+
+    
+    void OpenGLColorTextureProgram::Apply(OpenGL::OpenGLTexture& texture,
+                                          const AffineTransform2D& transform,
+                                          bool useAlpha)
+    {
+      OpenGLTextureProgram::Execution execution(program_, texture, transform);
+
+      if (useAlpha)
+      {
+        glEnable(GL_BLEND);
+        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+        execution.DrawTriangles();
+        glDisable(GL_BLEND);
+      }
+      else
+      {
+        execution.DrawTriangles();
+      }
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2D/Internals/OpenGLColorTextureProgram.h	Fri Apr 26 12:05:38 2019 +0200
@@ -0,0 +1,43 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "OpenGLTextureProgram.h"
+
+namespace OrthancStone
+{
+  namespace Internals
+  {
+    class OpenGLColorTextureProgram : public boost::noncopyable
+    {
+    private:
+      OpenGLTextureProgram  program_;
+
+    public:
+      OpenGLColorTextureProgram(OpenGL::IOpenGLContext&  context);
+
+      void Apply(OpenGL::OpenGLTexture& texture,
+                 const AffineTransform2D& transform,
+                 bool useAlpha);
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2D/Internals/OpenGLFloatTextureProgram.cpp	Fri Apr 26 12:05:38 2019 +0200
@@ -0,0 +1,146 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "OpenGLFloatTextureProgram.h"
+
+#include <Core/OrthancException.h>
+#include <Core/Images/Image.h>
+#include <Core/Images/ImageProcessing.h>
+
+
+static const char* FRAGMENT_SHADER = 
+  "uniform float u_offset;                       \n"
+  "uniform float u_slope;                        \n"
+  "uniform float u_windowCenter;                 \n"
+  "uniform float u_windowWidth;                  \n"
+  "uniform sampler2D u_texture;                  \n"
+  "varying vec2 v_texcoord;                      \n"
+  "void main()                                   \n"
+  "{                                             \n"
+  "  vec4 t = texture2D(u_texture, v_texcoord);  \n"
+  "  float v = (t.r * 256.0 + t.g) * 256.0;      \n"
+  "  v = v * u_slope + u_offset;                 \n"  // (*)
+  "  float a = u_windowCenter - u_windowWidth;   \n"
+  "  float dy = 1.0 / (2.0 * u_windowWidth);     \n"
+  "  if (v <= a)                                 \n"
+  "    v = 0.0;                                  \n"
+  "  else                                        \n"
+  "  {                                           \n"
+  "    v = (v - a) * dy;                         \n"
+  "    if (v >= 1.0)                             \n"
+  "      v = 1.0;                                \n"
+  "  }                                           \n"
+  "  gl_FragColor = vec4(v, v, v, 1);            \n"
+  "}";
+
+
+namespace OrthancStone
+{
+  namespace Internals
+  {
+    OpenGLFloatTextureProgram::OpenGLFloatTextureProgram(OpenGL::IOpenGLContext&  context) :
+      program_(context, FRAGMENT_SHADER)
+    {
+    }
+
+
+    OpenGLFloatTextureProgram::Data::Data(const Orthanc::ImageAccessor& texture,
+                                          bool isLinearInterpolation)
+    {
+      if (texture.GetFormat() != Orthanc::PixelFormat_Float32)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageFormat);
+      }
+
+      float minValue, maxValue;
+      Orthanc::ImageProcessing::GetMinMaxFloatValue(minValue, maxValue, texture);
+
+      offset_ = minValue;
+
+      if (LinearAlgebra::IsCloseToZero(maxValue - minValue))
+      {
+        slope_ = 1;
+      }
+      else
+      {
+        slope_ = (maxValue - minValue) / 65536.0f;
+        assert(!LinearAlgebra::IsCloseToZero(slope_));
+      }
+
+      const unsigned int width = texture.GetWidth();
+      const unsigned int height = texture.GetHeight();
+
+      Orthanc::Image converted(Orthanc::PixelFormat_RGB24, width, height, true);
+
+      for (unsigned int y = 0; y < height; y++)
+      {
+        const float *p = reinterpret_cast<const float*>(texture.GetConstRow(y));
+        uint8_t *q = reinterpret_cast<uint8_t*>(converted.GetRow(y));
+
+        for (unsigned int x = 0; x < width; x++)
+        {
+          /**
+           * At (*), the floating-point "value" is reconstructed as
+           * "value = texture * slope + offset".
+           * <=> texture = (value - offset) / slope
+           **/
+
+          float texture = (*p - offset_) / slope_;
+          if (texture < 0)
+          {
+            texture = 0;
+          }
+          else if (texture >= 65535.0f)
+          {
+            texture = 65535.0f;
+          }
+
+          uint16_t t = static_cast<uint16_t>(texture);
+
+          q[0] = t / 256;  // red
+          q[1] = t % 256;  // green
+          q[2] = 0;        // blue is unused
+
+          p++;
+          q += 3;
+        }
+      }
+
+      texture_.Load(converted, isLinearInterpolation);
+    }
+
+    
+    void OpenGLFloatTextureProgram::Apply(Data& data,
+                                          const AffineTransform2D& transform,
+                                          float windowCenter,
+                                          float windowWidth)
+    {
+      OpenGLTextureProgram::Execution execution(program_, data.GetTexture(), transform);
+
+      glUniform1f(execution.GetUniformLocation("u_slope"), data.GetSlope());
+      glUniform1f(execution.GetUniformLocation("u_offset"), data.GetOffset());
+      glUniform1f(execution.GetUniformLocation("u_windowCenter"), windowCenter);
+      glUniform1f(execution.GetUniformLocation("u_windowWidth"), windowWidth);
+
+      execution.DrawTriangles();
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2D/Internals/OpenGLFloatTextureProgram.h	Fri Apr 26 12:05:38 2019 +0200
@@ -0,0 +1,71 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "OpenGLTextureProgram.h"
+
+namespace OrthancStone
+{
+  namespace Internals
+  {
+    class OpenGLFloatTextureProgram : public boost::noncopyable
+    {
+    private:
+      OpenGLTextureProgram  program_;
+
+    public:
+      OpenGLFloatTextureProgram(OpenGL::IOpenGLContext&  context);
+
+      class Data : public boost::noncopyable
+      {
+      private:
+        OpenGL::OpenGLTexture  texture_;
+        float                  offset_;
+        float                  slope_;
+
+      public:
+        Data(const Orthanc::ImageAccessor& texture,
+             bool isLinearInterpolation);
+
+        float GetOffset() const
+        {
+          return offset_;
+        }
+
+        float GetSlope() const
+        {
+          return slope_;
+        }
+
+        OpenGL::OpenGLTexture& GetTexture()
+        {
+          return texture_;
+        }
+      };
+
+      void Apply(Data& data,
+                 const AffineTransform2D& transform,
+                 float windowCenter,
+                 float windowWidth);
+    };
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2D/Internals/OpenGLTextureProgram.cpp	Fri Apr 26 12:05:38 2019 +0200
@@ -0,0 +1,120 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "OpenGLTextureProgram.h"
+
+static const unsigned int COMPONENTS = 2;
+static const unsigned int COUNT = 6;  // 2 triangles in 2D
+
+static const char* VERTEX_SHADER = 
+  "attribute vec2 a_texcoord;             \n"
+  "attribute vec4 a_position;             \n"
+  "uniform mat4 u_matrix;                 \n"
+  "varying vec2 v_texcoord;               \n"
+  "void main()                            \n"
+  "{                                      \n"
+  "  gl_Position = u_matrix * a_position; \n"
+  "  v_texcoord = a_texcoord;             \n"
+  "}";
+
+
+namespace OrthancStone
+{
+  namespace Internals
+  {
+    void OpenGLTextureProgram::InitializeExecution(OpenGL::OpenGLTexture& texture,
+                                                   const AffineTransform2D& transform)
+    {
+      context_.MakeCurrent();
+      program_->Use();
+
+      AffineTransform2D scale = AffineTransform2D::CreateScaling
+        (texture.GetWidth(), texture.GetHeight());
+
+      AffineTransform2D t = AffineTransform2D::Combine(transform, scale);
+
+      float m[16];
+      t.ConvertToOpenGLMatrix(m, context_.GetCanvasWidth(), context_.GetCanvasHeight());
+
+      texture.Bind(program_->GetUniformLocation("u_texture"));
+      glUniformMatrix4fv(program_->GetUniformLocation("u_matrix"), 1, GL_FALSE, m);
+
+      glBindBuffer(GL_ARRAY_BUFFER, buffers_[0]);
+      glEnableVertexAttribArray(positionLocation_);
+      glVertexAttribPointer(positionLocation_, COMPONENTS, GL_FLOAT, GL_FALSE, 0, 0);
+
+      glBindBuffer(GL_ARRAY_BUFFER, buffers_[1]);
+      glEnableVertexAttribArray(textureLocation_);
+      glVertexAttribPointer(textureLocation_, COMPONENTS, GL_FLOAT, GL_FALSE, 0, 0);
+    }
+
+    
+    void OpenGLTextureProgram::FinalizeExecution()
+    {
+      glDisableVertexAttribArray(positionLocation_);
+      glDisableVertexAttribArray(textureLocation_);
+    }
+
+    
+    OpenGLTextureProgram::OpenGLTextureProgram(OpenGL::IOpenGLContext& context,
+                                               const char* fragmentShader) :
+      context_(context)
+    {
+      static const float POSITIONS[COMPONENTS * COUNT] = {
+        0, 0,
+        0, 1,
+        1, 0,
+        1, 0,
+        0, 1,
+        1, 1
+      };
+        
+      context_.MakeCurrent();
+
+      program_.reset(new OpenGL::OpenGLProgram);
+      program_->CompileShaders(VERTEX_SHADER, fragmentShader);
+
+      positionLocation_ = program_->GetAttributeLocation("a_position");
+      textureLocation_ = program_->GetAttributeLocation("a_texcoord");
+
+      glGenBuffers(2, buffers_);
+
+      glBindBuffer(GL_ARRAY_BUFFER, buffers_[0]);
+      glBufferData(GL_ARRAY_BUFFER, sizeof(float) * COMPONENTS * COUNT, POSITIONS, GL_STATIC_DRAW);
+
+      glBindBuffer(GL_ARRAY_BUFFER, buffers_[1]);
+      glBufferData(GL_ARRAY_BUFFER, sizeof(float) * COMPONENTS * COUNT, POSITIONS, GL_STATIC_DRAW);
+    }
+
+
+    OpenGLTextureProgram::~OpenGLTextureProgram()
+    {
+      context_.MakeCurrent();
+      glDeleteBuffers(2, buffers_);
+    }
+
+
+    void OpenGLTextureProgram::Execution::DrawTriangles()
+    {
+      glDrawArrays(GL_TRIANGLES, 0, COUNT);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Framework/Scene2D/Internals/OpenGLTextureProgram.h	Fri Apr 26 12:05:38 2019 +0200
@@ -0,0 +1,81 @@
+/**
+ * Stone of Orthanc
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ * Copyright (C) 2017-2019 Osimis S.A., Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Affero General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include "../../OpenGL/IOpenGLContext.h"
+#include "../../OpenGL/OpenGLProgram.h"
+#include "../../OpenGL/OpenGLTexture.h"
+#include "../../Toolbox/AffineTransform2D.h"
+
+namespace OrthancStone
+{
+  namespace Internals
+  {
+    class OpenGLTextureProgram : public boost::noncopyable
+    {
+    private:
+      OpenGL::IOpenGLContext&               context_;
+      std::auto_ptr<OpenGL::OpenGLProgram>  program_;
+      GLint                                 positionLocation_;
+      GLint                                 textureLocation_;
+      GLuint                                buffers_[2];
+
+      void InitializeExecution(OpenGL::OpenGLTexture& texture,
+                               const AffineTransform2D& transform);
+
+      void FinalizeExecution();
+
+    public:
+      OpenGLTextureProgram(OpenGL::IOpenGLContext& context,
+                           const char* fragmentShader);
+
+      ~OpenGLTextureProgram();
+
+      class Execution : public boost::noncopyable
+      {
+      private:
+        OpenGLTextureProgram&  that_;
+
+      public:
+        Execution(OpenGLTextureProgram& that,
+                  OpenGL::OpenGLTexture& texture,
+                  const AffineTransform2D& transform) :
+          that_(that)
+        {
+          that_.InitializeExecution(texture, transform);
+        }
+
+        ~Execution()
+        {
+          that_.FinalizeExecution();
+        }
+
+        void DrawTriangles();
+
+        GLint GetUniformLocation(const std::string& name)
+        {
+          return that_.program_->GetUniformLocation(name);
+        }
+      };
+    };
+  }
+}
--- a/Resources/CMake/OrthancStoneConfiguration.cmake	Fri Apr 26 11:33:57 2019 +0200
+++ b/Resources/CMake/OrthancStoneConfiguration.cmake	Fri Apr 26 12:05:38 2019 +0200
@@ -389,8 +389,9 @@
     ${ORTHANC_STONE_ROOT}/Framework/OpenGL/OpenGLProgram.cpp
     ${ORTHANC_STONE_ROOT}/Framework/OpenGL/OpenGLShader.cpp
     ${ORTHANC_STONE_ROOT}/Framework/OpenGL/OpenGLTexture.cpp
-    ${ORTHANC_STONE_ROOT}/Framework/OpenGL/TextOpenGLProgram.cpp
-    ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/ColorTextureOpenGLProgram.cpp
+    ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLFloatTextureProgram.cpp
+    ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLColorTextureProgram.cpp
+    ${ORTHANC_STONE_ROOT}/Framework/Scene2D/Internals/OpenGLTextureProgram.cpp
     )
 endif()