Blue Brain BioExplorer
ImageManager.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-2024, EPFL/Blue Brain Project
3  *
4  * The Blue Brain BioExplorer is a tool for scientists to extract and analyse
5  * scientific data from visualization
6  *
7  * This file is part of Blue Brain BioExplorer <https://github.com/BlueBrain/BioExplorer>
8  *
9  * This library is free software; you can redistribute it and/or modify it under
10  * the terms of the GNU Lesser General Public License version 3.0 as published
11  * by the Free Software Foundation.
12  *
13  * This library is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this library; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 #include "ImageManager.h"
24 
28 
29 namespace core
30 {
31 namespace
32 {
33 std::vector<unsigned char> getRawData(const freeimage::ImagePtr& image, const bool flip = true)
34 {
35 #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
36  freeimage::SwapRedBlue32(image.get());
37 #endif
38 
39  const auto width = FreeImage_GetWidth(image.get());
40  const auto height = FreeImage_GetHeight(image.get());
41  const auto bpp = FreeImage_GetBPP(image.get());
42  const auto pitch = width * bpp / 8;
43 
44  std::vector<unsigned char> rawData(height * pitch);
45  FreeImage_ConvertToRawBits(rawData.data(), image.get(), pitch, bpp, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK,
46  FI_RGBA_BLUE_MASK, flip);
47  return rawData;
48 }
49 
50 void setRawData(Texture2DPtr texture, const freeimage::ImagePtr& image, const uint8_t mip = 0)
51 {
52  auto width = texture->width;
53  auto height = texture->height;
54  for (uint8_t i = 0; i < mip; ++i)
55  {
56  width /= 2;
57  height /= 2;
58  }
59  const bool flipFace = !texture->isCubeMap();
60  for (uint8_t face = 0; face < texture->getNumFaces(); ++face)
61  {
62  const auto offset = face * width;
63  freeimage::ImagePtr faceImg(FreeImage_CreateView(image.get(), offset, 0, offset + width, height));
64  texture->setRawData(getRawData(faceImg, flipFace), face, mip);
65  }
66 }
67 } // namespace
68 
69 Texture2DPtr ImageManager::importTextureFromFile(const std::string& filename, const TextureType type)
70 {
71  auto format = FreeImage_GetFileType(filename.c_str());
72  if (format == FIF_UNKNOWN)
73  format = FreeImage_GetFIFFromFilename(filename.c_str());
74  if (format == FIF_UNKNOWN)
75  return {};
76 
77  freeimage::ImagePtr image(FreeImage_Load(format, filename.c_str()));
78  if (!image)
79  return {};
80 
81  uint8_t depth = 1;
82  switch (FreeImage_GetImageType(image.get()))
83  {
84  case FIT_BITMAP:
85  depth = 1;
86  break;
87  case FIT_UINT16:
88  case FIT_INT16:
89  case FIT_RGB16:
90  depth = 2;
91  break;
92  case FIT_UINT32:
93  case FIT_INT32:
94  case FIT_RGBA16:
95  case FIT_FLOAT:
96  case FIT_RGBF:
97  case FIT_RGBAF:
98  depth = 4;
99  break;
100  case FIT_DOUBLE:
101  case FIT_COMPLEX:
102  depth = 8;
103  break;
104  default:
105  return {};
106  }
107 
108  auto width = FreeImage_GetWidth(image.get());
109  const auto height = FreeImage_GetHeight(image.get());
110  const auto bytesPerPixel = FreeImage_GetBPP(image.get()) / 8;
111  const auto channels = bytesPerPixel / depth;
112  FreeImage_FlipVertical(image.get());
113 
115  const bool isCubeMap = type == TextureType::irradiance || type == TextureType::radiance;
116  if (isCubeMap)
117  {
118  textureType = Texture2D::Type::cubemap;
119  width /= 6;
120  }
121  else if (type == TextureType::normals) // TODO: only valid for PBR
122  textureType = Texture2D::Type::normal_roughness;
123  else if (type == TextureType::specular) // TODO: only valid for BBP
124  textureType = Texture2D::Type::aoe;
125 
126  auto texture = std::make_shared<Texture2D>(textureType, filename, channels, depth, width, height);
127  if (isCubeMap || type == TextureType::brdf_lut)
128  texture->setWrapMode(TextureWrapMode::clamp_to_edge);
129 
130  setRawData(texture, image);
131 
132  const auto path = fs::path(filename).parent_path().string();
133  const auto basename = path + "/" + fs::path(filename).stem().string();
134  const auto ext = fs::path(filename).extension().string();
135 
136  uint8_t mipLevels = 1;
137  while (fs::exists(basename + std::to_string((int)mipLevels) + ext))
138  ++mipLevels;
139 
140  texture->setMipLevels(mipLevels);
141 
142  for (uint8_t mip = 1; mip < mipLevels; ++mip)
143  {
144  freeimage::ImagePtr mipImage(FreeImage_Load(format, (basename + std::to_string((int)mip) + ext).c_str()));
145  FreeImage_FlipVertical(mipImage.get());
146 
147  setRawData(texture, mipImage, mip);
148  }
149  return texture;
150 }
151 } // namespace core
static Texture2DPtr importTextureFromFile(const std::string &filename, const TextureType type)
Import a Texture from file.
std::unique_ptr< FIBITMAP, ImageDeleter > ImagePtr
Definition: ImageUtils.h:49
bool SwapRedBlue32(FIBITMAP *freeImage)
Definition: ImageUtils.cpp:40
std::shared_ptr< Texture2D > Texture2DPtr
Definition: Types.h:159
TextureType
Definition: Types.h:244