Commit fb0b8400 authored by Johannes Braun's avatar Johannes Braun
Browse files

Final fixes for textures and some weird other errors/faults.

parent 8035abe0
......@@ -4,7 +4,7 @@
<item name="window_size_x" value="1440"/>
<item name="window_size_y" value="900"/>
<item name="vsync" value="0"/>
<item name="msaa" value="1"/>
<item name="msaa" value="4"/>
</group>
<item name="splash_screen" value="/preferences/splash_01.xml"/>
......
......@@ -27,8 +27,8 @@ void resetImportance(int id);
void main()
{
ivec2 target_size = u_render_target.imageSize();
if (!(int(gl_GlobalInvocationID.x) < target_size.x && int(gl_GlobalInvocationID.y) < target_size.y))
return;
//if (!(int(gl_GlobalInvocationID.x) < target_size.x && int(gl_GlobalInvocationID.y) < target_size.y))
// return;
int id = target_size.x * int(gl_GlobalInvocationID.y) + int(gl_GlobalInvocationID.x);
generate(id, target_size);
......
......@@ -66,7 +66,7 @@ void main()
if(material.emission.value != 0)
{
out_final_color += material.emission.value / u_samples;
out_final_color += material.emission.value;
continue;
}
......
......@@ -25,7 +25,11 @@ namespace glare::core
gl::TextureFilterMag filter_mag = gl::TextureFilterMag::eLinear;
gl::TextureCompareMode compare_mode = gl::TextureCompareMode::eRToTexture;
gl::CompareFunc compare_func = gl::CompareFunc::eLess;
gl::CompareFunc compare_func = gl::CompareFunc::eLess;
int base_level = 0;
int max_level = 8;
float anisotropy = -1.f;
};
......@@ -123,18 +127,18 @@ namespace glare::core
switch (texture_type)
{
case gl::Type::eByte:
converted[i] = clampConvert<int8_t, T>(data.data(), i);// static_cast<T>(glm::clamp(conversionFactor<int8_t, T>() * reinterpret_cast<int8_t*>(data.data())[i], std::numeric_limits<int8_t>::lowest(), std::numeric_limits<int8_t>::max()));
converted[i] = clampConvert<int8_t, T>(data.data(), i);
break;
case gl::Type::eUByte:
case gl::Type::eUInt_8_8_8_8:
case gl::Type::eUInt_8_8_8_8_rev:
converted[i] = clampConvert<uint8_t, T>(data.data(), i);// static_cast<T>(glm::clamp(conversionFactor<uint8_t, T>() * reinterpret_cast<uint8_t*>(data.data())[i], std::numeric_limits<uint8_t>::lowest(), std::numeric_limits<uint8_t>::max()));
converted[i] = clampConvert<uint8_t, T>(data.data(), i);
break;
case gl::Type::eShort:
converted[i] = clampConvert<int16_t, T>(data.data(), i); //static_cast<T>(glm::clamp(conversionFactor<int16_t, T>() * reinterpret_cast<int16_t*>(data.data())[i], std::numeric_limits<int16_t>::lowest(), std::numeric_limits<int16_t>::max()));
converted[i] = clampConvert<int16_t, T>(data.data(), i);
break;
case gl::Type::eUShort:
converted[i] = clampConvert<uint16_t, T>(data.data(), i);// static_cast<T>(glm::clamp(conversionFactor<uint16_t, T>() * reinterpret_cast<uint16_t*>(data.data())[i], std::numeric_limits<uint16_t>::lowest(), std::numeric_limits<uint16_t>::max()));
converted[i] = clampConvert<uint16_t, T>(data.data(), i);
break;
case gl::Type::eInt:
converted[i] = clampConvert<int32_t, T>(data.data(), i);// static_cast<T>(glm::clamp(conversionFactor<int32_t, T>() * reinterpret_cast<int32_t*>(data.data())[i], std::numeric_limits<int32_t>::lowest(), std::numeric_limits<int32_t>::max()));
......@@ -143,7 +147,7 @@ namespace glare::core
converted[i] = clampConvert<uint32_t, T>(data.data(), i);// static_cast<T>(glm::clamp(conversionFactor<uint32_t, T>() * reinterpret_cast<uint32_t*>(data.data())[i], std::numeric_limits<uint32_t>::lowest(), std::numeric_limits<uint32_t>::max()));
break;
case gl::Type::eFloat:
converted[i] = static_cast<T>(conversionFactor<float, T>() * reinterpret_cast<float*>(data.data())[i]);
converted[i] = clampConvert<float, T>(data.data(), i);
break;
default: throw std::invalid_argument("Texture format not valid.");
}
......@@ -173,15 +177,20 @@ namespace glare::core
set(t, image, m_latest_parameters);
}
template<typename T> void set(SubTarget t, const Image<T>& image, bool no_apply)
{
set(t, 0, image, m_latest_parameters, no_apply);
}
// up until the set methods, no openGL is needed yet.
// Upload an image
template<typename T> void set(SubTarget t, const Image<T>& image, Parameters parameters)
{
set(t, 0, image, std::move(parameters));
set(t, 0, image, std::move(parameters), false);
}
// Upload an image
template<typename T> void set(SubTarget t, int level, const Image<T>& image, Parameters parameters)
template<typename T> void set(SubTarget t, int level, const Image<T>& image, Parameters parameters, bool no_apply)
{
// Don't allow level parameter on MS textures.
// images are multisampled if sample count is not 0.
......@@ -205,7 +214,8 @@ namespace glare::core
m_components = image.components();
gl::pixelStorei(gl::PixelStoreAlignment::eUnpack, 1);
gl::textureImage(m_handle, t, level, m_format, texture_format, { image.width(), image.height(), image.depth() }, image.data().empty() ? nullptr : image.data().data());
apply(std::move(parameters));
if (!no_apply)
apply(std::move(parameters));
}
const Parameters& parameters() const
......@@ -227,7 +237,10 @@ namespace glare::core
gl::textureParameter(m_handle, gl::TextureParameter::eMagFilter, m_latest_parameters.filter_mag);
gl::textureParameter(m_handle, gl::TextureParameter::eMinFilter, m_latest_parameters.filter_min);
gl::textureParameter(m_handle, gl::TextureParameter::eCompareMode, m_latest_parameters.compare_mode);
gl::textureParameter(m_handle, gl::TextureParameter::eCompareFunc, m_latest_parameters.compare_func);
gl::textureParameter(m_handle, gl::TextureParameter::eCompareFunc, m_latest_parameters.compare_func);
gl::textureParameter(m_handle, gl::TextureParameter::eBaseLevel, m_latest_parameters.base_level);
gl::textureParameter(m_handle, gl::TextureParameter::eMaxLevel, m_latest_parameters.max_level);
gl::generateTextureMipmap(m_handle);
}
......@@ -308,7 +321,22 @@ namespace glare::core
template<typename From, typename To>
static To clampConvert(const void* data, int index)
{
return static_cast<To>(glm::clamp<float>(conversionFactor<From, To>() * reinterpret_cast<const From*>(data)[index], static_cast<float>(std::numeric_limits<From>::lowest()), static_cast<float>(std::numeric_limits<From>::max())));
if constexpr(std::is_same_v<To, From>)
{
return reinterpret_cast<const From*>(data)[index];
}
else if constexpr(std::is_same_v<To, float>)
{
return static_cast<To>(glm::clamp(static_cast<float>(reinterpret_cast<const From*>(data)[index]), 0.f, 1.f) / static_cast<float>(std::numeric_limits<From>::max()));
}
else if constexpr(std::is_same_v<From, float>)
{
return static_cast<To>(glm::clamp(static_cast<float>(reinterpret_cast<const From*>(data)[index]), 0.f, 1.f) * static_cast<float>(std::numeric_limits<To>::max()));
}
else
{
return static_cast<To>(glm::clamp(conversionFactor<From, To>() * reinterpret_cast<const From*>(data)[index], static_cast<float>(std::numeric_limits<From>::lowest()), static_cast<float>(std::numeric_limits<From>::max())));
}
}
template<typename T>
......
......@@ -30,24 +30,26 @@ namespace glare::core
void Skybox::reset(const std::vector<fs::path>& faces)
{
m_initialized = true;
int width; int height;
gl::textureParameter(m_handle, gl::TextureParameter::eBaseLevel, 0);
gl::textureParameter(m_handle, gl::TextureParameter::eMaxLevel, 8);
for (GLuint face = 0; face < faces.size(); face++)
m_texture = std::make_shared<Texture>(Texture::Target::eCubeMap, Texture::StoreFormat::eRGB8);
Texture::Parameters parameters;
parameters.base_level = 0;
parameters.max_level = 8;
parameters.filter_mag = gl::TextureFilterMag::eLinear;
parameters.filter_min = gl::TextureFilterMin::eLinearMipmapLinear;
parameters.wrap_r = gl::TextureWrapMode::eClampToEdge;
parameters.wrap_s = gl::TextureWrapMode::eClampToEdge;
parameters.wrap_t = gl::TextureWrapMode::eClampToEdge;
for (int face = 0; face < faces.size(); face++)
{
Log_Debug << "Face No " << face;
auto vec = images::load<unsigned char>(faces[face], width, height, 3);
images::flip(width, height, 3, vec.data());
gl::textureImage2D(m_handle, gl::TextureImageTarget2D(static_cast<int>(gl::TextureImageTarget2D::eCubeMapPosX) + face), 0, gl::TextureInternalFormat::eRGB, width, height, 0, gl::TextureFormat::eRGB, gl::Type::eUByte, vec.data());
Image<uint8_t> image(faces[face]);
image.flip();
m_texture->set(gl::ImageTarget(static_cast<int>(gl::ImageTarget::eCubeMapPosX) + face), image, true);
}
gl::textureParameter(m_handle, gl::TextureParameter::eMagFilter, gl::TextureFilterMag::eLinear);
gl::textureParameter(m_handle, gl::TextureParameter::eMinFilter, gl::TextureFilterMin::eLinearMipmapLinear);
gl::textureParameter(m_handle, gl::TextureParameter::eWrapS, gl::TextureWrapMode::eClampToEdge);
gl::textureParameter(m_handle, gl::TextureParameter::eWrapT, gl::TextureWrapMode::eClampToEdge);
gl::textureParameter(m_handle, gl::TextureParameter::eWrapR, gl::TextureWrapMode::eClampToEdge);
gl::generateTextureMipmap(m_handle);
m_texture->apply(parameters);
std::vector<math::Vertex> triangle_vertices
{
......@@ -98,35 +100,36 @@ namespace glare::core
unsigned Skybox::id() const
{
return m_handle;
return m_texture->id();
}
uint64_t Skybox::residentAddress() const
{
return m_resident_address;
return m_texture->textureAddress();
}
bool Skybox::resident() const
{
return m_resident_address != 0 && gl::isTextureHandleResident(m_resident_address);
return m_texture->textureResident();
//return m_resident_address != 0 && gl::isTextureHandleResident(m_resident_address);
}
uint64_t Skybox::makeResident() const
{
return m_texture->textureAddress();/*
if (!resident())
{
m_resident_address = gl::getTextureHandle(m_handle);
gl::makeTextureHandleResident(m_resident_address);
}
assert(resident());
return m_resident_address;
return m_resident_address;*/
}
void Skybox::makeNonResident() const
{
if (resident())
{
gl::makeTextureHandleNonResident(m_handle);
}
}
}
......@@ -8,6 +8,7 @@
#include <core/base/program.h>
#include <core/graph/component.h>
#include <core/rendering/batch_drawable.h>
#include <core/base/texture.h>
#include "mesh.h"
namespace glare::core
......@@ -49,6 +50,9 @@ namespace glare::core
private:
bool m_initialized = false;
std::shared_ptr<Texture> m_texture;
gl::handle::texture m_handle;
mutable uint64_t m_resident_address = 0;
......
......@@ -24,15 +24,59 @@ namespace glare::core
return to_float * float(std::numeric_limits<To>::max());
}
template<typename TBase> struct Image
struct Extents
{
using Dimensions = std::initializer_list<int>;
Extents() : Extents(-1, -1, -1) { dimensions = -1; }
Extents(int width)
: Extents(width, 1)
{
dimensions = 1;
}
Extents(int width, int height)
: Extents(width, height, 1)
{
dimensions = 2;
}
Extents(int width, int height, int depth)
: width(width), height(height), depth(depth)
{
dimensions = 3;
}
int linearize(Extents position)
{
return width*height*position.depth + height*position.height + position.width;
}
int size() const
{
return dimensions;
}
union
{
struct {
int width;
int height;
int depth;
};
int data[3];
};
private:
int dimensions;
};
template<typename TBase> struct Image
{
// You can either have a multisampled image without data.
explicit Image(Dimensions dimensions, int comp, int samples);
explicit Image(Extents extents, int comp, int samples);
// Or a single-sample image with data.
explicit Image(Dimensions dimensions, int comp, std::vector<TBase> data = std::vector<TBase>());
explicit Image(Extents extents, int comp, std::vector<TBase> data = std::vector<TBase>());
// Or load an image from HDD as single-sample image
explicit Image(const std::experimental::filesystem::path& path);
......@@ -41,7 +85,7 @@ namespace glare::core
void flip();
// return r,rg,rgb or rgba
std::tuple<TBase&, TBase&, TBase&, TBase&> operator[](Dimensions pixel);
std::tuple<TBase&, TBase&, TBase&, TBase&> operator[](Extents pixel);
int width() const;
int height() const;
......@@ -52,9 +96,7 @@ namespace glare::core
int dimensions() const;
private:
int m_width = 1;
int m_height = 1;
int m_depth = 1;
Extents m_extents;
int m_components = 0;
int m_samples = 0;
TBase m_ignore = 0;
......@@ -62,94 +104,81 @@ namespace glare::core
};
template <typename TBase>
Image<TBase>::Image(Dimensions dimensions, int comp, int samples): m_components(comp)
Image<TBase>::Image(Extents extents, int comp, int samples): m_extents(extents), m_components(comp), m_samples(samples)
{
m_width = dimensions.begin()[0];
m_height = dimensions.size() > 1 ? dimensions.begin()[1] : 1;
m_depth = dimensions.size() > 2 ? dimensions.begin()[2] : 1;
}
template <typename TBase>
Image<TBase>::Image(Dimensions dimensions, int comp, std::vector<TBase> data): m_components(comp), m_data(std::move(data))
Image<TBase>::Image(Extents extents, int comp, std::vector<TBase> data): m_extents(extents), m_components(comp), m_data(std::move(data))
{
m_width = dimensions.begin()[0];
m_height = dimensions.size() > 1 ? dimensions.begin()[1] : 1;
m_depth = dimensions.size() > 2 ? dimensions.begin()[2] : 1;
}
template <typename TBase>
Image<TBase>::Image(const std::experimental::filesystem::path& path)
{
m_depth = 1;
m_extents = Extents(1, 1);
if constexpr (std::is_same_v<TBase, uint8_t>)
{
uint8_t* raw_data = stb::stbi_load(path.string().c_str(), &m_width, &m_height, &m_components, 0);
uint8_t* raw_data = stb::stbi_load(path.string().c_str(), &m_extents.width, &m_extents.height, &m_components, 0);
if (!raw_data)
{
Log_Error << "Loading image failed! \"" << path << "\" not found.";
m_width = 0;
m_height = 0;
m_extents = Extents(0, 0);
m_components = 0;
return;
}
m_data = std::vector<uint8_t>(raw_data, raw_data + m_width * m_height * m_components);
m_data = std::vector<uint8_t>(raw_data, raw_data + m_extents.width * m_extents.height * m_components);
stb::stbi_image_free(raw_data);
}
else
{
float* raw_data = stb::stbi_loadf(path.string().c_str(), &m_width, &m_height, &m_components, 0);
float* raw_data = stb::stbi_loadf(path.string().c_str(), &m_extents.width, &m_extents.height, &m_components, 0);
if (!raw_data)
{
Log_Error << "Loading image failed! \"" << path << "\" not found.";
m_width = 0;
m_height = 0;
m_extents = Extents(0, 0);
m_components = 0;
return;
}
m_data = std::vector<TBase>(m_width * m_height * m_components);
m_data = std::vector<TBase>(m_extents.width * m_extents.height * m_components);
for (int i = 0; i < m_width * m_height * m_components; ++i)
for (int i = 0; i < m_extents.width * m_extents.height * m_components; ++i)
{
m_data[i] = static_cast<TBase>(conversionFactor<float, TBase>() * raw_data[i]);
}
stb::stbi_image_free(raw_data);
}
flip();
}
template <typename TBase>
std::tuple<TBase&, TBase&, TBase&, TBase&> Image<TBase>::operator[](Dimensions pixel)
std::tuple<TBase&, TBase&, TBase&, TBase&> Image<TBase>::operator[](Extents pixel)
{
// Don't allow texel fetches on MS images.
assert(m_samples == 0);
// Debug pixel size check.
assert(pixel.size() == 3 || (m_depth == 1 && (pixel.size() == 2 || (m_height == 1 && pixel.size() == 1))));
assert(pixel.size() == m_extents.size());
if (m_data.empty()) throw std::out_of_range("This texture has no data. Cannot fetch a pixel for an empty texture.");
glm::ivec3 position(0);
int pos = 0;
for (auto&& p : pixel)
{
position[pos++] = p;
}
glm::ivec3 position(pixel.width, pixel.height, pixel.depth);
// Debug bounds check.
assert(position.x >= 0 && position.x < m_width);
assert(position.y >= 0 && position.y < m_height);
assert(position.z >= 0 && position.z < m_depth);
assert(position.x >= 0 && position.x < m_extents.width);
assert(position.y >= 0 && position.y < m_extents.height);
assert(position.z >= 0 && position.z < m_extents.depth);
color<TBase> result(0);
for (int i = 0; i < m_components; ++i)
{
// 4D access :P
result[i] = m_data[m_width * m_height * m_components * position.z + m_width * m_components * position.y + m_components * position.x + i];
result[i] = m_data[m_extents.linearize(pixel)*m_components + i];
}
m_ignore = 0;
auto get = [this](const glm::ivec3 position, int offset) -> TBase&
{
return offset >= m_components ? m_ignore : m_data[m_width * m_height * m_components * position.z + m_width * m_components * position.y + m_components * position.x + offset];
return offset >= m_components ? m_ignore : m_data[m_extents.linearize(pixel)*m_components + offset];
};
return std::tie(get(position, 0), get(position, 1), get(position, 2), get(position, 3));
......@@ -164,45 +193,45 @@ namespace glare::core
//if is float and extension is png, convert!
if (path.extension() != ".hdr")
{
std::vector<uint8_t> converted(m_width * m_height * m_components);
std::vector<uint8_t> converted(m_extents.width * m_extents.height * m_components);
for (int i = 0; i < converted.size(); ++i)
{
converted[i] = static_cast<uint8_t>(conversionFactor<float, uint8_t>() * m_data[i]);
}
images::save(path, m_width, m_height, m_components, converted.data());
images::save(path, m_extents.width, m_extents.height, m_components, converted.data());
}
else
{
//Otherwise just save the floats.
images::save(path, m_width, m_height, m_components, m_data.data());
images::save(path, m_extents.width, m_extents.height, m_components, m_data.data());
}
}
else if constexpr(std::is_same_v<TBase, uint8_t>)
{
images::save(path, m_width, m_height, m_components, m_data.data());
images::save(path, m_extents.width, m_extents.height, m_components, m_data.data());
}
else
{
if (path.extension() == ".hdr")
{
std::vector<float> converted(m_width * m_height * m_components);
std::vector<float> converted(m_extents.width * m_extents.height * m_components);
for (int i = 0; i < converted.size(); ++i)
{
converted[i] = static_cast<float>(conversionFactor<TBase, float>() * m_data[i]);
}
images::save(path, m_width, m_height, m_components, converted.data());
images::save(path, m_extents.width, m_extents.height, m_components, converted.data());
}
else
{
std::vector<uint8_t> converted(m_width * m_height * m_components);
std::vector<uint8_t> converted(m_extents.width * m_extents.height * m_components);
for (int i = 0; i < converted.size(); ++i)
{
converted[i] = static_cast<uint8_t>(conversionFactor<TBase, uint8_t>() * m_data[i]);
}
images::save(path, m_width, m_height, m_components, converted.data());
images::save(path, m_extents.width, m_extents.height, m_components, converted.data());
}
}
flip();
......@@ -211,19 +240,19 @@ namespace glare::core
template <typename TBase>
int Image<TBase>::width() const
{
return m_width;
return m_extents.width;
}
template <typename TBase>
int Image<TBase>::height() const
{
return m_height;
return m_extents.height;
}
template <typename TBase>
int Image<TBase>::depth() const
{
return m_depth;
return m_extents.depth;
}
template <typename TBase>
......@@ -247,13 +276,13 @@ namespace glare::core
template <typename TBase>
void Image<TBase>::flip()
{
images::flip(static_cast<unsigned>(m_width), static_cast<unsigned>(m_height), static_cast<int>(m_components), m_data.data());
images::flip(static_cast<unsigned>(m_extents.width), static_cast<unsigned>(m_extents.height), static_cast<int>(m_components), m_data.data());
}
template <typename TBase>
int Image<TBase>::dimensions() const
{
return 1 + (m_height != 1) + (m_height != 1 && m_depth != 1);
return m_extents.size();
}
}
......
......@@ -7,7 +7,7 @@
namespace glare::raytrace
{
Pathtracer::Pathtracer(std::shared_ptr<core::SceneNode> graph_root, RayGenType ray_generator)
: Pathtracer(std::make_shared<SceneCollector>(graph_root), ray_generator)
: Pathtracer(graph_root ? std::make_shared<SceneCollector>(graph_root) : nullptr, ray_generator)
{
}
......@@ -97,8 +97,8 @@ namespace glare::raytrace
m_trace_buffer.reserve<Trace>(width * height, gl::BufferUsage::eDynamicCopy);
m_render_target->set(core::Texture::SubTarget::e2D, core::Image<float>({ static_cast<int>(width), static_cast<int>(height) }, 4));
m_color_storage->set(core::Texture::SubTarget::e2D, core::Image<float>({ static_cast<int>(width), static_cast<int>(height) }, 4));
m_render_target->set(core::Texture::SubTarget::e2D, core::Image<float>({ static_cast<int>(1440), static_cast<int>(900) }, 4));
m_color_storage->set(core::Texture::SubTarget::e2D, core::Image<float>({ static_cast<int>(1440), static_cast<int>(900) }, 4));
m_render_shader->uniform("u_render_target", m_render_target->imageAddress(gl::Access::eReadWrite));
m_render_shader->uniform("u_color_store", m_color_storage->imageAddress(gl::Access::eReadWrite));
......@@ -144,6 +144,8 @@ namespace glare::raytrace
// If it's not manually initialized via the GUI button, initialize the Pathtracer here.
if (!m_collector)
reload(node);
else
m_collector->collect(node);
static const std::shared_ptr<core::TextureRenderer> texture_renderer = core::DefaultTextureRenderers::makeSimpleRenderer();
texture_renderer->draw(render(core::Context::current().window().getWidth(), core::Context::current().window().getHeight()));
......
......@@ -569,13 +569,13 @@ namespace gl
{
case gl::ImageTargetMultisample::e2DMultisample:
case gl::ImageTargetMultisample::e2DMultisampleProxy:
assert(dimensions.size() == 2);
assert(dimensions.size() >= 2);
gl::textureImage2DMultisample(texture, gl::TextureImageTargetMultisample2D(target), samples, fmt, dimensions.begin()[0], dimensions.begin()[1], fixed_sample_locations);
break;
case gl::ImageTargetMultisample::e2DArrayMultisample:
case gl::ImageTargetMultisample::e2DArrayMultisampleProxy:
assert(dimensions.size() == 3);
assert(dimensions.size() >= 3);
gl::textureImage3DMultisample(texture, gl::TextureImageTargetMultisample3D(target), samples, fmt, dimensions.begin()[0], dimensions.begin()[1], dimensions.begin()[2], fixed_sample_locations);
break;
......