Commit 69ca59c2 authored by Johannes Braun's avatar Johannes Braun
Browse files

Still Texturing.

parent b780129f
......@@ -4,14 +4,322 @@
#include <functional>
#include <util/color.h>
#include <core/state.h>
#include <core/res/texture.h>
#include "raytrace/data/local_collector.h"
template<typename T>
struct Image
{
using type = T;
template<typename TSource, typename TTarget> struct conversion
{
constexpr static float value = 1.f;
};
template<> struct conversion<float, uint8_t>
{
constexpr static float value = 255.f;
};
template<> struct conversion<uint8_t, float>
{
constexpr static float value = 1 / 255.f;
};
template<typename TSource, typename TTarget> constexpr static float conversion_v = conversion<TSource, TTarget>::value;
int width = 1;
int height = 1;
int depth = 1;
int components = 0; //R, RG, RGB, RGBA
std::vector<T> data;
template<typename TOther>
operator Image<TOther>()
{
if constexpr (std::is_same_v<T, TOther>)
{
return *this;
}
else if constexpr (conversion_v<T, TOther> != 1.f)
{
Image<TOther> other;
other.width = width;
other.height = height;
other.depth = depth;
other.components = components;
other.data.resize(data.size());
for (int i = 0; i < data.size(); ++i)
{
other.data[i] = static_cast<TOther>(data[i] * conversion_v<T, TOther>);
}
return other;
}
else
{
static_assert(false, "The image template type is not supported!");
}
}
Image() {}
Image(int width, int components, std::vector<T> data = std::vector<T>())
: width(width), components(components), data(std::move(data)) {
assert((this->data.empty() || this->data.size() == width*components) && "Image data is not empty, but does not fit the given bounds.");
}
Image(int width, int height, int components, std::vector<T> data = std::vector<T>())
: width(width), height(height), components(components), data(std::move(data)) {
assert((this->data.empty() || this->data.size() == width*height*components) && "Image data is not empty, but does not fit the given bounds.");
}
Image(int width, int height, int depth, int components, std::vector<T> data = std::vector<T>())
: width(width), height(height), depth(depth), components(components), data(std::move(data)) {
assert((this->data.empty() || this->data.size() == width*height*depth*components) && "Image data is not empty, but does not fit the given bounds.");
}
explicit Image(const fs::path& path)
{
depth = 1;
if constexpr (std::is_same_v<T, uint8_t>)
{
uint8_t *raw_data = stb::stbi_load(path.string().c_str(), &width, &height, &components, 0);
if (!raw_data)
{
Log_Error << "Loading image failed! \"" << path << "\" not found.";
width = 0;
height = 0;
components = 0;
return;
}
data = std::vector<uint8_t>(raw_data, raw_data + width * height * components);
}
else if constexpr (std::is_same_v<T, float>)
{
float *raw_data = stb::stbi_loadf(path.string().c_str(), &width, &height, &components, 0);
if (!raw_data)
{
Log_Error << "Loading image failed! \"" << path << "\" not found.";
width = 0;
height = 0;
components = 0;
return;
}
data = std::vector<float>(raw_data, raw_data + width * height * components);
}
else
{
static_assert(false, "Loading images with the given template type is not supported!");
}
flip();
}
private:
void flip()
{
images::flip(static_cast<unsigned>(width), static_cast<unsigned>(height), static_cast<int>(components), data.data());
}
};
struct Texture
{
using Format = gl::TextureInternalFormat;
struct Parameters
{
gl::TextureWrapMode wrap_r = gl::TextureWrapMode::eRepeat;
gl::TextureWrapMode wrap_s = gl::TextureWrapMode::eRepeat;
gl::TextureWrapMode wrap_t = gl::TextureWrapMode::eRepeat;
gl::TextureFilterMin filter_min = gl::TextureFilterMin::eLinearMipmapLinear;
gl::TextureFilterMag filter_mag = gl::TextureFilterMag::eLinear;
gl::TextureCompareMode compare_mode = gl::TextureCompareMode::eRToTexture;
gl::CompareFunc compare_func = gl::CompareFunc::eLess;
float anisotropy = -1.f;
};
void setup() const
{
float anisotropy = m_parameters.anisotropy;
if (anisotropy == -1.f) gl::getFloatv(gl::GetParameter::eMaxTextureMaxAnisotropy, &anisotropy);
gl::textureParameter(m_handle, gl::TextureParameter::eMaxAnisotropy, anisotropy);
gl::textureParameter(m_handle, gl::TextureParameter::eWrapR, m_parameters.wrap_r);
gl::textureParameter(m_handle, gl::TextureParameter::eWrapS, m_parameters.wrap_s);
gl::textureParameter(m_handle, gl::TextureParameter::eWrapT, m_parameters.wrap_t);
gl::textureParameter(m_handle, gl::TextureParameter::eMagFilter, m_parameters.filter_mag);
gl::textureParameter(m_handle, gl::TextureParameter::eMinFilter, m_parameters.filter_min);
gl::textureParameter(m_handle, gl::TextureParameter::eCompareMode, m_parameters.compare_mode);
gl::textureParameter(m_handle, gl::TextureParameter::eCompareFunc, m_parameters.compare_func);
gl::generateTextureMipmap(m_handle);
}
Texture(gl::TextureType type, int width, Format format, Parameters parameters = Parameters(), const void* data = nullptr)
: Texture(type, width, 1, 1, format, 1, std::move(parameters), data)
{
}
Texture(gl::TextureType type, int width, int height, Format format, int samples, Parameters parameters = Parameters(), const void* data = nullptr)
: Texture(type, width, height, 1, format, samples, std::move(parameters), data)
{
}
Texture(gl::TextureType type, int width, int height, int depth, Format format, int samples, Parameters parameters = Parameters(), const void* data = nullptr)
: m_handle(std::move(type)), m_type(type)
{
m_parameters = std::move(parameters);
m_format = format;
m_width = width;
m_height = height;
m_depth = depth;
m_samples = samples;
}
template<typename T>
Texture(const Image<T>& image, Parameters parameters = Parameters())
{
m_parameters = std::move(parameters);
m_format = getFormat(image);
m_width = image.width;
m_height = image.height;
m_depth = image.depth;
gl::TextureFormat texture_format = [](int components)
{
switch(components)
{
case 1: return gl::TextureFormat::eRed;
case 2: return gl::TextureFormat::eRG;
case 3: return gl::TextureFormat::eRGB;
case 4: return gl::TextureFormat::eRGBA;
default: throw std::invalid_argument("Texture format not valid.");
}
}(image.components);
if(image.height == 1)
{
//1d texture
assert(image.depth == 1 && "Malformed image! Height is 1, but not depth.");
m_type = gl::TextureType::e1D;
m_handle.regenerate(gl::TextureType::e1D);
gl::pixelStorei(gl::PixelStoreAlignment::ePack, 1);
gl::textureImage(m_handle, gl::ImageTarget::e1D, 0, m_format, texture_format, { image.width }, image.data.empty() ? nullptr : image.data.data());
}
else if(image.depth == 1)
{
//2d texture
m_type = gl::TextureType::e2D;
m_handle.regenerate(gl::TextureType::e2D);
gl::pixelStorei(gl::PixelStoreAlignment::ePack, 1);
gl::textureImage(m_handle, gl::ImageTarget::e2D, 0, m_format, texture_format, { image.width, image.height }, image.data.empty() ? nullptr : image.data.data());
}
else
{
//3d texture
m_type = gl::TextureType::e3D;
m_handle.regenerate(gl::TextureType::e3D);
gl::pixelStorei(gl::PixelStoreAlignment::ePack, 1);
gl::textureImage(m_handle, gl::ImageTarget::e3D, 0, m_format, texture_format, { image.width, image.height, image.depth }, image.data.empty() ? nullptr : image.data.data());
}
setup();
}
bool textureResident() const
{
return m_texture_address != 0 && gl::isTextureHandleResident(m_texture_address);
}
uint64_t residentTextureAddress() const
{
if (!textureResident())
{
m_texture_address = gl::getTextureHandle(m_handle);
gl::makeTextureHandleResident(m_texture_address);
}
assert(textureResident());
return m_texture_address;
}
template<typename T>
static gl::TextureInternalFormat getFormat(const Image<T>& image)
{
switch(image.components)
{
case 1:
if constexpr(std::is_same_v<T, float>) return gl::TextureInternalFormat::eR32Float;
else if constexpr(std::is_same_v<T, uint8_t>) return gl::TextureInternalFormat::eRed;
else if constexpr(std::is_same_v<T, uint16_t>) return gl::TextureInternalFormat::eR16UInt;
else if constexpr(std::is_same_v<T, uint32_t>) return gl::TextureInternalFormat::eR32UInt;
else if constexpr(std::is_same_v<T, int8_t>) return gl::TextureInternalFormat::eR8Int;
else if constexpr(std::is_same_v<T, int16_t>) return gl::TextureInternalFormat::eR16Int;
else if constexpr(std::is_same_v<T, int32_t>) return gl::TextureInternalFormat::eR32Int;
case 2:
if constexpr(std::is_same_v<T, float>) return gl::TextureInternalFormat::eRG32Float;
else if constexpr(std::is_same_v<T, uint8_t>) return gl::TextureInternalFormat::eRG;
else if constexpr(std::is_same_v<T, uint16_t>) return gl::TextureInternalFormat::eRG16UInt;
else if constexpr(std::is_same_v<T, uint32_t>) return gl::TextureInternalFormat::eRG32UInt;
else if constexpr(std::is_same_v<T, int8_t>) return gl::TextureInternalFormat::eRG8Int;
else if constexpr(std::is_same_v<T, int16_t>) return gl::TextureInternalFormat::eRG16Int;
else if constexpr(std::is_same_v<T, int32_t>) return gl::TextureInternalFormat::eRG32Int;
case 3:
if constexpr(std::is_same_v<T, float>) return gl::TextureInternalFormat::eRGB32Float;
else if constexpr(std::is_same_v<T, uint8_t>) return gl::TextureInternalFormat::eRGB;
else if constexpr(std::is_same_v<T, uint16_t>) return gl::TextureInternalFormat::eRGB16UInt;
else if constexpr(std::is_same_v<T, uint32_t>) return gl::TextureInternalFormat::eRGB32UInt;
else if constexpr(std::is_same_v<T, int8_t>) return gl::TextureInternalFormat::eRGB8Int;
else if constexpr(std::is_same_v<T, int16_t>) return gl::TextureInternalFormat::eRGB16Int;
else if constexpr(std::is_same_v<T, int32_t>) return gl::TextureInternalFormat::eRGB32Int;
case 4:
if constexpr(std::is_same_v<T, float>) return gl::TextureInternalFormat::eRGBA32Float;
else if constexpr(std::is_same_v<T, uint8_t>) return gl::TextureInternalFormat::eRGBA;
else if constexpr(std::is_same_v<T, uint16_t>) return gl::TextureInternalFormat::eRGBA16UInt;
else if constexpr(std::is_same_v<T, uint32_t>) return gl::TextureInternalFormat::eRGBA32UInt;
else if constexpr(std::is_same_v<T, int8_t>) return gl::TextureInternalFormat::eRGBA8Int;
else if constexpr(std::is_same_v<T, int16_t>) return gl::TextureInternalFormat::eRGBA16Int;
else if constexpr(std::is_same_v<T, int32_t>) return gl::TextureInternalFormat::eRGBA32Int;
throw std::invalid_argument("Using images other than 32 bit float and integral types is not yet implemented");
default:
throw std::invalid_argument("Malformed image! Component count not in range 1 to 4.");
}
}
private:
gl::handle::texture m_handle{ gl::TextureType::e1D };
gl::TextureInternalFormat m_format;
gl::TextureType m_type;
int m_width = 1;
int m_height = 1;
int m_depth = 1;
int m_samples = 1;
Parameters m_parameters;
mutable uint64_t m_texture_address = 0;
};
int main()
{
glare::core::Texture texture;
Image<uint8_t> img(files::asset("textures/bricky.png"));
Image<uint16_t> image16(574, 87, 3);
Image<float> imf = img;
glare::core::Context::createAsCurrent(files::asset("/preferences/default.xml"));
Texture texture(imf);
texture.resize<color::rgba32f>(1024, 1024);
auto renderer = glare::core::DefaultTextureRenderers::makeSimpleRenderer();
glare::core::Context::current().loop([&renderer, &texture]() {
renderer->draw(texture);
});
system("pause");
return 0;
......
......@@ -29,22 +29,22 @@ namespace glare::core
for (auto &&texture : m_color_attachments) {
if (m_samples == 1)
{
texture.second->resize<color::rgba32f>(gl::TextureImageTarget2D::e2D, width, height, 4, gl::TextureInternalFormat::eRGBA32Float, gl::TextureFormat::eRGBA, gl::Type::eFloat);
texture.second->resize<color::rgba32f>(gl::TextureImageTarget2D::e2D, width, height, 4, gl::TextureInternalFormat::eRGBA32Float);
}
else
{
texture.second->resize<color::rgba32f>(gl::TextureImageTargetMultisample2D::e2DMultisample, width, height, samples, 4, gl::TextureInternalFormat::eRGBA32Float, gl::TextureFormat::eRGBA, gl::Type::eFloat);
texture.second->resize<color::rgba32f>(gl::TextureImageTargetMultisample2D::e2DMultisample, width, height, samples, 4, gl::TextureInternalFormat::eRGBA32Float);
}
}
if (m_depth_attachment) {
if (m_samples == 1)
{
m_depth_attachment->resize<color::r32f>(gl::TextureImageTarget2D::e2D, width, height, 4, gl::TextureInternalFormat::eDepthComponent32Float, gl::TextureFormat::eDepthComponent, gl::Type::eFloat);
m_depth_attachment->resize<color::r32f>(gl::TextureImageTarget2D::e2D, width, height, 4, gl::TextureInternalFormat::eDepthComponent32Float);
}
else
{
m_depth_attachment->resize<float>(gl::TextureImageTargetMultisample2D::e2DMultisample, width, height, samples, 4, gl::TextureInternalFormat::eDepthComponent32Float, gl::TextureFormat::eDepthComponent, gl::Type::eFloat);
m_depth_attachment->resize<color::r32f>(gl::TextureImageTargetMultisample2D::e2DMultisample, width, height, samples, 4, gl::TextureInternalFormat::eDepthComponent32Float);
}
}
}
......@@ -71,28 +71,28 @@ namespace glare::core
{
case gl::Attachment::eDepth:
case gl::Attachment::eDepthStencil:
m_depth_attachment = std::make_shared<TextureEXT>();
m_depth_attachment = std::make_shared<Texture>();
if (m_samples == 1)
{
m_depth_attachment->resize<color::r32f>(gl::TextureImageTarget2D::e2D, m_width, m_height, 4, gl::TextureInternalFormat::eDepthComponent32Float, gl::TextureFormat::eDepthComponent, gl::Type::eFloat);
m_depth_attachment->resize<color::r32f>(gl::TextureImageTarget2D::e2D, m_width, m_height, 4, gl::TextureInternalFormat::eDepthComponent32Float);
}
else
{
m_depth_attachment->resize<color::r32f>(gl::TextureImageTargetMultisample2D::e2DMultisample, m_width, m_height, m_samples, 4, gl::TextureInternalFormat::eDepthComponent32Float, gl::TextureFormat::eDepthComponent, gl::Type::eFloat);
m_depth_attachment->resize<color::r32f>(gl::TextureImageTargetMultisample2D::e2DMultisample, m_width, m_height, m_samples, 4, gl::TextureInternalFormat::eDepthComponent32Float);
}
gl::namedFramebufferTexture(m_handle, att, m_depth_attachment->id(), 0);
break;
default:
{
std::shared_ptr<TextureEXT> new_attachment = std::make_shared<TextureEXT>();
std::shared_ptr<Texture> new_attachment = std::make_shared<Texture>();
if (m_samples == 1)
{
new_attachment->resize<color::rgba32f>(gl::TextureImageTarget2D::e2D, m_width, m_height, 4, gl::TextureInternalFormat::eRGBA32Float, gl::TextureFormat::eRGBA, gl::Type::eFloat);
new_attachment->resize<color::rgba32f>(gl::TextureImageTarget2D::e2D, m_width, m_height, 4, gl::TextureInternalFormat::eRGBA32Float);
}
else
{
new_attachment->resize<color::rgba32f>(gl::TextureImageTargetMultisample2D::e2DMultisample, m_width, m_height, m_samples, 4, gl::TextureInternalFormat::eRGBA32Float, gl::TextureFormat::eRGBA, gl::Type::eFloat);
new_attachment->resize<color::rgba32f>(gl::TextureImageTargetMultisample2D::e2DMultisample, m_width, m_height, m_samples, 4, gl::TextureInternalFormat::eRGBA32Float);
}
m_color_attachments.emplace(att, new_attachment);
......@@ -101,7 +101,7 @@ namespace glare::core
}
}
const TextureEXT &Framebuffer::attachment(gl::Attachment attachment) const
const Texture &Framebuffer::attachment(gl::Attachment attachment) const
{
switch (attachment)
{
......
......@@ -41,7 +41,7 @@ namespace glare::core
void deactivate() const;
void attach(gl::Attachment attachment);
const TextureEXT &attachment(gl::Attachment attachment) const;
const Texture &attachment(gl::Attachment attachment) const;
unsigned attachments() const;
unsigned samples() const;
......@@ -50,8 +50,8 @@ namespace glare::core
void putAttachment(gl::Attachment attachment, unsigned texture);
std::vector<gl::Attachment> m_draw_buffers;
std::map<gl::Attachment, std::shared_ptr<core::TextureEXT>> m_color_attachments;
std::shared_ptr<core::TextureEXT> m_depth_attachment;
std::map<gl::Attachment, std::shared_ptr<core::Texture>> m_color_attachments;
std::shared_ptr<core::Texture> m_depth_attachment;
int m_samples = 1;
int m_width = 1;
......
......@@ -69,33 +69,33 @@ namespace glare::core
{
program.uniform(name + ".base.value", base.value);
if (base.texture)
program.uniform(name + ".base.texture", base.texture->makeTextureResident());
program.uniform(name + ".base.texture", base.texture->residentTextureAddress());
program.uniform(name + ".base.texture_available", static_cast<uint32_t>(static_cast<bool>(base.texture)));
program.uniform(name + ".roughness.value", roughness.value);
if (roughness.texture)
program.uniform(name + ".roughness.texture", roughness.texture->makeTextureResident());
program.uniform(name + ".roughness.texture", roughness.texture->residentTextureAddress());
program.uniform(name + ".roughness.texture_available", static_cast<uint32_t>(static_cast<bool>(roughness.texture)));
program.uniform(name + ".metallic.value", metallic.value);
if (metallic.texture)
program.uniform(name + ".metallic.texture", metallic.texture->makeTextureResident());
program.uniform(name + ".metallic.texture", metallic.texture->residentTextureAddress());
program.uniform(name + ".metallic.texture_available", static_cast<uint32_t>(static_cast<bool>(metallic.texture)));
program.uniform(name + ".transmission.value", transmissive.value);
if (transmissive.texture)
program.uniform(name + ".transmission.texture", transmissive.texture->makeTextureResident());
program.uniform(name + ".transmission.texture", transmissive.texture->residentTextureAddress());
program.uniform(name + ".transmission.texture_available", static_cast<uint32_t>(static_cast<bool>(transmissive.texture)));
program.uniform(name + ".emission.value", emission.value);
if (emission.texture)
program.uniform(name + ".emission.texture", emission.texture->makeTextureResident());
program.uniform(name + ".emission.texture", emission.texture->residentTextureAddress());
program.uniform(name + ".emission.texture_available", static_cast<uint32_t>(static_cast<bool>(emission.texture)));
if (map_normal)
program.uniform(name + ".normal_map", map_normal->makeTextureResident());
program.uniform(name + ".normal_map", map_normal->residentTextureAddress());
if (map_displacement)
program.uniform(name + ".displacement_map", map_displacement->makeTextureResident());
program.uniform(name + ".displacement_map", map_displacement->residentTextureAddress());
program.uniform(name + ".has_displacement_map", static_cast<bool>(map_displacement));
program.uniform(name + ".has_normal_map", static_cast<bool>(emission.texture));
......
......@@ -5,21 +5,20 @@
#include <atomic>
#include <core/base/program.h>
#include <core/res/texture2d.h>
#include <core/res/texture.h>
namespace glare::core
{
struct MaterialParameter1f
{
float value;
std::shared_ptr<TextureRGBA_UB> texture;
std::shared_ptr<Texture> texture;
};
struct MaterialParameter3f
{
glm::vec3 value;
std::shared_ptr<TextureRGBA_UB> texture;
std::shared_ptr<Texture> texture;
};
class Material
......@@ -42,8 +41,8 @@ namespace glare::core
MaterialParameter1f emission = { 0 };
float index_of_refraction = 1.45f;
std::shared_ptr<TextureRGBA_UB> map_normal;
std::shared_ptr<TextureRGBA_UB> map_displacement;
std::shared_ptr<Texture> map_normal;
std::shared_ptr<Texture> map_displacement;
private:
static std::atomic<size_t> m_current_id;
......
......@@ -4,7 +4,6 @@
#include <core/base/framebuffer.h>
#include <core/graph/scene_node.h>
#include <core/res/texture2d.h>
#include <core/objects/camera.h>
namespace glare::core
......
......@@ -7,7 +7,6 @@
#include <core/base/framebuffer.h>
#include <core/base/program.h>
#include <core/objects/skybox.h>
#include <core/res/texture2d_multisample.h>
#include <core/objects/light.h>
#include "texture_renderer.h"
......
......@@ -40,7 +40,7 @@ namespace glare::core
if (asset_path != "") {
m_background_config |= 1 << 3;
m_background_texture = std::make_unique<core::TextureEXT>(files::asset(asset_path));
m_background_texture = std::make_unique<core::Texture>(files::asset(asset_path));
m_background_scale = splash_background.child("texture").attribute("scale").as_float();
}
......@@ -51,7 +51,7 @@ namespace glare::core
{
m_duration = duration;
m_logo_renderer = core::DefaultTextureRenderers::makeCenterTextureRenderer();
m_texture = std::make_unique<core::TextureEXT>(logo);
m_texture = std::make_unique<core::Texture>(logo);
m_sound = global_resources::sounds.get(sound);
m_sound_source = std::make_unique<core::SoundSource>(m_sound->id());
......
......@@ -3,7 +3,6 @@
#include <memory>
#include <filesystem>
#include <core/res/texture2d.h>
#include <core/res/texture.h>
#include <core/audio/sound_buffer.h>
#include <core/audio/sound_source.h>
......@@ -31,14 +30,14 @@ namespace glare::core
void initialize(const fs::path &logo, const fs::path &sound, double duration = 500);
std::shared_ptr<core::TextureRenderer> m_logo_renderer;
std::shared_ptr<core::TextureEXT> m_texture;
std::shared_ptr<core::Texture> m_texture;
std::shared_ptr<core::SoundBuffer> m_sound;
std::unique_ptr<core::SoundSource> m_sound_source;
color::rgba32f m_color;
gradient m_gradient_vertical;
gradient m_gradient_horizontal;
std::shared_ptr<core::TextureEXT> m_background_texture;
std::shared_ptr<core::Texture> m_background_texture;
float m_background_scale;
unsigned m_background_config = 0;
......
......@@ -19,7 +19,7 @@ namespace glare::core
return *m_shader;
}
void TextureRenderer::draw(const core::TextureEXT& texture) const
void TextureRenderer::draw(const core::Texture& texture) const
{
draw(texture.residentTextureAddress(), texture.samples());
}
......
......@@ -36,7 +36,7 @@ namespace glare::core
* \tparam TextureType The type of texture to render. (Mostly an implicite parameter, so usually no need to set it manually)
* \param texture The texture to render.
*/
void draw(const core::TextureEXT& texture) const;
void draw(const core::Texture& texture) const;
void draw(uint64_t texture, unsigned samples = 1) const;
void draw(unsigned samples = 1) const;
......@@ -55,7 +55,7 @@ namespace glare::core
template <typename TextureType>
void TextureRenderer::draw(const TextureType& texture, unsigned samples) const
{
draw(texture.makeTextureResident(), samples);
draw(texture.residentTextureAddress(), samples);
}