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

added implicit Image cast

parent fb0b8400
......@@ -57,7 +57,7 @@ int main(int argc, char* argv[])
core::Context::current().callbacks().addKeyDownCallback("main_application", keyPress);
// Create a skybox from cube map.
core::Context::current().skybox()->reset(core::Skybox::collectFilesFrom(skybox_files_path));
core::Context::current().skybox()->reset(skybox_files_path);
// Load the pre-determined startup scene
loadScene(startup_scene_path, 1.f);
......
#include "texture.h"
namespace glare::core
{
Texture::Texture(Target target, StoreFormat store_format)
: m_target(target), m_handle(std::move(target)), m_format(store_format)
{ }
const Texture::Parameters& Texture::parameters() const
{
return m_latest_parameters;
}
void Texture::apply(Parameters parameters)
{
m_latest_parameters = std::move(parameters);
float anisotropy = m_latest_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_latest_parameters.wrap_r);
gl::textureParameter(m_handle, gl::TextureParameter::eWrapS, m_latest_parameters.wrap_s);
gl::textureParameter(m_handle, gl::TextureParameter::eWrapT, m_latest_parameters.wrap_t);
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::eBaseLevel, m_latest_parameters.base_level);
gl::textureParameter(m_handle, gl::TextureParameter::eMaxLevel, m_latest_parameters.max_level);
gl::generateTextureMipmap(m_handle);
}
unsigned Texture::id() const
{
return m_handle;
}
bool Texture::textureResident() const
{
return m_texture_address != 0 && gl::isTextureHandleResident(m_texture_address);
}
bool Texture::imageResident() const
{
return m_image_address != 0 && gl::isImageHandleResident(m_image_address);
}
uint64_t Texture::textureAddress() const
{
if (!textureResident())
{
m_texture_address = gl::getTextureHandle(m_handle);
gl::makeTextureHandleResident(m_texture_address);
}
assert(textureResident());
return m_texture_address;
}
uint64_t Texture::imageAddress(gl::Access access) const
{
if (!imageResident())
{
m_image_address = gl::getImageHandle(m_handle, 0, false, 0, gl::ImageUnitFormat(m_format));
gl::makeImageHandleResident(m_image_address, access);
}
assert(imageResident());
return m_image_address;
}
int Texture::samples() const
{
int s;
gl::getTextureLevelParameteriv(m_handle, 0, gl::TextureLevelParameter::eSamples, &s);
return s;
}
gl::Type Texture::type() const
{
gl::Type type;
gl::getInternalFormatParameter(m_target, m_format, gl::TextureInternalFormatParameter::eTextureImageType, reinterpret_cast<int*>(&type));
return type;
}
int Texture::width() const
{
int width;
gl::getTextureLevelParameteriv(m_handle, 0, gl::TextureLevelParameter::eWidth, &width);
return width;
}
int Texture::height() const
{
int height;
gl::getTextureLevelParameteriv(m_handle, 0, gl::TextureLevelParameter::eHeight, &height);
return height;
}
int Texture::depth() const
{
int depth;
gl::getTextureLevelParameteriv(m_handle, 0, gl::TextureLevelParameter::eDepth, &depth);
return depth;
}
}
\ No newline at end of file
......@@ -34,288 +34,35 @@ namespace glare::core
};
// General initialization
Texture(Target target, StoreFormat store_format)
: m_target(target), m_handle(std::move(target)), m_format(store_format)
{
}
Texture(Target target, StoreFormat store_format);
// Direct initialization for either 1D, 2D or 3D target.
template<typename T> Texture(const Image<T>& image)
: Texture([&image]() {
switch (image.dimensions())
{
case 1: return Target::e1D;
case 2: return Target::e2D;
case 3: return Target::e3D;
default: return Target::e2D;
}
}(), getFormat(image))
{
switch (m_target)
{
case Target::e1D:
set(SubTarget::e1D, image, m_latest_parameters);
break;
case Target::e2D:
set(SubTarget::e2D, image, m_latest_parameters);
break;
case Target::e3D:
set(SubTarget::e3D, image, m_latest_parameters);
break;
default: throw std::invalid_argument("Target not defined as 1D, 2D or 3D. How exactly did you manage to come to this point???");
}
}
template<typename T>
Image<T> get()
{
if (m_target != gl::TextureType::e2D || m_components == -1)
{
throw std::invalid_argument("You cannot download this texture.");
}
int texture_width = width();
int texture_height = height();
int components = m_components;
auto texture_type = type();
int type_size = static_cast<int>([](gl::Type type)
{
switch (type)
{
case gl::Type::eByte:
return sizeof(int8_t);
case gl::Type::eUByte:
case gl::Type::eUInt_8_8_8_8:
case gl::Type::eUInt_8_8_8_8_rev:
return sizeof(uint8_t);
case gl::Type::eInt:
return sizeof(int32_t);
case gl::Type::eUInt:
return sizeof(uint32_t);
case gl::Type::eFloat:
return sizeof(float);
default: throw std::invalid_argument("Texture format not valid.");
}
}(texture_type));
gl::TextureFormat texture_format = [](int components, gl::Type type)
{
switch (components)
{
case 1: if (type == gl::Type::eInt || type == gl::Type::eUInt) return gl::TextureFormat::eRedInt;
else return gl::TextureFormat::eRed;
case 2: if (type == gl::Type::eInt || type == gl::Type::eUInt) return gl::TextureFormat::eRGInt;
else return gl::TextureFormat::eRG;
case 3: if (type == gl::Type::eInt || type == gl::Type::eUInt) return gl::TextureFormat::eRGBInt;
else return gl::TextureFormat::eRGB;
case 4: if (type == gl::Type::eInt || type == gl::Type::eUInt) return gl::TextureFormat::eRGBAInt;
else return gl::TextureFormat::eRGBA;
default: throw std::invalid_argument("Texture format not valid.");
}
}(components, texture_type);
std::vector<uint8_t> data(texture_width * texture_height * components * type_size);
std::vector<T> converted(texture_width*texture_height*components);
gl::getTextureImage(m_handle, 0, texture_format, texture_type, data.size(), data.data());
for (int i = 0; i < texture_width*texture_height*components; ++i)
{
switch (texture_type)
{
case gl::Type::eByte:
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);
break;
case gl::Type::eShort:
converted[i] = clampConvert<int16_t, T>(data.data(), i);
break;
case gl::Type::eUShort:
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()));
break;
case gl::Type::eUInt:
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] = clampConvert<float, T>(data.data(), i);
break;
default: throw std::invalid_argument("Texture format not valid.");
}
}
return Image<T>({ texture_width, texture_height }, components, converted);
}
template<typename T> void set(SubTargetMultisample t, const Image<T>& image)
{
set(t, image, m_latest_parameters);
}
// up until the set methods, no openGL is needed yet.
// Upload an image
template<typename T> void set(SubTargetMultisample t, const Image<T>& image, Parameters parameters)
{
assert(image.samples() != 0);
m_components = image.components();
gl::pixelStorei(gl::PixelStoreAlignment::eUnpack, 1);
gl::textureImage(m_handle, t, image.samples(), m_format, { image.width(), image.height(), image.depth() });
apply(std::move(parameters));
}
template<typename T> void set(SubTarget t, const Image<T>& image)
{
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), false);
}
// Upload an image
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.
assert(image.samples() == 0);
gl::TextureFormat texture_format = [](int components, StoreFormat format)
{
switch (components)
{
case 1: if constexpr(std::is_same_v<T, int32_t> || std::is_same_v<T, uint32_t>) return gl::TextureFormat::eRedInt;
else return !(format == StoreFormat::eDepthComponent32Float || format == StoreFormat::eDepthComponent) ? gl::TextureFormat::eRed : gl::TextureFormat::eDepthComponent;
case 2: if constexpr(std::is_same_v<T, int32_t> || std::is_same_v<T, uint32_t>) return gl::TextureFormat::eRGInt;
else return !(format == StoreFormat::eDepthComponent32Float || format == StoreFormat::eDepthComponent) ? gl::TextureFormat::eRG : gl::TextureFormat::eDepthComponent;
case 3: if constexpr(std::is_same_v<T, int32_t> || std::is_same_v<T, uint32_t>) return gl::TextureFormat::eRGBInt;
else return !(format == StoreFormat::eDepthComponent32Float || format == StoreFormat::eDepthComponent) ? gl::TextureFormat::eRGB : gl::TextureFormat::eDepthComponent;
case 4: if constexpr(std::is_same_v<T, int32_t> || std::is_same_v<T, uint32_t>) return gl::TextureFormat::eRGBAInt;
else return !(format == StoreFormat::eDepthComponent32Float || format == StoreFormat::eDepthComponent) ? gl::TextureFormat::eRGBA : gl::TextureFormat::eDepthComponent;
default: throw std::invalid_argument("Texture format not valid.");
}
}(image.components(), m_format);
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());
if (!no_apply)
apply(std::move(parameters));
}
const Parameters& parameters() const
{
return m_latest_parameters;
}
void apply(Parameters parameters)
{
m_latest_parameters = std::move(parameters);
float anisotropy = m_latest_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_latest_parameters.wrap_r);
gl::textureParameter(m_handle, gl::TextureParameter::eWrapS, m_latest_parameters.wrap_s);
gl::textureParameter(m_handle, gl::TextureParameter::eWrapT, m_latest_parameters.wrap_t);
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::eBaseLevel, m_latest_parameters.base_level);
gl::textureParameter(m_handle, gl::TextureParameter::eMaxLevel, m_latest_parameters.max_level);
gl::generateTextureMipmap(m_handle);
}
unsigned id() const
{
return m_handle;
}
bool textureResident() const
{
return m_texture_address != 0 && gl::isTextureHandleResident(m_texture_address);
}
bool imageResident() const
{
return m_image_address != 0 && gl::isImageHandleResident(m_image_address);
}
uint64_t textureAddress() const
{
if (!textureResident())
{
m_texture_address = gl::getTextureHandle(m_handle);
gl::makeTextureHandleResident(m_texture_address);
}
assert(textureResident());
return m_texture_address;
}
template<typename T> Texture(const Image<T>& image);
uint64_t imageAddress(gl::Access access) const
{
if (!imageResident())
{
m_image_address = gl::getImageHandle(m_handle, 0, false, 0, gl::ImageUnitFormat(m_format));
gl::makeImageHandleResident(m_image_address, access);
}
assert(imageResident());
return m_image_address;
}
template<typename T> Image<T> get() const;
int samples() const
{
int s;
gl::getTextureLevelParameteriv(m_handle, 0, gl::TextureLevelParameter::eSamples, &s);
return s;
}
template<typename T> void set(SubTargetMultisample t, const Image<T>& image);
template<typename T> void set(SubTargetMultisample t, const Image<T>& image, Parameters parameters);
gl::Type type() const
{
gl::Type type;
gl::getInternalFormatParameter(m_target, m_format, gl::TextureInternalFormatParameter::eTextureImageType, reinterpret_cast<int*>(&type));
return type;
}
template<typename T> void set(SubTarget t, const Image<T>& image);
template<typename T> void set(SubTarget t, const Image<T>& image, bool no_apply);
template<typename T> void set(SubTarget t, const Image<T>& image, Parameters parameters);
template<typename T> void set(SubTarget t, int level, const Image<T>& image, Parameters parameters, bool no_apply);
int width() const
{
int width;
gl::getTextureLevelParameteriv(m_handle, 0, gl::TextureLevelParameter::eWidth, &width);
return width;
}
void apply(Parameters parameters);
int height() const
{
int height;
gl::getTextureLevelParameteriv(m_handle, 0, gl::TextureLevelParameter::eHeight, &height);
return height;
}
bool textureResident() const;
bool imageResident() const;
uint64_t textureAddress() const;
uint64_t imageAddress(gl::Access access) const;
int depth() const
{
int depth;
gl::getTextureLevelParameteriv(m_handle, 0, gl::TextureLevelParameter::eDepth, &depth);
return depth;
}
const Parameters& parameters() const;
unsigned id() const;
gl::Type type() const;
int width() const;
int height() const;
int depth() const;
int samples() const;
private:
template<typename From, typename To>
......@@ -391,10 +138,256 @@ namespace glare::core
StoreFormat m_format;
Parameters m_latest_parameters;
int m_width = 0;
int m_height = 0;
int m_depth = 0;
gl::handle::texture m_handle;
mutable uint64_t m_texture_address = 0;
mutable uint64_t m_image_address = 0;
};
template<typename T> Texture::Texture(const Image<T>& image)
: Texture([&image]() {
switch (image.dimensions())
{
case 1: return Target::e1D;
case 2: return Target::e2D;
case 3: return Target::e3D;
default: return Target::e2D;
}
}(), getFormat(image))
{
switch (m_target)
{
case Target::e1D:
set(SubTarget::e1D, image, m_latest_parameters);
break;
case Target::e2D:
set(SubTarget::e2D, image, m_latest_parameters);
break;
case Target::e3D:
set(SubTarget::e3D, image, m_latest_parameters);
break;
default: throw std::invalid_argument("Target not defined as 1D, 2D or 3D. How exactly did you manage to come to this point???");
}
}
template<typename T> Image<T> Texture::get() const
{
if (m_target != gl::TextureType::e2D || m_components == -1)
{
throw std::invalid_argument("You cannot download this texture.");
}
int texture_width = width();
int texture_height = height();
int components = m_components;
auto texture_type = type();
gl::TextureFormat texture_format = [](int components, gl::Type type)
{
switch (components)
{
case 1: if (type == gl::Type::eInt || type == gl::Type::eUInt) return gl::TextureFormat::eRedInt;
else return gl::TextureFormat::eRed;
case 2: if (type == gl::Type::eInt || type == gl::Type::eUInt) return gl::TextureFormat::eRGInt;
else return gl::TextureFormat::eRG;
case 3: if (type == gl::Type::eInt || type == gl::Type::eUInt) return gl::TextureFormat::eRGBInt;
else return gl::TextureFormat::eRGB;
case 4: if (type == gl::Type::eInt || type == gl::Type::eUInt) return gl::TextureFormat::eRGBAInt;
else return gl::TextureFormat::eRGBA;
default: throw std::invalid_argument("Texture format not valid.");
}
}(components, texture_type);
switch (texture_type)
{
case gl::Type::eByte:
{
Image<int8_t> image({ texture_width, texture_height }, components, std::vector<int8_t>(texture_width * texture_height * components));
gl::getTextureImage(m_handle, 0, texture_format, texture_type, image.data().size() * sizeof(int8_t), const_cast<int8_t*>(image.data().data()));
return image;
}
case gl::Type::eUByte:
case gl::Type::eUInt_8_8_8_8:
case gl::Type::eUInt_8_8_8_8_rev:
{
Image<uint8_t> image({ texture_width, texture_height }, components, std::vector<uint8_t>(texture_width * texture_height * components));
gl::getTextureImage(m_handle, 0, texture_format, texture_type, image.data().size() * sizeof(uint8_t), const_cast<uint8_t*>(image.data().data()));
return image;
}
case gl::Type::eShort:
{
Image<int16_t> image({ texture_width, texture_height }, components, std::vector<int16_t>(texture_width * texture_height * components));
gl::getTextureImage(m_handle, 0, texture_format, texture_type, image.data().size() * sizeof(int16_t), const_cast<int16_t*>(image.data().data()));
return image;
}
case gl::Type::eUShort:
{
Image<uint16_t> image({ texture_width, texture_height }, components, std::vector<uint16_t>(texture_width * texture_height * components));
gl::getTextureImage(m_handle, 0, texture_format, texture_type, image.data().size() * sizeof(uint16_t), const_cast<uint16_t*>(image.data().data()));
return image;
}
case gl::Type::eInt:
{
Image<int32_t> image({ texture_width, texture_height }, components, std::vector<int32_t>(texture_width * texture_height * components));
gl::getTextureImage(m_handle, 0, texture_format, texture_type, image.data().size() * sizeof(int32_t), const_cast<int32_t*>(image.data().data()));
return image;
}
case gl::Type::eUInt:
{
Image<uint32_t> image({ texture_width, texture_height }, components, std::vector<uint32_t>(texture_width * texture_height * components));
gl::getTextureImage(m_handle, 0, texture_format, texture_type, image.data().size() * sizeof(uint32_t), const_cast<uint32_t*>(image.data().data()));
return image;
}
case gl::Type::eFloat:
{
Image<float> image({ texture_width, texture_height }, components, std::vector<float>(texture_width * texture_height * components));
gl::getTextureImage(m_handle, 0, texture_format, texture_type, image.data().size() * sizeof(float), const_cast<float*>(image.data().data()));
return image;
}
default: throw std::invalid_argument("Texture format not valid.");
}
//int type_size = static_cast<int>([](gl::Type type)
//{
// switch (type)
// {
// case gl::Type::eByte:
// return sizeof(int8_t);
// case gl::Type::eUByte:
// case gl::Type::eUInt_8_8_8_8:
// case gl::Type::eUInt_8_8_8_8_rev:
// return sizeof(uint8_t);
// case gl::Type::eInt:
// return sizeof(int32_t);
// case gl::Type::eUInt:
// return sizeof(uint32_t);
// case gl::Type::eFloat:
// return sizeof(float);
// default: throw std::invalid_argument("Texture format not valid.");
// }
//}(texture_type));
//gl::TextureFormat texture_format = [](int components, gl::Type type)
//{
// switch (components)
// {
// case 1: if (type == gl::Type::eInt || type == gl::Type::eUInt) return gl::TextureFormat::eRedInt;
// else return gl::TextureFormat::eRed;
// case 2: if (type == gl::Type::eInt || type == gl::Type::eUInt) return gl::TextureFormat::eRGInt;
// else return gl::TextureFormat::eRG;
// case 3: if (type == gl::Type::eInt || type == gl::Type::eUInt) return gl::TextureFormat::eRGBInt;
// else return gl::TextureFormat::eRGB;
// case 4: if (type == gl::Type::eInt || type == gl::Type::eUInt) return gl::TextureFormat::eRGBAInt;
// else return gl::TextureFormat::eRGBA;
// default: throw std::invalid_argument("Texture format not valid.");
// }
//}(components, texture_type);
//std::vector<uint8_t> data(texture_width * texture_height * components * type_size);
//std::vector<T> converted(texture_width*texture_height*components);
//gl::getTextureImage(m_handle, 0, texture_format, texture_type, data.size(), data.data());
//for (int i = 0; i < texture_width*texture_height*components; ++i)
//{
// switch (texture_type)
// {
// case gl::Type::eByte:
// converted[i] = clampConvert<int8_t, T>(data.data(), i);