Refactor the way resources are loaded (#191)

* WIP

* WIP

* Font works

* WIP: Only Music remains

* Looks like it's working

* Fix oopsie

* Core/ObjectRef: Add cast functions

* Update ChangeLog.md

* Audio/SoundStream: Make sound stream thread-safe
This commit is contained in:
Jérôme Leclercq
2018-10-28 01:53:11 +02:00
committed by GitHub
parent fa7cbc21e5
commit ed46c87781
64 changed files with 1058 additions and 1071 deletions

View File

@@ -106,7 +106,7 @@ namespace Nz
for (unsigned int i = 0; i < levels.size(); ++i)
{
unsigned int pixelsPerFace = width * height;
levels[i].reset(new UInt8[pixelsPerFace * depth * PixelFormat::GetBytesPerPixel(newFormat)]);
levels[i] = std::make_unique<UInt8[]>(pixelsPerFace * depth * PixelFormat::GetBytesPerPixel(newFormat));
UInt8* dst = levels[i].get();
UInt8* src = m_sharedImage->levels[i].get();
@@ -143,29 +143,13 @@ namespace Nz
return true;
}
void Image::Copy(const Image& source, const Boxui& srcBox, const Vector3ui& dstPos)
void Image::Copy(const Image* source, const Boxui& srcBox, const Vector3ui& dstPos)
{
#if NAZARA_UTILITY_SAFE
if (m_sharedImage == &emptyImage)
{
NazaraError("Image must be valid");
return;
}
NazaraAssert(IsValid(), "Invalid image");
NazaraAssert(source && source->IsValid(), "Invalid source image");
NazaraAssert(source->GetFormat() == m_sharedImage->format, "Image formats don't match");
if (!source.IsValid())
{
NazaraError("Source image must be valid");
return;
}
if (source.GetFormat() != m_sharedImage->format)
{
NazaraError("Source image format does not match destination image format");
return;
}
#endif
const UInt8* srcPtr = source.GetConstPixels(srcBox.x, srcBox.y, srcBox.z);
const UInt8* srcPtr = source->GetConstPixels(srcBox.x, srcBox.y, srcBox.z);
#if NAZARA_UTILITY_SAFE
if (!srcPtr)
{
@@ -177,7 +161,7 @@ namespace Nz
UInt8 bpp = PixelFormat::GetBytesPerPixel(m_sharedImage->format);
UInt8* dstPtr = GetPixelPtr(m_sharedImage->levels[0].get(), bpp, dstPos.x, dstPos.y, dstPos.z, m_sharedImage->width, m_sharedImage->height);
Copy(dstPtr, srcPtr, m_sharedImage->format, srcBox.width, srcBox.height, srcBox.depth, m_sharedImage->width, m_sharedImage->height, source.GetWidth(), source.GetHeight());
Copy(dstPtr, srcPtr, m_sharedImage->format, srcBox.width, srcBox.height, srcBox.depth, m_sharedImage->width, m_sharedImage->height, source->GetWidth(), source->GetHeight());
}
bool Image::Create(ImageType type, PixelFormatType format, unsigned int width, unsigned int height, unsigned int depth, UInt8 levelCount)
@@ -271,7 +255,7 @@ namespace Nz
// Cette allocation est protégée car sa taille dépend directement de paramètres utilisateurs
try
{
levels[i].reset(new UInt8[PixelFormat::ComputeSize(format, w, h, d)]);
levels[i] = std::make_unique<UInt8[]>(PixelFormat::ComputeSize(format, w, h, d));
if (w > 1)
w >>= 1;
@@ -337,12 +321,12 @@ namespace Nz
// Les images 3D et cubemaps sont stockés de la même façon
unsigned int depth = (m_sharedImage->type == ImageType_Cubemap) ? 6 : m_sharedImage->depth;
for (unsigned int i = 0; i < levels.size(); ++i)
for (auto & level : levels)
{
std::size_t size = PixelFormat::ComputeSize(m_sharedImage->format, width, height, depth);
levels[i].reset(new UInt8[size]);
level = std::make_unique<UInt8[]>(size);
UInt8* ptr = levels[i].get();
UInt8* ptr = level.get();
UInt8* end = &ptr[size];
while (ptr < end)
@@ -514,9 +498,9 @@ namespace Nz
unsigned int width = m_sharedImage->width;
unsigned int height = m_sharedImage->height;
unsigned int depth = (m_sharedImage->type == ImageType_Cubemap) ? 6 : m_sharedImage->depth;
for (unsigned int level = 0; level < m_sharedImage->levels.size(); ++level)
for (auto& level : m_sharedImage->levels)
{
UInt8* ptr = m_sharedImage->levels[level].get();
UInt8* ptr = level.get();
if (!PixelFormat::Flip(PixelFlipping_Horizontally, m_sharedImage->format, width, height, depth, ptr, ptr))
{
NazaraError("Failed to flip image");
@@ -557,9 +541,9 @@ namespace Nz
unsigned int width = m_sharedImage->width;
unsigned int height = m_sharedImage->height;
unsigned int depth = (m_sharedImage->type == ImageType_Cubemap) ? 6 : m_sharedImage->depth;
for (unsigned int level = 0; level < m_sharedImage->levels.size(); ++level)
for (auto& level : m_sharedImage->levels)
{
UInt8* ptr = m_sharedImage->levels[level].get();
UInt8* ptr = level.get();
if (!PixelFormat::Flip(PixelFlipping_Vertically, m_sharedImage->format, width, height, depth, ptr, ptr))
{
NazaraError("Failed to flip image");
@@ -805,7 +789,7 @@ namespace Nz
return Vector3ui(GetLevelSize(m_sharedImage->width, level), GetLevelSize(m_sharedImage->height, level), GetLevelSize(m_sharedImage->depth, level));
}
ImageType Image::GetType() const
ImageType Image::GetType() const
{
return m_sharedImage->type;
}
@@ -865,67 +849,48 @@ namespace Nz
return m_sharedImage != &emptyImage;
}
bool Image::LoadFromFile(const String& filePath, const ImageParams& params)
{
return ImageLoader::LoadFromFile(this, filePath, params);
}
bool Image::LoadFromMemory(const void* data, std::size_t size, const ImageParams& params)
{
return ImageLoader::LoadFromMemory(this, data, size, params);
}
bool Image::LoadFromStream(Stream& stream, const ImageParams& params)
{
return ImageLoader::LoadFromStream(this, stream, params);
}
// LoadArray
bool Image::LoadArrayFromFile(const String& filePath, const ImageParams& imageParams, const Vector2ui& atlasSize)
ImageRef Image::LoadArrayFromFile(const String& filePath, const ImageParams& imageParams, const Vector2ui& atlasSize)
{
Image image;
if (!image.LoadFromFile(filePath, imageParams))
ImageRef image = Image::LoadFromFile(filePath, imageParams);
if (!image)
{
NazaraError("Failed to load image");
return false;
return nullptr;
}
return LoadArrayFromImage(image, atlasSize);
}
bool Image::LoadArrayFromImage(const Image& image, const Vector2ui& atlasSize)
ImageRef Image::LoadArrayFromImage(const Image* image, const Vector2ui& atlasSize)
{
#if NAZARA_UTILITY_SAFE
if (!image.IsValid())
{
NazaraError("Image must be valid");
return false;
}
NazaraAssert(image && image->IsValid(), "Invalid image");
#if NAZARA_UTILITY_SAFE
if (atlasSize.x == 0)
{
NazaraError("Atlas width must be over zero");
return false;
return nullptr;
}
if (atlasSize.y == 0)
{
NazaraError("Atlas height must be over zero");
return false;
return nullptr;
}
#endif
ImageType type = image.GetType();
ImageType type = image->GetType();
#if NAZARA_UTILITY_SAFE
if (type != ImageType_1D && type != ImageType_2D)
{
NazaraError("Image type not handled (0x" + String::Number(type, 16) + ')');
return false;
return nullptr;
}
#endif
Vector2ui imageSize(image.GetWidth(), image.GetHeight());
Vector2ui imageSize(image->GetWidth(), image->GetHeight());
if (imageSize.x % atlasSize.x != 0)
{
@@ -941,82 +906,85 @@ namespace Nz
unsigned int layerCount = atlasSize.x*atlasSize.y;
ImageRef arrayImage = New();
// Selon le type de l'image de base, on va créer un array d'images 2D ou 1D
if (type == ImageType_2D)
Create(ImageType_2D_Array, image.GetFormat(), faceSize.x, faceSize.y, layerCount);
arrayImage->Create(ImageType_2D_Array, image->GetFormat(), faceSize.x, faceSize.y, layerCount);
else
Create(ImageType_1D_Array, image.GetFormat(), faceSize.x, layerCount);
arrayImage->Create(ImageType_1D_Array, image->GetFormat(), faceSize.x, layerCount);
if (!arrayImage->IsValid())
{
NazaraError("Failed to create image");
return nullptr;
}
unsigned int layer = 0;
for (unsigned int j = 0; j < atlasSize.y; ++j)
for (unsigned int i = 0; i < atlasSize.x; ++i)
Copy(image, Rectui(i*faceSize.x, j*faceSize.y, faceSize.x, faceSize.y), Vector3ui(0, 0, layer++));
arrayImage->Copy(image, Rectui(i*faceSize.x, j*faceSize.y, faceSize.x, faceSize.y), Vector3ui(0, 0, layer++));
return true;
return arrayImage;
}
bool Image::LoadArrayFromMemory(const void* data, std::size_t size, const ImageParams& imageParams, const Vector2ui& atlasSize)
ImageRef Image::LoadArrayFromMemory(const void* data, std::size_t size, const ImageParams& imageParams, const Vector2ui& atlasSize)
{
Image image;
if (!image.LoadFromMemory(data, size, imageParams))
ImageRef image = Image::LoadFromMemory(data, size, imageParams);
if (!image)
{
NazaraError("Failed to load image");
return false;
return nullptr;
}
return LoadArrayFromImage(image, atlasSize);
}
bool Image::LoadArrayFromStream(Stream& stream, const ImageParams& imageParams, const Vector2ui& atlasSize)
ImageRef Image::LoadArrayFromStream(Stream& stream, const ImageParams& imageParams, const Vector2ui& atlasSize)
{
Image image;
if (!image.LoadFromStream(stream, imageParams))
ImageRef image = Image::LoadFromStream(stream, imageParams);
if (!image)
{
NazaraError("Failed to load image");
return false;
return nullptr;
}
return LoadArrayFromImage(image, atlasSize);
}
bool Image::LoadCubemapFromFile(const String& filePath, const ImageParams& imageParams, const CubemapParams& cubemapParams)
ImageRef Image::LoadCubemapFromFile(const String& filePath, const ImageParams& imageParams, const CubemapParams& cubemapParams)
{
Image image;
if (!image.LoadFromFile(filePath, imageParams))
ImageRef image = Image::LoadFromFile(filePath, imageParams);
if (!image)
{
NazaraError("Failed to load image");
return false;
return nullptr;
}
return LoadCubemapFromImage(image, cubemapParams);
}
bool Image::LoadCubemapFromImage(const Image& image, const CubemapParams& params)
ImageRef Image::LoadCubemapFromImage(const Image* image, const CubemapParams& params)
{
#if NAZARA_UTILITY_SAFE
if (!image.IsValid())
{
NazaraError("Image must be valid");
return false;
}
NazaraAssert(image && image->IsValid(), "Invalid image");
ImageType type = image.GetType();
#if NAZARA_UTILITY_SAFE
ImageType type = image->GetType();
if (type != ImageType_2D)
{
NazaraError("Image type not handled (0x" + String::Number(type, 16) + ')');
return false;
return nullptr;
}
#endif
unsigned int width = image.GetWidth();
unsigned int height = image.GetHeight();
unsigned int width = image->GetWidth();
unsigned int height = image->GetHeight();
unsigned int faceSize = (params.faceSize == 0) ? std::max(width, height)/4 : params.faceSize;
// Sans cette vérification, celles des rectangles pourrait réussir via un overflow
if (width < faceSize || height < faceSize)
{
NazaraError("Image is too small for this face size");
return false;
return nullptr;
}
// Calcul et vérification des surfaces
@@ -1027,84 +995,80 @@ namespace Nz
if (backPos.x > limitX || backPos.y > limitY)
{
NazaraError("Back rectangle is out of image");
return false;
return nullptr;
}
Vector2ui downPos = params.downPosition * faceSize;
if (downPos.x > limitX || downPos.y > limitY)
{
NazaraError("Down rectangle is out of image");
return false;
return nullptr;
}
Vector2ui forwardPos = params.forwardPosition * faceSize;
if (forwardPos.x > limitX || forwardPos.y > limitY)
{
NazaraError("Forward rectangle is out of image");
return false;
return nullptr;
}
Vector2ui leftPos = params.leftPosition * faceSize;
if (leftPos.x > limitX || leftPos.y > limitY)
{
NazaraError("Left rectangle is out of image");
return false;
return nullptr;
}
Vector2ui rightPos = params.rightPosition * faceSize;
if (rightPos.x > limitX || rightPos.y > limitY)
{
NazaraError("Right rectangle is out of image");
return false;
return nullptr;
}
Vector2ui upPos = params.upPosition * faceSize;
if (upPos.x > limitX || upPos.y > limitY)
{
NazaraError("Up rectangle is out of image");
return false;
return nullptr;
}
Create(ImageType_Cubemap, image.GetFormat(), faceSize, faceSize);
#ifdef NAZARA_DEBUG
// Les paramètres sont valides, que Create ne fonctionne pas relèverait d'un bug
if (m_sharedImage == &emptyImage)
ImageRef cubemap = New();
if (!cubemap->Create(ImageType_Cubemap, image->GetFormat(), faceSize, faceSize))
{
NazaraInternalError("Failed to create cubemap");
return false;
NazaraError("Failed to create cubemap");
return nullptr;
}
#endif
Copy(image, Rectui(backPos.x, backPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_NegativeZ));
Copy(image, Rectui(downPos.x, downPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_NegativeY));
Copy(image, Rectui(forwardPos.x, forwardPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_PositiveZ));
Copy(image, Rectui(leftPos.x, leftPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_NegativeX));
Copy(image, Rectui(rightPos.x, rightPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_PositiveX));
Copy(image, Rectui(upPos.x, upPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_PositiveY));
cubemap->Copy(image, Rectui(backPos.x, backPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_NegativeZ));
cubemap->Copy(image, Rectui(downPos.x, downPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_NegativeY));
cubemap->Copy(image, Rectui(forwardPos.x, forwardPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_PositiveZ));
cubemap->Copy(image, Rectui(leftPos.x, leftPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_NegativeX));
cubemap->Copy(image, Rectui(rightPos.x, rightPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_PositiveX));
cubemap->Copy(image, Rectui(upPos.x, upPos.y, faceSize, faceSize), Vector3ui(0, 0, CubemapFace_PositiveY));
return true;
return cubemap;
}
bool Image::LoadCubemapFromMemory(const void* data, std::size_t size, const ImageParams& imageParams, const CubemapParams& cubemapParams)
ImageRef Image::LoadCubemapFromMemory(const void* data, std::size_t size, const ImageParams& imageParams, const CubemapParams& cubemapParams)
{
Image image;
if (!image.LoadFromMemory(data, size, imageParams))
ImageRef image = Image::LoadFromMemory(data, size, imageParams);
if (!image)
{
NazaraError("Failed to load image");
return false;
return nullptr;
}
return LoadCubemapFromImage(image, cubemapParams);
}
bool Image::LoadCubemapFromStream(Stream& stream, const ImageParams& imageParams, const CubemapParams& cubemapParams)
ImageRef Image::LoadCubemapFromStream(Stream& stream, const ImageParams& imageParams, const CubemapParams& cubemapParams)
{
Image image;
if (!image.LoadFromStream(stream, imageParams))
ImageRef image = Image::LoadFromStream(stream, imageParams);
if (!image)
{
NazaraError("Failed to load image");
return false;
return nullptr;
}
return LoadCubemapFromImage(image, cubemapParams);
@@ -1114,21 +1078,21 @@ namespace Nz
{
NazaraAssert(IsValid() && IsCubemap(), "Texture must be a valid cubemap");
Image image;
if (!image.LoadFromFile(filePath, params))
ImageRef image = Image::LoadFromFile(filePath, params);
if (!image)
{
NazaraError("Failed to load image");
return false;
}
if (!image.Convert(GetFormat()))
if (!image->Convert(GetFormat()))
{
NazaraError("Failed to convert image to texture format");
return false;
}
unsigned int faceSize = GetWidth();
if (image.GetWidth() != faceSize || image.GetHeight() != faceSize)
if (image->GetWidth() != faceSize || image->GetHeight() != faceSize)
{
NazaraError("Image size must match texture face size");
return false;
@@ -1142,21 +1106,21 @@ namespace Nz
{
NazaraAssert(IsValid() && IsCubemap(), "Texture must be a valid cubemap");
Image image;
if (!image.LoadFromMemory(data, size, params))
ImageRef image = Image::LoadFromMemory(data, size, params);
if (!image)
{
NazaraError("Failed to load image");
return false;
}
if (!image.Convert(GetFormat()))
if (!image->Convert(GetFormat()))
{
NazaraError("Failed to convert image to texture format");
return false;
}
unsigned int faceSize = GetWidth();
if (image.GetWidth() != faceSize || image.GetHeight() != faceSize)
if (image->GetWidth() != faceSize || image->GetHeight() != faceSize)
{
NazaraError("Image size must match texture face size");
return false;
@@ -1170,21 +1134,21 @@ namespace Nz
{
NazaraAssert(IsValid() && IsCubemap(), "Texture must be a valid cubemap");
Image image;
if (!image.LoadFromStream(stream, params))
ImageRef image = Image::LoadFromStream(stream, params);
if (!image)
{
NazaraError("Failed to load image");
return false;
}
if (!image.Convert(GetFormat()))
if (!image->Convert(GetFormat()))
{
NazaraError("Failed to convert image to texture format");
return false;
}
unsigned int faceSize = GetWidth();
if (image.GetWidth() != faceSize || image.GetHeight() != faceSize)
if (image->GetWidth() != faceSize || image->GetHeight() != faceSize)
{
NazaraError("Image size must match texture face size");
return false;
@@ -1232,7 +1196,7 @@ namespace Nz
m_sharedImage->levels.resize(levelCount);
for (UInt8 i = oldLevelCount; i < maxLevelCount; ++i)
m_sharedImage->levels[i].reset(new UInt8[GetMemoryUsage(i)]);
m_sharedImage->levels[i] = std::make_unique<UInt8[]>(GetMemoryUsage(i));
}
bool Image::SetPixelColor(const Color& color, unsigned int x, unsigned int y, unsigned int z)
@@ -1463,7 +1427,21 @@ namespace Nz
NazaraError("Image type not handled (0x" + String::Number(type, 16) + ')');
return 0;
}
ImageRef Image::LoadFromFile(const String& filePath, const ImageParams& params)
{
return ImageLoader::LoadFromFile(filePath, params);
}
ImageRef Image::LoadFromMemory(const void* data, std::size_t size, const ImageParams& params)
{
return ImageLoader::LoadFromMemory(data, size, params);
}
ImageRef Image::LoadFromStream(Stream& stream, const ImageParams& params)
{
return ImageLoader::LoadFromStream(stream, params);
}
void Image::EnsureOwnership()
@@ -1477,7 +1455,7 @@ namespace Nz
for (unsigned int i = 0; i < levels.size(); ++i)
{
std::size_t size = GetMemoryUsage(i);
levels[i].reset(new UInt8[size]);
levels[i] = std::make_unique<UInt8[]>(size);
std::memcpy(levels[i].get(), m_sharedImage->levels[i].get(), size);
}