diff Framework/Scene2D/Internals/OpenGLFloatTextureProgram.cpp @ 591:b66ced2c43d4

OpenGLTextureProgram
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 26 Apr 2019 12:05:38 +0200
parents
children bbe29efd3d1c
line wrap: on
line diff
--- /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();
+    }
+  }
+}