Skip to content

Commit

Permalink
[Render/Texture] A 3D texture can load image slices
Browse files Browse the repository at this point in the history
- These are supposed to be consecutive 2D images that represent a 3D texture as a whole
  • Loading branch information
Razakhel committed Feb 2, 2024
1 parent 32c7492 commit 65da76e
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 27 deletions.
12 changes: 12 additions & 0 deletions include/RaZ/Render/Texture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "RaZ/Data/OwnerValue.hpp"

#include <memory>
#include <vector>

namespace Raz {

Expand Down Expand Up @@ -80,6 +81,11 @@ class Texture {
protected:
explicit Texture(TextureType type);

/// Assigns default parameters after image loading. Must be called after having loaded the images' data in order to properly create the mipmaps.
/// \param createMipmaps True to generate texture mipmaps, false otherwise.
void setLoadedParameters(bool createMipmaps) const;
/// Generates mipmaps for the current texture.
void generateMipmaps() const;
virtual void load() const = 0;

OwnerValue<unsigned int> m_index {};
Expand Down Expand Up @@ -175,6 +181,7 @@ class Texture3D final : public Texture {
Texture3D(TextureColorspace colorspace, TextureDataType dataType) : Texture3D() { setColorspace(colorspace, dataType); }
Texture3D(unsigned int width, unsigned int height, unsigned int depth, TextureColorspace colorspace) : Texture3D(colorspace) { resize(width, height, depth); }
Texture3D(unsigned int width, unsigned int height, unsigned int depth, TextureColorspace colorspace, TextureDataType dataType);
explicit Texture3D(const std::vector<Image>& imageSlices, bool createMipmaps = true) : Texture3D() { load(imageSlices, createMipmaps); }
/// Constructs a plain colored texture.
/// \param color Color to fill the texture with.
/// \param width Width of the texture to create.
Expand All @@ -194,6 +201,11 @@ class Texture3D final : public Texture {
/// \param height New texture height.
/// \param depth New texture depth.
void resize(unsigned int width, unsigned int height, unsigned int depth);
/// Loads the images' data onto the graphics card.
/// \param imageSlices Images along the depth to load the data from. All of them must have the same attributes (width, height, colorspace, ...)
/// and the number of images will become the texture's depth.
/// \param createMipmaps True to generate texture mipmaps, false otherwise.
void load(const std::vector<Image>& imageSlices, bool createMipmaps = true);
/// Fills the texture with a single color.
/// \param color Color to fill the texture with.
void fill(const Color& color);
Expand Down
107 changes: 80 additions & 27 deletions src/RaZ/Render/Texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
#include "RaZ/Render/Texture.hpp"
#include "RaZ/Utils/Logger.hpp"

#include <utility>

namespace Raz {

namespace {
Expand Down Expand Up @@ -176,6 +174,30 @@ Texture::Texture(TextureType type) : m_type{ type } {
setWrapping(TextureWrapping::CLAMP);
}

void Texture::setLoadedParameters(bool createMipmaps) const {
if (m_colorspace == TextureColorspace::GRAY || m_colorspace == TextureColorspace::RG) {
Renderer::setTextureParameter(m_type, TextureParam::SWIZZLE_R, static_cast<int>(TextureFormat::RED));
Renderer::setTextureParameter(m_type, TextureParam::SWIZZLE_G, static_cast<int>(TextureFormat::RED));
Renderer::setTextureParameter(m_type, TextureParam::SWIZZLE_B, static_cast<int>(TextureFormat::RED));
Renderer::setTextureParameter(m_type, TextureParam::SWIZZLE_A, (m_colorspace == TextureColorspace::RG ? static_cast<int>(TextureFormat::GREEN) : 1));
}

if (createMipmaps) {
generateMipmaps();
setFilter(TextureFilter::LINEAR, TextureFilter::LINEAR, TextureFilter::LINEAR);
} else {
setFilter(TextureFilter::LINEAR);
}

setWrapping(TextureWrapping::REPEAT);
}

void Texture::generateMipmaps() const {
bind();
Renderer::generateMipmap(m_type);
unbind();
}

#if !defined(USE_OPENGL_ES)
Texture1D::Texture1D()
: Texture(TextureType::TEXTURE_1D) {}
Expand Down Expand Up @@ -255,35 +277,20 @@ void Texture2D::load(const Image& image, bool createMipmaps) {
return;
}

#if defined(USE_OPENGL_ES)
if ((image.getWidth() & (image.getWidth() - 1)) != 0 || (image.getHeight() & (image.getHeight() - 1)) != 0) {
Logger::warn("[Texture] The given image's dimensions (" + std::to_string(image.getWidth()) + 'x' + std::to_string(image.getHeight())
+ ") are not powers of two; this can give unexpected results.");
}
#endif

m_width = image.getWidth();
m_height = image.getHeight();
m_colorspace = static_cast<TextureColorspace>(image.getColorspace());
m_dataType = (image.getDataType() == ImageDataType::FLOAT ? TextureDataType::FLOAT16 : TextureDataType::BYTE);

if (createMipmaps)
setFilter(TextureFilter::LINEAR, TextureFilter::LINEAR, TextureFilter::LINEAR);
else
setFilter(TextureFilter::LINEAR);

setWrapping(TextureWrapping::REPEAT);
#if defined(USE_OPENGL_ES)
if ((m_width & (m_width - 1)) != 0 || (m_height & (m_height - 1)) != 0) {
Logger::warn("[Texture] The given image's dimensions (" + std::to_string(m_width) + 'x' + std::to_string(m_height)
+ ") are not powers of two; this can give unexpected results.");
}
#endif

bind();

if (m_colorspace == TextureColorspace::GRAY || m_colorspace == TextureColorspace::RG) {
Renderer::setTextureParameter(TextureType::TEXTURE_2D, TextureParam::SWIZZLE_R, static_cast<int>(TextureFormat::RED));
Renderer::setTextureParameter(TextureType::TEXTURE_2D, TextureParam::SWIZZLE_G, static_cast<int>(TextureFormat::RED));
Renderer::setTextureParameter(TextureType::TEXTURE_2D, TextureParam::SWIZZLE_B, static_cast<int>(TextureFormat::RED));
Renderer::setTextureParameter(TextureType::TEXTURE_2D, TextureParam::SWIZZLE_A,
(m_colorspace == TextureColorspace::RG ? static_cast<int>(TextureFormat::GREEN) : 1));
}

Renderer::sendImageData2D(TextureType::TEXTURE_2D,
0,
recoverInternalFormat(m_colorspace, m_dataType),
Expand All @@ -293,10 +300,7 @@ void Texture2D::load(const Image& image, bool createMipmaps) {
(m_dataType == TextureDataType::BYTE ? PixelDataType::UBYTE : PixelDataType::FLOAT),
image.getDataPtr());

if (createMipmaps)
Renderer::generateMipmap(TextureType::TEXTURE_2D);

unbind();
setLoadedParameters(createMipmaps);
}

void Texture2D::fill(const Color& color) {
Expand Down Expand Up @@ -371,6 +375,55 @@ void Texture3D::resize(unsigned int width, unsigned int height, unsigned int dep
load();
}

void Texture3D::load(const std::vector<Image>& imageSlices, bool createMipmaps) {
if (imageSlices.empty() || imageSlices.front().isEmpty()) {
// Images not found, defaulting texture to pure white
fill(ColorPreset::White);
return;
}

m_width = imageSlices.front().getWidth();
m_height = imageSlices.front().getHeight();
m_depth = static_cast<unsigned int>(imageSlices.size());
m_colorspace = static_cast<TextureColorspace>(imageSlices.front().getColorspace());
m_dataType = (imageSlices.front().getDataType() == ImageDataType::FLOAT ? TextureDataType::FLOAT16 : TextureDataType::BYTE);

#if defined(USE_OPENGL_ES)
if ((m_width & (m_width - 1)) != 0 || (m_height & (m_height - 1)) != 0 || (m_depth & (m_depth - 1)) != 0) {
Logger::warn("[Texture] The given image's dimensions (" + std::to_string(m_width) + 'x' + std::to_string(m_height) + 'x' + std::to_string(m_depth)
+ ") are not powers of two; this can give unexpected results.");
}
#endif

load();

const TextureFormat format = recoverFormat(m_colorspace);
const PixelDataType pixelDataType = (m_dataType == TextureDataType::BYTE ? PixelDataType::UBYTE : PixelDataType::FLOAT);

bind();

for (std::size_t imgIndex = 0; imgIndex < imageSlices.size(); ++imgIndex) {
const Image& img = imageSlices[imgIndex];

if (img.getWidth() != m_width || img.getHeight() != m_height || static_cast<TextureColorspace>(img.getColorspace()) != m_colorspace)
throw std::invalid_argument("[Texture3D] The given images have different attributes.");

Renderer::sendImageSubData3D(TextureType::TEXTURE_3D,
0,
0,
0,
static_cast<unsigned int>(imgIndex),
m_width,
m_height,
1,
format,
pixelDataType,
img.getDataPtr());
}

setLoadedParameters(createMipmaps);
}

void Texture3D::fill(const Color& color) {
m_colorspace = TextureColorspace::RGB;
m_dataType = TextureDataType::BYTE;
Expand Down

0 comments on commit 65da76e

Please sign in to comment.