1 //============================================================================ 2 // Copyright (c) Kitware, Inc. 3 // All rights reserved. 4 // See LICENSE.txt for details. 5 // 6 // This software is distributed WITHOUT ANY WARRANTY; without even 7 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 8 // PURPOSE. See the above copyright notice for more information. 9 //============================================================================ 10 11 #ifndef vtk_m_rendering_Texture2D_h 12 #define vtk_m_rendering_Texture2D_h 13 14 #include <vtkm/cont/Algorithm.h> 15 #include <vtkm/cont/ArrayHandle.h> 16 #include <vtkm/cont/ExecutionObjectBase.h> 17 18 namespace vtkm 19 { 20 namespace rendering 21 { 22 23 enum class TextureFilterMode 24 { 25 NearestNeighbour, 26 Linear, 27 }; // enum TextureFilterMode 28 29 enum class TextureWrapMode 30 { 31 Clamp, 32 Repeat, 33 }; // enum TextureWrapMode 34 35 template <vtkm::IdComponent NumComponents> 36 class Texture2D 37 { 38 public: 39 using TextureDataHandle = typename vtkm::cont::ArrayHandle<vtkm::UInt8>; 40 using ColorType = vtkm::Vec<vtkm::Float32, NumComponents>; 41 42 class Texture2DSampler; 43 44 #define UV_BOUNDS_CHECK(u, v, NoneType) \ 45 if (u < 0.0f || u > 1.0f || v < 0.0f || v > 1.0f) \ 46 { \ 47 return NoneType(); \ 48 } 49 50 VTKM_CONT Texture2D()51 Texture2D() 52 : Width(0) 53 , Height(0) 54 { 55 } 56 57 VTKM_CONT Texture2D(vtkm::Id width,vtkm::Id height,const TextureDataHandle & data)58 Texture2D(vtkm::Id width, vtkm::Id height, const TextureDataHandle& data) 59 : Width(width) 60 , Height(height) 61 , FilterMode(TextureFilterMode::Linear) 62 , WrapMode(TextureWrapMode::Clamp) 63 { 64 VTKM_ASSERT(data.GetNumberOfValues() == (Width * Height * NumComponents)); 65 // We do not know the lifetime of the underlying data source of input `data`. Since it might 66 // be from a shallow copy of the data source, we make a deep copy of the input data and keep 67 // it's portal. The copy operation is very fast. 68 vtkm::cont::Algorithm::Copy(data, Data); 69 } 70 71 VTKM_CONT IsValid()72 bool IsValid() const { return Width > 0 && Height > 0; } 73 74 VTKM_CONT GetFilterMode()75 TextureFilterMode GetFilterMode() const { return this->FilterMode; } 76 77 VTKM_CONT SetFilterMode(TextureFilterMode filterMode)78 void SetFilterMode(TextureFilterMode filterMode) { this->FilterMode = filterMode; } 79 80 VTKM_CONT GetWrapMode()81 TextureWrapMode GetWrapMode() const { return this->WrapMode; } 82 83 VTKM_CONT SetWrapMode(TextureWrapMode wrapMode)84 void SetWrapMode(TextureWrapMode wrapMode) { this->WrapMode = wrapMode; } 85 GetExecObjectFactory()86 VTKM_CONT Texture2DSampler GetExecObjectFactory() const 87 { 88 return Texture2DSampler(Width, Height, Data, FilterMode, WrapMode); 89 } 90 91 template <typename Device> 92 class Texture2DSamplerExecutionObject 93 { 94 public: 95 using TextureExecPortal = typename TextureDataHandle::ReadPortalType; 96 97 VTKM_CONT Texture2DSamplerExecutionObject()98 Texture2DSamplerExecutionObject() 99 : Width(0) 100 , Height(0) 101 { 102 } 103 104 VTKM_CONT Texture2DSamplerExecutionObject(vtkm::Id width,vtkm::Id height,const TextureDataHandle & data,TextureFilterMode filterMode,TextureWrapMode wrapMode,vtkm::cont::Token & token)105 Texture2DSamplerExecutionObject(vtkm::Id width, 106 vtkm::Id height, 107 const TextureDataHandle& data, 108 TextureFilterMode filterMode, 109 TextureWrapMode wrapMode, 110 vtkm::cont::Token& token) 111 : Width(width) 112 , Height(height) 113 , Data(data.PrepareForInput(Device(), token)) 114 , FilterMode(filterMode) 115 , WrapMode(wrapMode) 116 { 117 } 118 119 VTKM_EXEC GetColor(vtkm::Float32 u,vtkm::Float32 v)120 inline ColorType GetColor(vtkm::Float32 u, vtkm::Float32 v) const 121 { 122 v = 1.0f - v; 123 UV_BOUNDS_CHECK(u, v, ColorType); 124 switch (FilterMode) 125 { 126 case TextureFilterMode::NearestNeighbour: 127 return GetNearestNeighbourFilteredColor(u, v); 128 129 case TextureFilterMode::Linear: 130 return GetLinearFilteredColor(u, v); 131 132 default: 133 return ColorType(); 134 } 135 } 136 137 private: 138 VTKM_EXEC GetNearestNeighbourFilteredColor(vtkm::Float32 u,vtkm::Float32 v)139 inline ColorType GetNearestNeighbourFilteredColor(vtkm::Float32 u, vtkm::Float32 v) const 140 { 141 vtkm::Id x = static_cast<vtkm::Id>(vtkm::Round(u * static_cast<vtkm::Float32>(Width - 1))); 142 vtkm::Id y = static_cast<vtkm::Id>(vtkm::Round(v * static_cast<vtkm::Float32>(Height - 1))); 143 return GetColorAtCoords(x, y); 144 } 145 146 VTKM_EXEC GetLinearFilteredColor(vtkm::Float32 u,vtkm::Float32 v)147 inline ColorType GetLinearFilteredColor(vtkm::Float32 u, vtkm::Float32 v) const 148 { 149 u = u * static_cast<vtkm::Float32>(Width) - 0.5f; 150 v = v * static_cast<vtkm::Float32>(Height) - 0.5f; 151 vtkm::Id x = static_cast<vtkm::Id>(vtkm::Floor(u)); 152 vtkm::Id y = static_cast<vtkm::Id>(vtkm::Floor(v)); 153 vtkm::Float32 uRatio = u - static_cast<vtkm::Float32>(x); 154 vtkm::Float32 vRatio = v - static_cast<vtkm::Float32>(y); 155 vtkm::Float32 uOpposite = 1.0f - uRatio; 156 vtkm::Float32 vOpposite = 1.0f - vRatio; 157 vtkm::Id xn, yn; 158 GetNextCoords(x, y, xn, yn); 159 ColorType c1 = GetColorAtCoords(x, y); 160 ColorType c2 = GetColorAtCoords(xn, y); 161 ColorType c3 = GetColorAtCoords(x, yn); 162 ColorType c4 = GetColorAtCoords(xn, yn); 163 return (c1 * uOpposite + c2 * uRatio) * vOpposite + (c3 * uOpposite + c4 * uRatio) * vRatio; 164 } 165 166 VTKM_EXEC GetColorAtCoords(vtkm::Id x,vtkm::Id y)167 inline ColorType GetColorAtCoords(vtkm::Id x, vtkm::Id y) const 168 { 169 vtkm::Id idx = (y * Width + x) * NumComponents; 170 ColorType color; 171 for (vtkm::IdComponent i = 0; i < NumComponents; ++i) 172 { 173 color[i] = Data.Get(idx + i) / 255.0f; 174 } 175 return color; 176 } 177 178 VTKM_EXEC GetNextCoords(vtkm::Id x,vtkm::Id y,vtkm::Id & xn,vtkm::Id & yn)179 inline void GetNextCoords(vtkm::Id x, vtkm::Id y, vtkm::Id& xn, vtkm::Id& yn) const 180 { 181 switch (WrapMode) 182 { 183 case TextureWrapMode::Clamp: 184 xn = (x + 1) < Width ? (x + 1) : x; 185 yn = (y + 1) < Height ? (y + 1) : y; 186 break; 187 case TextureWrapMode::Repeat: 188 default: 189 xn = (x + 1) % Width; 190 yn = (y + 1) % Height; 191 break; 192 } 193 } 194 195 vtkm::Id Width; 196 vtkm::Id Height; 197 TextureExecPortal Data; 198 TextureFilterMode FilterMode; 199 TextureWrapMode WrapMode; 200 }; 201 202 class Texture2DSampler : public vtkm::cont::ExecutionObjectBase 203 { 204 public: 205 VTKM_CONT Texture2DSampler()206 Texture2DSampler() 207 : Width(0) 208 , Height(0) 209 { 210 } 211 212 VTKM_CONT Texture2DSampler(vtkm::Id width,vtkm::Id height,const TextureDataHandle & data,TextureFilterMode filterMode,TextureWrapMode wrapMode)213 Texture2DSampler(vtkm::Id width, 214 vtkm::Id height, 215 const TextureDataHandle& data, 216 TextureFilterMode filterMode, 217 TextureWrapMode wrapMode) 218 : Width(width) 219 , Height(height) 220 , Data(data) 221 , FilterMode(filterMode) 222 , WrapMode(wrapMode) 223 { 224 } 225 226 template <typename Device> PrepareForExecution(Device,vtkm::cont::Token & token)227 VTKM_CONT Texture2DSamplerExecutionObject<Device> PrepareForExecution( 228 Device, 229 vtkm::cont::Token& token) const 230 { 231 return Texture2DSamplerExecutionObject<Device>( 232 this->Width, this->Height, this->Data, this->FilterMode, this->WrapMode, token); 233 } 234 235 private: 236 vtkm::Id Width; 237 vtkm::Id Height; 238 TextureDataHandle Data; 239 TextureFilterMode FilterMode; 240 TextureWrapMode WrapMode; 241 }; // class Texture2DSampler 242 243 private: 244 vtkm::Id Width; 245 vtkm::Id Height; 246 TextureDataHandle Data; 247 TextureFilterMode FilterMode; 248 TextureWrapMode WrapMode; 249 }; // class Texture2D 250 } 251 } // namespace vtkm::rendering 252 253 #endif // vtk_m_rendering_Texture2D_h 254