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

@@ -14,7 +14,9 @@
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/File.hpp>
#include <Nazara/Core/MemoryView.hpp>
#include <Nazara/Core/Mutex.hpp>
#include <Nazara/Core/Stream.hpp>
#include <iostream>
#include <memory>
#include <set>
#include <vector>
@@ -97,6 +99,11 @@ namespace Nz
return m_format;
}
Mutex& GetMutex() override
{
return m_mutex;
}
UInt64 GetSampleCount() const override
{
return m_sampleCount;
@@ -124,7 +131,7 @@ namespace Nz
bool Open(const void* data, std::size_t size, bool forceMono)
{
m_ownedStream.reset(new MemoryView(data, size));
m_ownedStream = std::make_unique<MemoryView>(data, size);
return Open(*m_ownedStream, forceMono);
}
@@ -201,12 +208,18 @@ namespace Nz
sf_seek(m_handle, offset*m_sampleRate / 1000, SEEK_SET);
}
UInt64 Tell() override
{
return sf_seek(m_handle, 0, SEEK_CUR) * 1000 / m_sampleRate;
}
private:
std::vector<Int16> m_mixBuffer;
std::unique_ptr<Stream> m_ownedStream;
AudioFormat m_format;
SNDFILE* m_handle;
bool m_mixToMono;
Mutex m_mutex;
UInt32 m_duration;
UInt32 m_sampleRate;
UInt64 m_sampleCount;
@@ -222,7 +235,7 @@ namespace Nz
return supportedExtensions.find(extension) != supportedExtensions.end();
}
Ternary CheckMusic(Stream& stream, const MusicParams& parameters)
Ternary CheckSoundStream(Stream& stream, const SoundStreamParams& parameters)
{
NazaraUnused(parameters);
@@ -240,67 +253,43 @@ namespace Nz
return Ternary_False;
}
bool LoadMusicFile(Music* music, const String& filePath, const MusicParams& parameters)
SoundStreamRef LoadSoundStreamFile(const String& filePath, const SoundStreamParams& parameters)
{
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
if (!musicStream->Open(filePath, parameters.forceMono))
std::unique_ptr<sndfileStream> soundStream(new sndfileStream);
if (!soundStream->Open(filePath, parameters.forceMono))
{
NazaraError("Failed to open music stream");
return false;
NazaraError("Failed to open sound stream");
return nullptr;
}
if (!music->Create(musicStream.get())) // Transfert de propriété
{
NazaraError("Failed to create music");
return false;
}
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
musicStream.release();
return true;
soundStream->SetPersistent(false);
return soundStream.release();
}
bool LoadMusicMemory(Music* music, const void* data, std::size_t size, const MusicParams& parameters)
SoundStreamRef LoadSoundStreamMemory(const void* data, std::size_t size, const SoundStreamParams& parameters)
{
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
if (!musicStream->Open(data, size, parameters.forceMono))
std::unique_ptr<sndfileStream> soundStream(new sndfileStream);
if (!soundStream->Open(data, size, parameters.forceMono))
{
NazaraError("Failed to open music stream");
return false;
return nullptr;
}
if (!music->Create(musicStream.get())) // Transfert de propriété
{
NazaraError("Failed to create music");
return false;
}
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
musicStream.release();
return true;
soundStream->SetPersistent(false);
return soundStream.release();
}
bool LoadMusicStream(Music* music, Stream& stream, const MusicParams& parameters)
SoundStreamRef LoadSoundStreamStream(Stream& stream, const SoundStreamParams& parameters)
{
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
if (!musicStream->Open(stream, parameters.forceMono))
std::unique_ptr<sndfileStream> soundStream(new sndfileStream);
if (!soundStream->Open(stream, parameters.forceMono))
{
NazaraError("Failed to open music stream");
return false;
return nullptr;
}
if (!music->Create(musicStream.get())) // Transfert de propriété
{
NazaraError("Failed to create music");
return false;
}
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
musicStream.release();
return true;
soundStream->SetPersistent(false);
return soundStream.release();
}
Ternary CheckSoundBuffer(Stream& stream, const SoundBufferParams& parameters)
@@ -320,7 +309,7 @@ namespace Nz
return Ternary_False;
}
bool LoadSoundBuffer(SoundBuffer* soundBuffer, Stream& stream, const SoundBufferParams& parameters)
SoundBufferRef LoadSoundBuffer(Stream& stream, const SoundBufferParams& parameters)
{
SF_INFO info;
info.format = 0;
@@ -329,7 +318,7 @@ namespace Nz
if (!file)
{
NazaraError("Failed to load sound file: " + String(sf_strerror(file)));
return false;
return nullptr;
}
// Lynix utilise RAII...
@@ -344,7 +333,7 @@ namespace Nz
if (format == AudioFormat_Unknown)
{
NazaraError("Channel count not handled");
return false;
return nullptr;
}
// https://github.com/LaurentGomila/SFML/issues/271
@@ -359,7 +348,7 @@ namespace Nz
if (sf_read_short(file, samples.get(), sampleCount) != sampleCount)
{
NazaraError("Failed to read samples");
return false;
return nullptr;
}
// Une conversion en mono est-elle nécessaire ?
@@ -372,13 +361,7 @@ namespace Nz
sampleCount = static_cast<unsigned int>(info.frames);
}
if (!soundBuffer->Create(format, sampleCount, info.samplerate, samples.get()))
{
NazaraError("Failed to create sound buffer");
return false;
}
return true;
return SoundBuffer::New(format, sampleCount, info.samplerate, samples.get());
}
}
@@ -386,14 +369,14 @@ namespace Nz
{
void Register_sndfile()
{
MusicLoader::RegisterLoader(Detail::IsSupported, Detail::CheckMusic, Detail::LoadMusicStream, Detail::LoadMusicFile, Detail::LoadMusicMemory);
SoundBufferLoader::RegisterLoader(Detail::IsSupported, Detail::CheckSoundBuffer, Detail::LoadSoundBuffer);
SoundStreamLoader::RegisterLoader(Detail::IsSupported, Detail::CheckSoundStream, Detail::LoadSoundStreamStream, Detail::LoadSoundStreamFile, Detail::LoadSoundStreamMemory);
}
void Unregister_sndfile()
{
MusicLoader::UnregisterLoader(Detail::IsSupported, Detail::CheckMusic, Detail::LoadMusicStream, Detail::LoadMusicFile, Detail::LoadMusicMemory);
SoundBufferLoader::UnregisterLoader(Detail::IsSupported, Detail::CheckSoundBuffer, Detail::LoadSoundBuffer);
SoundStreamLoader::UnregisterLoader(Detail::IsSupported, Detail::CheckSoundStream, Detail::LoadSoundStreamStream, Detail::LoadSoundStreamFile, Detail::LoadSoundStreamMemory);
}
}
}

View File

@@ -5,9 +5,12 @@
#include <Nazara/Audio/Music.hpp>
#include <Nazara/Audio/OpenAL.hpp>
#include <Nazara/Audio/SoundStream.hpp>
#include <Nazara/Core/LockGuard.hpp>
#include <Nazara/Core/Mutex.hpp>
#include <Nazara/Core/Thread.hpp>
#include <atomic>
#include <memory>
#include <iostream>
#include <vector>
#include <Nazara/Audio/Debug.hpp>
@@ -21,24 +24,15 @@ namespace Nz
* \remark Module Audio needs to be initialized to use this class
*/
/*!
* \brief Checks whether the parameters for the loading of the music are correct
* \return true If parameters are valid
*/
bool MusicParams::IsValid() const
{
return true;
}
struct MusicImpl
{
ALenum audioFormat;
std::unique_ptr<SoundStream> stream;
std::atomic<UInt64> processedSamples;
std::vector<Int16> chunkSamples;
Mutex bufferLock;
SoundStreamRef stream;
Thread thread;
UInt64 processedSamples;
UInt64 playingOffset;
bool loop = false;
bool streaming = false;
unsigned int sampleRate;
@@ -74,7 +68,7 @@ namespace Nz
m_impl->sampleRate = soundStream->GetSampleRate();
m_impl->audioFormat = OpenAL::AudioFormat[format];
m_impl->chunkSamples.resize(format * m_impl->sampleRate); // One second of samples
m_impl->stream.reset(soundStream);
m_impl->stream = soundStream;
SetPlayingOffset(0);
@@ -221,9 +215,12 @@ namespace Nz
* \param filePath Path to the file
* \param params Parameters for the music
*/
bool Music::OpenFromFile(const String& filePath, const MusicParams& params)
bool Music::OpenFromFile(const String& filePath, const SoundStreamParams& params)
{
return MusicLoader::LoadFromFile(this, filePath, params);
if (SoundStreamRef soundStream = SoundStream::OpenFromFile(filePath, params))
return Create(soundStream);
else
return false;
}
/*!
@@ -236,9 +233,12 @@ namespace Nz
*
* \remark The memory pointer must stay valid (accessible) as long as the music is playing
*/
bool Music::OpenFromMemory(const void* data, std::size_t size, const MusicParams& params)
bool Music::OpenFromMemory(const void* data, std::size_t size, const SoundStreamParams& params)
{
return MusicLoader::LoadFromMemory(this, data, size, params);
if (SoundStreamRef soundStream = SoundStream::OpenFromMemory(data, size, params))
return Create(soundStream);
else
return false;
}
/*!
@@ -250,9 +250,12 @@ namespace Nz
*
* \remark The stream must stay valid as long as the music is playing
*/
bool Music::OpenFromStream(Stream& stream, const MusicParams& params)
bool Music::OpenFromStream(Stream& stream, const SoundStreamParams& params)
{
return MusicLoader::LoadFromStream(this, stream, params);
if (SoundStreamRef soundStream = SoundStream::OpenFromStream(stream, params))
return Create(soundStream);
else
return false;
}
/*!
@@ -324,7 +327,7 @@ namespace Nz
if (isPlaying)
Stop();
m_impl->stream->Seek(offset);
m_impl->playingOffset = offset;
m_impl->processedSamples = UInt64(offset) * m_impl->sampleRate * m_impl->stream->GetFormat() / 1000ULL;
if (isPlaying)
@@ -349,6 +352,10 @@ namespace Nz
std::size_t sampleCount = m_impl->chunkSamples.size();
std::size_t sampleRead = 0;
Nz::LockGuard lock(m_impl->stream->GetMutex());
m_impl->stream->Seek(m_impl->playingOffset);
// Fill the buffer by reading from the stream
for (;;)
{
@@ -364,6 +371,10 @@ namespace Nz
break;
}
m_impl->playingOffset = m_impl->stream->Tell();
lock.Unlock();
// Update the buffer (send it to OpenAL) and queue it if we got any data
if (sampleRead > 0)
{
@@ -380,9 +391,9 @@ namespace Nz
ALuint buffers[NAZARA_AUDIO_STREAMED_BUFFER_COUNT];
alGenBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers);
for (unsigned int i = 0; i < NAZARA_AUDIO_STREAMED_BUFFER_COUNT; ++i)
for (unsigned int buffer : buffers)
{
if (FillAndQueueBuffer(buffers[i]))
if (FillAndQueueBuffer(buffer))
break; // We have reached the end of the stream, there is no use to add new buffers
}
@@ -448,6 +459,4 @@ namespace Nz
m_impl->thread.Join();
}
}
MusicLoader::LoaderList Music::s_loaders;
}

View File

@@ -151,8 +151,8 @@ namespace Nz
*/
bool Sound::LoadFromFile(const String& filePath, const SoundBufferParams& params)
{
SoundBufferRef buffer = SoundBuffer::New();
if (!buffer->LoadFromFile(filePath, params))
SoundBufferRef buffer = SoundBuffer::LoadFromFile(filePath, params);
if (!buffer)
{
NazaraError("Failed to load buffer from file (" + filePath + ')');
return false;
@@ -174,8 +174,8 @@ namespace Nz
*/
bool Sound::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params)
{
SoundBufferRef buffer = SoundBuffer::New();
if (!buffer->LoadFromMemory(data, size, params))
SoundBufferRef buffer = SoundBuffer::LoadFromMemory(data, size, params);
if (!buffer)
{
NazaraError("Failed to load buffer from memory (" + String::Pointer(data) + ')');
return false;
@@ -196,8 +196,8 @@ namespace Nz
*/
bool Sound::LoadFromStream(Stream& stream, const SoundBufferParams& params)
{
SoundBufferRef buffer = SoundBuffer::New();
if (!buffer->LoadFromStream(stream, params))
SoundBufferRef buffer = SoundBuffer::LoadFromStream(stream, params);
if (!buffer)
{
NazaraError("Failed to load buffer from stream");
return false;

View File

@@ -152,7 +152,7 @@ namespace Nz
m_impl->format = format;
m_impl->sampleCount = sampleCount;
m_impl->sampleRate = sampleRate;
m_impl->samples.reset(new Int16[sampleCount]);
m_impl->samples = std::make_unique<Int16[]>(sampleCount);
std::memcpy(&m_impl->samples[0], samples, sampleCount*sizeof(Int16));
clearBufferOnExit.Reset();
@@ -251,6 +251,17 @@ namespace Nz
return m_impl != nullptr;
}
/*!
* \brief Checks whether the format is supported by the engine
* \return true if it is the case
*
* \param format Format to check
*/
bool SoundBuffer::IsFormatSupported(AudioFormat format)
{
return Audio::IsFormatSupported(format);
}
/*!
* \brief Loads the sound buffer from file
* \return true if loading is successful
@@ -258,9 +269,9 @@ namespace Nz
* \param filePath Path to the file
* \param params Parameters for the sound buffer
*/
bool SoundBuffer::LoadFromFile(const String& filePath, const SoundBufferParams& params)
SoundBufferRef SoundBuffer::LoadFromFile(const String& filePath, const SoundBufferParams& params)
{
return SoundBufferLoader::LoadFromFile(this, filePath, params);
return SoundBufferLoader::LoadFromFile(filePath, params);
}
/*!
@@ -271,9 +282,9 @@ namespace Nz
* \param size Size of the memory
* \param params Parameters for the sound buffer
*/
bool SoundBuffer::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params)
SoundBufferRef SoundBuffer::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params)
{
return SoundBufferLoader::LoadFromMemory(this, data, size, params);
return SoundBufferLoader::LoadFromMemory(data, size, params);
}
/*!
@@ -283,20 +294,9 @@ namespace Nz
* \param stream Stream to the sound buffer
* \param params Parameters for the sound buffer
*/
bool SoundBuffer::LoadFromStream(Stream& stream, const SoundBufferParams& params)
SoundBufferRef SoundBuffer::LoadFromStream(Stream& stream, const SoundBufferParams& params)
{
return SoundBufferLoader::LoadFromStream(this, stream, params);
}
/*!
* \brief Checks whether the format is supported by the engine
* \return true if it is the case
*
* \param format Format to check
*/
bool SoundBuffer::IsFormatSupported(AudioFormat format)
{
return Audio::IsFormatSupported(format);
return SoundBufferLoader::LoadFromStream(stream, params);
}
/*!

View File

@@ -6,6 +6,11 @@
namespace Nz
{
bool SoundStreamParams::IsValid() const
{
return true;
}
/*!
* \ingroup audio
* \class Nz::SoundStream
@@ -15,4 +20,21 @@ namespace Nz
*/
SoundStream::~SoundStream() = default;
SoundStreamRef SoundStream::OpenFromFile(const String& filePath, const SoundStreamParams& params)
{
return SoundStreamLoader::LoadFromFile(filePath, params);
}
SoundStreamRef SoundStream::OpenFromMemory(const void* data, std::size_t size, const SoundStreamParams& params)
{
return SoundStreamLoader::LoadFromMemory(data, size, params);
}
SoundStreamRef SoundStream::OpenFromStream(Stream& stream, const SoundStreamParams& params)
{
return SoundStreamLoader::LoadFromStream(stream, params);
}
SoundStreamLoader::LoaderList SoundStream::s_loaders;
}

View File

@@ -31,8 +31,7 @@ namespace Nz
filePath += ".tga";
}
MaterialRef material = Material::New();
if (material->LoadFromFile(filePath, parameters.material))
if (MaterialRef material = Material::LoadFromFile(filePath, parameters.material))
model->SetMaterial(i, std::move(material));
else
NazaraWarning("Failed to load material from file " + String::Number(i));
@@ -47,7 +46,7 @@ namespace Nz
}
}
Ternary CheckStatic(Stream& stream, const ModelParameters& parameters)
Ternary Check(Stream& stream, const ModelParameters& parameters)
{
NazaraUnused(stream);
@@ -58,65 +57,29 @@ namespace Nz
return Ternary_Unknown;
}
bool LoadStatic(Model* model, Stream& stream, const ModelParameters& parameters)
ModelRef Load(Stream& stream, const ModelParameters& parameters)
{
NazaraUnused(parameters);
MeshRef mesh = Mesh::New();
if (!mesh->LoadFromStream(stream, parameters.mesh))
MeshRef mesh = Mesh::LoadFromStream(stream, parameters.mesh);
if (!mesh)
{
NazaraError("Failed to load model mesh");
return false;
return nullptr;
}
ModelRef model;
if (mesh->IsAnimable())
{
NazaraError("Can't load animated mesh into static model");
return false;
}
model = SkeletalModel::New();
else
model = Model::New();
model->SetMesh(mesh);
if (parameters.loadMaterials)
LoadMaterials(model, parameters);
return true;
}
Ternary CheckAnimated(Stream& stream, const SkeletalModelParameters& parameters)
{
NazaraUnused(stream);
bool skip;
if (parameters.custom.GetBooleanParameter("SkipNativeAnimatedMeshLoader", &skip) && skip)
return Ternary_False;
return Ternary_Unknown;
}
bool LoadAnimated(SkeletalModel* model, Stream& stream, const SkeletalModelParameters& parameters)
{
NazaraUnused(parameters);
MeshRef mesh = Mesh::New();
if (!mesh->LoadFromStream(stream, parameters.mesh))
{
NazaraError("Failed to load model mesh");
return false;
}
if (!mesh->IsAnimable())
{
NazaraError("Can't load static mesh into animated model");
return false;
}
model->SetMesh(mesh);
if (parameters.loadMaterials)
LoadMaterials(model, parameters);
return true;
return model;
}
}
@@ -124,14 +87,12 @@ namespace Nz
{
void RegisterMesh()
{
ModelLoader::RegisterLoader(MeshLoader::IsExtensionSupported, CheckStatic, LoadStatic);
SkeletalModelLoader::RegisterLoader(MeshLoader::IsExtensionSupported, CheckAnimated, LoadAnimated);
ModelLoader::RegisterLoader(MeshLoader::IsExtensionSupported, Check, Load);
}
void UnregisterMesh()
{
ModelLoader::UnregisterLoader(MeshLoader::IsExtensionSupported, CheckStatic, LoadStatic);
SkeletalModelLoader::UnregisterLoader(MeshLoader::IsExtensionSupported, CheckAnimated, LoadAnimated);
ModelLoader::UnregisterLoader(MeshLoader::IsExtensionSupported, Check, Load);
}
}
}

View File

@@ -22,22 +22,22 @@ namespace Nz
return Ternary_Unknown;
}
bool Load(Material* material, Stream& stream, const MaterialParams& parameters)
MaterialRef Load(Stream& stream, const MaterialParams& parameters)
{
NazaraUnused(parameters);
TextureRef texture = Texture::New();
if (!texture->LoadFromStream(stream))
TextureRef texture = Texture::LoadFromStream(stream);
if (!texture)
{
NazaraError("Failed to load diffuse map");
return false;
return nullptr;
}
material->Reset();
MaterialRef material = Material::New();
material->SetDiffuseMap(texture);
material->SetShader(parameters.shaderName);
return true;
return material;
}
}

View File

@@ -52,7 +52,7 @@ namespace Nz
return nullptr;
}
if (!newTexture->Update(image, Rectui(0, 0, image.GetWidth(), image.GetHeight())))
if (!newTexture->Update(&image, Rectui(0, 0, image.GetWidth(), image.GetHeight())))
{
NazaraError("Failed to update texture");
return nullptr;

View File

@@ -149,46 +149,6 @@ namespace Nz
return false;
}
/*!
* \brief Loads the model from file
* \return true if loading is successful
*
* \param filePath Path to the file
* \param params Parameters for the model
*/
bool Model::LoadFromFile(const String& filePath, const ModelParameters& params)
{
return ModelLoader::LoadFromFile(this, filePath, params);
}
/*!
* \brief Loads the model from memory
* \return true if loading is successful
*
* \param data Raw memory
* \param size Size of the memory
* \param params Parameters for the model
*/
bool Model::LoadFromMemory(const void* data, std::size_t size, const ModelParameters& params)
{
return ModelLoader::LoadFromMemory(this, data, size, params);
}
/*!
* \brief Loads the model from stream
* \return true if loading is successful
*
* \param stream Stream to the model
* \param params Parameters for the model
*/
bool Model::LoadFromStream(Stream& stream, const ModelParameters& params)
{
return ModelLoader::LoadFromStream(this, stream, params);
}
/*!
* \brief Sets the material of the named submesh
* \return true If successful
@@ -272,6 +232,43 @@ namespace Nz
InvalidateBoundingVolume();
}
/*!
* \brief Loads the model from file
* \return true if loading is successful
*
* \param filePath Path to the file
* \param params Parameters for the model
*/
ModelRef Model::LoadFromFile(const String& filePath, const ModelParameters& params)
{
return ModelLoader::LoadFromFile(filePath, params);
}
/*!
* \brief Loads the model from memory
* \return true if loading is successful
*
* \param data Raw memory
* \param size Size of the memory
* \param params Parameters for the model
*/
ModelRef Model::LoadFromMemory(const void* data, std::size_t size, const ModelParameters& params)
{
return ModelLoader::LoadFromMemory(data, size, params);
}
/*!
* \brief Loads the model from stream
* \return true if loading is successful
*
* \param stream Stream to the model
* \param params Parameters for the model
*/
ModelRef Model::LoadFromStream(Stream& stream, const ModelParameters& params)
{
return ModelLoader::LoadFromStream(stream, params);
}
/*
* \brief Makes the bounding volume of this billboard
*/

View File

@@ -220,46 +220,6 @@ namespace Nz
return m_animationEnabled;
}
/*!
* \brief Loads the skeleton model from file
* \return true if loading is successful
*
* \param filePath Path to the file
* \param params Parameters for the skeleton model
*/
bool SkeletalModel::LoadFromFile(const String& filePath, const SkeletalModelParameters& params)
{
return SkeletalModelLoader::LoadFromFile(this, filePath, params);
}
/*!
* \brief Loads the skeleton model from memory
* \return true if loading is successful
*
* \param data Raw memory
* \param size Size of the memory
* \param params Parameters for the skeleton model
*/
bool SkeletalModel::LoadFromMemory(const void* data, std::size_t size, const SkeletalModelParameters& params)
{
return SkeletalModelLoader::LoadFromMemory(this, data, size, params);
}
/*!
* \brief Loads the skeleton model from stream
* \return true if loading is successful
*
* \param stream Stream to the skeleton model
* \param params Parameters for the skeleton model
*/
bool SkeletalModel::LoadFromStream(Stream& stream, const SkeletalModelParameters& params)
{
return SkeletalModelLoader::LoadFromStream(this, stream, params);
}
/*!
* \brief Sets the animation for the model
* \return true If successful
@@ -432,6 +392,4 @@ namespace Nz
/*if (m_animationEnabled && m_animation)
AdvanceAnimation(m_scene->GetUpdateTime());*/
}
SkeletalModelLoader::LoaderList SkeletalModel::s_loaders;
}

View File

@@ -54,7 +54,7 @@ namespace Nz
Create(type, format, width, height, depth, levelCount);
}
Texture::Texture(const Image& image)
Texture::Texture(const Image* image)
{
ErrorFlags flags(ErrorFlag_ThrowException);
LoadFromImage(image);
@@ -489,225 +489,6 @@ namespace Nz
return m_impl != nullptr;
}
bool Texture::LoadFromFile(const String& filePath, const ImageParams& params, bool generateMipmaps)
{
Image image;
if (!image.LoadFromFile(filePath, params))
{
NazaraError("Failed to load image");
return false;
}
return LoadFromImage(image, generateMipmaps);
}
bool Texture::LoadFromImage(const Image& image, bool generateMipmaps)
{
#if NAZARA_RENDERER_SAFE
if (!image.IsValid())
{
NazaraError("Image must be valid");
return false;
}
#endif
// Vive le Copy-On-Write
Image newImage(image);
PixelFormatType format = newImage.GetFormat();
if (!IsFormatSupported(format))
{
///TODO: Sélectionner le format le plus adapté selon les composantes présentes dans le premier format
PixelFormatType newFormat = (PixelFormat::HasAlpha(format)) ? PixelFormatType_BGRA8 : PixelFormatType_BGR8;
NazaraWarning("Format " + PixelFormat::GetName(format) + " not supported, trying to convert it to " + PixelFormat::GetName(newFormat) + "...");
if (PixelFormat::IsConversionSupported(format, newFormat))
{
if (newImage.Convert(newFormat))
{
NazaraWarning("Conversion succeed");
format = newFormat;
}
else
{
NazaraError("Conversion failed");
return false;
}
}
else
{
NazaraError("Conversion not supported");
return false;
}
}
ImageType type = newImage.GetType();
UInt8 levelCount = newImage.GetLevelCount();
if (!Create(type, format, newImage.GetWidth(), newImage.GetHeight(), newImage.GetDepth(), (generateMipmaps) ? 0xFF : levelCount))
{
NazaraError("Failed to create texture");
return false;
}
CallOnExit destroyOnExit([this]()
{
Destroy();
});
if (type == ImageType_Cubemap)
{
for (UInt8 level = 0; level < levelCount; ++level)
{
for (unsigned int i = 0; i <= CubemapFace_Max; ++i)
{
if (!Update(newImage.GetConstPixels(0, 0, i, level), Rectui(0, 0, newImage.GetWidth(level), newImage.GetHeight(level)), i, level))
{
NazaraError("Failed to update texture");
return false;
}
}
}
}
else
{
for (UInt8 level = 0; level < levelCount; ++level)
{
if (!Update(newImage.GetConstPixels(0, 0, 0, level), level))
{
NazaraError("Failed to update texture");
return false;
}
}
}
// Keep resource path info
SetFilePath(image.GetFilePath());
destroyOnExit.Reset();
return true;
}
bool Texture::LoadFromMemory(const void* data, std::size_t size, const ImageParams& params, bool generateMipmaps)
{
Image image;
if (!image.LoadFromMemory(data, size, params))
{
NazaraError("Failed to load image");
return false;
}
return LoadFromImage(image, generateMipmaps);
}
bool Texture::LoadFromStream(Stream& stream, const ImageParams& params, bool generateMipmaps)
{
Image image;
if (!image.LoadFromStream(stream, params))
{
NazaraError("Failed to load image");
return false;
}
return LoadFromImage(image, generateMipmaps);
}
bool Texture::LoadArrayFromFile(const String& filePath, const ImageParams& imageParams, bool generateMipmaps, const Vector2ui& atlasSize)
{
Image cubemap;
if (!cubemap.LoadArrayFromFile(filePath, imageParams, atlasSize))
{
NazaraError("Failed to load cubemap");
return false;
}
return LoadFromImage(cubemap, generateMipmaps);
}
bool Texture::LoadArrayFromImage(const Image& image, bool generateMipmaps, const Vector2ui& atlasSize)
{
Image cubemap;
if (!cubemap.LoadArrayFromImage(image, atlasSize))
{
NazaraError("Failed to load cubemap");
return false;
}
return LoadFromImage(cubemap, generateMipmaps);
}
bool Texture::LoadArrayFromMemory(const void* data, std::size_t size, const ImageParams& imageParams, bool generateMipmaps, const Vector2ui& atlasSize)
{
Image cubemap;
if (!cubemap.LoadArrayFromMemory(data, size, imageParams, atlasSize))
{
NazaraError("Failed to load cubemap");
return false;
}
return LoadFromImage(cubemap, generateMipmaps);
}
bool Texture::LoadArrayFromStream(Stream& stream, const ImageParams& imageParams, bool generateMipmaps, const Vector2ui& atlasSize)
{
Image cubemap;
if (!cubemap.LoadArrayFromStream(stream, imageParams, atlasSize))
{
NazaraError("Failed to load cubemap");
return false;
}
return LoadFromImage(cubemap, generateMipmaps);
}
bool Texture::LoadCubemapFromFile(const String& filePath, const ImageParams& imageParams, bool generateMipmaps, const CubemapParams& cubemapParams)
{
Image cubemap;
if (!cubemap.LoadCubemapFromFile(filePath, imageParams, cubemapParams))
{
NazaraError("Failed to load cubemap");
return false;
}
return LoadFromImage(cubemap, generateMipmaps);
}
bool Texture::LoadCubemapFromImage(const Image& image, bool generateMipmaps, const CubemapParams& params)
{
Image cubemap;
if (!cubemap.LoadCubemapFromImage(image, params))
{
NazaraError("Failed to load cubemap");
return false;
}
return LoadFromImage(cubemap, generateMipmaps);
}
bool Texture::LoadCubemapFromMemory(const void* data, std::size_t size, const ImageParams& imageParams, bool generateMipmaps, const CubemapParams& cubemapParams)
{
Image cubemap;
if (!cubemap.LoadCubemapFromMemory(data, size, imageParams, cubemapParams))
{
NazaraError("Failed to load cubemap");
return false;
}
return LoadFromImage(cubemap, generateMipmaps);
}
bool Texture::LoadCubemapFromStream(Stream& stream, const ImageParams& imageParams, bool generateMipmaps, const CubemapParams& cubemapParams)
{
Image cubemap;
if (!cubemap.LoadCubemapFromStream(stream, imageParams, cubemapParams))
{
NazaraError("Failed to load cubemap");
return false;
}
return LoadFromImage(cubemap, generateMipmaps);
}
bool Texture::LoadFaceFromFile(CubemapFace face, const String& filePath, const ImageParams& params)
{
#if NAZARA_RENDERER_SAFE
@@ -724,21 +505,21 @@ namespace Nz
}
#endif
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(m_impl->format))
if (!image->Convert(m_impl->format))
{
NazaraError("Failed to convert image to texture format");
return false;
}
unsigned int faceSize = m_impl->width;
if (image.GetWidth() != faceSize || image.GetHeight() != faceSize)
if (image->GetWidth() != faceSize || image->GetHeight() != faceSize)
{
NazaraError("Image size must match texture face size");
return false;
@@ -763,21 +544,21 @@ namespace Nz
}
#endif
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(m_impl->format))
if (!image->Convert(m_impl->format))
{
NazaraError("Failed to convert image to texture format");
return false;
}
unsigned int faceSize = m_impl->width;
if (image.GetWidth() != faceSize || image.GetHeight() != faceSize)
if (image->GetWidth() != faceSize || image->GetHeight() != faceSize)
{
NazaraError("Image size must match texture face size");
return false;
@@ -802,14 +583,14 @@ namespace Nz
}
#endif
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(m_impl->format))
if (!image->Convert(m_impl->format))
{
NazaraError("Failed to convert image to texture format");
return false;
@@ -817,7 +598,7 @@ namespace Nz
unsigned int faceSize = m_impl->width;
if (image.GetWidth() != faceSize || image.GetHeight() != faceSize)
if (image->GetWidth() != faceSize || image->GetHeight() != faceSize)
{
NazaraError("Image size must match texture face size");
return false;
@@ -879,82 +660,49 @@ namespace Nz
return true;
}
bool Texture::Update(const Image& image, UInt8 level)
bool Texture::Update(const Image* image, UInt8 level)
{
#if NAZARA_RENDERER_SAFE
if (!image.IsValid())
{
NazaraError("Image must be valid");
return false;
}
NazaraAssert(image && image->IsValid(), "Invalid image");
NazaraAssert(image->GetFormat() == m_impl->format, "Image format doesn't match texture format");
if (image.GetFormat() != m_impl->format)
{
NazaraError("Image format does not match texture format");
return false;
}
#endif
const UInt8* pixels = image.GetConstPixels(0, 0, 0, level);
const UInt8* pixels = image->GetConstPixels(0, 0, 0, level);
if (!pixels)
{
NazaraError("Failed to access image's pixels");
return false;
}
return Update(pixels, image.GetWidth(level), image.GetHeight(level), level);
return Update(pixels, image->GetWidth(level), image->GetHeight(level), level);
}
bool Texture::Update(const Image& image, const Boxui& box, UInt8 level)
bool Texture::Update(const Image* image, const Boxui& box, UInt8 level)
{
#if NAZARA_RENDERER_SAFE
if (!image.IsValid())
{
NazaraError("Image must be valid");
return false;
}
NazaraAssert(image && image->IsValid(), "Invalid image");
NazaraAssert(image->GetFormat() == m_impl->format, "Image format doesn't match texture format");
if (image.GetFormat() != m_impl->format)
{
NazaraError("Image format does not match texture format");
return false;
}
#endif
const UInt8* pixels = image.GetConstPixels(0, 0, 0, level);
const UInt8* pixels = image->GetConstPixels(0, 0, 0, level);
if (!pixels)
{
NazaraError("Failed to access image's pixels");
return false;
}
return Update(pixels, box, image.GetWidth(level), image.GetHeight(level), level);
return Update(pixels, box, image->GetWidth(level), image->GetHeight(level), level);
}
bool Texture::Update(const Image& image, const Rectui& rect, unsigned int z, UInt8 level)
bool Texture::Update(const Image* image, const Rectui& rect, unsigned int z, UInt8 level)
{
#if NAZARA_RENDERER_SAFE
if (!image.IsValid())
{
NazaraError("Image must be valid");
return false;
}
NazaraAssert(image && image->IsValid(), "Invalid image");
NazaraAssert(image->GetFormat() == m_impl->format, "Image format doesn't match texture format");
if (image.GetFormat() != m_impl->format)
{
NazaraError("Image format does not match texture format");
return false;
}
#endif
const UInt8* pixels = image.GetConstPixels(0, 0, 0, level);
const UInt8* pixels = image->GetConstPixels(0, 0, 0, level);
if (!pixels)
{
NazaraError("Failed to access image's pixels");
return false;
}
return Update(pixels, rect, z, image.GetWidth(level), image.GetHeight(level), level);
return Update(pixels, rect, z, image->GetWidth(level), image->GetHeight(level), level);
}
bool Texture::Update(const UInt8* pixels, unsigned int srcWidth, unsigned int srcHeight, UInt8 level)
@@ -1193,6 +941,214 @@ namespace Nz
return false;
}
TextureRef Texture::LoadFromFile(const String& filePath, const ImageParams& params, bool generateMipmaps)
{
ImageRef image = Image::LoadFromFile(filePath, params);
if (!image)
{
NazaraError("Failed to load image");
return nullptr;
}
return LoadFromImage(image, generateMipmaps);
}
TextureRef Texture::LoadFromImage(const Image* image, bool generateMipmaps)
{
NazaraAssert(image && image->IsValid(), "Invalid image");
// Make use of COW
Image newImage(*image);
PixelFormatType format = newImage.GetFormat();
if (!IsFormatSupported(format))
{
///TODO: Sélectionner le format le plus adapté selon les composantes présentes dans le premier format
PixelFormatType newFormat = (PixelFormat::HasAlpha(format)) ? PixelFormatType_BGRA8 : PixelFormatType_BGR8;
NazaraWarning("Format " + PixelFormat::GetName(format) + " not supported, trying to convert it to " + PixelFormat::GetName(newFormat) + "...");
if (PixelFormat::IsConversionSupported(format, newFormat))
{
if (newImage.Convert(newFormat))
{
NazaraWarning("Conversion succeed");
format = newFormat;
}
else
{
NazaraError("Conversion failed");
return nullptr;
}
}
else
{
NazaraError("Conversion not supported");
return nullptr;
}
}
ImageType type = newImage.GetType();
UInt8 levelCount = newImage.GetLevelCount();
TextureRef texture = New();
if (!texture->Create(type, format, newImage.GetWidth(), newImage.GetHeight(), newImage.GetDepth(), (generateMipmaps) ? 0xFF : levelCount))
{
NazaraError("Failed to create texture");
return nullptr;
}
if (type == ImageType_Cubemap)
{
for (UInt8 level = 0; level < levelCount; ++level)
{
for (unsigned int i = 0; i <= CubemapFace_Max; ++i)
{
if (!texture->Update(newImage.GetConstPixels(0, 0, i, level), Rectui(0, 0, newImage.GetWidth(level), newImage.GetHeight(level)), i, level))
{
NazaraError("Failed to update texture");
return nullptr;
}
}
}
}
else
{
for (UInt8 level = 0; level < levelCount; ++level)
{
if (!texture->Update(newImage.GetConstPixels(0, 0, 0, level), level))
{
NazaraError("Failed to update texture");
return nullptr;
}
}
}
// Keep resource path info
texture->SetFilePath(image->GetFilePath());
return texture;
}
TextureRef Texture::LoadFromMemory(const void* data, std::size_t size, const ImageParams& params, bool generateMipmaps)
{
ImageRef image = Image::LoadFromMemory(data, size, params);
if (!image)
{
NazaraError("Failed to load image");
return nullptr;
}
return LoadFromImage(image, generateMipmaps);
}
TextureRef Texture::LoadFromStream(Stream& stream, const ImageParams& params, bool generateMipmaps)
{
ImageRef image = Image::LoadFromStream(stream, params);
if (!image)
{
NazaraError("Failed to load image");
return nullptr;
}
return LoadFromImage(image, generateMipmaps);
}
TextureRef Texture::LoadArrayFromFile(const String& filePath, const ImageParams& imageParams, bool generateMipmaps, const Vector2ui& atlasSize)
{
ImageRef cubemap = Image::LoadArrayFromFile(filePath, imageParams, atlasSize);
if (!cubemap)
{
NazaraError("Failed to load cubemap");
return nullptr;
}
return LoadFromImage(cubemap, generateMipmaps);
}
TextureRef Texture::LoadArrayFromImage(const Image* image, bool generateMipmaps, const Vector2ui& atlasSize)
{
ImageRef cubemap = Image::LoadArrayFromImage(image, atlasSize);
if (!cubemap)
{
NazaraError("Failed to load cubemap");
return nullptr;
}
return LoadFromImage(cubemap, generateMipmaps);
}
TextureRef Texture::LoadArrayFromMemory(const void* data, std::size_t size, const ImageParams& imageParams, bool generateMipmaps, const Vector2ui& atlasSize)
{
ImageRef cubemap = Image::LoadArrayFromMemory(data, size, imageParams, atlasSize);
if (!cubemap)
{
NazaraError("Failed to load cubemap");
return nullptr;
}
return LoadFromImage(cubemap, generateMipmaps);
}
TextureRef Texture::LoadArrayFromStream(Stream& stream, const ImageParams& imageParams, bool generateMipmaps, const Vector2ui& atlasSize)
{
ImageRef cubemap = Image::LoadArrayFromStream(stream, imageParams, atlasSize);
if (!cubemap)
{
NazaraError("Failed to load cubemap");
return nullptr;
}
return LoadFromImage(cubemap, generateMipmaps);
}
TextureRef Texture::LoadCubemapFromFile(const String& filePath, const ImageParams& imageParams, bool generateMipmaps, const CubemapParams& cubemapParams)
{
ImageRef cubemap = Image::LoadCubemapFromFile(filePath, imageParams, cubemapParams);
if (!cubemap)
{
NazaraError("Failed to load cubemap");
return nullptr;
}
return LoadFromImage(cubemap, generateMipmaps);
}
TextureRef Texture::LoadCubemapFromImage(const Image* image, bool generateMipmaps, const CubemapParams& params)
{
ImageRef cubemap = Image::LoadCubemapFromImage(image, params);
if (!cubemap)
{
NazaraError("Failed to load cubemap");
return nullptr;
}
return LoadFromImage(cubemap, generateMipmaps);
}
TextureRef Texture::LoadCubemapFromMemory(const void* data, std::size_t size, const ImageParams& imageParams, bool generateMipmaps, const CubemapParams& cubemapParams)
{
ImageRef cubemap = Image::LoadCubemapFromMemory(data, size, imageParams, cubemapParams);
if (!cubemap)
{
NazaraError("Failed to load cubemap");
return nullptr;
}
return LoadFromImage(cubemap, generateMipmaps);
}
TextureRef Texture::LoadCubemapFromStream(Stream& stream, const ImageParams& imageParams, bool generateMipmaps, const CubemapParams& cubemapParams)
{
ImageRef cubemap = Image::LoadCubemapFromStream(stream, imageParams, cubemapParams);
if (!cubemap)
{
NazaraError("Failed to load cubemap");
return nullptr;
}
return LoadFromImage(cubemap, generateMipmaps);
}
bool Texture::CreateTexture(bool proxy)
{
OpenGL::Format openGLFormat;

View File

@@ -261,21 +261,6 @@ namespace Nz
return m_impl != nullptr;
}
bool Animation::LoadFromFile(const String& filePath, const AnimationParams& params)
{
return AnimationLoader::LoadFromFile(this, filePath, params);
}
bool Animation::LoadFromMemory(const void* data, std::size_t size, const AnimationParams& params)
{
return AnimationLoader::LoadFromMemory(this, data, size, params);
}
bool Animation::LoadFromStream(Stream& stream, const AnimationParams& params)
{
return AnimationLoader::LoadFromStream(this, stream, params);
}
void Animation::RemoveSequence(const String& identifier)
{
NazaraAssert(m_impl, "Animation not created");
@@ -304,6 +289,21 @@ namespace Nz
m_impl->sequences.erase(it);
}
AnimationRef Animation::LoadFromFile(const String& filePath, const AnimationParams& params)
{
return AnimationLoader::LoadFromFile(filePath, params);
}
AnimationRef Animation::LoadFromMemory(const void* data, std::size_t size, const AnimationParams& params)
{
return AnimationLoader::LoadFromMemory(data, size, params);
}
AnimationRef Animation::LoadFromStream(Stream& stream, const AnimationParams& params)
{
return AnimationLoader::LoadFromStream(stream, params);
}
bool Animation::Initialize()
{
if (!AnimationLibrary::Initialize())

View File

@@ -280,21 +280,6 @@ namespace Nz
return true;
}
bool Font::OpenFromFile(const String& filePath, const FontParams& params)
{
return FontLoader::LoadFromFile(this, filePath, params);
}
bool Font::OpenFromMemory(const void* data, std::size_t size, const FontParams& params)
{
return FontLoader::LoadFromMemory(this, data, size, params);
}
bool Font::OpenFromStream(Stream& stream, const FontParams& params)
{
return FontLoader::LoadFromStream(this, stream, params);
}
void Font::SetAtlas(const std::shared_ptr<AbstractAtlas>& atlas)
{
if (m_atlas != atlas)
@@ -358,10 +343,8 @@ namespace Nz
if (!s_defaultFont)
{
FontRef cabin = Font::New();
if (cabin->OpenFromMemory(r_cabinRegular, sizeof(r_cabinRegular)))
s_defaultFont = cabin;
else
s_defaultFont = Font::OpenFromMemory(r_cabinRegular, sizeof(r_cabinRegular));
if (!s_defaultFont)
NazaraError("Failed to open default font");
}
@@ -378,6 +361,21 @@ namespace Nz
return s_defaultMinimumStepSize;
}
FontRef Font::OpenFromFile(const String& filePath, const FontParams& params)
{
return FontLoader::LoadFromFile(filePath, params);
}
FontRef Font::OpenFromMemory(const void* data, std::size_t size, const FontParams& params)
{
return FontLoader::LoadFromMemory(data, size, params);
}
FontRef Font::OpenFromStream(Stream& stream, const FontParams& params)
{
return FontLoader::LoadFromStream(stream, params);
}
void Font::SetDefaultAtlas(const std::shared_ptr<AbstractAtlas>& atlas)
{
s_defaultAtlas = atlas;

View File

@@ -38,7 +38,7 @@ namespace Nz
return (magic == DDS_Magic) ? Ternary_True : Ternary_False;
}
static bool Load(Image* image, Stream& stream, const ImageParams& parameters)
static ImageRef Load(Stream& stream, const ImageParams& parameters)
{
NazaraUnused(parameters);
@@ -81,14 +81,14 @@ namespace Nz
// First, identify the type
ImageType type;
if (!IdentifyImageType(header, headerDX10, &type))
return false;
return nullptr;
// Then the format
PixelFormatType format;
if (!IdentifyPixelFormat(header, headerDX10, &format))
return false;
return nullptr;
image->Create(type, format, width, height, depth, levelCount);
ImageRef image = Image::New(type, format, width, height, depth, levelCount);
// Read all mipmap levels
for (unsigned int i = 0; i < image->GetLevelCount(); i++)
@@ -100,7 +100,7 @@ namespace Nz
if (byteStream.Read(ptr, byteCount) != byteCount)
{
NazaraError("Failed to read level #" + String::Number(i));
return false;
return nullptr;
}
if (width > 1)
@@ -117,7 +117,7 @@ namespace Nz
if (parameters.loadFormat != PixelFormatType_Undefined)
image->Convert(parameters.loadFormat);
return true;
return image;
}
private:

View File

@@ -361,7 +361,7 @@ namespace Nz
return Ternary_False;
}
bool LoadFile(Font* font, const String& filePath, const FontParams& parameters)
FontRef LoadFile(const String& filePath, const FontParams& parameters)
{
NazaraUnused(parameters);
@@ -370,25 +370,26 @@ namespace Nz
if (!face->SetFile(filePath))
{
NazaraError("Failed to open file");
return false;
return nullptr;
}
if (!face->Open())
{
NazaraError("Failed to open face");
return false;
return nullptr;
}
FontRef font = Font::New();
if (font->Create(face.get()))
{
face.release();
return true;
return font;
}
else
return false;
return nullptr;
}
bool LoadMemory(Font* font, const void* data, std::size_t size, const FontParams& parameters)
FontRef LoadMemory(const void* data, std::size_t size, const FontParams& parameters)
{
NazaraUnused(parameters);
@@ -398,19 +399,20 @@ namespace Nz
if (!face->Open())
{
NazaraError("Failed to open face");
return false;
return nullptr;
}
FontRef font = Font::New();
if (font->Create(face.get()))
{
face.release();
return true;
return font;
}
else
return false;
return nullptr;
}
bool LoadStream(Font* font, Stream& stream, const FontParams& parameters)
FontRef LoadStream(Stream& stream, const FontParams& parameters)
{
NazaraUnused(parameters);
@@ -420,16 +422,17 @@ namespace Nz
if (!face->Open())
{
NazaraError("Failed to open face");
return false;
return nullptr;
}
FontRef font = Font::New();
if (font->Create(face.get()))
{
face.release();
return true;
return font;
}
else
return false;
return nullptr;
}
}
@@ -439,7 +442,7 @@ namespace Nz
{
if (FT_Init_FreeType(&s_library) == 0)
{
s_libraryOwner.reset(new FreeTypeLibrary);
s_libraryOwner = std::make_shared<FreeTypeLibrary>();
FontLoader::RegisterLoader(IsSupported, Check, LoadStream, LoadFile, LoadMemory);
}
else

View File

@@ -46,13 +46,13 @@ namespace Nz
return Ternary_False;
}
bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
MeshRef Load(Stream& stream, const MeshParams& parameters)
{
MD2_Header header;
if (stream.Read(&header, sizeof(MD2_Header)) != sizeof(MD2_Header))
{
NazaraError("Failed to read header");
return false;
return nullptr;
}
#ifdef NAZARA_BIG_ENDIAN
@@ -76,14 +76,15 @@ namespace Nz
if (stream.GetSize() < header.offset_end)
{
NazaraError("Incomplete MD2 file");
return false;
return nullptr;
}
// Since the engine no longer supports keyframe animations, let's make a static mesh
MeshRef mesh = Nz::Mesh::New();
if (!mesh->CreateStatic())
{
NazaraInternalError("Failed to create mesh");
return false;
return nullptr;
}
// Extract skins (texture name)
@@ -253,7 +254,7 @@ namespace Nz
if (parameters.center)
mesh->Recenter();
return true;
return mesh;
}
}

View File

@@ -28,7 +28,7 @@ namespace Nz
return parser.Check();
}
bool Load(Animation* animation, Stream& stream, const AnimationParams& /*parameters*/)
AnimationRef Load(Stream& stream, const AnimationParams& /*parameters*/)
{
///TODO: Utiliser les paramètres
MD5AnimParser parser(stream);
@@ -36,7 +36,7 @@ namespace Nz
if (!parser.Parse())
{
NazaraError("MD5Anim parser failed");
return false;
return nullptr;
}
const MD5AnimParser::Frame* frames = parser.GetFrames();
@@ -46,6 +46,7 @@ namespace Nz
UInt32 jointCount = parser.GetJointCount();
// À ce stade, nous sommes censés avoir assez d'informations pour créer l'animation
AnimationRef animation = Animation::New();
animation->CreateSkeletal(frameCount, jointCount);
Sequence sequence;
@@ -84,7 +85,7 @@ namespace Nz
}
}
return true;
return animation;
}
}

View File

@@ -35,13 +35,13 @@ namespace Nz
return parser.Check();
}
bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
MeshRef Load(Stream& stream, const MeshParams& parameters)
{
MD5MeshParser parser(stream);
if (!parser.Parse())
{
NazaraError("MD5Mesh parser failed");
return false;
return nullptr;
}
// Pour que le squelette soit correctement aligné, il faut appliquer un quaternion "de correction" aux joints à la base du squelette
@@ -62,6 +62,7 @@ namespace Nz
if (parameters.animated)
{
MeshRef mesh = Mesh::New();
mesh->CreateSkeletal(jointCount);
Skeleton* skeleton = mesh->GetSkeleton();
@@ -218,13 +219,16 @@ namespace Nz
mesh->SetAnimation(path);
}
}
return mesh;
}
else
{
MeshRef mesh = Mesh::New();
if (!mesh->CreateStatic()) // Ne devrait jamais échouer
{
NazaraInternalError("Failed to create mesh");
return false;
return nullptr;
}
mesh->SetMaterialCount(meshCount);
@@ -309,9 +313,9 @@ namespace Nz
if (parameters.center)
mesh->Recenter();
}
return true;
return mesh;
}
}
}

View File

@@ -153,7 +153,7 @@ namespace Nz
return true;
}
bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
MeshRef Load(Stream& stream, const MeshParams& parameters)
{
long long reservedVertexCount;
if (!parameters.custom.GetIntegerParameter("NativeOBJLoader_VertexCount", &reservedVertexCount))
@@ -163,9 +163,10 @@ namespace Nz
if (!parser.Parse(stream, reservedVertexCount))
{
NazaraError("OBJ parser failed");
return false;
return nullptr;
}
MeshRef mesh = Mesh::New();
mesh->CreateStatic();
const String* materials = parser.GetMaterials();
@@ -341,7 +342,7 @@ namespace Nz
ParseMTL(mesh, stream.GetDirectory() + mtlLib, materials, meshes, meshCount);
}
return true;
return mesh;
}
}

View File

@@ -61,7 +61,7 @@ namespace Nz
return Ternary_False;
}
bool Load(Image* image, Stream& stream, const ImageParams& parameters)
ImageRef Load(Stream& stream, const ImageParams& parameters)
{
NazaraUnused(parameters);
@@ -69,7 +69,7 @@ namespace Nz
if (stream.Read(&header, sizeof(pcx_header)) != sizeof(pcx_header))
{
NazaraError("Failed to read header");
return false;
return nullptr;
}
#ifdef NAZARA_BIG_ENDIAN
@@ -91,10 +91,11 @@ namespace Nz
unsigned int width = header.xmax - header.xmin+1;
unsigned int height = header.ymax - header.ymin+1;
ImageRef image = Image::New();
if (!image->Create(ImageType_2D, PixelFormatType_RGB8, width, height, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1))
{
NazaraError("Failed to create image");
return false;
return nullptr;
}
UInt8* pixels = image->GetPixels();
@@ -119,7 +120,7 @@ namespace Nz
if (!stream.Read(&rle_value, 1))
{
NazaraError("Failed to read stream (byte " + String::Number(stream.GetCursorPos()) + ')');
return false;
return nullptr;
}
if (rle_value < 0xc0)
@@ -130,7 +131,7 @@ namespace Nz
if (!stream.Read(&rle_value, 1))
{
NazaraError("Failed to read stream (byte " + String::Number(stream.GetCursorPos()) + ')');
return false;
return nullptr;
}
}
}
@@ -174,7 +175,7 @@ namespace Nz
if (!stream.Read(&rle_value, 1))
{
NazaraError("Failed to read stream (byte " + String::Number(stream.GetCursorPos()) + ')');
return false;
return nullptr;
}
if (rle_value < 0xc0)
@@ -185,7 +186,7 @@ namespace Nz
if (!stream.Read(&rle_value, 1))
{
NazaraError("Failed to read stream (byte " + String::Number(stream.GetCursorPos()) + ')');
return false;
return nullptr;
}
}
}
@@ -225,21 +226,21 @@ namespace Nz
if (!stream.Read(&magic, 1))
{
NazaraError("Failed to read stream (byte " + String::Number(stream.GetCursorPos()) + ')');
return false;
return nullptr;
}
/* first byte must be equal to 0x0c (12) */
if (magic != 0x0c)
{
NazaraError("Colormap's first byte must be 0x0c (0x" + String::Number(magic, 16) + ')');
return false;
return nullptr;
}
/* read palette */
if (stream.Read(palette, 768) != 768)
{
NazaraError("Failed to read palette");
return false;
return nullptr;
}
stream.SetCursorPos(curPos);
@@ -258,7 +259,7 @@ namespace Nz
if (!stream.Read(&rle_value, 1))
{
NazaraError("Failed to read stream (byte " + String::Number(stream.GetCursorPos()) + ')');
return false;
return nullptr;
}
if (rle_value < 0xc0)
@@ -269,7 +270,7 @@ namespace Nz
if (!stream.Read(&rle_value, 1))
{
NazaraError("Failed to read stream (byte " + String::Number(stream.GetCursorPos()) + ')');
return false;
return nullptr;
}
}
}
@@ -302,7 +303,7 @@ namespace Nz
if (!stream.Read(&rle_value, 1))
{
NazaraError("Failed to read stream (byte " + String::Number(stream.GetCursorPos()) + ')');
return false;
return nullptr;
}
if (rle_value < 0xc0)
@@ -313,7 +314,7 @@ namespace Nz
if (!stream.Read(&rle_value, 1))
{
NazaraError("Failed to read stream (byte " + String::Number(stream.GetCursorPos()) + ')');
return false;
return nullptr;
}
}
}
@@ -329,13 +330,13 @@ namespace Nz
default:
NazaraError("Unsupported " + String::Number(bitCount) + " bitcount for pcx files");
return false;
return nullptr;
}
if (parameters.loadFormat != PixelFormatType_Undefined)
image->Convert(parameters.loadFormat);
return true;
return image;
}
}

View File

@@ -4,6 +4,7 @@
#include <Nazara/Utility/Formats/STBLoader.hpp>
#include <stb/stb_image.h>
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/Endianness.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/Stream.hpp>
@@ -54,7 +55,7 @@ namespace Nz
return Ternary_False;
}
bool Load(Image* image, Stream& stream, const ImageParams& parameters)
ImageRef Load(Stream& stream, const ImageParams& parameters)
{
// Je charge tout en RGBA8 et je converti ensuite via la méthode Convert
// Ceci à cause d'un bug de STB lorsqu'il s'agit de charger certaines images (ex: JPG) en "default"
@@ -64,24 +65,29 @@ namespace Nz
if (!ptr)
{
NazaraError("Failed to load image: " + String(stbi_failure_reason()));
return false;
return nullptr;
}
CallOnExit freeStbiImage([ptr]()
{
stbi_image_free(ptr);
});
ImageRef image = Image::New();
if (!image->Create(ImageType_2D, PixelFormatType_RGBA8, width, height, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1))
{
NazaraError("Failed to create image");
stbi_image_free(ptr);
return false;
return nullptr;
}
image->Update(ptr);
stbi_image_free(ptr);
freeStbiImage.CallAndReset();
if (parameters.loadFormat != PixelFormatType_Undefined)
image->Convert(parameters.loadFormat);
return true;
return image;
}
}

View File

@@ -166,8 +166,7 @@ namespace Nz
std::unique_ptr<Image> newImage(new Image(ImageType_2D, PixelFormatType_A8, size.x, size.y));
if (oldImage)
{
Image& image = *static_cast<Image*>(oldImage);
newImage->Copy(image, Rectui(size), Vector2ui(0, 0)); // Copie des anciennes données
newImage->Copy(static_cast<Image*>(oldImage), Rectui(size), Vector2ui(0, 0)); // Copie des anciennes données
}
return newImage.release();

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);
}

View File

@@ -521,21 +521,6 @@ namespace Nz
return m_isValid;
}
bool Mesh::LoadFromFile(const String& filePath, const MeshParams& params)
{
return MeshLoader::LoadFromFile(this, filePath, params);
}
bool Mesh::LoadFromMemory(const void* data, std::size_t size, const MeshParams& params)
{
return MeshLoader::LoadFromMemory(this, data, size, params);
}
bool Mesh::LoadFromStream(Stream& stream, const MeshParams& params)
{
return MeshLoader::LoadFromStream(this, stream, params);
}
void Mesh::Recenter()
{
NazaraAssert(m_isValid, "Mesh should be created first");
@@ -663,6 +648,21 @@ namespace Nz
}
}
MeshRef Mesh::LoadFromFile(const String& filePath, const MeshParams& params)
{
return MeshLoader::LoadFromFile(filePath, params);
}
MeshRef Mesh::LoadFromMemory(const void* data, std::size_t size, const MeshParams& params)
{
return MeshLoader::LoadFromMemory(data, size, params);
}
MeshRef Mesh::LoadFromStream(Stream& stream, const MeshParams& params)
{
return MeshLoader::LoadFromStream(stream, params);
}
bool Mesh::Initialize()
{
if (!MeshLibrary::Initialize())