From b243d15c7416547f732af113b761cc5a04f325e1 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 24 May 2012 18:55:48 +0200 Subject: [PATCH 01/15] Added formats conversion Functor, NonCopyable, Tuple are now parts of NazaraCore (NazaraCore no longer needs NazaraUtility) Added loadFormat image parameter (ask loader to load image in specific format) Fixed utility project building It is now possible to convert, get validity or get name of pixel formats Changed endianness macros' name Removed useless NazaraEndianness macro Removed unused files --- build/scripts/module/utility.lua | 1 + include/Nazara/Audio/Sound.hpp | 27 - include/Nazara/Core/DynLib.hpp | 2 +- include/Nazara/Core/Endianness.hpp | 22 +- include/Nazara/Core/Endianness.inl | 26 +- include/Nazara/Core/File.hpp | 2 +- include/Nazara/{Utility => Core}/Functor.hpp | 4 +- include/Nazara/{Utility => Core}/Functor.inl | 0 include/Nazara/Core/Hash.hpp | 2 +- include/Nazara/Core/HashImpl.hpp | 2 +- include/Nazara/Core/Log.hpp | 2 +- include/Nazara/Core/Mutex.hpp | 2 +- .../Nazara/{Utility => Core}/NonCopyable.hpp | 0 include/Nazara/Core/Semaphore.hpp | 2 +- include/Nazara/Core/Thread.hpp | 4 +- include/Nazara/{Utility => Core}/Tuple.hpp | 2 +- include/Nazara/{Utility => Core}/Tuple.inl | 0 include/Nazara/Prerequesites.hpp | 3 +- include/Nazara/Renderer/Buffer.hpp | 2 +- include/Nazara/Renderer/OcclusionQuery.hpp | 2 +- include/Nazara/Renderer/Shader.hpp | 2 +- include/Nazara/Utility/Image.hpp | 13 +- include/Nazara/Utility/PixelFormat.hpp | 52 +- include/Nazara/Utility/PixelFormat.inl | 199 ++- include/Nazara/Utility/Window.hpp | 2 +- src/Nazara/Core/Hash/CRC32.cpp | 5 +- src/Nazara/Core/Hash/Fletcher16.cpp | 6 +- src/Nazara/Core/Hash/MD5.cpp | 2 +- src/Nazara/Core/Hash/SHA/Internal.cpp | 36 +- src/Nazara/Core/Win32/DirectoryImpl.hpp | 2 +- src/Nazara/Core/Win32/DynLibImpl.hpp | 2 +- src/Nazara/Core/Win32/FileImpl.hpp | 2 +- src/Nazara/Core/Win32/ThreadImpl.cpp | 2 +- src/Nazara/Renderer/OpenGL.cpp | 4 - src/Nazara/Utility/Image.cpp | 97 +- src/Nazara/Utility/Loaders/PCX.cpp | 7 +- src/Nazara/Utility/Loaders/STB.cpp | 47 +- src/Nazara/Utility/PixelFormat.cpp | 1161 +++++++++++++++++ src/Nazara/Utility/Utility.cpp | 9 + src/Nazara/Utility/Win32/WindowImpl.hpp | 2 +- 40 files changed, 1609 insertions(+), 150 deletions(-) delete mode 100644 include/Nazara/Audio/Sound.hpp rename include/Nazara/{Utility => Core}/Functor.hpp (91%) rename include/Nazara/{Utility => Core}/Functor.inl (100%) rename include/Nazara/{Utility => Core}/NonCopyable.hpp (100%) rename include/Nazara/{Utility => Core}/Tuple.hpp (91%) rename include/Nazara/{Utility => Core}/Tuple.inl (100%) create mode 100644 src/Nazara/Utility/PixelFormat.cpp diff --git a/build/scripts/module/utility.lua b/build/scripts/module/utility.lua index 4a9c930d4..8cadea0b3 100644 --- a/build/scripts/module/utility.lua +++ b/build/scripts/module/utility.lua @@ -7,6 +7,7 @@ files "../include/Nazara/Utility/**.hpp", "../include/Nazara/Utility/**.inl", "../src/Nazara/Utility/**.hpp", + "../src/Nazara/Utility/**.c", "../src/Nazara/Utility/**.cpp" } diff --git a/include/Nazara/Audio/Sound.hpp b/include/Nazara/Audio/Sound.hpp deleted file mode 100644 index ad7704775..000000000 --- a/include/Nazara/Audio/Sound.hpp +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (C) 2012 Jérôme Leclercq -// This file is part of the "Nazara Engine". -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_SOUND_HPP -#define NAZARA_SOUND_HPP - -#include -#include -#include - -class NAZARA_API NzSound -{ - public: - NzSound(); - ~NzSound(); - - bool LoadFromFile(const NzString& filePath); - bool LoadFromMemory(const nzUInt8* ptr, std::size_t size); - - private: - -}; - -#endif // NAZARA_SOUND_HPP diff --git a/include/Nazara/Core/DynLib.hpp b/include/Nazara/Core/DynLib.hpp index 3fccb82e2..a7da89da8 100644 --- a/include/Nazara/Core/DynLib.hpp +++ b/include/Nazara/Core/DynLib.hpp @@ -8,8 +8,8 @@ #define NAZARA_DYNLIB_HPP #include +#include #include -#include #define NAZARA_CLASS_DYNLIB #include diff --git a/include/Nazara/Core/Endianness.hpp b/include/Nazara/Core/Endianness.hpp index 763b0fc07..d5af604c9 100644 --- a/include/Nazara/Core/Endianness.hpp +++ b/include/Nazara/Core/Endianness.hpp @@ -9,26 +9,18 @@ #include -#if defined(NAZARA_ENDIANNESS_BIGENDIAN) - #define NAZARA_ENDIANNESS_DETECTED 1 - #define NazaraEndianness nzEndianness_BigEndian -#elif defined(NAZARA_ENDIANNESS_LITTLEENDIAN) - #define NAZARA_ENDIANNESS_DETECTED 1 - #define NazaraEndianness nzEndianness_LittleEndian -#else +#if !defined(NAZARA_BIG_ENDIAN) && !defined(NAZARA_LITTLE_ENDIAN) + // Détection automatique selon les macros du compilateur #if defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || (defined(__MIPS__) && defined(__MISPEB__)) || \ defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || defined(__sparc__) || defined(__hppa__) - #define NAZARA_ENDIANNESS_DETECTED 1 - #define NAZARA_ENDIANNESS_BIGENDIAN - #define NazaraEndianness nzEndianness_BigEndian + #define NAZARA_BIG_ENDIAN #elif defined(__i386__) || defined(__i386) || defined(__X86__) || defined (__x86_64) - #define NAZARA_ENDIANNESS_DETECTED 1 - #define NAZARA_ENDIANNESS_LITTLEENDIAN - #define NazaraEndianness nzEndianness_LittleEndian + #define NAZARA_LITTLE_ENDIAN #else - #define NAZARA_ENDIANNESS_DETECTED 0 - #define NazaraEndianness NzGetPlatformEndianness() + #error Failed to identify endianness, you must define either NAZARA_BIG_ENDIAN or NAZARA_LITTLE_ENDIAN #endif +#elif defined(NAZARA_BIG_ENDIAN) && defined(NAZARA_LITTLE_ENDIAN) + #error You cannot define both NAZARA_BIG_ENDIAN and NAZARA_LITTLE_ENDIAN #endif enum nzEndianness diff --git a/include/Nazara/Core/Endianness.inl b/include/Nazara/Core/Endianness.inl index 253abc00d..20edee20f 100644 --- a/include/Nazara/Core/Endianness.inl +++ b/include/Nazara/Core/Endianness.inl @@ -17,27 +17,11 @@ inline void NzByteSwap(void* buffer, unsigned int size) inline nzEndianness NzGetPlatformEndianness() { -#if NAZARA_ENDIANNESS_DETECTED - return NazaraEndianness; -#else - static nzEndianness endianness = nzEndianness_Unknown; - static bool tested = false; - if (!tested) - { - nzUInt32 i = 1; - nzUInt8* p = reinterpret_cast(&i); - - // Méthode de récupération de l'endianness au runtime - if (p[0] == 1) - endianness = nzEndianness_LittleEndian; - else if (p[3] == 1) - endianness = nzEndianness_BigEndian; - - tested = true; - } - - return endianness; -#endif + #if defined(NAZARA_BIG_ENDIAN) + return nzEndianness_BigEndian; + #elif defined(NAZARA_LITTLE_ENDIAN) + return nzEndianness_LittleEndian; + #endif } #include diff --git a/include/Nazara/Core/File.hpp b/include/Nazara/Core/File.hpp index 79b8fc42f..b253d30b9 100644 --- a/include/Nazara/Core/File.hpp +++ b/include/Nazara/Core/File.hpp @@ -13,8 +13,8 @@ #include #include #include +#include #include -#include #define NAZARA_CLASS_FILE #include diff --git a/include/Nazara/Utility/Functor.hpp b/include/Nazara/Core/Functor.hpp similarity index 91% rename from include/Nazara/Utility/Functor.hpp rename to include/Nazara/Core/Functor.hpp index ebfb35b73..620423d70 100644 --- a/include/Nazara/Utility/Functor.hpp +++ b/include/Nazara/Core/Functor.hpp @@ -7,7 +7,7 @@ #ifndef NAZARA_FUNCTOR_HPP #define NAZARA_FUNCTOR_HPP -#include +#include // Inspiré du code de la SFML par Laurent Gomila @@ -40,6 +40,6 @@ template struct NzFunctorWithArgs : NzFunctor template struct NzFunctorWithoutArgs; template struct NzFunctorWithArgs; -#include +#include #endif // NAZARA_FUNCTOR_HPP diff --git a/include/Nazara/Utility/Functor.inl b/include/Nazara/Core/Functor.inl similarity index 100% rename from include/Nazara/Utility/Functor.inl rename to include/Nazara/Core/Functor.inl diff --git a/include/Nazara/Core/Hash.hpp b/include/Nazara/Core/Hash.hpp index a2913a689..2243326b4 100644 --- a/include/Nazara/Core/Hash.hpp +++ b/include/Nazara/Core/Hash.hpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include class NAZARA_API NzHash : NzNonCopyable { diff --git a/include/Nazara/Core/HashImpl.hpp b/include/Nazara/Core/HashImpl.hpp index b2d7cec5c..83f087bd6 100644 --- a/include/Nazara/Core/HashImpl.hpp +++ b/include/Nazara/Core/HashImpl.hpp @@ -8,7 +8,7 @@ #define NAZARA_HASHIMPL_HPP #include -#include +#include class NzHashDigest; diff --git a/include/Nazara/Core/Log.hpp b/include/Nazara/Core/Log.hpp index 71e69c418..8c61ffb4c 100644 --- a/include/Nazara/Core/Log.hpp +++ b/include/Nazara/Core/Log.hpp @@ -9,8 +9,8 @@ #include #include +#include #include -#include #define NAZARA_CLASS_LOG #include diff --git a/include/Nazara/Core/Mutex.hpp b/include/Nazara/Core/Mutex.hpp index bd534d4a5..01b410fcd 100644 --- a/include/Nazara/Core/Mutex.hpp +++ b/include/Nazara/Core/Mutex.hpp @@ -8,7 +8,7 @@ #define NAZARA_MUTEX_HPP #include -#include +#include class NzMutexImpl; class NzThreadCondition; diff --git a/include/Nazara/Utility/NonCopyable.hpp b/include/Nazara/Core/NonCopyable.hpp similarity index 100% rename from include/Nazara/Utility/NonCopyable.hpp rename to include/Nazara/Core/NonCopyable.hpp diff --git a/include/Nazara/Core/Semaphore.hpp b/include/Nazara/Core/Semaphore.hpp index 24ff442b4..53e7ae509 100644 --- a/include/Nazara/Core/Semaphore.hpp +++ b/include/Nazara/Core/Semaphore.hpp @@ -8,7 +8,7 @@ #define NAZARA_SEMAPHORE_HPP #include -#include +#include class NzSemaphoreImpl; diff --git a/include/Nazara/Core/Thread.hpp b/include/Nazara/Core/Thread.hpp index 49c782818..d5bd416ab 100644 --- a/include/Nazara/Core/Thread.hpp +++ b/include/Nazara/Core/Thread.hpp @@ -10,8 +10,8 @@ #define NAZARA_THREAD_HPP #include -#include -#include +#include +#include class NzThreadImpl; diff --git a/include/Nazara/Utility/Tuple.hpp b/include/Nazara/Core/Tuple.hpp similarity index 91% rename from include/Nazara/Utility/Tuple.hpp rename to include/Nazara/Core/Tuple.hpp index d0159b33e..94d0b77da 100644 --- a/include/Nazara/Utility/Tuple.hpp +++ b/include/Nazara/Core/Tuple.hpp @@ -11,6 +11,6 @@ template void NzUnpackTuple(F func, const std::tuple& t); -#include +#include #endif // NAZARA_TUPLE_HPP diff --git a/include/Nazara/Utility/Tuple.inl b/include/Nazara/Core/Tuple.inl similarity index 100% rename from include/Nazara/Utility/Tuple.inl rename to include/Nazara/Core/Tuple.inl diff --git a/include/Nazara/Prerequesites.hpp b/include/Nazara/Prerequesites.hpp index 71bbfeff5..ff66261cc 100644 --- a/include/Nazara/Prerequesites.hpp +++ b/include/Nazara/Prerequesites.hpp @@ -23,9 +23,8 @@ #define NAZARA_FUNCTION __FUNCSIG__ #elif defined(__GNUC__) #define NAZARA_COMPILER_GCC - #define NAZARA_FUNCTION __PRETTY_FUNCTION__ - #define NAZARA_DEPRECATED(txt) __attribute__((__deprecated__(txt))) + #define NAZARA_FUNCTION __PRETTY_FUNCTION__ #elif defined(__BORLANDC__) #define NAZARA_COMPILER_BORDLAND #define NAZARA_DEPRECATED(txt) diff --git a/include/Nazara/Renderer/Buffer.hpp b/include/Nazara/Renderer/Buffer.hpp index 285a6774b..8176f1c61 100644 --- a/include/Nazara/Renderer/Buffer.hpp +++ b/include/Nazara/Renderer/Buffer.hpp @@ -8,7 +8,7 @@ #define NAZARA_BUFFER_HPP #include -#include +#include #include enum nzBufferLock diff --git a/include/Nazara/Renderer/OcclusionQuery.hpp b/include/Nazara/Renderer/OcclusionQuery.hpp index 42580e6d1..e6ea73e3a 100644 --- a/include/Nazara/Renderer/OcclusionQuery.hpp +++ b/include/Nazara/Renderer/OcclusionQuery.hpp @@ -8,7 +8,7 @@ #define NAZARA_OCCLUSIONQUERY_HPP #include -#include +#include class NAZARA_API NzOcclusionQuery : NzNonCopyable { diff --git a/include/Nazara/Renderer/Shader.hpp b/include/Nazara/Renderer/Shader.hpp index e54de851d..f143d213a 100644 --- a/include/Nazara/Renderer/Shader.hpp +++ b/include/Nazara/Renderer/Shader.hpp @@ -8,9 +8,9 @@ #define NAZARA_SHADER_HPP #include +#include #include #include -#include #include enum nzShaderLanguage diff --git a/include/Nazara/Utility/Image.hpp b/include/Nazara/Utility/Image.hpp index 0273249a0..515a3607c 100644 --- a/include/Nazara/Utility/Image.hpp +++ b/include/Nazara/Utility/Image.hpp @@ -35,12 +35,21 @@ enum nzImageType struct NzImageParams { + // GCC 4.7 je te veux + NzImageParams() : + loadFormat(nzPixelFormat_Undefined) + { + } + + nzPixelFormat loadFormat; + bool IsValid() const { - return true; + return loadFormat == nzPixelFormat_Undefined || NzPixelFormat::IsValid(loadFormat); } }; +///TODO: Animations ? ///TODO: Filtres ///TODO: Mipmaps @@ -55,6 +64,8 @@ class NAZARA_API NzImage : public NzResource, public NzResourceLoader +#include enum nzPixelFormat { nzPixelFormat_Undefined, - nzPixelFormat_B8G8R8, - nzPixelFormat_B8G8R8A8, + nzPixelFormat_BGR8, + nzPixelFormat_BGRA8, nzPixelFormat_DXT1, nzPixelFormat_DXT3, nzPixelFormat_DXT5, nzPixelFormat_L8, - nzPixelFormat_L8A8, - nzPixelFormat_R4G4A4A4, - nzPixelFormat_R5G5A5A1, - nzPixelFormat_R8, - nzPixelFormat_R8G8, - nzPixelFormat_R8G8B8, - nzPixelFormat_R8G8B8A8 + nzPixelFormat_LA8, + /* + nzPixelFormat_RGB16F, + nzPixelFormat_RGB16I, + nzPixelFormat_RGB32F, + nzPixelFormat_RGB32I, + */ + nzPixelFormat_RGBA16F, + nzPixelFormat_RGBA16I, + /* + nzPixelFormat_RGBA32F, + nzPixelFormat_RGBA32I, + */ + nzPixelFormat_RGBA4, + nzPixelFormat_RGB5A1, + nzPixelFormat_RGB8, + nzPixelFormat_RGBA8, + + nzPixelFormat_Count }; +class NzUtility; + class NzPixelFormat { + friend class NzUtility; + public: + typedef nzUInt8* (*ConvertFunction)(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst); + + static bool Convert(nzPixelFormat srcFormat, nzPixelFormat dstFormat, const void* src, void* dst); + static bool Convert(nzPixelFormat srcFormat, nzPixelFormat dstFormat, const void* start, const void* end, void* dst); + static nzUInt8 GetBPP(nzPixelFormat format); + static bool IsCompressed(nzPixelFormat format); + static bool IsValid(nzPixelFormat format); + + static void SetConvertFunction(nzPixelFormat srcFormat, nzPixelFormat dstFormat, ConvertFunction); + + static NzString ToString(nzPixelFormat format); + + private: + static bool Initialize(); + static void Uninitialize(); + + static ConvertFunction s_convertFunctions[nzPixelFormat_Count][nzPixelFormat_Count]; }; #include diff --git a/include/Nazara/Utility/PixelFormat.inl b/include/Nazara/Utility/PixelFormat.inl index f89ca81ab..c50f9b304 100644 --- a/include/Nazara/Utility/PixelFormat.inl +++ b/include/Nazara/Utility/PixelFormat.inl @@ -2,19 +2,76 @@ // This file is part of the "Nazara Engine". // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include +#include +#include + +inline bool NzPixelFormat::Convert(nzPixelFormat srcFormat, nzPixelFormat dstFormat, const void* src, void* dst) +{ + if (srcFormat == dstFormat) + { + std::memcpy(dst, src, GetBPP(srcFormat)); + return true; + } + + #if NAZARA_UTILITY_SAFE + if (IsCompressed(srcFormat)) + { + NazaraError("Cannot convert single pixel from compressed format"); + return false; + } + + if (IsCompressed(dstFormat)) + { + NazaraError("Cannot convert single pixel to compressed format"); + return false; + } + #endif + + ConvertFunction func = s_convertFunctions[srcFormat][dstFormat]; + if (!func) + { + NazaraError("Pixel format conversion from " + ToString(srcFormat) + " to " + ToString(dstFormat) + " not supported"); + return false; + } + + func(static_cast(src), static_cast(src) + GetBPP(srcFormat), static_cast(dst)); + + return true; +} + +inline bool NzPixelFormat::Convert(nzPixelFormat srcFormat, nzPixelFormat dstFormat, const void* start, const void* end, void* dst) +{ + if (srcFormat == dstFormat) + { + std::memcpy(dst, start, static_cast(end)-static_cast(start)); + return true; + } + + ConvertFunction func = s_convertFunctions[srcFormat][dstFormat]; + if (!func) + { + NazaraError("Pixel format conversion from " + ToString(srcFormat) + " to " + ToString(dstFormat) + " not supported"); + return false; + } + + func(static_cast(start), static_cast(end), static_cast(dst)); + + return true; +} inline nzUInt8 NzPixelFormat::GetBPP(nzPixelFormat format) { switch (format) { + case nzPixelFormat_Count: case nzPixelFormat_Undefined: return 0; - case nzPixelFormat_B8G8R8: + case nzPixelFormat_BGR8: return 3; - case nzPixelFormat_B8G8R8A8: + case nzPixelFormat_BGRA8: return 4; case nzPixelFormat_DXT1: @@ -29,28 +86,48 @@ inline nzUInt8 NzPixelFormat::GetBPP(nzPixelFormat format) case nzPixelFormat_L8: return 1; - case nzPixelFormat_L8A8: + case nzPixelFormat_LA8: + return 2; +/* + case nzPixelFormat_RGB16F: + return 6; + + case nzPixelFormat_RGB16I: + return 6; + + case nzPixelFormat_RGB32F: + return 12; + + case nzPixelFormat_RGB32I: + return 12; +*/ + case nzPixelFormat_RGBA16F: + return 8; + + case nzPixelFormat_RGBA16I: + return 8; +/* + case nzPixelFormat_RGBA32F: + return 16; + + case nzPixelFormat_RGBA32I: + return 16; +*/ + case nzPixelFormat_RGBA4: return 2; - case nzPixelFormat_R4G4A4A4: + case nzPixelFormat_RGB5A1: return 2; - case nzPixelFormat_R5G5A5A1: - return 2; - - case nzPixelFormat_R8: - return 1; - - case nzPixelFormat_R8G8: - return 2; - - case nzPixelFormat_R8G8B8: + case nzPixelFormat_RGB8: return 3; - case nzPixelFormat_R8G8B8A8: + case nzPixelFormat_RGBA8: return 4; } + NazaraInternalError("Invalid pixel format"); + return 0; } @@ -68,4 +145,92 @@ inline bool NzPixelFormat::IsCompressed(nzPixelFormat format) } } -#include +inline bool NzPixelFormat::IsValid(nzPixelFormat format) +{ + switch (format) + { + case nzPixelFormat_Count: + case nzPixelFormat_Undefined: + return false; + + default: + return true; + } +} + +inline void NzPixelFormat::SetConvertFunction(nzPixelFormat srcFormat, nzPixelFormat dstFormat, ConvertFunction func) +{ + s_convertFunctions[srcFormat][dstFormat] = func; +} + +inline NzString NzPixelFormat::ToString(nzPixelFormat format) +{ + switch (format) + { + case nzPixelFormat_BGR8: + return "BGR8"; + + case nzPixelFormat_BGRA8: + return "BGRA8"; + + case nzPixelFormat_DXT1: + return "DXT1"; + + case nzPixelFormat_DXT3: + return "DXT3"; + + case nzPixelFormat_DXT5: + return "DXT5"; + + case nzPixelFormat_L8: + return "L8"; + + case nzPixelFormat_LA8: + return "LA8"; +/* + case nzPixelFormat_RGB16F: + return "RGB16F"; + + case nzPixelFormat_RGB16I: + return "RGB16I"; + + case nzPixelFormat_RGB32F: + return "RGB32F"; + + case nzPixelFormat_RGB32I: + return "RGB32I"; +*/ + case nzPixelFormat_RGBA16F: + return "RGBA16F"; + + case nzPixelFormat_RGBA16I: + return "RGBA16I"; +/* + case nzPixelFormat_RGBA32F: + return "RGBA32F"; + + case nzPixelFormat_RGBA32I: + return "RGBA32I"; +*/ + case nzPixelFormat_RGBA4: + return "RGBA4"; + + case nzPixelFormat_RGB5A1: + return "RGB5A1"; + + case nzPixelFormat_RGB8: + return "RGB8"; + + case nzPixelFormat_RGBA8: + return "RGBA8"; + + default: + NazaraInternalError("Invalid pixel format"); + + case nzPixelFormat_Count: + case nzPixelFormat_Undefined: + return "Invalid format"; + } +} + +#include diff --git a/include/Nazara/Utility/Window.hpp b/include/Nazara/Utility/Window.hpp index b51239f52..fd9f98c2e 100644 --- a/include/Nazara/Utility/Window.hpp +++ b/include/Nazara/Utility/Window.hpp @@ -10,11 +10,11 @@ #define NAZARA_WINDOW_HPP #include +#include #include #include #include #include -#include #include #include #include diff --git a/src/Nazara/Core/Hash/CRC32.cpp b/src/Nazara/Core/Hash/CRC32.cpp index 2c0a0685c..6a481e1c4 100644 --- a/src/Nazara/Core/Hash/CRC32.cpp +++ b/src/Nazara/Core/Hash/CRC32.cpp @@ -111,8 +111,9 @@ NzHashDigest NzHashCRC32::End() { m_state->crc ^= 0xFFFFFFFF; - if (NazaraEndianness == nzEndianness_LittleEndian) - NzByteSwap(&m_state->crc, sizeof(nzUInt32)); + #ifdef NAZARA_LITTLE_ENDIAN + NzByteSwap(&m_state->crc, sizeof(nzUInt32)); + #endif return NzHashDigest(GetHashName(), reinterpret_cast(&m_state->crc), 4); } diff --git a/src/Nazara/Core/Hash/Fletcher16.cpp b/src/Nazara/Core/Hash/Fletcher16.cpp index 6239a7ccf..e3c20b32d 100644 --- a/src/Nazara/Core/Hash/Fletcher16.cpp +++ b/src/Nazara/Core/Hash/Fletcher16.cpp @@ -52,8 +52,10 @@ NzHashDigest NzHashFletcher16::End() m_state->sum2 = (m_state->sum2 & 0xff) + (m_state->sum2 >> 8); nzUInt32 fletcher = (m_state->sum2 << 8) | m_state->sum1; - if (NazaraEndianness == nzEndianness_BigEndian) - NzByteSwap(&fletcher, sizeof(nzUInt32)); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&fletcher, sizeof(nzUInt32)); + #endif return NzHashDigest(GetHashName(), reinterpret_cast(&fletcher), 2); } diff --git a/src/Nazara/Core/Hash/MD5.cpp b/src/Nazara/Core/Hash/MD5.cpp index d27faa985..6570fc8cc 100644 --- a/src/Nazara/Core/Hash/MD5.cpp +++ b/src/Nazara/Core/Hash/MD5.cpp @@ -114,7 +114,7 @@ namespace nzUInt32 d = state->abcd[3]; nzUInt32 t; - #ifdef NAZARA_ENDIANNESS_BIGENDIAN + #ifdef NAZARA_BIG_ENDIAN /* Define storage only for big-endian CPUs. */ nzUInt32 X[16]; diff --git a/src/Nazara/Core/Hash/SHA/Internal.cpp b/src/Nazara/Core/Hash/SHA/Internal.cpp index 0ab51a9ce..734de4ede 100644 --- a/src/Nazara/Core/Hash/SHA/Internal.cpp +++ b/src/Nazara/Core/Hash/SHA/Internal.cpp @@ -42,7 +42,7 @@ #include /*** ENDIAN REVERSAL MACROS *******************************************/ -#ifdef NAZARA_ENDIANNESS_LITTLEENDIAN +#ifdef NAZARA_LITTLE_ENDIAN #define REVERSE32(w,x) { \ nzUInt32 tmp = (w); \ @@ -272,7 +272,7 @@ void SHA1_Init(SHA_CTX* context) context->s1.bitcount = 0; } -#ifdef NAZARA_ENDIANNESS_LITTLEENDIAN +#ifdef NAZARA_LITTLE_ENDIAN #define ROUND1_0_TO_15(a,b,c,d,e) \ REVERSE32(*data++, W1[j]); \ @@ -281,7 +281,7 @@ void SHA1_Init(SHA_CTX* context) (b) = ROTL32(30, (b)); \ j++; -#else // NAZARA_ENDIANNESS_LITTLEENDIAN +#else // NAZARA_LITTLE_ENDIAN #define ROUND1_0_TO_15(a,b,c,d,e) \ (e) = ROTL32(5, (a)) + Ch((b), (c), (d)) + (e) + \ @@ -289,7 +289,7 @@ void SHA1_Init(SHA_CTX* context) (b) = ROTL32(30, (b)); \ j++; -#endif // NAZARA_ENDIANNESS_LITTLEENDIAN +#endif // NAZARA_LITTLE_ENDIAN #define ROUND1_16_TO_19(a,b,c,d,e) \ T1 = W1[(j+13)&0x0f] ^ W1[(j+8)&0x0f] ^ W1[(j+2)&0x0f] ^ W1[j&0x0f]; \ @@ -512,7 +512,7 @@ void SHA1_End(SHA_CTX* context, nzUInt8* digest) } } /* Set the bit count: */ -#ifdef NAZARA_ENDIANNESS_LITTLEENDIAN +#ifdef NAZARA_LITTLE_ENDIAN /* Convert FROM host byte order */ REVERSE64(context->s1.bitcount,context->s1.bitcount); #endif @@ -523,7 +523,7 @@ void SHA1_End(SHA_CTX* context, nzUInt8* digest) SHA1_Internal_Transform(context, reinterpret_cast(context->s1.buffer)); /* Save the hash data for output: */ -#ifdef NAZARA_ENDIANNESS_LITTLEENDIAN +#ifdef NAZARA_LITTLE_ENDIAN { /* Convert TO host byte order */ for (int j = 0; j < (SHA1_DIGEST_LENGTH >> 2); j++) @@ -551,7 +551,7 @@ void SHA256_Init(SHA_CTX* context) SHA256_Internal_Init(context, sha256_initial_hash_value); } -#ifdef NAZARA_ENDIANNESS_LITTLEENDIAN +#ifdef NAZARA_LITTLE_ENDIAN #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ REVERSE32(*data++, W256[j]); \ @@ -561,7 +561,7 @@ void SHA256_Init(SHA_CTX* context) (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ -#else // NAZARA_ENDIANNESS_LITTLEENDIAN +#else // NAZARA_LITTLE_ENDIAN #define ROUND256_0_TO_15(a,b,c,d,e,f,g,h) \ T1 = (h) + Sigma1_256(e) + Ch((e), (f), (g)) + \ @@ -570,7 +570,7 @@ void SHA256_Init(SHA_CTX* context) (h) = T1 + Sigma0_256(a) + Maj((a), (b), (c)); \ j++ -#endif // NAZARA_ENDIANNESS_LITTLEENDIAN +#endif // NAZARA_LITTLE_ENDIAN #define ROUND256(a,b,c,d,e,f,g,h) \ s0 = W256[(j+1)&0x0f]; \ @@ -693,7 +693,7 @@ void SHA256_Update(SHA_CTX* context, const nzUInt8 *data, std::size_t len) void SHA256_Internal_Last(SHA_CTX* context) { unsigned int usedspace = (context->s256.bitcount >> 3) % 64; -#ifdef NAZARA_ENDIANNESS_LITTLEENDIAN +#ifdef NAZARA_LITTLE_ENDIAN /* Convert FROM host byte order */ REVERSE64(context->s256.bitcount,context->s256.bitcount); #endif @@ -744,7 +744,7 @@ void SHA256_End(SHA_CTX* context, nzUInt8* digest) SHA256_Internal_Last(context); /* Save the hash data for output: */ -#ifdef NAZARA_ENDIANNESS_LITTLEENDIAN +#ifdef NAZARA_LITTLE_ENDIAN { /* Convert TO host byte order */ for (int j = 0; j < (SHA256_DIGEST_LENGTH >> 2); j++) @@ -786,7 +786,7 @@ void SHA224_End(SHA_CTX* context, nzUInt8* digest) SHA256_Internal_Last(context); /* Save the hash data for output: */ -#ifdef NAZARA_ENDIANNESS_LITTLEENDIAN +#ifdef NAZARA_LITTLE_ENDIAN { /* Convert TO host byte order */ for (int j = 0; j < (SHA224_DIGEST_LENGTH >> 2); j++) @@ -816,7 +816,7 @@ void SHA512_Init(SHA_CTX* context) } /* Unrolled SHA-512 round macros: */ -#ifdef NAZARA_ENDIANNESS_LITTLEENDIAN +#ifdef NAZARA_LITTLE_ENDIAN #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ REVERSE64(*data++, W512[j]); \ @@ -827,7 +827,7 @@ void SHA512_Init(SHA_CTX* context) j++ -#else // NAZARA_ENDIANNESS_LITTLEENDIAN +#else // NAZARA_LITTLE_ENDIAN #define ROUND512_0_TO_15(a,b,c,d,e,f,g,h) \ T1 = (h) + Sigma1_512(e) + Ch((e), (f), (g)) + \ @@ -836,7 +836,7 @@ void SHA512_Init(SHA_CTX* context) (h) = T1 + Sigma0_512(a) + Maj((a), (b), (c)); \ j++ -#endif // NAZARA_ENDIANNESS_LITTLEENDIAN +#endif // NAZARA_LITTLE_ENDIAN #define ROUND512(a,b,c,d,e,f,g,h) \ s0 = W512[(j+1)&0x0f]; \ @@ -958,7 +958,7 @@ void SHA512_Internal_Last(SHA_CTX* context) unsigned int usedspace; usedspace = (context->s512.bitcount[0] >> 3) % 128; -#ifdef NAZARA_ENDIANNESS_LITTLEENDIAN +#ifdef NAZARA_LITTLE_ENDIAN /* Convert FROM host byte order */ REVERSE64(context->s512.bitcount[0],context->s512.bitcount[0]); REVERSE64(context->s512.bitcount[1],context->s512.bitcount[1]); @@ -1011,7 +1011,7 @@ void SHA512_End(SHA_CTX* context, nzUInt8* digest) SHA512_Internal_Last(context); /* Save the hash data for output: */ -#ifdef NAZARA_ENDIANNESS_LITTLEENDIAN +#ifdef NAZARA_LITTLE_ENDIAN { /* Convert TO host byte order */ for (int j = 0; j < (SHA512_DIGEST_LENGTH >> 3); j++) @@ -1051,7 +1051,7 @@ void SHA384_End(SHA_CTX* context, nzUInt8* digest) SHA512_Internal_Last(context); /* Save the hash data for output: */ -#ifdef NAZARA_ENDIANNESS_LITTLEENDIAN +#ifdef NAZARA_LITTLE_ENDIAN { /* Convert TO host byte order */ for (int j = 0; j < (SHA384_DIGEST_LENGTH >> 3); j++) diff --git a/src/Nazara/Core/Win32/DirectoryImpl.hpp b/src/Nazara/Core/Win32/DirectoryImpl.hpp index ce4ce1ae1..799cee9c6 100644 --- a/src/Nazara/Core/Win32/DirectoryImpl.hpp +++ b/src/Nazara/Core/Win32/DirectoryImpl.hpp @@ -8,7 +8,7 @@ #define NAZARA_DIRECTORYIMPL_HPP #include -#include +#include #include class NzDirectory; diff --git a/src/Nazara/Core/Win32/DynLibImpl.hpp b/src/Nazara/Core/Win32/DynLibImpl.hpp index 4734a105d..6688a98fd 100644 --- a/src/Nazara/Core/Win32/DynLibImpl.hpp +++ b/src/Nazara/Core/Win32/DynLibImpl.hpp @@ -8,7 +8,7 @@ #define NAZARA_DYNLIBIMPL_HPP #include -#include +#include #include class NzString; diff --git a/src/Nazara/Core/Win32/FileImpl.hpp b/src/Nazara/Core/Win32/FileImpl.hpp index fac9186f3..8f3cf3ad0 100644 --- a/src/Nazara/Core/Win32/FileImpl.hpp +++ b/src/Nazara/Core/Win32/FileImpl.hpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include diff --git a/src/Nazara/Core/Win32/ThreadImpl.cpp b/src/Nazara/Core/Win32/ThreadImpl.cpp index 3a9c6ac65..e6a627e0b 100644 --- a/src/Nazara/Core/Win32/ThreadImpl.cpp +++ b/src/Nazara/Core/Win32/ThreadImpl.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index 9e863a952..e76b224c6 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -383,10 +383,6 @@ bool NzOpenGL::Initialize() NzContextParameters::defaultMajorVersion = openGLversion/100; NzContextParameters::defaultMinorVersion = (openGLversion%100)/10; -/* - NzContextParameters::defaultMajorVersion = std::min(openGLversion/100, 2U); - NzContextParameters::defaultMinorVersion = std::min((openGLversion%100)/10, 1U); -*/ if (!NzContext::InitializeReference()) { NazaraError("Failed to initialize reference context"); diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index 04c753094..3e906de75 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -36,6 +36,79 @@ NzImage::~NzImage() ReleaseImage(); } +bool NzImage::Convert(nzPixelFormat format) +{ + if (format == m_sharedImage->format) + return true; + + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (!NzPixelFormat::IsValid(format)) + { + NazaraError("Invalid pixel format"); + return false; + } + #endif + + EnsureOwnership(); + + unsigned int depth = (IsCubemap()) ? 6 : m_sharedImage->depth; + unsigned int pixelsPerFace = m_sharedImage->width*m_sharedImage->height; + + nzUInt8* buffer; + if (depth > 1) + { + // Les images 3D sont un empilement d'images 2D + // Quant aux cubemaps, ils sont stockés côte à côte, ce qui revient au même + buffer = new nzUInt8[pixelsPerFace*depth*NzPixelFormat::GetBPP(format)]; + + nzUInt8* ptr = buffer; + nzUInt8* pixels = m_sharedImage->pixels; + unsigned int srcStride = pixelsPerFace * NzPixelFormat::GetBPP(m_sharedImage->format); + unsigned int dstStride = pixelsPerFace * NzPixelFormat::GetBPP(format); + + for (unsigned int i = 0; i < depth; ++i) + { + if (!NzPixelFormat::Convert(m_sharedImage->format, format, pixels, &pixels[srcStride], ptr)) + { + NazaraError("Failed to convert image"); + delete[] buffer; + + return false; + } + + pixels += srcStride; + ptr += dstStride; + } + + delete[] buffer; + } + else + { + buffer = new nzUInt8[pixelsPerFace*NzPixelFormat::GetBPP(format)]; + + if (!NzPixelFormat::Convert(m_sharedImage->format, format, m_sharedImage->pixels, &m_sharedImage->pixels[pixelsPerFace*NzPixelFormat::GetBPP(m_sharedImage->format)], buffer)) + { + NazaraError("Failed to convert image"); + delete[] buffer; + + return false; + } + } + + delete[] m_sharedImage->pixels; + + m_sharedImage->format = format; + m_sharedImage->pixels = buffer; + + return true; +} + bool NzImage::Copy(const NzImage& source, const NzRectui& srcRect, const NzVector2ui& dstPos) { #if NAZARA_UTILITY_SAFE @@ -78,6 +151,14 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width, { ReleaseImage(); + #if NAZARA_UTILITY_SAFE + if (!NzPixelFormat::IsValid(format)) + { + NazaraError("Invalid pixel format"); + return false; + } + #endif + unsigned int size = width*height*depth*NzPixelFormat::GetBPP(format); if (size == 0) return true; @@ -131,7 +212,19 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width, size *= 6; // Les cubemaps ont six faces #endif - m_sharedImage = new SharedImage(1, type, format, new nzUInt8[size], width, height, depth); + // Cette allocation est protégée car sa taille dépend directement de paramètres utilisateurs + nzUInt8* buffer; + try + { + buffer = new nzUInt8[size]; + } + catch (const std::exception& e) + { + NazaraError("Failed to allocate image buffer (" + NzString(e.what()) + ')'); + return false; + } + + m_sharedImage = new SharedImage(1, type, format, buffer, width, height, depth); return true; } @@ -472,4 +565,4 @@ void NzImage::ReleaseImage() m_sharedImage = &emptyImage; } -NzImage::SharedImage NzImage::emptyImage(0, nzImageType_2D, nzPixelFormat_R8G8B8, nullptr, 0, 0, 0); +NzImage::SharedImage NzImage::emptyImage(0, nzImageType_2D, nzPixelFormat_Undefined, nullptr, 0, 0, 0); diff --git a/src/Nazara/Utility/Loaders/PCX.cpp b/src/Nazara/Utility/Loaders/PCX.cpp index 67f8a803e..0eab2c186 100644 --- a/src/Nazara/Utility/Loaders/PCX.cpp +++ b/src/Nazara/Utility/Loaders/PCX.cpp @@ -74,7 +74,7 @@ namespace return false; } - #if NAZARA_ENDIANNESS_BIGENDIAN + #if NAZARA_BIG_ENDIAN // Les fichiers PCX sont en little endian NzByteSwap(&header.xmin, sizeof(nzUInt16)); NzByteSwap(&header.ymin, sizeof(nzUInt16)); @@ -93,7 +93,7 @@ namespace unsigned int width = header.xmax - header.xmin+1; unsigned int height = header.ymax - header.ymin+1; - if (!resource->Create(nzImageType_2D, nzPixelFormat_R8G8B8, width, height)) + if (!resource->Create(nzImageType_2D, nzPixelFormat_RGB8, width, height)) { NazaraError("Failed to create image"); return false; @@ -343,6 +343,9 @@ namespace return false; } + if (parameters.loadFormat != nzPixelFormat_Undefined) + resource->Convert(parameters.loadFormat); + return true; } diff --git a/src/Nazara/Utility/Loaders/STB.cpp b/src/Nazara/Utility/Loaders/STB.cpp index 10441f4e3..d4910e6ef 100644 --- a/src/Nazara/Utility/Loaders/STB.cpp +++ b/src/Nazara/Utility/Loaders/STB.cpp @@ -63,15 +63,44 @@ namespace { NazaraUnused(parameters); - static nzPixelFormat format[4] = { + static nzPixelFormat formats[4] = { nzPixelFormat_L8, - nzPixelFormat_L8A8, - nzPixelFormat_R8G8B8, - nzPixelFormat_R8G8B8A8 + nzPixelFormat_LA8, + nzPixelFormat_RGB8, + nzPixelFormat_RGBA8 }; + nzPixelFormat format; + int stbiFormat; + switch (parameters.loadFormat) + { + case nzPixelFormat_L8: + format = nzPixelFormat_L8; + stbiFormat = STBI_grey; + break; + + case nzPixelFormat_LA8: + format = nzPixelFormat_LA8; + stbiFormat = STBI_grey_alpha; + break; + + case nzPixelFormat_RGB8: + format = nzPixelFormat_RGB8; + stbiFormat = STBI_rgb; + break; + + case nzPixelFormat_RGBA8: + format = nzPixelFormat_RGBA8; + stbiFormat = STBI_rgb_alpha; + break; + + default: + format = nzPixelFormat_Undefined; + stbiFormat = STBI_default; + } + int width, height, bpp; - nzUInt8* ptr = stbi_load_from_callbacks(&callbacks, &stream, &width, &height, &bpp, STBI_default); + nzUInt8* ptr = stbi_load_from_callbacks(&callbacks, &stream, &width, &height, &bpp, stbiFormat); if (!ptr) { @@ -79,7 +108,10 @@ namespace return false; } - if (!resource->Create(nzImageType_2D, format[bpp-1], width, height)) + if (format == nzPixelFormat_Undefined) + format = formats[bpp-1]; + + if (!resource->Create(nzImageType_2D, format, width, height)) { NazaraError("Failed to create image"); stbi_image_free(ptr); @@ -90,6 +122,9 @@ namespace resource->Update(ptr); stbi_image_free(ptr); + if (stbiFormat == STBI_default && parameters.loadFormat != nzPixelFormat_Undefined) + resource->Convert(parameters.loadFormat); + return true; } diff --git a/src/Nazara/Utility/PixelFormat.cpp b/src/Nazara/Utility/PixelFormat.cpp new file mode 100644 index 000000000..de721769b --- /dev/null +++ b/src/Nazara/Utility/PixelFormat.cpp @@ -0,0 +1,1161 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +///FIXME: Endianness (nzUInt16) + +namespace +{ + inline nzUInt8 c4to8(nzUInt8 c) + { + return c * 255.f/15.f; + } + + inline nzUInt8 c5to8(nzUInt8 c) + { + return c * 255.f/31.f; + } + + inline nzUInt8 c8to4(nzUInt8 c) + { + return c * 15.f/255.f; + } + + inline nzUInt8 c8to5(nzUInt8 c) + { + return c * 31.f/255.f; + } + + template + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + NazaraUnused(start); + NazaraUnused(dst); + NazaraUnused(end); + + NazaraInternalError("Conversion from " + NzPixelFormat::ToString(from) + " to " + NzPixelFormat::ToString(to) + " is not supported"); + return nullptr; + } + + /**********************************BGR8***********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + *dst++ = start[1]; + *dst++ = start[2]; + *dst++ = 0xFF; + + start += 3; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = static_cast(start[2] * 0.3 + start[1] * 0.59 + start[0] * 0.11); + + start += 3; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = static_cast(start[2] * 0.3 + start[1] * 0.59 + start[0] * 0.11); + *dst++ = 0xFF; + + start += 3; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = ((c8to4(start[2])) << 4) | c8to4(start[1]); + *dst++ = ((c8to4(start[0])) << 4) | 0x0F; + + start += 3; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + *ptr++ = (static_cast(c8to5(start[2])) << 11) | + (static_cast(c8to5(start[1])) << 6) | + (static_cast(c8to5(start[0])) << 1) | + 0x1; + + start += 3; + } + + return reinterpret_cast(ptr); + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[2]; + *dst++ = start[1]; + *dst++ = start[0]; + + start += 3; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[2]; + *dst++ = start[1]; + *dst++ = start[0]; + *dst++ = 0xFF; + + start += 3; + } + + return dst; + } + + /**********************************BGRA8**********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + *dst++ = start[1]; + *dst++ = start[2]; + + start += 4; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = static_cast(start[2] * 0.3 + start[1] * 0.59 + start[0] * 0.11); + + start += 4; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = static_cast(start[2] * 0.3 + start[1] * 0.59 + start[0] * 0.11); + *dst++ = start[3]; + + start += 4; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = (c8to4(start[2]) << 4) | c8to4(start[1]); + *dst++ = (c8to4(start[0]) << 4) | c8to4(start[3]); + + start += 4; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + *ptr++ = (static_cast(c8to5(start[2])) << 11) | + (static_cast(c8to5(start[1])) << 6) | + (static_cast(c8to5(start[0])) << 1) | + ((start[3] == 0xFF) ? 1 : 0); + + start += 4; + } + + return reinterpret_cast(ptr); + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[2]; + *dst++ = start[1]; + *dst++ = start[0]; + + start += 4; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[2]; + *dst++ = start[1]; + *dst++ = start[0]; + *dst++ = start[3]; + + start += 4; + } + + return dst; + } + + /***********************************L8************************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + *dst++ = start[0]; + *dst++ = start[0]; + + start += 1; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + *dst++ = start[0]; + *dst++ = start[0]; + *dst++ = 0xFF; + + start += 1; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + *dst++ = 0xFF; + + start += 1; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + nzUInt8 l = c8to4(start[0]); + + *dst++ = (l << 4) | l; + *dst++ = (l << 4) | 0x0F; + + start += 1; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + nzUInt16 l = static_cast(c8to5(start[0])); + + *ptr++ = (l << 11) | + (l << 6) | + (l << 1) | + 1; + + start += 1; + } + + return reinterpret_cast(ptr); + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + *dst++ = start[0]; + *dst++ = start[0]; + + start += 1; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + *dst++ = start[0]; + *dst++ = start[0]; + *dst++ = 0xFF; + + start += 1; + } + + return dst; + } + + /***********************************LA8***********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + *dst++ = start[0]; + *dst++ = start[0]; + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + *dst++ = start[0]; + *dst++ = start[0]; + *dst++ = start[1]; + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + nzUInt8 l = c8to4(start[0]); + + *dst++ = (l << 4) | l; + *dst++ = (l << 4) | c8to4(start[1]); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + nzUInt16 l = static_cast(c8to5(start[0])); + + *ptr++ = (l << 11) | (l << 6) | (l << 1) | ((start[1] == 0xFF) ? 1 : 0); + + start += 2; + } + + return reinterpret_cast(ptr); + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + *dst++ = start[0]; + *dst++ = start[0]; + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + *dst++ = start[0]; + *dst++ = start[0]; + *dst++ = start[1]; + + start += 2; + } + + return dst; + } + + /*********************************RGBA4***********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = (c4to8((start[1] & 0xF0) >> 4)); + *dst++ = (c4to8((start[0] & 0x0F) >> 0)); + *dst++ = (c4to8((start[0] & 0xF0) >> 4)); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = c4to8((start[1] & 0xF0) >> 4); + *dst++ = c4to8((start[0] & 0x0F) >> 0); + *dst++ = c4to8((start[0] & 0xF0) >> 4); + *dst++ = c4to8((start[1] & 0x0F) >> 0); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + nzUInt8 r = c4to8((start[0] & 0xF0) >> 4); + nzUInt8 g = c4to8((start[0] & 0x0F) >> 0); + nzUInt8 b = c4to8((start[1] & 0xF0) >> 4); + + *dst++ = static_cast(r * 0.3 + g * 0.59 + b * 0.11); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + nzUInt8 r = c4to8((start[0] & 0xF0) >> 4); + nzUInt8 g = c4to8((start[0] & 0x0F) >> 0); + nzUInt8 b = c4to8((start[1] & 0xF0) >> 4); + + *dst++ = static_cast(r * 0.3 + g * 0.59 + b * 0.11); + *dst++ = c4to8(start[1] & 0x0F); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + nzUInt16 r = (start[0] & 0xF0) >> 4; + nzUInt16 g = (start[0] & 0x0F) >> 0; + nzUInt16 b = (start[1] & 0xF0) >> 4; + nzUInt8 a = (start[1] & 0x0F) >> 0; + + *ptr++ = (r << 11) | (g << 6) | (b << 1) | ((a == 0xFF) ? 1 : 0); + + start += 2; + } + + return reinterpret_cast(ptr); + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = c4to8((start[0] & 0xF0) >> 4); + *dst++ = c4to8((start[0] & 0x0F) >> 0); + *dst++ = c4to8((start[1] & 0xF0) >> 4); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = c4to8((start[0] & 0xF0) >> 4); + *dst++ = c4to8((start[0] & 0x0F) >> 0); + *dst++ = c4to8((start[1] & 0xF0) >> 4); + *dst++ = c4to8((start[1] & 0x0F) >> 0); + + start += 2; + } + + return dst; + } + + /*********************************RGB5A1**********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + nzUInt16 pixel = *reinterpret_cast(start); + + *dst++ = c5to8((pixel & 0x003E) >> 1); + *dst++ = c5to8((pixel & 0x07C0) >> 6); + *dst++ = c5to8((pixel & 0xF800) >> 11); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + nzUInt16 pixel = *reinterpret_cast(start); + + *dst++ = c5to8((pixel & 0x003E) >> 1); + *dst++ = c5to8((pixel & 0x07C0) >> 6); + *dst++ = c5to8((pixel & 0xF800) >> 11); + *dst++ = static_cast((pixel & 0x1)*0xFF); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + nzUInt16 pixel = *reinterpret_cast(start); + + nzUInt8 r = c5to8((pixel & 0xF800) >> 11); + nzUInt8 g = c5to8((pixel & 0x07C0) >> 6); + nzUInt8 b = c5to8((pixel & 0x003E) >> 1); + + *dst++ = static_cast(r * 0.3 + g * 0.59 + b * 0.11); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + nzUInt16 pixel = *reinterpret_cast(start); + + nzUInt8 r = c5to8((pixel & 0xF800) >> 11); + nzUInt8 g = c5to8((pixel & 0x07C0) >> 6); + nzUInt8 b = c5to8((pixel & 0x003E) >> 1); + + *dst++ = static_cast(r * 0.3 + g * 0.59 + b * 0.11); + *dst++ = static_cast((pixel & 0x1)*0xFF); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + nzUInt16 pixel = *reinterpret_cast(start); + + nzUInt8 r = c5to8((pixel & 0xF800) >> 11); + nzUInt8 g = c5to8((pixel & 0x07C0) >> 6); + nzUInt8 b = c5to8((pixel & 0x003E) >> 1); + + *dst++ = (c8to4(r) << 4) | c8to4(g); + *dst++ = (c8to4(b) << 4) | ((pixel & 0x1)*0x0F); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + nzUInt16 pixel = *reinterpret_cast(start); + + *dst++ = c5to8((pixel & 0xF800) >> 11); + *dst++ = c5to8((pixel & 0x07C0) >> 6); + *dst++ = c5to8((pixel & 0x003E) >> 1); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + nzUInt16 pixel = *reinterpret_cast(start); + + *dst++ = c5to8((pixel & 0xF800) >> 11); + *dst++ = c5to8((pixel & 0x07C0) >> 6); + *dst++ = c5to8((pixel & 0x003E) >> 1); + *dst++ = static_cast((pixel & 0x1)*0xFF); + + start += 2; + } + + return dst; + } + + /**********************************RGB8***********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[2]; + *dst++ = start[1]; + *dst++ = start[0]; + + start += 3; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[2]; + *dst++ = start[1]; + *dst++ = start[0]; + *dst++ = 0xFF; + + start += 3; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = static_cast(start[0] * 0.3 + start[1] * 0.59 + start[2] * 0.11); + + start += 3; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = static_cast(start[0] * 0.3 + start[1] * 0.59 + start[2] * 0.11); + *dst++ = 0xFF; + + start += 3; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = (c8to4(start[0]) << 4) | c8to4(start[1]); + *dst++ = (c8to4(start[2]) << 4) | 0x0F; + + start += 3; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + NazaraWarning("r: " + NzString::Number(c8to5(start[0]))); + + *ptr++ = (static_cast(c8to5(start[0])) << 11) | + (static_cast(c8to5(start[1])) << 6) | + (static_cast(c8to5(start[2])) << 1) | + 0x1; + + start += 3; + } + + return reinterpret_cast(ptr); + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + *dst++ = start[1]; + *dst++ = start[2]; + *dst++ = 0xFF; + + start += 3; + } + + return dst; + } + + /**********************************RGBA8**********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[2]; + *dst++ = start[1]; + *dst++ = start[0]; + + start += 4; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[2]; + *dst++ = start[1]; + *dst++ = start[0]; + *dst++ = start[3]; + + start += 4; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = static_cast(start[0] * 0.3 + start[1] * 0.59 + start[2] * 0.11); + + start += 4; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = static_cast(start[0] * 0.3 + start[1] * 0.59 + start[2] * 0.11); + *dst++ = start[3]; + + start += 4; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = (c8to4(start[0]) << 4) | c8to4(start[1]); + *dst++ = (c8to4(start[2]) << 4) | c8to4(start[3]); + + start += 4; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + *ptr++ = (static_cast(c8to5(start[0])) << 11) | + (static_cast(c8to5(start[1])) << 6) | + (static_cast(c8to5(start[2])) << 1) | + ((start[3] == 0xFF) ? 1 : 0); + + start += 4; + } + + return reinterpret_cast(ptr); + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + *dst++ = start[0]; + *dst++ = start[1]; + *dst++ = start[2]; + + start += 4; + } + + return dst; + } + + template + void RegisterConverter() + { + NzPixelFormat::SetConvertFunction(format1, format2, &ConvertPixels); + } +} + +bool NzPixelFormat::Initialize() +{ + /**********************************BGR8***********************************/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + + /**********************************BGRA8**********************************/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + + /**********************************DXT1***********************************/ + ///TODO +/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); +*/ + + /**********************************DXT3***********************************/ + ///TODO +/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); +*/ + + /**********************************DXT5***********************************/ + ///TODO +/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); +*/ + + /***********************************L8************************************/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + + /***********************************LA8***********************************/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + + /**********************************RGBA4**********************************/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + + /*********************************RGB5A1**********************************/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + + /**********************************RGB8***********************************/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + + /**********************************RGBA8**********************************/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter();*/ + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + + return true; +} + +void NzPixelFormat::Uninitialize() +{ + std::memset(s_convertFunctions, 0, nzPixelFormat_Count*nzPixelFormat_Count*sizeof(NzPixelFormat::ConvertFunction)); +} + +NzPixelFormat::ConvertFunction NzPixelFormat::s_convertFunctions[nzPixelFormat_Count][nzPixelFormat_Count] = {{0}}; diff --git a/src/Nazara/Utility/Utility.cpp b/src/Nazara/Utility/Utility.cpp index 02bc5576e..64de352dc 100644 --- a/src/Nazara/Utility/Utility.cpp +++ b/src/Nazara/Utility/Utility.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include NzUtility::NzUtility() @@ -29,6 +30,12 @@ bool NzUtility::Initialize() } #endif + if (!NzPixelFormat::Initialize()) + { + NazaraError("Failed to initialize pixel format"); + return false; + } + // Loaders spécialisés NzLoaders_PCX_Register(); // Loader de fichiers .PCX (1, 4, 8, 24) @@ -53,6 +60,8 @@ void NzUtility::Uninitialize() NzLoaders_STB_Unregister(); NzLoaders_PCX_Unregister(); + NzPixelFormat::Uninitialize(); + s_initialized = false; } diff --git a/src/Nazara/Utility/Win32/WindowImpl.hpp b/src/Nazara/Utility/Win32/WindowImpl.hpp index 99a6025c9..caf84d163 100644 --- a/src/Nazara/Utility/Win32/WindowImpl.hpp +++ b/src/Nazara/Utility/Win32/WindowImpl.hpp @@ -9,12 +9,12 @@ #ifndef NAZARA_WINDOWIMPL_HPP #define NAZARA_WINDOWIMPL_HPP +#include #include #include #include #include #include -#include #include #include #include From f55cf9671329eccaf4329a2a252bf55a12297956 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 25 May 2012 07:42:48 +0200 Subject: [PATCH 02/15] Optimized NzImage::Convert Removed debug warning --- src/Nazara/Utility/Image.cpp | 58 ++++++++++-------------------- src/Nazara/Utility/PixelFormat.cpp | 2 -- 2 files changed, 18 insertions(+), 42 deletions(-) diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index 3e906de75..6d85cc3c0 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -38,9 +38,6 @@ NzImage::~NzImage() bool NzImage::Convert(nzPixelFormat format) { - if (format == m_sharedImage->format) - return true; - #if NAZARA_UTILITY_SAFE if (!IsValid()) { @@ -55,56 +52,37 @@ bool NzImage::Convert(nzPixelFormat format) } #endif - EnsureOwnership(); + if (format == m_sharedImage->format) + return true; - unsigned int depth = (IsCubemap()) ? 6 : m_sharedImage->depth; + // Les images 3D et cubemaps sont stockés de la même façon + unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth; unsigned int pixelsPerFace = m_sharedImage->width*m_sharedImage->height; - nzUInt8* buffer; - if (depth > 1) + nzUInt8* buffer = new nzUInt8[pixelsPerFace*depth*NzPixelFormat::GetBPP(format)]; + nzUInt8* ptr = buffer; + nzUInt8* pixels = m_sharedImage->pixels; + unsigned int srcStride = pixelsPerFace * NzPixelFormat::GetBPP(m_sharedImage->format); + unsigned int dstStride = pixelsPerFace * NzPixelFormat::GetBPP(format); + + for (unsigned int i = 0; i < depth; ++i) { - // Les images 3D sont un empilement d'images 2D - // Quant aux cubemaps, ils sont stockés côte à côte, ce qui revient au même - buffer = new nzUInt8[pixelsPerFace*depth*NzPixelFormat::GetBPP(format)]; - - nzUInt8* ptr = buffer; - nzUInt8* pixels = m_sharedImage->pixels; - unsigned int srcStride = pixelsPerFace * NzPixelFormat::GetBPP(m_sharedImage->format); - unsigned int dstStride = pixelsPerFace * NzPixelFormat::GetBPP(format); - - for (unsigned int i = 0; i < depth; ++i) - { - if (!NzPixelFormat::Convert(m_sharedImage->format, format, pixels, &pixels[srcStride], ptr)) - { - NazaraError("Failed to convert image"); - delete[] buffer; - - return false; - } - - pixels += srcStride; - ptr += dstStride; - } - - delete[] buffer; - } - else - { - buffer = new nzUInt8[pixelsPerFace*NzPixelFormat::GetBPP(format)]; - - if (!NzPixelFormat::Convert(m_sharedImage->format, format, m_sharedImage->pixels, &m_sharedImage->pixels[pixelsPerFace*NzPixelFormat::GetBPP(m_sharedImage->format)], buffer)) + if (!NzPixelFormat::Convert(m_sharedImage->format, format, pixels, &pixels[srcStride], ptr)) { NazaraError("Failed to convert image"); delete[] buffer; return false; } + + pixels += srcStride; + ptr += dstStride; } - delete[] m_sharedImage->pixels; + SharedImage* newImage = new SharedImage(1, m_sharedImage->type, format, buffer, m_sharedImage->width, m_sharedImage->height, m_sharedImage->depth); - m_sharedImage->format = format; - m_sharedImage->pixels = buffer; + ReleaseImage(); + m_sharedImage = newImage; return true; } diff --git a/src/Nazara/Utility/PixelFormat.cpp b/src/Nazara/Utility/PixelFormat.cpp index de721769b..35dc5612f 100644 --- a/src/Nazara/Utility/PixelFormat.cpp +++ b/src/Nazara/Utility/PixelFormat.cpp @@ -800,8 +800,6 @@ namespace nzUInt16* ptr = reinterpret_cast(dst); while (start < end) { - NazaraWarning("r: " + NzString::Number(c8to5(start[0]))); - *ptr++ = (static_cast(c8to5(start[0])) << 11) | (static_cast(c8to5(start[1])) << 6) | (static_cast(c8to5(start[2])) << 1) | From 7659fdf4608bd75de5eebf63156fc734d20a9c9d Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 25 May 2012 12:23:04 +0200 Subject: [PATCH 03/15] Window's subsystem is now initialized by NzUtility Optimized Image --- include/Nazara/Utility/Window.hpp | 5 ++ src/Nazara/Utility/Image.cpp | 8 +-- src/Nazara/Utility/PixelFormat.cpp | 10 ++-- src/Nazara/Utility/Utility.cpp | 11 ++++ src/Nazara/Utility/Win32/WindowImpl.cpp | 68 +++++++++---------------- src/Nazara/Utility/Win32/WindowImpl.hpp | 6 ++- src/Nazara/Utility/Window.cpp | 10 ++++ 7 files changed, 64 insertions(+), 54 deletions(-) diff --git a/include/Nazara/Utility/Window.hpp b/include/Nazara/Utility/Window.hpp index fd9f98c2e..e6b202df3 100644 --- a/include/Nazara/Utility/Window.hpp +++ b/include/Nazara/Utility/Window.hpp @@ -24,10 +24,12 @@ #include #endif +class NzUtility; class NzWindowImpl; class NAZARA_API NzWindow : NzNonCopyable { + friend class NzUtility; friend class NzWindowImpl; public: @@ -99,6 +101,9 @@ class NAZARA_API NzWindow : NzNonCopyable private: void PushEvent(const NzEvent& event); + static bool Initialize(); + static void Uninitialize(); + std::queue m_events; #if NAZARA_UTILITY_THREADED_WINDOW NzMutex m_eventMutex; diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index 6d85cc3c0..96d037cce 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -298,7 +298,7 @@ bool NzImage::Update(const nzUInt8* pixels) return false; } - if (IsCubemap()) + if (m_sharedImage->type == nzImageType_Cubemap) { NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); return false; @@ -327,7 +327,7 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect) return false; } - if (IsCubemap()) + if (m_sharedImage->type == nzImageType_Cubemap) { NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); return false; @@ -380,7 +380,7 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels) return false; } - if (!IsCubemap()) + if (m_sharedImage->type != nzImageType_Cubemap) { NazaraError("Update is only designed for cubemaps, use Update instead"); return false; @@ -410,7 +410,7 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRect return false; } - if (!IsCubemap()) + if (m_sharedImage->type != nzImageType_Cubemap) { NazaraError("Update is only designed for cubemaps, use Update instead"); return false; diff --git a/src/Nazara/Utility/PixelFormat.cpp b/src/Nazara/Utility/PixelFormat.cpp index 35dc5612f..8dff3adcb 100644 --- a/src/Nazara/Utility/PixelFormat.cpp +++ b/src/Nazara/Utility/PixelFormat.cpp @@ -14,22 +14,22 @@ namespace { inline nzUInt8 c4to8(nzUInt8 c) { - return c * 255.f/15.f; + return c * (255.f/15.f); } inline nzUInt8 c5to8(nzUInt8 c) { - return c * 255.f/31.f; + return c * (255.f/31.f); } inline nzUInt8 c8to4(nzUInt8 c) { - return c * 15.f/255.f; + return c * (15.f/255.f); } inline nzUInt8 c8to5(nzUInt8 c) { - return c * 31.f/255.f; + return c * (31.f/255.f); } template @@ -215,7 +215,7 @@ namespace *ptr++ = (static_cast(c8to5(start[2])) << 11) | (static_cast(c8to5(start[1])) << 6) | (static_cast(c8to5(start[0])) << 1) | - ((start[3] == 0xFF) ? 1 : 0); + ((start[3] == 0xFF) ? 1 : 0); start += 4; } diff --git a/src/Nazara/Utility/Utility.cpp b/src/Nazara/Utility/Utility.cpp index 64de352dc..3d1bfe716 100644 --- a/src/Nazara/Utility/Utility.cpp +++ b/src/Nazara/Utility/Utility.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include NzUtility::NzUtility() @@ -36,6 +37,14 @@ bool NzUtility::Initialize() return false; } + if (!NzWindow::Initialize()) + { + NazaraError("Failed to initialize window's system"); + NzPixelFormat::Uninitialize(); + + return false; + } + // Loaders spécialisés NzLoaders_PCX_Register(); // Loader de fichiers .PCX (1, 4, 8, 24) @@ -60,6 +69,8 @@ void NzUtility::Uninitialize() NzLoaders_STB_Unregister(); NzLoaders_PCX_Unregister(); + NzWindow::Uninitialize(); + NzPixelFormat::Uninitialize(); s_initialized = false; diff --git a/src/Nazara/Utility/Win32/WindowImpl.cpp b/src/Nazara/Utility/Win32/WindowImpl.cpp index 937b1c311..f020cbdfa 100644 --- a/src/Nazara/Utility/Win32/WindowImpl.cpp +++ b/src/Nazara/Utility/Win32/WindowImpl.cpp @@ -25,7 +25,6 @@ namespace { const wchar_t* className = L"Nazara Window"; NzWindowImpl* fullscreenWindow = nullptr; - unsigned int windowCount = 0; } NzWindowImpl::NzWindowImpl(NzWindow* parent) : @@ -62,19 +61,10 @@ void NzWindowImpl::Close() } else SetEventListener(false); - - if (--windowCount == 0) - Uninitialize(); } bool NzWindowImpl::Create(NzVideoMode mode, const NzString& title, nzUInt32 style) { - if (windowCount++ == 0 && !Initialize()) - { - NazaraError("Unable to initialize window implementation"); - return false; - } - bool fullscreen = (style & NzWindow::Fullscreen) != 0; DWORD win32Style, win32StyleEx; unsigned int x, y; @@ -165,15 +155,7 @@ bool NzWindowImpl::Create(NzVideoMode mode, const NzString& title, nzUInt32 styl m_eventListener = true; m_ownsWindow = true; - if (m_handle != nullptr) - return true; - else - { - if (--windowCount == 0) - Uninitialize(); - - return false; - } + return m_handle != nullptr; } bool NzWindowImpl::Create(NzWindowHandle handle) @@ -776,6 +758,30 @@ bool NzWindowImpl::HandleMessage(HWND window, UINT message, WPARAM wParam, LPARA return false; } +bool NzWindowImpl::Initialize() +{ + // Nous devons faire un type Unicode pour que la fenêtre le soit également + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms633574(v=vs.85).aspx + WNDCLASSW windowClass; + windowClass.cbClsExtra = 0; + windowClass.cbWndExtra = 0; + windowClass.hbrBackground = nullptr; + windowClass.hCursor = nullptr; // Le curseur est définit dynamiquement + windowClass.hIcon = nullptr; // L'icône est définie dynamiquement + windowClass.hInstance = GetModuleHandle(nullptr); + windowClass.lpfnWndProc = MessageHandler; + windowClass.lpszClassName = className; + windowClass.lpszMenuName = nullptr; + windowClass.style = CS_DBLCLKS; // Gestion du double-clic + + return RegisterClassW(&windowClass); +} + +void NzWindowImpl::Uninitialize() +{ + UnregisterClassW(className, GetModuleHandle(nullptr)); +} + LRESULT CALLBACK NzWindowImpl::MessageHandler(HWND window, UINT message, WPARAM wParam, LPARAM lParam) { NzWindowImpl* me; @@ -798,25 +804,6 @@ LRESULT CALLBACK NzWindowImpl::MessageHandler(HWND window, UINT message, WPARAM return DefWindowProcW(window, message, wParam, lParam); } -bool NzWindowImpl::Initialize() -{ - // Nous devons faire un type Unicode pour que la fenêtre le soit également - // http://msdn.microsoft.com/en-us/library/windows/desktop/ms633574(v=vs.85).aspx - WNDCLASSW windowClass; - windowClass.cbClsExtra = 0; - windowClass.cbWndExtra = 0; - windowClass.hbrBackground = nullptr; - windowClass.hCursor = nullptr; // Le curseur est définit dynamiquement - windowClass.hIcon = nullptr; // L'icône est définie dynamiquement - windowClass.hInstance = GetModuleHandle(nullptr); - windowClass.lpfnWndProc = MessageHandler; - windowClass.lpszClassName = className; - windowClass.lpszMenuName = nullptr; - windowClass.style = CS_DBLCLKS; // Gestion du double-clic - - return RegisterClassW(&windowClass); -} - NzKeyboard::Key NzWindowImpl::ConvertVirtualKey(WPARAM key, LPARAM flags) { switch (key) @@ -949,11 +936,6 @@ NzKeyboard::Key NzWindowImpl::ConvertVirtualKey(WPARAM key, LPARAM flags) } } -void NzWindowImpl::Uninitialize() -{ - UnregisterClassW(className, GetModuleHandle(nullptr)); -} - #if NAZARA_UTILITY_THREADED_WINDOW void NzWindowImpl::WindowThread(HWND* handle, DWORD styleEx, const wchar_t* title, DWORD style, unsigned int x, unsigned int y, unsigned int width, unsigned int height, NzWindowImpl* window, NzMutex* mutex, NzThreadCondition* condition) { diff --git a/src/Nazara/Utility/Win32/WindowImpl.hpp b/src/Nazara/Utility/Win32/WindowImpl.hpp index caf84d163..48791c68c 100644 --- a/src/Nazara/Utility/Win32/WindowImpl.hpp +++ b/src/Nazara/Utility/Win32/WindowImpl.hpp @@ -24,6 +24,7 @@ class NzMutex; class NzThread; class NzThreadCondition; #endif +class NzWindow; #undef IsMinimized // Conflit avec la méthode du même nom @@ -67,13 +68,14 @@ class NzWindowImpl : NzNonCopyable void ShowMouseCursor(bool show); void StayOnTop(bool stayOnTop); + static bool Initialize(); + static void Uninitialize(); + private: bool HandleMessage(HWND window, UINT message, WPARAM wParam, LPARAM lParam); - static bool Initialize(); static LRESULT CALLBACK MessageHandler(HWND window, UINT message, WPARAM wParam, LPARAM lParam); static NzKeyboard::Key ConvertVirtualKey(WPARAM key, LPARAM flags); - static void Uninitialize(); #if NAZARA_UTILITY_THREADED_WINDOW static void WindowThread(HWND* handle, DWORD styleEx, const wchar_t* title, DWORD style, unsigned int x, unsigned int y, unsigned int width, unsigned int height, NzWindowImpl* window, NzMutex* mutex, NzThreadCondition* condition); #endif diff --git a/src/Nazara/Utility/Window.cpp b/src/Nazara/Utility/Window.cpp index 384549143..b8425bd7e 100644 --- a/src/Nazara/Utility/Window.cpp +++ b/src/Nazara/Utility/Window.cpp @@ -473,3 +473,13 @@ void NzWindow::PushEvent(const NzEvent& event) } #endif } + +bool NzWindow::Initialize() +{ + return NzWindowImpl::Initialize(); +} + +void NzWindow::Uninitialize() +{ + NzWindowImpl::Uninitialize(); +} From 96ea5fdaa724f2590be7ed50ecd6a71df1a5788a Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 27 May 2012 11:57:34 +0200 Subject: [PATCH 04/15] Added NzImage::Get/SetPixel(Face) NzImage::Update(const nzUInt8* pixels, const NzRectui& rect) now takes a third argument to specify the layer of the 3D image (if a 3D image), default to 0 Optimized NzPixelFormat conversion from RGBA4 Added NzColor --- include/Nazara/Core/Color.hpp | 68 +++++ include/Nazara/Core/Color.inl | 410 +++++++++++++++++++++++++++++ include/Nazara/Utility/Image.hpp | 9 +- src/Nazara/Core/Color.cpp | 16 ++ src/Nazara/Utility/Image.cpp | 212 ++++++++++++++- src/Nazara/Utility/PixelFormat.cpp | 10 +- 6 files changed, 711 insertions(+), 14 deletions(-) create mode 100644 include/Nazara/Core/Color.hpp create mode 100644 include/Nazara/Core/Color.inl create mode 100644 src/Nazara/Core/Color.cpp diff --git a/include/Nazara/Core/Color.hpp b/include/Nazara/Core/Color.hpp new file mode 100644 index 000000000..be4143c7f --- /dev/null +++ b/include/Nazara/Core/Color.hpp @@ -0,0 +1,68 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_COLOR_HPP +#define NAZARA_COLOR_HPP + +#include +#include +#include + +class NzColor +{ + public: + NzColor(); + NzColor(nzUInt8 red, nzUInt8 green, nzUInt8 blue, nzUInt8 alpha = 255); + explicit NzColor(nzUInt8 lightness); + NzColor(nzUInt8 color[3], nzUInt8 alpha = 255); + NzColor(const NzColor& color) = default; + ~NzColor() = default; + + NzString ToString() const; + + NzColor operator+(const NzColor& angles) const; + NzColor operator*(const NzColor& angles) const; + + NzColor operator+=(const NzColor& angles); + NzColor operator*=(const NzColor& angles); + + bool operator==(const NzColor& angles) const; + bool operator!=(const NzColor& angles) const; + + static NzColor FromCMY(float cyan, float magenta, float yellow); + static NzColor FromCMYK(float cyan, float magenta, float yellow, float black); + static NzColor FromHSL(nzUInt8 hue, nzUInt8 saturation, nzUInt8 lightness); + static NzColor FromHSV(nzUInt8 hue, nzUInt8 saturation, float value); + static NzColor FromXYZ(const NzVector3f& vec); + static NzColor FromXYZ(float x, float y, float z); + static void ToCMY(const NzColor& color, float* cyan, float* magenta, float* yellow); + static void ToCMYK(const NzColor& color, float* cyan, float* magenta, float* yellow, float* black); + static void ToXYZ(const NzColor& color, NzVector3f* vec); + static void ToXYZ(const NzColor& color, float* x, float* y, float* z); + static void ToHSL(const NzColor& color, nzUInt8* hue, nzUInt8* saturation, nzUInt8* lightness); + static void ToHSV(const NzColor& color, nzUInt8* hue, nzUInt8* saturation, float* value); + + nzUInt8 r, g, b, a; + + static const NzColor Black; + static const NzColor Blue; + static const NzColor Cyan; + static const NzColor Green; + static const NzColor Magenta; + static const NzColor Orange; + static const NzColor Red; + static const NzColor Yellow; + static const NzColor White; + + private: + static float Hue2RGB(float v1, float v2, float vH); +}; + +std::ostream& operator<<(std::ostream& out, const NzColor& color); + +#include + +#endif // NAZARA_COLOR_HPP diff --git a/include/Nazara/Core/Color.inl b/include/Nazara/Core/Color.inl new file mode 100644 index 000000000..ec5491dd8 --- /dev/null +++ b/include/Nazara/Core/Color.inl @@ -0,0 +1,410 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +inline NzColor::NzColor() +{ +} + +inline NzColor::NzColor(nzUInt8 red, nzUInt8 green, nzUInt8 blue, nzUInt8 alpha) : +r(red), +g(green), +b(blue), +a(alpha) +{ +} + +inline NzColor::NzColor(nzUInt8 lightness) : +r(lightness), +g(lightness), +b(lightness), +a(255) +{ +} + +inline NzColor::NzColor(nzUInt8 vec[3], nzUInt8 alpha) : +r(vec[0]), +g(vec[1]), +b(vec[2]), +a(alpha) +{ +} + +inline NzString NzColor::ToString() const +{ + NzStringStream ss; + ss << "Color(" << static_cast(r) << ", " << static_cast(g) << ", " << static_cast(b); + + if (a != 255) + ss << ", " << static_cast(a); + + ss << ')'; + + return ss; +} + +inline NzColor NzColor::operator+(const NzColor& color) const +{ + return NzColor(std::min(static_cast(r) + color.r, 255), + std::min(static_cast(r) + color.r, 255), + std::min(static_cast(r) + color.r, 255), + std::min(static_cast(r) + color.r, 255)); +} + +inline NzColor NzColor::operator*(const NzColor& color) const +{ + return NzColor(static_cast(r) * color.r/255, + static_cast(r) * color.r/255, + static_cast(r) * color.r/255, + static_cast(r) * color.r/255); +} + +inline NzColor NzColor::operator+=(const NzColor& color) +{ + return operator=(operator+(color)); +} + +inline NzColor NzColor::operator*=(const NzColor& color) +{ + return operator=(operator+(color)); +} + +inline bool NzColor::operator==(const NzColor& color) const +{ + return r == color.r && g == color.g && b == color.b && a == color.a; +} + +inline bool NzColor::operator!=(const NzColor& color) const +{ + return !operator==(color); +} + +// Algorithmes venant de http://www.easyrgb.com/index.php?X=MATH + +inline NzColor NzColor::FromCMY(float cyan, float magenta, float yellow) +{ + return NzColor((1.f-cyan)*255.f, (1.f-magenta)*255.f, (1.f-yellow)*255.f); +} + +inline NzColor NzColor::FromCMYK(float cyan, float magenta, float yellow, float black) +{ + return FromCMY(cyan * (1.f - black) + black, + magenta * (1.f - black) + black, + yellow * (1.f - black) + black); +} + +inline NzColor NzColor::FromHSL(nzUInt8 hue, nzUInt8 saturation, nzUInt8 lightness) +{ + // Norme Windows + float l = lightness/240.f; + + if (saturation == 0) + { + // RGB results from 0 to 255 + return NzColor(lightness * 255.f, + lightness * 255.f, + lightness * 255.f); + } + else + { + float h = hue/240.f; + float s = saturation/240.f; + + float v2; + if (l < 0.5f) + v2 = l * (1.f + s); + else + v2 = (l + s) - (s*l); + + float v1 = 2.f * l - v2; + + return NzColor(255.f * Hue2RGB(v1, v2, h + (1.f/3.f)), + 255.f * Hue2RGB(v1, v2, h), + 255.f * Hue2RGB(v1, v2, h - (1.f/3.f))); + } +} + +inline NzColor NzColor::FromHSV(nzUInt8 hue, nzUInt8 saturation, float value) +{ + if (saturation == 0) + return NzColor(static_cast(value * 255.f)); + else + { + float h = hue/240.f * 6.f; + float s = saturation/240.f; + + if (NzNumberEquals(h, 6.f)) + h = 0; // hue must be < 1 + + int i = h; + float v1 = value * (1.f - s); + float v2 = value * (1.f - s * (h - i)); + float v3 = value * (1.f - s * (1.f - (h - i))); + + float r, g, b; + switch (i) + { + case 0: + r = value; + g = v3; + b = v1; + + case 1: + r = v2; + g = value; + b = v1; + + case 2: + r = v1; + g = value; + b = v3; + + case 3: + r = v1; + g = v2; + b = value; + + case 4: + r = v3; + g = v1; + b = value; + + default: + r = value; + g = v1; + b = v2; + } + + // RGB results from 0 to 255 + return NzColor(r*255.f, g*255.f, b*255.f); + } +} +inline NzColor NzColor::FromXYZ(const NzVector3f& vec) +{ + return FromXYZ(vec.x, vec.y, vec.z); +} + +inline NzColor NzColor::FromXYZ(float x, float y, float z) +{ + x /= 100; // X from 0 to 95.047 + y /= 100; // Y from 0 to 100.000 + z /= 100; // Z from 0 to 108.883 + + double r = x * 3.2406 + y * -1.5372 + z * -0.4986; + double g = x * -0.9689 + y * 1.8758 + z * 0.0415; + double b = x * 0.0557 + y * -0.2040 + z * 1.0570; + + if (r > 0.0031308) + r = 1.055 * (std::pow(r, 1.0/2.4)) - 0.055; + else + r *= 12.92; + + if (g > 0.0031308) + g = 1.055 * (std::pow(g, 1.0/2.4)) - 0.055; + else + g *= 12.92; + + if (b > 0.0031308) + b = 1.055 * (std::pow(b, 1.0/2.4)) - 0.055; + else + b *= 12.92; + + return NzColor(r * 255.0, g * 255.0, b * 255.0); +} + +inline void NzColor::ToCMY(const NzColor& color, float* cyan, float* magenta, float* yellow) +{ + *cyan = 1.f - color.r/255.f; + *magenta = 1.f - color.g/255.f; + *yellow = 1.f - color.b/255.f; +} + +inline void NzColor::ToCMYK(const NzColor& color, float* cyan, float* magenta, float* yellow, float* black) +{ + float c, m, y; + ToCMY(color, &c, &m, &y); + + float k = std::min(std::min(std::min(1.f, c), m), y); + + if (NzNumberEquals(k, 1.f)) + { + //Black + *cyan = 0.f; + *magenta = 0.f; + *yellow = 0.f; + } + else + { + *cyan = (c-k)/(1.f-k); + *magenta = (m-k)/(1.f-k); + *yellow = (y-k)/(1.f-k); + } + + *black = k; +} + +inline void NzColor::ToHSL(const NzColor& color, nzUInt8* hue, nzUInt8* saturation, nzUInt8* lightness) +{ + float r = color.r / 255.f; + float g = color.g / 255.f; + float b = color.b / 255.f; + + float min = std::min(std::min(r, g), b); // Min. value of RGB + float max = std::max(std::max(r, g), b); // Max. value of RGB + + float deltaMax = max - min; //Delta RGB value + + float l = (max + min)/2.f; + + if (NzNumberEquals(deltaMax, 0.f)) + { + //This is a gray, no chroma... + *hue = 0; //HSL results from 0 to 1 + *saturation = 0; + } + else + { + //Chromatic data... + if (l < 0.5f) + *saturation = deltaMax/(max+min)*240.f; + else + *saturation = deltaMax/(2.f-max-min)*240.f; + + *lightness = l*240.f; + + float deltaR = ((max - r)/6.f + deltaMax/2.f)/deltaMax; + float deltaG = ((max - g)/6.f + deltaMax/2.f)/deltaMax; + float deltaB = ((max - b)/6.f + deltaMax/2.f)/deltaMax; + + float h; + + if (NzNumberEquals(r, max)) + h = deltaB - deltaG; + else if (NzNumberEquals(g, max)) + h = (1.f/3.f) + deltaR - deltaB; + else if (NzNumberEquals(b, max)) + h = (2.f/3.f) + deltaG - deltaR; + + if (h < 0.f) + h += 1.f; + else if (h > 1.f) + h -= 1.f; + + *hue = h*240.f; + } +} + +inline void NzColor::ToHSV(const NzColor& color, nzUInt8* hue, nzUInt8* saturation, float* value) +{ + float r = color.r / 255.f; + float g = color.g / 255.f; + float b = color.b / 255.f; + + float min = std::min(std::min(r, g), b); //Min. value of RGB + float max = std::max(std::max(r, g), b); //Max. value of RGB + + float deltaMax = max - min; //Delta RGB value + + *value = max; + + if (NzNumberEquals(deltaMax, 0.f)) + { + //This is a gray, no chroma... + *hue = 0; //HSV results from 0 to 1 + *saturation = 0; + } + else + { + //Chromatic data... + *saturation = deltaMax/max*240.f; + + float deltaR = ((max - r)/6.f + deltaMax/2.f)/deltaMax; + float deltaG = ((max - g)/6.f + deltaMax/2.f)/deltaMax; + float deltaB = ((max - b)/6.f + deltaMax/2.f)/deltaMax; + + float h; + + if (NzNumberEquals(r, max)) + h = deltaB - deltaG; + else if (NzNumberEquals(g, max)) + h = (1.f/3.f) + deltaR - deltaB; + else if (NzNumberEquals(b, max)) + h = (2.f/3.f) + deltaG - deltaR; + + if (h < 0.f) + h += 1.f; + else if (h > 1.f) + h -= 1.f; + + *hue = h*240.f; + } +} + +inline void NzColor::ToXYZ(const NzColor& color, NzVector3f* vec) +{ + return ToXYZ(color, &vec->x, &vec->y, &vec->z); +} + +inline void NzColor::ToXYZ(const NzColor& color, float* x, float* y, float* z) +{ + double r = color.r/255.0; //R from 0 to 255 + double g = color.g/255.0; //G from 0 to 255 + double b = color.b/255.0; //B from 0 to 255 + + if (r > 0.04045) + r = std::pow((r + 0.055)/1.055, 2.4); + else + r /= 12.92; + + if (g > 0.04045) + g = std::pow((g + 0.055)/1.055, 2.4); + else + g /= 12.92; + + if (b > 0.04045) + b = std::pow((b + 0.055)/1.055, 2.4); + else + b /= 12.92; + + r *= 100.0; + g *= 100.0; + b *= 100.0; + + //Observer. = 2°, Illuminant = D65 + *x = r*0.4124 + g*0.3576 + b*0.1805; + *y = r*0.2126 + g*0.7152 + b*0.0722; + *z = r*0.0193 + g*0.1192 + b*0.9505; +} + +inline float NzColor::Hue2RGB(float v1, float v2, float vH) +{ + if (vH < 0.f) + vH += 1; + + if (vH > 1.f) + vH -= 1; + + if ((6.f * vH) < 1.f) + return v1 + (v2-v1)*6*vH; + + if ((2.f * vH) < 1.f) + return v2; + + if ((3.f * vH) < 2.f) + return v1 + (v2 - v1)*(2.f/3.f - vH)*6; + + return v1; +} + +inline std::ostream& operator<<(std::ostream& out, const NzColor& color) +{ + return out << color.ToString(); +} + +#include diff --git a/include/Nazara/Utility/Image.hpp b/include/Nazara/Utility/Image.hpp index 515a3607c..c77ad76d3 100644 --- a/include/Nazara/Utility/Image.hpp +++ b/include/Nazara/Utility/Image.hpp @@ -8,6 +8,7 @@ #define NAZARA_IMAGE_HPP #include +#include #include #include #include @@ -77,6 +78,8 @@ class NAZARA_API NzImage : public NzResource, public NzResourceLoader +#include + +const NzColor NzColor::Black(0, 0, 0); +const NzColor NzColor::Blue(0, 0, 255); +const NzColor NzColor::Cyan(0, 255, 255); +const NzColor NzColor::Green(0, 255, 0); +const NzColor NzColor::Magenta(255, 0, 255); +const NzColor NzColor::Orange(255, 165, 0); +const NzColor NzColor::Red(255, 0, 0); +const NzColor NzColor::Yellow(255, 255, 0); +const NzColor NzColor::White(255, 255, 255); diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index 96d037cce..2ede746b5 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -237,6 +237,100 @@ unsigned int NzImage::GetHeight() const return m_sharedImage->height; } +NzColor NzImage::GetPixel(unsigned int x, unsigned int y, unsigned int z) const +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return NzColor(); + } + + if (m_sharedImage->type == nzImageType_Cubemap) + { + NazaraError("GetPixel is not designed for cubemaps, use GetPixelFace instead"); + return NzColor(); + } + + if (NzPixelFormat::IsCompressed(m_sharedImage->format)) + { + NazaraError("Cannot access pixels from compressed image"); + return NzColor(); + } + + if (x >= m_sharedImage->width) + { + NazaraError("X value exceeds width (" + NzString::Number(x) + " >= (" + NzString::Number(m_sharedImage->width) + ')'); + return NzColor(); + } + + if (y >= m_sharedImage->height) + { + NazaraError("Y value exceeds width (" + NzString::Number(y) + " >= (" + NzString::Number(m_sharedImage->height) + ')'); + return NzColor(); + } + + if (z >= m_sharedImage->depth) + { + NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(m_sharedImage->depth) + ')'); + return NzColor(); + } + #endif + + NzColor color; + + const nzUInt8* pixel = &m_sharedImage->pixels[(m_sharedImage->height*(m_sharedImage->width*z+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + + if (!NzPixelFormat::Convert(m_sharedImage->format, nzPixelFormat_RGBA8, pixel, &color.r)) + NazaraError("Failed to convert image's format to RGBA8"); + + return color; +} + +NzColor NzImage::GetPixelFace(nzCubemapFace face, unsigned int x, unsigned int y) const +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return NzColor(); + } + + if (m_sharedImage->type != nzImageType_Cubemap) + { + NazaraError("GetPixelFace is designed for cubemaps, use GetPixel instead"); + return NzColor(); + } + + if (NzPixelFormat::IsCompressed(m_sharedImage->format)) + { + NazaraError("Cannot access pixels from compressed image"); + return NzColor(); + } + + if (x >= m_sharedImage->width) + { + NazaraError("X value exceeds width (" + NzString::Number(x) + " >= (" + NzString::Number(m_sharedImage->width) + ')'); + return NzColor(); + } + + if (y >= m_sharedImage->height) + { + NazaraError("Y value exceeds width (" + NzString::Number(y) + " >= (" + NzString::Number(m_sharedImage->height) + ')'); + return NzColor(); + } + #endif + + NzColor color; + + const nzUInt8* pixel = &m_sharedImage->pixels[(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX)+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + + if (!NzPixelFormat::Convert(m_sharedImage->format, nzPixelFormat_RGBA8, pixel, &color.r)) + NazaraError("Failed to convert image's format to RGBA8"); + + return color; +} + nzUInt8* NzImage::GetPixels() { EnsureOwnership(); @@ -246,7 +340,7 @@ nzUInt8* NzImage::GetPixels() unsigned int NzImage::GetSize() const { - return m_sharedImage->width * m_sharedImage->height * m_sharedImage->depth * NzPixelFormat::GetBPP(m_sharedImage->format); + return m_sharedImage->width * m_sharedImage->height * ((m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth) * NzPixelFormat::GetBPP(m_sharedImage->format); } nzImageType NzImage::GetType() const @@ -289,6 +383,102 @@ bool NzImage::LoadFromStream(NzInputStream& stream, const NzImageParams& params) return NzResourceLoader::LoadResourceFromStream(this, stream, params); } +bool NzImage::SetPixel(const NzColor& color, unsigned int x, unsigned int y, unsigned int z) +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (m_sharedImage->type == nzImageType_Cubemap) + { + NazaraError("SetPixel is not designed for cubemaps, use SetPixelFace instead"); + return false; + } + + if (NzPixelFormat::IsCompressed(m_sharedImage->format)) + { + NazaraError("Cannot access pixels from compressed image"); + return false; + } + + if (x >= m_sharedImage->width) + { + NazaraError("X value exceeds width (" + NzString::Number(x) + " >= (" + NzString::Number(m_sharedImage->width) + ')'); + return false; + } + + if (y >= m_sharedImage->height) + { + NazaraError("Y value exceeds width (" + NzString::Number(y) + " >= (" + NzString::Number(m_sharedImage->height) + ')'); + return false; + } + + if (z >= m_sharedImage->depth) + { + NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(m_sharedImage->depth) + ')'); + return false; + } + #endif + + nzUInt8* pixel = &m_sharedImage->pixels[(m_sharedImage->height*(m_sharedImage->width*z+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + + if (!NzPixelFormat::Convert(nzPixelFormat_RGBA8, m_sharedImage->format, &color.r, pixel)) + { + NazaraError("Failed to convert RGBA8 to image's format"); + return false; + } + + return true; +} + +bool NzImage::SetPixelFace(const NzColor& color, nzCubemapFace face, unsigned int x, unsigned int y) +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (m_sharedImage->type != nzImageType_Cubemap) + { + NazaraError("SetPixelFace is designed for cubemaps, use SetPixel instead"); + return false; + } + + if (NzPixelFormat::IsCompressed(m_sharedImage->format)) + { + NazaraError("Cannot access pixels from compressed image"); + return false; + } + + if (x >= m_sharedImage->width) + { + NazaraError("X value exceeds width (" + NzString::Number(x) + " >= (" + NzString::Number(m_sharedImage->width) + ')'); + return false; + } + + if (y >= m_sharedImage->height) + { + NazaraError("Y value exceeds width (" + NzString::Number(y) + " >= (" + NzString::Number(m_sharedImage->height) + ')'); + return false; + } + #endif + + nzUInt8* pixel = &m_sharedImage->pixels[(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX)+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + + if (!NzPixelFormat::Convert(nzPixelFormat_RGBA8, m_sharedImage->format, &color.r, pixel)) + { + NazaraError("Failed to convert RGBA8 to image's format"); + return false; + } + + return true; +} + bool NzImage::Update(const nzUInt8* pixels) { #if NAZARA_UTILITY_SAFE @@ -318,7 +508,7 @@ bool NzImage::Update(const nzUInt8* pixels) return true; } -bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect) +bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z) { #if NAZARA_UTILITY_SAFE if (!IsValid()) @@ -345,18 +535,24 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect) return false; } - if (rect.width > m_sharedImage->width || rect.height > m_sharedImage->height) + if (rect.x+rect.width > m_sharedImage->width || rect.y+rect.height > m_sharedImage->height) { NazaraError("Rectangle dimensions are out of bounds"); return false; } + + if (z >= m_sharedImage->depth) + { + NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(m_sharedImage->depth) + ')'); + return false; + } #endif EnsureOwnership(); nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); - nzUInt8* dstPixels = m_sharedImage->pixels + (rect.x + rect.y * m_sharedImage->width) * bpp; + nzUInt8* dstPixels = &m_sharedImage->pixels[(m_sharedImage->height*(m_sharedImage->width*z + rect.y) + rect.x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; unsigned int srcStride = rect.width * bpp; unsigned int dstStride = m_sharedImage->width * bpp; @@ -382,7 +578,7 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels) if (m_sharedImage->type != nzImageType_Cubemap) { - NazaraError("Update is only designed for cubemaps, use Update instead"); + NazaraError("Update is designed for cubemaps, use Update instead"); return false; } @@ -412,7 +608,7 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRect if (m_sharedImage->type != nzImageType_Cubemap) { - NazaraError("Update is only designed for cubemaps, use Update instead"); + NazaraError("Update is designed for cubemaps, use Update instead"); return false; } @@ -428,7 +624,7 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRect return false; } - if (rect.width > m_sharedImage->width || rect.height > m_sharedImage->height) + if (rect.x+rect.width > m_sharedImage->width || rect.y+rect.height > m_sharedImage->height) { NazaraError("Rectangle dimensions are out of bounds"); return false; @@ -439,7 +635,7 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRect nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); - nzUInt8* dstPixels = m_sharedImage->pixels + (rect.x + rect.y * m_sharedImage->width + (face-nzCubemapFace_PositiveX)*m_sharedImage->width*m_sharedImage->height) * bpp; + nzUInt8* dstPixels = &m_sharedImage->pixels[(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX) + rect.y) + rect.x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; unsigned int srcStride = rect.width * bpp; unsigned int dstStride = m_sharedImage->width * bpp; diff --git a/src/Nazara/Utility/PixelFormat.cpp b/src/Nazara/Utility/PixelFormat.cpp index 8dff3adcb..9723b970d 100644 --- a/src/Nazara/Utility/PixelFormat.cpp +++ b/src/Nazara/Utility/PixelFormat.cpp @@ -14,7 +14,7 @@ namespace { inline nzUInt8 c4to8(nzUInt8 c) { - return c * (255.f/15.f); + return c * (255/15); } inline nzUInt8 c5to8(nzUInt8 c) @@ -327,7 +327,7 @@ namespace *ptr++ = (l << 11) | (l << 6) | (l << 1) | - 1; + 1; start += 1; } @@ -480,9 +480,9 @@ namespace { while (start < end) { - *dst++ = (c4to8((start[1] & 0xF0) >> 4)); - *dst++ = (c4to8((start[0] & 0x0F) >> 0)); - *dst++ = (c4to8((start[0] & 0xF0) >> 4)); + *dst++ = c4to8((start[1] & 0xF0) >> 4); + *dst++ = c4to8((start[0] & 0x0F) >> 0); + *dst++ = c4to8((start[0] & 0xF0) >> 4); start += 2; } From f39e2f7d36a81fba2353283d795bef8b64be4845 Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 28 May 2012 16:21:27 +0200 Subject: [PATCH 05/15] NzString::Trim(med) can now take a limit flag Fixed NzString::Simplified removing non-separator character with HandleUtf8 flag --- include/Nazara/Core/String.hpp | 8 ++- src/Nazara/Core/String.cpp | 100 ++++++++++++++++++++++----------- 2 files changed, 71 insertions(+), 37 deletions(-) diff --git a/include/Nazara/Core/String.hpp b/include/Nazara/Core/String.hpp index 4451433d1..0d85c4e9f 100644 --- a/include/Nazara/Core/String.hpp +++ b/include/Nazara/Core/String.hpp @@ -25,9 +25,11 @@ class NAZARA_API NzString : public NzHashable public: enum Flags { - None = 0x00, // Mode par défaut - CaseInsensitive = 0x01, // Insensible à la casse - HandleUtf8 = 0x02 // Traite les octets comme une suite de caractères UTF-8 + None = 0x00, // Mode par défaut + CaseInsensitive = 0x01, // Insensible à la casse + HandleUtf8 = 0x02, // Traite les octets comme une suite de caractères UTF-8 + TrimOnlyLeft = 0x04, // Trim(med), ne coupe que la partie gauche de la chaîne + TrimOnlyRight = 0x08 // Trim(med), ne coupe que la partie droite de la chaîne }; struct SharedString; diff --git a/src/Nazara/Core/String.cpp b/src/Nazara/Core/String.cpp index d55bbdb08..84d7e639b 100644 --- a/src/Nazara/Core/String.cpp +++ b/src/Nazara/Core/String.cpp @@ -3317,7 +3317,7 @@ NzString NzString::Simplified(nzUInt32 flags) const utf8::unchecked::iterator it(ptr); do { - if (NzUnicode::GetCategory(*it)) + if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator) { if (inword) { @@ -3941,39 +3941,59 @@ NzString NzString::Trimmed(nzUInt32 flags) const if (m_sharedString->size == 0) return *this; - unsigned int startPos = 0; - unsigned int endPos = m_sharedString->size-1; + unsigned int startPos; + unsigned int endPos; if (flags & HandleUtf8) { - utf8::unchecked::iterator it(m_sharedString->string); - do + if ((flags & TrimOnlyRight) == 0) { - if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator) - break; - } - while (*++it); - startPos = it.base() - m_sharedString->string; + utf8::unchecked::iterator it(m_sharedString->string); + do + { + if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator) + break; + } + while (*++it); - utf8::unchecked::iterator itR(&m_sharedString->string[m_sharedString->size]); - while ((itR--).base() != m_sharedString->string) - { - if (NzUnicode::GetCategory(*itR) & NzUnicode::Category_Separator) - break; + startPos = it.base() - m_sharedString->string; } - endPos = itR.base() - m_sharedString->string; + else + startPos = 0; + + if ((flags & TrimOnlyLeft) == 0) + { + utf8::unchecked::iterator it(&m_sharedString->string[m_sharedString->size]); + while ((it--).base() != m_sharedString->string) + { + if (NzUnicode::GetCategory(*it) & NzUnicode::Category_Separator) + break; + } + + endPos = it.base() - m_sharedString->string; + } + else + endPos = m_sharedString->size-1; } else { - for (; startPos < m_sharedString->size; ++startPos) + startPos = 0; + if ((flags & TrimOnlyRight) == 0) { - if (!std::isspace(m_sharedString->string[startPos])) - break; + for (; startPos < m_sharedString->size; ++startPos) + { + if (!std::isspace(m_sharedString->string[startPos])) + break; + } } - for (; endPos > 0; --endPos) + endPos = m_sharedString->size-1; + if ((flags & TrimOnlyLeft) == 0) { - if (!std::isspace(m_sharedString->string[endPos])) - break; + for (; endPos > 0; --endPos) + { + if (!std::isspace(m_sharedString->string[endPos])) + break; + } } } @@ -3990,30 +4010,42 @@ NzString NzString::Trimmed(char character, nzUInt32 flags) const if (flags & CaseInsensitive) { char ch = nzToLower(character); - for (; startPos < m_sharedString->size; ++startPos) + if ((flags & TrimOnlyRight) == 0) { - if (nzToLower(m_sharedString->string[startPos]) != ch) - break; + for (; startPos < m_sharedString->size; ++startPos) + { + if (nzToLower(m_sharedString->string[startPos]) != ch) + break; + } } - for (; endPos > 0; --endPos) + if ((flags & TrimOnlyLeft) == 0) { - if (nzToLower(m_sharedString->string[startPos]) != ch) - break; + for (; endPos > 0; --endPos) + { + if (nzToLower(m_sharedString->string[startPos]) != ch) + break; + } } } else { - for (; startPos < m_sharedString->size; ++startPos) + if ((flags & TrimOnlyRight) == 0) { - if (m_sharedString->string[startPos] != character) - break; + for (; startPos < m_sharedString->size; ++startPos) + { + if (m_sharedString->string[startPos] != character) + break; + } } - for (; endPos > 0; --endPos) + if ((flags & TrimOnlyLeft) == 0) { - if (m_sharedString->string[startPos] != character) - break; + for (; endPos > 0; --endPos) + { + if (m_sharedString->string[startPos] != character) + break; + } } } From b220e00c887203cf997c389cdad5315c370e1997 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 30 May 2012 18:10:17 +0200 Subject: [PATCH 06/15] NzImage now handles mipmaps Added NzRenderer::SetClearColor(const Color&) Added describe comment for pixel formats Fixed NzPixelFormat conversion for RGBA4 and RGB5A1 types Fixed NzRenderer::Clear prototype Renamed NzLock to NzLockGuard ResourceLoader's loaders are now tested from newest to oldest --- include/Nazara/Core/Color.hpp | 4 +- .../Nazara/Core/{Lock.hpp => LockGuard.hpp} | 12 +- include/Nazara/Core/ThreadSafety.hpp | 4 +- include/Nazara/Renderer/Renderer.hpp | 4 +- include/Nazara/Utility/Image.hpp | 37 +- include/Nazara/Utility/PixelFormat.hpp | 27 +- include/Nazara/Utility/PixelFormat.inl | 32 +- include/Nazara/Utility/ResourceLoader.inl | 13 +- src/Nazara/Core/{Lock.cpp => LockGuard.cpp} | 6 +- src/Nazara/Renderer/GLSLShader.cpp | 2 +- src/Nazara/Renderer/RenderWindow.cpp | 1 + src/Nazara/Renderer/Renderer.cpp | 16 +- src/Nazara/Renderer/Win32/ContextImpl.cpp | 4 +- src/Nazara/Utility/Image.cpp | 334 +++++++++++++----- src/Nazara/Utility/Loaders/STB.cpp | 1 + src/Nazara/Utility/PixelFormat.cpp | 307 ++++++++++++---- src/Nazara/Utility/Window.cpp | 8 +- 17 files changed, 591 insertions(+), 221 deletions(-) rename include/Nazara/Core/{Lock.hpp => LockGuard.hpp} (62%) rename src/Nazara/Core/{Lock.cpp => LockGuard.cpp} (72%) diff --git a/include/Nazara/Core/Color.hpp b/include/Nazara/Core/Color.hpp index be4143c7f..7a3b59f42 100644 --- a/include/Nazara/Core/Color.hpp +++ b/include/Nazara/Core/Color.hpp @@ -40,10 +40,10 @@ class NzColor static NzColor FromXYZ(float x, float y, float z); static void ToCMY(const NzColor& color, float* cyan, float* magenta, float* yellow); static void ToCMYK(const NzColor& color, float* cyan, float* magenta, float* yellow, float* black); - static void ToXYZ(const NzColor& color, NzVector3f* vec); - static void ToXYZ(const NzColor& color, float* x, float* y, float* z); static void ToHSL(const NzColor& color, nzUInt8* hue, nzUInt8* saturation, nzUInt8* lightness); static void ToHSV(const NzColor& color, nzUInt8* hue, nzUInt8* saturation, float* value); + static void ToXYZ(const NzColor& color, NzVector3f* vec); + static void ToXYZ(const NzColor& color, float* x, float* y, float* z); nzUInt8 r, g, b, a; diff --git a/include/Nazara/Core/Lock.hpp b/include/Nazara/Core/LockGuard.hpp similarity index 62% rename from include/Nazara/Core/Lock.hpp rename to include/Nazara/Core/LockGuard.hpp index 62e3707a2..c9397bc2d 100644 --- a/include/Nazara/Core/Lock.hpp +++ b/include/Nazara/Core/LockGuard.hpp @@ -4,21 +4,21 @@ #pragma once -#ifndef NAZARA_LOCK_HPP -#define NAZARA_LOCK_HPP +#ifndef NAZARA_LOCKGUARD_HPP +#define NAZARA_LOCKGUARD_HPP #include class NzMutex; -class NAZARA_API NzLock +class NAZARA_API NzLockGuard { public: - NzLock(NzMutex& mutex); - ~NzLock(); + NzLockGuard(NzMutex& mutex); + ~NzLockGuard(); private: NzMutex& m_mutex; }; -#endif // NAZARA_LOCK_HPP +#endif // NAZARA_LOCKGUARD_HPP diff --git a/include/Nazara/Core/ThreadSafety.hpp b/include/Nazara/Core/ThreadSafety.hpp index 53b7e05cf..dcbc4a515 100644 --- a/include/Nazara/Core/ThreadSafety.hpp +++ b/include/Nazara/Core/ThreadSafety.hpp @@ -24,10 +24,10 @@ (NAZARA_THREADSAFETY_STRING && defined(NAZARA_CLASS_STRING)) || \ (NAZARA_THREADSAFETY_STRINGSTREAM && defined(NAZARA_CLASS_STRINGSTREAM))) - #include + #include #include - #define NazaraLock(mutex) NzLock lock_mutex(mutex); + #define NazaraLock(mutex) NzLockGuard lock_mutex(mutex); #define NazaraMutex(name) NzMutex name; #define NazaraMutexAttrib(name, attribute) attribute NzMutex name; #define NazaraMutexLock(mutex) mutex.Lock(); diff --git a/include/Nazara/Renderer/Renderer.hpp b/include/Nazara/Renderer/Renderer.hpp index f2aa3d76c..6b509ece0 100644 --- a/include/Nazara/Renderer/Renderer.hpp +++ b/include/Nazara/Renderer/Renderer.hpp @@ -44,6 +44,7 @@ enum nzRendererClear nzRendererClear_Stencil = 0x04 }; +class NzColor; class NzIndexBuffer; class NzRenderTarget; class NzShader; @@ -57,7 +58,7 @@ class NAZARA_API NzRenderer NzRenderer(); ~NzRenderer(); - void Clear(nzRendererClear flags); + void Clear(unsigned long flags = nzRendererClear_Color | nzRendererClear_Depth); void DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int firstIndex, unsigned int indexCount); void DrawPrimitives(nzPrimitiveType primitive, unsigned int firstVertex, unsigned int vertexCount); @@ -69,6 +70,7 @@ class NAZARA_API NzRenderer bool HasCapability(nzRendererCap capability) const; bool Initialize(); + void SetClearColor(const NzColor& color); void SetClearColor(nzUInt8 r, nzUInt8 g, nzUInt8 b, nzUInt8 a = 255); void SetClearDepth(double depth); void SetClearStencil(unsigned int value); diff --git a/include/Nazara/Utility/Image.hpp b/include/Nazara/Utility/Image.hpp index c77ad76d3..aafbb72c1 100644 --- a/include/Nazara/Utility/Image.hpp +++ b/include/Nazara/Utility/Image.hpp @@ -50,9 +50,7 @@ struct NzImageParams } }; -///TODO: Animations ? ///TODO: Filtres -///TODO: Mipmaps class NAZARA_API NzImage : public NzResource, public NzResourceLoader { @@ -70,20 +68,23 @@ class NAZARA_API NzImage : public NzResource, public NzResourceLoader(src), static_cast(src) + GetBPP(srcFormat), static_cast(dst)); + if (!func(static_cast(src), static_cast(src) + GetBPP(srcFormat), static_cast(dst))) + { + NazaraError("Pixel format conversion from " + ToString(srcFormat) + " to " + ToString(dstFormat) + " failed"); + return false; + } return true; } @@ -51,11 +55,15 @@ inline bool NzPixelFormat::Convert(nzPixelFormat srcFormat, nzPixelFormat dstFor ConvertFunction func = s_convertFunctions[srcFormat][dstFormat]; if (!func) { - NazaraError("Pixel format conversion from " + ToString(srcFormat) + " to " + ToString(dstFormat) + " not supported"); + NazaraError("Pixel format conversion from " + ToString(srcFormat) + " to " + ToString(dstFormat) + " is not supported"); return false; } - func(static_cast(start), static_cast(end), static_cast(dst)); + if (!func(static_cast(start), static_cast(end), static_cast(dst))) + { + NazaraError("Pixel format conversion from " + ToString(srcFormat) + " to " + ToString(dstFormat) + " failed"); + return false; + } return true; } @@ -100,13 +108,13 @@ inline nzUInt8 NzPixelFormat::GetBPP(nzPixelFormat format) case nzPixelFormat_RGB32I: return 12; -*/ + case nzPixelFormat_RGBA16F: return 8; case nzPixelFormat_RGBA16I: return 8; -/* + case nzPixelFormat_RGBA32F: return 16; @@ -145,6 +153,14 @@ inline bool NzPixelFormat::IsCompressed(nzPixelFormat format) } } +inline bool NzPixelFormat::IsConversionSupported(nzPixelFormat srcFormat, nzPixelFormat dstFormat) +{ + if (srcFormat == dstFormat) + return true; + + return s_convertFunctions[srcFormat][dstFormat] != nullptr; +} + inline bool NzPixelFormat::IsValid(nzPixelFormat format) { switch (format) @@ -199,13 +215,13 @@ inline NzString NzPixelFormat::ToString(nzPixelFormat format) case nzPixelFormat_RGB32I: return "RGB32I"; -*/ + case nzPixelFormat_RGBA16F: return "RGBA16F"; case nzPixelFormat_RGBA16I: return "RGBA16I"; -/* + case nzPixelFormat_RGBA32F: return "RGBA32F"; diff --git a/include/Nazara/Utility/ResourceLoader.inl b/include/Nazara/Utility/ResourceLoader.inl index dc1e60e01..ccc3cae0e 100644 --- a/include/Nazara/Utility/ResourceLoader.inl +++ b/include/Nazara/Utility/ResourceLoader.inl @@ -35,14 +35,20 @@ bool NzResourceLoader::LoadResourceFromFile(Type* resource, co return false; } - for (auto it = range.first; it != range.second; ++it) + // range.second est un itérateur vers l'élément après le dernier élémént du range + auto it = range.second; + + do { + it--; + // Chargement de la ressource if (it->second(resource, filePath, parameters)) return true; NazaraWarning("Loader failed"); } + while (it != range.first); NazaraError("Failed to load file: all loaders failed"); @@ -66,7 +72,7 @@ bool NzResourceLoader::LoadResourceFromMemory(Type* resource, } #endif - for (auto loader = s_memoryLoaders.begin(); loader != s_memoryLoaders.end(); ++loader) + for (auto loader = s_memoryLoaders.rbegin(); loader != s_memoryLoaders.rend(); ++loader) { // Le loader supporte-t-il les données ? if (!loader->first(data, size, parameters)) @@ -101,7 +107,7 @@ bool NzResourceLoader::LoadResourceFromStream(Type* resource, #endif nzUInt64 streamPos = stream.GetCursorPos(); - for (auto loader = s_streamLoaders.begin(); loader != s_streamLoaders.end(); ++loader) + for (auto loader = s_streamLoaders.rbegin(); loader != s_streamLoaders.rend(); ++loader) { stream.SetCursorPos(streamPos); @@ -164,7 +170,6 @@ void NzResourceLoader::UnregisterResourceFileLoader(const NzSt } } } - //s_fileLoaders.erase(std::make_pair(ext, loadFile)); } template diff --git a/src/Nazara/Core/Lock.cpp b/src/Nazara/Core/LockGuard.cpp similarity index 72% rename from src/Nazara/Core/Lock.cpp rename to src/Nazara/Core/LockGuard.cpp index a48fe13a5..34f04fd16 100644 --- a/src/Nazara/Core/Lock.cpp +++ b/src/Nazara/Core/LockGuard.cpp @@ -2,17 +2,17 @@ // This file is part of the "Nazara Engine". // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include -NzLock::NzLock(NzMutex& mutex) : +NzLockGuard::NzLockGuard(NzMutex& mutex) : m_mutex(mutex) { m_mutex.Lock(); } -NzLock::~NzLock() +NzLockGuard::~NzLockGuard() { m_mutex.Unlock(); } diff --git a/src/Nazara/Renderer/GLSLShader.cpp b/src/Nazara/Renderer/GLSLShader.cpp index 624c33fc9..eda9240e8 100644 --- a/src/Nazara/Renderer/GLSLShader.cpp +++ b/src/Nazara/Renderer/GLSLShader.cpp @@ -123,7 +123,7 @@ bool NzGLSLShader::Create() glBindAttribLocation(m_program, attribIndex[nzElementUsage_Diffuse], "Diffuse"); glBindAttribLocation(m_program, attribIndex[nzElementUsage_Tangent], "Tangent"); - NzString uniformName = "TexCoord0"; + NzString uniformName = "TexCoordi"; for (unsigned int i = 0; i < 8; ++i) { uniformName[8] = '0'+i; diff --git a/src/Nazara/Renderer/RenderWindow.cpp b/src/Nazara/Renderer/RenderWindow.cpp index 5d3bf24f2..38be6c833 100644 --- a/src/Nazara/Renderer/RenderWindow.cpp +++ b/src/Nazara/Renderer/RenderWindow.cpp @@ -137,6 +137,7 @@ bool NzRenderWindow::OnCreate() { m_parameters.doubleBuffered = true; m_parameters.window = GetHandle(); + m_context = new NzContext; if (!m_context->Create(m_parameters)) { diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 9d5f660d5..6daae067c 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -4,6 +4,7 @@ #include // Pour éviter une redéfinition de WIN32_LEAN_AND_MEAN #include +#include #include #include #include @@ -53,7 +54,7 @@ NzRenderer::~NzRenderer() s_instance = nullptr; } -void NzRenderer::Clear(nzRendererClear flags) +void NzRenderer::Clear(unsigned long flags) { #ifdef NAZARA_DEBUG if (NzContext::GetCurrent() == nullptr) @@ -205,6 +206,19 @@ bool NzRenderer::Initialize() return false; } +void NzRenderer::SetClearColor(const NzColor& color) +{ + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + + glClearColor(color.r/255.f, color.g/255.f, color.b/255.f, color.a/255.f); +} + void NzRenderer::SetClearColor(nzUInt8 r, nzUInt8 g, nzUInt8 b, nzUInt8 a) { #ifdef NAZARA_DEBUG diff --git a/src/Nazara/Renderer/Win32/ContextImpl.cpp b/src/Nazara/Renderer/Win32/ContextImpl.cpp index 071545de5..c9abbac2c 100644 --- a/src/Nazara/Renderer/Win32/ContextImpl.cpp +++ b/src/Nazara/Renderer/Win32/ContextImpl.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -180,7 +180,7 @@ bool NzContextImpl::Create(NzContextParameters& parameters) { // wglShareLists n'est pas thread-safe (source: SFML) static NzMutex mutex; - NzLock lock(mutex); + NzLockGuard lock(mutex); if (!wglShareLists(shareContext, m_context)) NazaraWarning("Failed to share the context: " + NzGetLastSystemError()); diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index 2ede746b5..e23d24cbd 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include NzImage::NzImage() : @@ -50,36 +51,63 @@ bool NzImage::Convert(nzPixelFormat format) NazaraError("Invalid pixel format"); return false; } + + if (!NzPixelFormat::IsConversionSupported(m_sharedImage->format, format)) + { + NazaraError("Conversion from " + NzPixelFormat::ToString(m_sharedImage->format) + " to " + NzPixelFormat::ToString(format) + " is not supported"); + return false; + } #endif if (format == m_sharedImage->format) return true; + nzUInt8** levels = new nzUInt8*[m_sharedImage->levelCount]; + + unsigned int width = m_sharedImage->width; + unsigned int height = m_sharedImage->height; + // Les images 3D et cubemaps sont stockés de la même façon unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth; - unsigned int pixelsPerFace = m_sharedImage->width*m_sharedImage->height; - nzUInt8* buffer = new nzUInt8[pixelsPerFace*depth*NzPixelFormat::GetBPP(format)]; - nzUInt8* ptr = buffer; - nzUInt8* pixels = m_sharedImage->pixels; - unsigned int srcStride = pixelsPerFace * NzPixelFormat::GetBPP(m_sharedImage->format); - unsigned int dstStride = pixelsPerFace * NzPixelFormat::GetBPP(format); - - for (unsigned int i = 0; i < depth; ++i) + for (unsigned int i = 0; i < m_sharedImage->levelCount; ++i) { - if (!NzPixelFormat::Convert(m_sharedImage->format, format, pixels, &pixels[srcStride], ptr)) - { - NazaraError("Failed to convert image"); - delete[] buffer; + unsigned int pixelsPerFace = width*height; + nzUInt8* ptr = new nzUInt8[pixelsPerFace*depth*NzPixelFormat::GetBPP(format)]; + nzUInt8* pixels = m_sharedImage->pixels[i]; + unsigned int srcStride = pixelsPerFace * NzPixelFormat::GetBPP(m_sharedImage->format); + unsigned int dstStride = pixelsPerFace * NzPixelFormat::GetBPP(format); - return false; + levels[i] = ptr; + + for (unsigned int d = 0; d < depth; ++d) + { + if (!NzPixelFormat::Convert(m_sharedImage->format, format, pixels, &pixels[srcStride], ptr)) + { + NazaraError("Failed to convert image"); + for (unsigned int j = 0; j <= i; ++j) + delete[] levels[j]; + + delete[] levels; + + return false; + } + + pixels += srcStride; + ptr += dstStride; } - pixels += srcStride; - ptr += dstStride; + if (width > 1) + width /= 2; + + if (height > 1) + height /= 2; + + if (depth > 1 && m_sharedImage->type != nzImageType_Cubemap) + depth /= 2; } - SharedImage* newImage = new SharedImage(1, m_sharedImage->type, format, buffer, m_sharedImage->width, m_sharedImage->height, m_sharedImage->depth); + SharedImage* newImage = new SharedImage(1, m_sharedImage->type, format, m_sharedImage->levelCount, levels, m_sharedImage->width, m_sharedImage->height, m_sharedImage->depth); ReleaseImage(); m_sharedImage = newImage; @@ -103,7 +131,8 @@ bool NzImage::Copy(const NzImage& source, const NzRectui& srcRect, const NzVecto } #endif - return Update(&source.GetConstPixels()[(srcRect.x + srcRect.y * source.GetHeight()) * source.GetBPP()], NzRectui(dstPos.x, dstPos.y, srcRect.width, srcRect.height)); + return Update(&source.GetConstPixels()[(srcRect.x + srcRect.y * source.GetHeight()) * source.GetBPP()], + NzRectui(dstPos.x, dstPos.y, srcRect.width, srcRect.height)); } bool NzImage::CopyToFace(nzCubemapFace face, const NzImage& source, const NzRectui& srcRect, const NzVector2ui& dstPos) @@ -122,10 +151,12 @@ bool NzImage::CopyToFace(nzCubemapFace face, const NzImage& source, const NzRect } #endif - return UpdateFace(face, &source.GetConstPixels()[(srcRect.x + srcRect.y * source.GetHeight()) * source.GetBPP()], NzRectui(dstPos.x, dstPos.y, srcRect.width, srcRect.height)); + return UpdateFace(face, + &source.GetConstPixels()[(srcRect.x + srcRect.y * source.GetHeight()) * source.GetBPP()], + NzRectui(dstPos.x, dstPos.y, srcRect.width, srcRect.height)); } -bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth) +bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth, nzUInt8 levelCount) { ReleaseImage(); @@ -135,13 +166,7 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width, NazaraError("Invalid pixel format"); return false; } - #endif - unsigned int size = width*height*depth*NzPixelFormat::GetBPP(format); - if (size == 0) - return true; - - #if NAZARA_UTILITY_SAFE switch (type) { case nzImageType_1D: @@ -178,31 +203,53 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width, NazaraError("Cubemaps must have square dimensions"); return false; } - - size *= 6; // Les cubemaps ont six faces break; default: break; } - #else - if (type == nzImageType_Cubemap) - size *= 6; // Les cubemaps ont six faces #endif - // Cette allocation est protégée car sa taille dépend directement de paramètres utilisateurs - nzUInt8* buffer; - try + if (width == 0 || height == 0 || depth == 0) + return true; + + levelCount = std::min(levelCount, GetMaxLevel(width, height, depth)); + + nzUInt8** levels = new nzUInt8*[levelCount]; + + unsigned int w = width; + unsigned int h = height; + unsigned int d = (type == nzImageType_Cubemap) ? 6 : depth; + + for (unsigned int i = 0; i < levelCount; ++i) { - buffer = new nzUInt8[size]; - } - catch (const std::exception& e) - { - NazaraError("Failed to allocate image buffer (" + NzString(e.what()) + ')'); - return false; + // Cette allocation est protégée car sa taille dépend directement de paramètres utilisateurs + try + { + levels[i] = new nzUInt8[w * h * d * NzPixelFormat::GetBPP(format)]; + + if (w > 1) + w /= 2; + + if (h > 1) + h /= 2; + + if (d > 1 && type != nzImageType_Cubemap) + d /= 2; + } + catch (const std::exception& e) + { + NazaraError("Failed to allocate image's level " + NzString::Number(i) + " (" + NzString(e.what()) + ')'); + for (unsigned int j = 0; j <= i; ++j) + delete[] levels[j]; + + delete[] levels; + + return false; + } } - m_sharedImage = new SharedImage(1, type, format, buffer, width, height, depth); + m_sharedImage = new SharedImage(1, type, format, levelCount, levels, width, height, depth); return true; } @@ -217,14 +264,14 @@ nzUInt8 NzImage::GetBPP() const return NzPixelFormat::GetBPP(m_sharedImage->format); } -const nzUInt8* NzImage::GetConstPixels() const +const nzUInt8* NzImage::GetConstPixels(nzUInt8 level) const { - return m_sharedImage->pixels; + return m_sharedImage->pixels[level]; } -unsigned int NzImage::GetDepth() const +unsigned int NzImage::GetDepth(nzUInt8 level) const { - return m_sharedImage->depth; + return m_sharedImage->depth/(1 << level); } nzPixelFormat NzImage::GetFormat() const @@ -232,9 +279,19 @@ nzPixelFormat NzImage::GetFormat() const return m_sharedImage->format; } -unsigned int NzImage::GetHeight() const +unsigned int NzImage::GetHeight(nzUInt8 level) const { - return m_sharedImage->height; + return m_sharedImage->height/(1 << level); +} + +nzUInt8 NzImage::GetLevelCount() const +{ + return m_sharedImage->levelCount; +} + +nzUInt8 NzImage::GetMaxLevel() const +{ + return GetMaxLevel(m_sharedImage->width, m_sharedImage->height, m_sharedImage->depth); } NzColor NzImage::GetPixel(unsigned int x, unsigned int y, unsigned int z) const @@ -277,10 +334,9 @@ NzColor NzImage::GetPixel(unsigned int x, unsigned int y, unsigned int z) const } #endif + const nzUInt8* pixel = &m_sharedImage->pixels[0][(m_sharedImage->height*(m_sharedImage->width*z+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + NzColor color; - - const nzUInt8* pixel = &m_sharedImage->pixels[(m_sharedImage->height*(m_sharedImage->width*z+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; - if (!NzPixelFormat::Convert(m_sharedImage->format, nzPixelFormat_RGBA8, pixel, &color.r)) NazaraError("Failed to convert image's format to RGBA8"); @@ -321,26 +377,55 @@ NzColor NzImage::GetPixelFace(nzCubemapFace face, unsigned int x, unsigned int y } #endif + const nzUInt8* pixel = &m_sharedImage->pixels[0][(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX)+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + NzColor color; - - const nzUInt8* pixel = &m_sharedImage->pixels[(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX)+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; - if (!NzPixelFormat::Convert(m_sharedImage->format, nzPixelFormat_RGBA8, pixel, &color.r)) NazaraError("Failed to convert image's format to RGBA8"); return color; } -nzUInt8* NzImage::GetPixels() +nzUInt8* NzImage::GetPixels(nzUInt8 level) { EnsureOwnership(); - return m_sharedImage->pixels; + return m_sharedImage->pixels[level]; } unsigned int NzImage::GetSize() const { - return m_sharedImage->width * m_sharedImage->height * ((m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth) * NzPixelFormat::GetBPP(m_sharedImage->format); + unsigned int width = m_sharedImage->width; + unsigned int height = m_sharedImage->height; + unsigned int depth = m_sharedImage->depth; + + unsigned int size = 0; + for (unsigned int i = 0; i < m_sharedImage->levelCount; ++i) + { + size += width * height * depth; + + if (width > 1) + width /= 2; + + if (height > 1) + height /= 2; + + if (depth > 1) + depth /= 2; + } + + if (m_sharedImage->type == nzImageType_Cubemap) + size *= 6; + + return size * NzPixelFormat::GetBPP(m_sharedImage->format); +} + +unsigned int NzImage::GetSize(nzUInt8 level) const +{ + return (std::max(m_sharedImage->width/(1 << level), 1)) * + (std::max(m_sharedImage->height/(1 << level), 1)) * + ((m_sharedImage->type == nzImageType_Cubemap) ? 6 : std::min(m_sharedImage->depth/(1 << level), 1)) * + NzPixelFormat::GetBPP(m_sharedImage->format); } nzImageType NzImage::GetType() const @@ -348,9 +433,9 @@ nzImageType NzImage::GetType() const return m_sharedImage->type; } -unsigned int NzImage::GetWidth() const +unsigned int NzImage::GetWidth(nzUInt8 level) const { - return m_sharedImage->width; + return m_sharedImage->width/(1 << level); } bool NzImage::IsCompressed() const @@ -383,6 +468,50 @@ bool NzImage::LoadFromStream(NzInputStream& stream, const NzImageParams& params) return NzResourceLoader::LoadResourceFromStream(this, stream, params); } +bool NzImage::SetLevelCount(nzUInt8 levelCount) +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (levelCount == 0) + { + NazaraError("Level count must be positive"); + return false; + } + #endif + + levelCount = std::min(levelCount, GetMaxLevel(m_sharedImage->width, m_sharedImage->height, m_sharedImage->depth)); + + if (m_sharedImage->levelCount == levelCount) + return true; + + EnsureOwnership(); + + nzUInt8** pixels = new nzUInt8*[levelCount]; + for (unsigned int i = 0; i < levelCount; ++i) + { + if (i < m_sharedImage->levelCount) + pixels[i] = m_sharedImage->pixels[i]; + else + { + unsigned int size = GetSize(i); + pixels[i] = new nzUInt8[size]; + std::memcpy(pixels[i], m_sharedImage->pixels[i], size); + } + } + + delete[] m_sharedImage->pixels; + + m_sharedImage->levelCount = levelCount; + m_sharedImage->pixels = pixels; + + return true; +} + bool NzImage::SetPixel(const NzColor& color, unsigned int x, unsigned int y, unsigned int z) { #if NAZARA_UTILITY_SAFE @@ -423,7 +552,7 @@ bool NzImage::SetPixel(const NzColor& color, unsigned int x, unsigned int y, uns } #endif - nzUInt8* pixel = &m_sharedImage->pixels[(m_sharedImage->height*(m_sharedImage->width*z+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + nzUInt8* pixel = &m_sharedImage->pixels[0][(m_sharedImage->height*(m_sharedImage->width*z+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; if (!NzPixelFormat::Convert(nzPixelFormat_RGBA8, m_sharedImage->format, &color.r, pixel)) { @@ -434,7 +563,7 @@ bool NzImage::SetPixel(const NzColor& color, unsigned int x, unsigned int y, uns return true; } -bool NzImage::SetPixelFace(const NzColor& color, nzCubemapFace face, unsigned int x, unsigned int y) +bool NzImage::SetPixelFace(nzCubemapFace face, const NzColor& color, unsigned int x, unsigned int y) { #if NAZARA_UTILITY_SAFE if (!IsValid()) @@ -468,7 +597,7 @@ bool NzImage::SetPixelFace(const NzColor& color, nzCubemapFace face, unsigned in } #endif - nzUInt8* pixel = &m_sharedImage->pixels[(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX)+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + nzUInt8* pixel = &m_sharedImage->pixels[0][(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX)+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; if (!NzPixelFormat::Convert(nzPixelFormat_RGBA8, m_sharedImage->format, &color.r, pixel)) { @@ -479,7 +608,7 @@ bool NzImage::SetPixelFace(const NzColor& color, nzCubemapFace face, unsigned in return true; } -bool NzImage::Update(const nzUInt8* pixels) +bool NzImage::Update(const nzUInt8* pixels, nzUInt8 level) { #if NAZARA_UTILITY_SAFE if (!IsValid()) @@ -499,16 +628,22 @@ bool NzImage::Update(const nzUInt8* pixels) NazaraError("Invalid pixel source"); return false; } + + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return false; + } #endif EnsureOwnership(); - std::memcpy(m_sharedImage->pixels, pixels, GetSize()); + std::memcpy(m_sharedImage->pixels[level], pixels, GetSize(level)); return true; } -bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z) +bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z, nzUInt8 level) { #if NAZARA_UTILITY_SAFE if (!IsValid()) @@ -535,13 +670,19 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z return false; } - if (rect.x+rect.width > m_sharedImage->width || rect.y+rect.height > m_sharedImage->height) + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return false; + } + + if (rect.x+rect.width > (m_sharedImage->width << level) || rect.y+rect.height > (m_sharedImage->height) << level) { NazaraError("Rectangle dimensions are out of bounds"); return false; } - if (z >= m_sharedImage->depth) + if (z >= (m_sharedImage->depth << level)) { NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(m_sharedImage->depth) + ')'); return false; @@ -552,22 +693,20 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); - nzUInt8* dstPixels = &m_sharedImage->pixels[(m_sharedImage->height*(m_sharedImage->width*z + rect.y) + rect.x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + nzUInt8* dstPixels = &m_sharedImage->pixels[level][(m_sharedImage->height*(m_sharedImage->width*z + rect.y) + rect.x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; unsigned int srcStride = rect.width * bpp; - unsigned int dstStride = m_sharedImage->width * bpp; - unsigned int blockSize = m_sharedImage->width * bpp; for (unsigned int i = 0; i < rect.height; ++i) { std::memcpy(dstPixels, pixels, blockSize); pixels += srcStride; - dstPixels += dstStride; + dstPixels += blockSize; } return true; } -bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels) +bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, nzUInt8 level) { #if NAZARA_UTILITY_SAFE if (!IsValid()) @@ -587,17 +726,23 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels) NazaraError("Invalid pixel source"); return false; } + + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return false; + } #endif EnsureOwnership(); - unsigned int size = GetSize(); - std::memcpy(&m_sharedImage->pixels[size*(face-nzCubemapFace_PositiveX)], pixels, size); + unsigned int size = GetSize(level); + std::memcpy(&m_sharedImage->pixels[level][size*(face-nzCubemapFace_PositiveX)], pixels, size); return true; } -bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRectui& rect) +bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRectui& rect, nzUInt8 level) { #if NAZARA_UTILITY_SAFE if (!IsValid()) @@ -624,7 +769,13 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRect return false; } - if (rect.x+rect.width > m_sharedImage->width || rect.y+rect.height > m_sharedImage->height) + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return false; + } + + if (rect.x+rect.width > (m_sharedImage->width << level) || rect.y+rect.height > (m_sharedImage->height) << level) { NazaraError("Rectangle dimensions are out of bounds"); return false; @@ -635,16 +786,14 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRect nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); - nzUInt8* dstPixels = &m_sharedImage->pixels[(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX) + rect.y) + rect.x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + nzUInt8* dstPixels = &m_sharedImage->pixels[level][(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX) + rect.y) + rect.x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; unsigned int srcStride = rect.width * bpp; - unsigned int dstStride = m_sharedImage->width * bpp; - unsigned int blockSize = m_sharedImage->width * bpp; for (unsigned int i = 0; i < rect.height; ++i) { std::memcpy(dstPixels, pixels, blockSize); pixels += srcStride; - dstPixels += dstStride; + dstPixels += blockSize; } return true; @@ -672,6 +821,17 @@ NzImage& NzImage::operator=(NzImage&& image) return *this; } +nzUInt8 NzImage::GetMaxLevel(unsigned int width, unsigned int height, unsigned int depth) +{ + static const float l2 = std::log(2); + + unsigned int widthLevel = std::log(width)/l2; + unsigned int heightLevel = std::log(height)/l2; + unsigned int depthLevel = std::log(depth)/l2; + + return std::max(std::max(widthLevel, heightLevel), depthLevel); +} + void NzImage::RegisterFileLoader(const NzString& extensions, LoadFileFunction loadFile) { return RegisterResourceFileLoader(extensions, loadFile); @@ -712,12 +872,15 @@ void NzImage::EnsureOwnership() { m_sharedImage->refCount--; - unsigned int size = GetSize(); + nzUInt8** pixels = new nzUInt8*[m_sharedImage->levelCount]; + for (unsigned int i = 0; i < m_sharedImage->levelCount; ++i) + { + unsigned int size = GetSize(i); + pixels[i] = new nzUInt8[size]; + std::memcpy(pixels[i], &m_sharedImage->pixels[i], size); + } - nzUInt8* pixels = new nzUInt8[size]; - std::memcpy(pixels, m_sharedImage->pixels, size); - - m_sharedImage = new SharedImage(1, m_sharedImage->type, m_sharedImage->format, pixels, m_sharedImage->width, m_sharedImage->height, m_sharedImage->depth); + m_sharedImage = new SharedImage(1, m_sharedImage->type, m_sharedImage->format, m_sharedImage->levelCount, pixels, m_sharedImage->width, m_sharedImage->height, m_sharedImage->depth); } } @@ -732,6 +895,9 @@ void NzImage::ReleaseImage() if (m_sharedImage->refCount == 0) { + for (unsigned int i = 0; i < m_sharedImage->levelCount; ++i) + delete[] m_sharedImage->pixels[i]; + delete[] m_sharedImage->pixels; delete m_sharedImage; } @@ -739,4 +905,4 @@ void NzImage::ReleaseImage() m_sharedImage = &emptyImage; } -NzImage::SharedImage NzImage::emptyImage(0, nzImageType_2D, nzPixelFormat_Undefined, nullptr, 0, 0, 0); +NzImage::SharedImage NzImage::emptyImage(0, nzImageType_2D, nzPixelFormat_Undefined, 0, nullptr, 0, 0, 0); diff --git a/src/Nazara/Utility/Loaders/STB.cpp b/src/Nazara/Utility/Loaders/STB.cpp index d4910e6ef..e6b42ba6f 100644 --- a/src/Nazara/Utility/Loaders/STB.cpp +++ b/src/Nazara/Utility/Loaders/STB.cpp @@ -120,6 +120,7 @@ namespace } resource->Update(ptr); + stbi_image_free(ptr); if (stbiFormat == STBI_default && parameters.loadFormat != nzPixelFormat_Undefined) diff --git a/src/Nazara/Utility/PixelFormat.cpp b/src/Nazara/Utility/PixelFormat.cpp index 9723b970d..84685f296 100644 --- a/src/Nazara/Utility/PixelFormat.cpp +++ b/src/Nazara/Utility/PixelFormat.cpp @@ -8,15 +8,23 @@ #include #include -///FIXME: Endianness (nzUInt16) - namespace { + inline nzUInt8 c4to5(nzUInt8 c) + { + return c * (31.f/15.f); + } + inline nzUInt8 c4to8(nzUInt8 c) { return c * (255/15); } + inline nzUInt8 c5to4(nzUInt8 c) + { + return c * (15.f/31.f); + } + inline nzUInt8 c5to8(nzUInt8 c) { return c * (255.f/31.f); @@ -90,11 +98,19 @@ namespace template<> nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) { + nzUInt16* ptr = reinterpret_cast(dst); while (start < end) { - *dst++ = ((c8to4(start[2])) << 4) | c8to4(start[1]); - *dst++ = ((c8to4(start[0])) << 4) | 0x0F; + *ptr = (static_cast(c8to4(start[2])) << 12) | + (static_cast(c8to4(start[1])) << 8) | + (static_cast(c8to4(start[0])) << 4) | + 0x0F; + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 3; } @@ -107,11 +123,16 @@ namespace nzUInt16* ptr = reinterpret_cast(dst); while (start < end) { - *ptr++ = (static_cast(c8to5(start[2])) << 11) | - (static_cast(c8to5(start[1])) << 6) | - (static_cast(c8to5(start[0])) << 1) | - 0x1; + *ptr = (static_cast(c8to5(start[2])) << 11) | + (static_cast(c8to5(start[1])) << 6) | + (static_cast(c8to5(start[0])) << 1) | + 0x1; + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 3; } @@ -195,11 +216,19 @@ namespace template<> nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) { + nzUInt16* ptr = reinterpret_cast(dst); while (start < end) { - *dst++ = (c8to4(start[2]) << 4) | c8to4(start[1]); - *dst++ = (c8to4(start[0]) << 4) | c8to4(start[3]); + *ptr = (static_cast(c8to4(start[2])) << 12) | + (static_cast(c8to4(start[1])) << 8) | + (static_cast(c8to4(start[0])) << 4) | + (static_cast(c8to4(start[3])) << 0); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 4; } @@ -212,11 +241,16 @@ namespace nzUInt16* ptr = reinterpret_cast(dst); while (start < end) { - *ptr++ = (static_cast(c8to5(start[2])) << 11) | - (static_cast(c8to5(start[1])) << 6) | - (static_cast(c8to5(start[0])) << 1) | - ((start[3] == 0xFF) ? 1 : 0); + *ptr = (static_cast(c8to5(start[2])) << 11) | + (static_cast(c8to5(start[1])) << 6) | + (static_cast(c8to5(start[0])) << 1) | + ((start[3] == 0xFF) ? 1 : 0); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 4; } @@ -303,13 +337,21 @@ namespace template<> nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) { + nzUInt16* ptr = reinterpret_cast(dst); while (start < end) { - nzUInt8 l = c8to4(start[0]); + nzUInt16 l = static_cast(c8to4(start[0])); - *dst++ = (l << 4) | l; - *dst++ = (l << 4) | 0x0F; + *ptr = (l << 12) | + (l << 8) | + (l << 4) | + 0x0F; + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 1; } @@ -324,11 +366,16 @@ namespace { nzUInt16 l = static_cast(c8to5(start[0])); - *ptr++ = (l << 11) | - (l << 6) | - (l << 1) | - 1; + *ptr = (l << 11) | + (l << 6) | + (l << 1) | + 1; + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 1; } @@ -414,13 +461,18 @@ namespace template<> nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) { + nzUInt16* ptr = reinterpret_cast(dst); while (start < end) { - nzUInt8 l = c8to4(start[0]); + nzUInt16 l = static_cast(c8to4(start[0])); - *dst++ = (l << 4) | l; - *dst++ = (l << 4) | c8to4(start[1]); + *ptr = (l << 12) | (l << 8) | (l << 4) | c8to4(start[1]); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 2; } @@ -435,8 +487,13 @@ namespace { nzUInt16 l = static_cast(c8to5(start[0])); - *ptr++ = (l << 11) | (l << 6) | (l << 1) | ((start[1] == 0xFF) ? 1 : 0); + *ptr = (l << 11) | (l << 6) | (l << 1) | ((start[1] == 0xFF) ? 1 : 0); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 2; } @@ -480,9 +537,15 @@ namespace { while (start < end) { - *dst++ = c4to8((start[1] & 0xF0) >> 4); - *dst++ = c4to8((start[0] & 0x0F) >> 0); - *dst++ = c4to8((start[0] & 0xF0) >> 4); + nzUInt16 pixel = *reinterpret_cast(start); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + + *dst++ = c4to8((pixel & 0x00F0) >> 4); + *dst++ = c4to8((pixel & 0x0F00) >> 8); + *dst++ = c4to8((pixel & 0xF000) >> 12); start += 2; } @@ -495,10 +558,16 @@ namespace { while (start < end) { - *dst++ = c4to8((start[1] & 0xF0) >> 4); - *dst++ = c4to8((start[0] & 0x0F) >> 0); - *dst++ = c4to8((start[0] & 0xF0) >> 4); - *dst++ = c4to8((start[1] & 0x0F) >> 0); + nzUInt16 pixel = *reinterpret_cast(start); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + + *dst++ = c4to8((pixel & 0x00F0) >> 4); + *dst++ = c4to8((pixel & 0x0F00) >> 8); + *dst++ = c4to8((pixel & 0xF000) >> 12); + *dst++ = c4to8((pixel & 0x000F) >> 0); start += 2; } @@ -511,9 +580,15 @@ namespace { while (start < end) { - nzUInt8 r = c4to8((start[0] & 0xF0) >> 4); - nzUInt8 g = c4to8((start[0] & 0x0F) >> 0); - nzUInt8 b = c4to8((start[1] & 0xF0) >> 4); + nzUInt16 pixel = *reinterpret_cast(start); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + + nzUInt16 r = c4to8((pixel & 0xF000) >> 12); + nzUInt16 g = c4to8((pixel & 0x0F00) >> 8); + nzUInt16 b = c4to8((pixel & 0x00F0) >> 4); *dst++ = static_cast(r * 0.3 + g * 0.59 + b * 0.11); @@ -528,12 +603,18 @@ namespace { while (start < end) { - nzUInt8 r = c4to8((start[0] & 0xF0) >> 4); - nzUInt8 g = c4to8((start[0] & 0x0F) >> 0); - nzUInt8 b = c4to8((start[1] & 0xF0) >> 4); + nzUInt16 pixel = *reinterpret_cast(start); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + + nzUInt16 r = c4to8((pixel & 0xF000) >> 12); + nzUInt16 g = c4to8((pixel & 0x0F00) >> 8); + nzUInt16 b = c4to8((pixel & 0x00F0) >> 4); *dst++ = static_cast(r * 0.3 + g * 0.59 + b * 0.11); - *dst++ = c4to8(start[1] & 0x0F); + *dst++ = c4to8(pixel & 0x000F); start += 2; } @@ -547,13 +628,24 @@ namespace nzUInt16* ptr = reinterpret_cast(dst); while (start < end) { - nzUInt16 r = (start[0] & 0xF0) >> 4; - nzUInt16 g = (start[0] & 0x0F) >> 0; - nzUInt16 b = (start[1] & 0xF0) >> 4; - nzUInt8 a = (start[1] & 0x0F) >> 0; + nzUInt16 pixel = *reinterpret_cast(start); - *ptr++ = (r << 11) | (g << 6) | (b << 1) | ((a == 0xFF) ? 1 : 0); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + nzUInt16 r = c4to5((pixel & 0xF000) >> 12); + nzUInt16 g = c4to5((pixel & 0x0F00) >> 8); + nzUInt16 b = c4to5((pixel & 0x00F0) >> 4); + nzUInt16 a = c4to5((pixel & 0x000F) >> 0); + + *ptr = (r << 11) | (g << 6) | (b << 1) | ((a == 0xFF) ? 1 : 0); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 2; } @@ -565,9 +657,15 @@ namespace { while (start < end) { - *dst++ = c4to8((start[0] & 0xF0) >> 4); - *dst++ = c4to8((start[0] & 0x0F) >> 0); - *dst++ = c4to8((start[1] & 0xF0) >> 4); + nzUInt16 pixel = *reinterpret_cast(start); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + + *dst++ = c4to8((pixel & 0xF000) >> 12); + *dst++ = c4to8((pixel & 0x0F00) >> 8); + *dst++ = c4to8((pixel & 0x00F0) >> 4); start += 2; } @@ -580,10 +678,16 @@ namespace { while (start < end) { - *dst++ = c4to8((start[0] & 0xF0) >> 4); - *dst++ = c4to8((start[0] & 0x0F) >> 0); - *dst++ = c4to8((start[1] & 0xF0) >> 4); - *dst++ = c4to8((start[1] & 0x0F) >> 0); + nzUInt16 pixel = *reinterpret_cast(start); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + + *dst++ = c4to8((pixel & 0xF000) >> 12); + *dst++ = c4to8((pixel & 0x0F00) >> 8); + *dst++ = c4to8((pixel & 0x00F0) >> 4); + *dst++ = c4to8((pixel & 0x000F) >> 0); start += 2; } @@ -599,6 +703,10 @@ namespace { nzUInt16 pixel = *reinterpret_cast(start); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + *dst++ = c5to8((pixel & 0x003E) >> 1); *dst++ = c5to8((pixel & 0x07C0) >> 6); *dst++ = c5to8((pixel & 0xF800) >> 11); @@ -616,6 +724,10 @@ namespace { nzUInt16 pixel = *reinterpret_cast(start); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + *dst++ = c5to8((pixel & 0x003E) >> 1); *dst++ = c5to8((pixel & 0x07C0) >> 6); *dst++ = c5to8((pixel & 0xF800) >> 11); @@ -634,6 +746,10 @@ namespace { nzUInt16 pixel = *reinterpret_cast(start); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + nzUInt8 r = c5to8((pixel & 0xF800) >> 11); nzUInt8 g = c5to8((pixel & 0x07C0) >> 6); nzUInt8 b = c5to8((pixel & 0x003E) >> 1); @@ -653,6 +769,10 @@ namespace { nzUInt16 pixel = *reinterpret_cast(start); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + nzUInt8 r = c5to8((pixel & 0xF800) >> 11); nzUInt8 g = c5to8((pixel & 0x07C0) >> 6); nzUInt8 b = c5to8((pixel & 0x003E) >> 1); @@ -669,17 +789,26 @@ namespace template<> nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) { + nzUInt16* ptr = reinterpret_cast(dst); while (start < end) { nzUInt16 pixel = *reinterpret_cast(start); - nzUInt8 r = c5to8((pixel & 0xF800) >> 11); - nzUInt8 g = c5to8((pixel & 0x07C0) >> 6); - nzUInt8 b = c5to8((pixel & 0x003E) >> 1); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif - *dst++ = (c8to4(r) << 4) | c8to4(g); - *dst++ = (c8to4(b) << 4) | ((pixel & 0x1)*0x0F); + nzUInt8 r = c5to4((pixel & 0xF800) >> 11); + nzUInt8 g = c5to4((pixel & 0x07C0) >> 6); + nzUInt8 b = c5to4((pixel & 0x003E) >> 1); + *ptr = (r << 12) | (g << 8) | (b << 4) | ((pixel & 0x1)*0x0F); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 2; } @@ -693,6 +822,10 @@ namespace { nzUInt16 pixel = *reinterpret_cast(start); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + *dst++ = c5to8((pixel & 0xF800) >> 11); *dst++ = c5to8((pixel & 0x07C0) >> 6); *dst++ = c5to8((pixel & 0x003E) >> 1); @@ -710,6 +843,10 @@ namespace { nzUInt16 pixel = *reinterpret_cast(start); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + *dst++ = c5to8((pixel & 0xF800) >> 11); *dst++ = c5to8((pixel & 0x07C0) >> 6); *dst++ = c5to8((pixel & 0x003E) >> 1); @@ -783,11 +920,19 @@ namespace template<> nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) { + nzUInt16* ptr = reinterpret_cast(dst); while (start < end) { - *dst++ = (c8to4(start[0]) << 4) | c8to4(start[1]); - *dst++ = (c8to4(start[2]) << 4) | 0x0F; + *ptr = (static_cast(c8to4(start[0])) << 12) | + (static_cast(c8to4(start[1])) << 8) | + (static_cast(c8to4(start[2])) << 4) | + 0x0F; + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 3; } @@ -800,11 +945,16 @@ namespace nzUInt16* ptr = reinterpret_cast(dst); while (start < end) { - *ptr++ = (static_cast(c8to5(start[0])) << 11) | - (static_cast(c8to5(start[1])) << 6) | - (static_cast(c8to5(start[2])) << 1) | - 0x1; + *ptr = (static_cast(c8to5(start[0])) << 11) | + (static_cast(c8to5(start[1])) << 6) | + (static_cast(c8to5(start[2])) << 1) | + 0x1; + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 3; } @@ -889,11 +1039,19 @@ namespace template<> nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) { + nzUInt16* ptr = reinterpret_cast(dst); while (start < end) { - *dst++ = (c8to4(start[0]) << 4) | c8to4(start[1]); - *dst++ = (c8to4(start[2]) << 4) | c8to4(start[3]); + *ptr = (static_cast(c8to4(start[0])) << 12) | + (static_cast(c8to4(start[1])) << 8) | + (static_cast(c8to4(start[2])) << 4) | + (static_cast(c8to4(start[3])) << 0); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 4; } @@ -906,11 +1064,16 @@ namespace nzUInt16* ptr = reinterpret_cast(dst); while (start < end) { - *ptr++ = (static_cast(c8to5(start[0])) << 11) | - (static_cast(c8to5(start[1])) << 6) | - (static_cast(c8to5(start[2])) << 1) | - ((start[3] == 0xFF) ? 1 : 0); + *ptr = (static_cast(c8to5(start[0])) << 11) | + (static_cast(c8to5(start[1])) << 6) | + (static_cast(c8to5(start[2])) << 1) | + ((start[3] == 0xFF) ? 1 : 0); + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; start += 4; } @@ -976,7 +1139,7 @@ bool NzPixelFormat::Initialize() RegisterConverter(); /**********************************DXT1***********************************/ - ///TODO + ///TODO: Décompresseur DXT1 /* RegisterConverter(); RegisterConverter(); @@ -999,7 +1162,7 @@ bool NzPixelFormat::Initialize() */ /**********************************DXT3***********************************/ - ///TODO + ///TODO: Décompresseur DXT3 /* RegisterConverter(); RegisterConverter(); @@ -1022,7 +1185,7 @@ bool NzPixelFormat::Initialize() */ /**********************************DXT5***********************************/ - ///TODO + ///TODO: Décompresseur DXT5 /* RegisterConverter(); RegisterConverter(); @@ -1091,7 +1254,6 @@ bool NzPixelFormat::Initialize() RegisterConverter(); RegisterConverter(); RegisterConverter();*/ - RegisterConverter(); RegisterConverter(); RegisterConverter(); RegisterConverter(); @@ -1110,7 +1272,6 @@ bool NzPixelFormat::Initialize() RegisterConverter(); RegisterConverter();*/ RegisterConverter(); - RegisterConverter(); RegisterConverter(); RegisterConverter(); diff --git a/src/Nazara/Utility/Window.cpp b/src/Nazara/Utility/Window.cpp index b8425bd7e..dbe29b835 100644 --- a/src/Nazara/Utility/Window.cpp +++ b/src/Nazara/Utility/Window.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include #if defined(NAZARA_PLATFORM_WINDOWS) @@ -281,7 +281,7 @@ bool NzWindow::PollEvent(NzEvent* event) return false; #if NAZARA_UTILITY_THREADED_WINDOW - NzLock lock(m_eventMutex); + NzLockGuard lock(m_eventMutex); #else m_impl->ProcessEvents(false); #endif @@ -308,7 +308,7 @@ void NzWindow::SetEventListener(bool listener) m_impl->SetEventListener(listener); if (!listener) { - NzLock lock(m_eventMutex); + NzLockGuard lock(m_eventMutex); while (!m_events.empty()) m_events.pop(); } @@ -408,7 +408,7 @@ bool NzWindow::WaitEvent(NzEvent* event) return false; #if NAZARA_UTILITY_THREADED_WINDOW - NzLock lock(m_eventMutex); + NzLockGuard lock(m_eventMutex); if (m_events.empty()) { From 3720967802107930121aa911131a1c31324ea977 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 30 May 2012 19:21:20 +0200 Subject: [PATCH 07/15] Fixed compilation error from last commit Fixed NzImage::GetWidth/Height/Depth returning 0 when level > image's max level --- include/Nazara/Utility/Image.hpp | 2 +- src/Nazara/Utility/Image.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/Nazara/Utility/Image.hpp b/include/Nazara/Utility/Image.hpp index aafbb72c1..272c1c7b6 100644 --- a/include/Nazara/Utility/Image.hpp +++ b/include/Nazara/Utility/Image.hpp @@ -122,7 +122,7 @@ class NAZARA_API NzImage : public NzResource, public NzResourceLoaderdepth/(1 << level); + return std::max(m_sharedImage->depth/(1 << level), 1U); } nzPixelFormat NzImage::GetFormat() const @@ -281,7 +281,7 @@ nzPixelFormat NzImage::GetFormat() const unsigned int NzImage::GetHeight(nzUInt8 level) const { - return m_sharedImage->height/(1 << level); + return std::max(m_sharedImage->height/(1 << level), 1U); } nzUInt8 NzImage::GetLevelCount() const @@ -422,9 +422,9 @@ unsigned int NzImage::GetSize() const unsigned int NzImage::GetSize(nzUInt8 level) const { - return (std::max(m_sharedImage->width/(1 << level), 1)) * - (std::max(m_sharedImage->height/(1 << level), 1)) * - ((m_sharedImage->type == nzImageType_Cubemap) ? 6 : std::min(m_sharedImage->depth/(1 << level), 1)) * + return (std::max(m_sharedImage->width/(1 << level), 1U)) * + (std::max(m_sharedImage->height/(1 << level), 1U)) * + ((m_sharedImage->type == nzImageType_Cubemap) ? 6 : std::min(m_sharedImage->depth/(1 << level), 1U)) * NzPixelFormat::GetBPP(m_sharedImage->format); } @@ -435,7 +435,7 @@ nzImageType NzImage::GetType() const unsigned int NzImage::GetWidth(nzUInt8 level) const { - return m_sharedImage->width/(1 << level); + return std::max(m_sharedImage->width/(1 << level), 1U); } bool NzImage::IsCompressed() const From f4b194f6fed0396570c3b82127fbc77269de9494 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 31 May 2012 18:18:28 +0200 Subject: [PATCH 08/15] Fixed rendering with OpenGL core profile Added (automatic) support of Vertex Arrays Objects (VAO) to fix rendering with an OpenGL core profile (OpenGL 3.2 require the use of VAOs) Added level check to NzImage::GetDepth/Height/Size/Width Fixed occlussion query support not correctly setted --- include/Nazara/Prerequesites.hpp | 26 ++-- include/Nazara/Renderer/OpenGL.hpp | 6 +- include/Nazara/Renderer/Renderer.hpp | 10 +- src/Nazara/Renderer/GLSLShader.cpp | 57 +-------- src/Nazara/Renderer/GLSLShader.hpp | 2 - src/Nazara/Renderer/OpenGL.cpp | 27 +++- src/Nazara/Renderer/Renderer.cpp | 177 +++++++++++++++++++++------ src/Nazara/Renderer/ShaderImpl.hpp | 3 - src/Nazara/Utility/Image.cpp | 34 ++++- 9 files changed, 220 insertions(+), 122 deletions(-) diff --git a/include/Nazara/Prerequesites.hpp b/include/Nazara/Prerequesites.hpp index ff66261cc..2a3fe5140 100644 --- a/include/Nazara/Prerequesites.hpp +++ b/include/Nazara/Prerequesites.hpp @@ -62,24 +62,18 @@ #if NAZARA_CORE_WINDOWS_VISTA // Version de Windows minimale : Vista - #if defined(_WIN32_WINNT) - #if _WIN32_WINNT < 0x0600 - #undef _WIN32_WINNT - #define _WIN32_WINNT 0x0600 - #endif - #else - #define _WIN32_WINNT 0x0600 + #define NAZARA_WINNT 0x0600 + #else + #define NAZARA_WINNT 0x0501 + #endif + + #if defined(_WIN32_WINNT) + #if _WIN32_WINNT < NAZARA_WINNT + #undef _WIN32_WINNT + #define _WIN32_WINNT NAZARA_WINNT #endif #else - // Version de Windows minimale : XP - #if defined(_WIN32_WINNT) - #if _WIN32_WINNT < 0x0501 - #undef _WIN32_WINNT - #define _WIN32_WINNT 0x0501 - #endif - #else - #define _WIN32_WINNT 0x0501 - #endif + #define _WIN32_WINNT NAZARA_WINNT #endif #endif #elif defined(linux) || defined(__linux) diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index fc229991f..832d558a6 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -35,8 +35,9 @@ class NAZARA_API NzOpenGL { AnisotropicFilter, FP64, - Framebuffer_Object, + FrameBufferObject, Texture3D, + VertexArrayObject, Count }; @@ -56,6 +57,7 @@ NAZARA_API extern PFNGLBINDBUFFERPROC glBindBuffer; NAZARA_API extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; NAZARA_API extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; NAZARA_API extern PFNGLBINDTEXTUREPROC glBindTexture; +NAZARA_API extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; NAZARA_API extern PFNGLBLENDFUNCPROC glBlendFunc; NAZARA_API extern PFNGLBUFFERDATAPROC glBufferData; NAZARA_API extern PFNGLBUFFERSUBDATAPROC glBufferSubData; @@ -76,6 +78,7 @@ NAZARA_API extern PFNGLDELETEQUERIESPROC glDeleteQueries; NAZARA_API extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers; NAZARA_API extern PFNGLDELETESHADERPROC glDeleteShader; NAZARA_API extern PFNGLDELETETEXTURESPROC glDeleteTextures; +NAZARA_API extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; NAZARA_API extern PFNGLDEPTHFUNCPROC glDepthFunc; NAZARA_API extern PFNGLDEPTHMASKPROC glDepthMask; NAZARA_API extern PFNGLDISABLEPROC glDisable; @@ -96,6 +99,7 @@ NAZARA_API extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; NAZARA_API extern PFNGLGENQUERIESPROC glGenQueries; NAZARA_API extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; NAZARA_API extern PFNGLGENTEXTURESPROC glGenTextures; +NAZARA_API extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; NAZARA_API extern PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv; NAZARA_API extern PFNGLGETERRORPROC glGetError; NAZARA_API extern PFNGLGETINTEGERVPROC glGetIntegerv; diff --git a/include/Nazara/Renderer/Renderer.hpp b/include/Nazara/Renderer/Renderer.hpp index 6b509ece0..86cee1cba 100644 --- a/include/Nazara/Renderer/Renderer.hpp +++ b/include/Nazara/Renderer/Renderer.hpp @@ -8,6 +8,8 @@ #define NAZARA_RENDERER_HPP #include +#include +#include #define NazaraRenderer NzRenderer::Instance() @@ -45,6 +47,7 @@ enum nzRendererClear }; class NzColor; +class NzContext; class NzIndexBuffer; class NzRenderTarget; class NzShader; @@ -86,8 +89,11 @@ class NAZARA_API NzRenderer static bool IsInitialized(); private: - bool UpdateVertexBuffer(); + bool UpdateStates(); + typedef std::tuple VAO_Key; + + std::map m_vaos; const NzIndexBuffer* m_indexBuffer; NzRenderTarget* m_target; NzShader* m_shader; @@ -95,7 +101,7 @@ class NAZARA_API NzRenderer const NzVertexBuffer* m_vertexBuffer; const NzVertexDeclaration* m_vertexDeclaration; bool m_capabilities[nzRendererCap_Count]; - bool m_vertexBufferUpdated; + bool m_statesUpdated; static NzRenderer* s_instance; static bool s_initialized; diff --git a/src/Nazara/Renderer/GLSLShader.cpp b/src/Nazara/Renderer/GLSLShader.cpp index eda9240e8..af9403f89 100644 --- a/src/Nazara/Renderer/GLSLShader.cpp +++ b/src/Nazara/Renderer/GLSLShader.cpp @@ -6,14 +6,13 @@ #include #include #include -#include -#include #include #include namespace { - nzUInt8 attribIndex[] = + ///FIXME: Déclaré deux fois (ici et dans Renderer.cpp) + const nzUInt8 attribIndex[] = { 2, // nzElementUsage_Diffuse 1, // nzElementUsage_Normal @@ -27,32 +26,6 @@ namespace GL_GEOMETRY_SHADER, // nzShaderType_Geometry GL_VERTEX_SHADER // nzShaderType_Vertex }; - - const nzUInt8 size[] = - { - 4, // nzElementType_Color - 1, // nzElementType_Double1 - 2, // nzElementType_Double2 - 3, // nzElementType_Double3 - 4, // nzElementType_Double4 - 1, // nzElementType_Float1 - 2, // nzElementType_Float2 - 3, // nzElementType_Float3 - 4 // nzElementType_Float4 - }; - - const GLenum type[] = - { - GL_UNSIGNED_BYTE, // nzElementType_Color - GL_DOUBLE, // nzElementType_Double1 - GL_DOUBLE, // nzElementType_Double2 - GL_DOUBLE, // nzElementType_Double3 - GL_DOUBLE, // nzElementType_Double4 - GL_FLOAT, // nzElementType_Float1 - GL_FLOAT, // nzElementType_Float2 - GL_FLOAT, // nzElementType_Float3 - GL_FLOAT // nzElementType_Float4 - }; } NzGLSLShader::NzGLSLShader(NzShader* parent) : @@ -331,29 +304,3 @@ void NzGLSLShader::Unlock() const if (--m_lockedLevel == 0 && m_lockedPrevious != m_program) glUseProgram(m_lockedPrevious); } - -bool NzGLSLShader::UpdateVertexBuffer(const NzVertexBuffer* vertexBuffer, const NzVertexDeclaration* vertexDeclaration) -{ - vertexBuffer->GetBuffer()->GetImpl()->Bind(); - const nzUInt8* buffer = reinterpret_cast(vertexBuffer->GetBufferPtr()); - - ///FIXME: Améliorer les déclarations pour permettre de faire ça plus simplement - for (int i = 0; i < 12; ++i) // Solution temporaire, à virer - glDisableVertexAttribArray(i); // Chaque itération tue un chaton :( - - unsigned int stride = vertexDeclaration->GetStride(); - unsigned int elementCount = vertexDeclaration->GetElementCount(); - for (unsigned int i = 0; i < elementCount; ++i) - { - const NzVertexDeclaration::Element* element = vertexDeclaration->GetElement(i); - glEnableVertexAttribArray(attribIndex[element->usage]+element->usageIndex); - glVertexAttribPointer(attribIndex[element->usage]+element->usageIndex, - size[element->type], - type[element->type], - (element->type == nzElementType_Color) ? GL_TRUE : GL_FALSE, - stride, - &buffer[element->offset]); - } - - return true; -} diff --git a/src/Nazara/Renderer/GLSLShader.hpp b/src/Nazara/Renderer/GLSLShader.hpp index 86efaabaf..653955999 100644 --- a/src/Nazara/Renderer/GLSLShader.hpp +++ b/src/Nazara/Renderer/GLSLShader.hpp @@ -47,8 +47,6 @@ class NzGLSLShader : public NzShaderImpl void Unlock() const; private: - bool UpdateVertexBuffer(const NzVertexBuffer* vertexBuffer, const NzVertexDeclaration* vertexDeclaration); - mutable std::map m_idCache; mutable GLuint m_lockedPrevious; GLuint m_program; diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index e76b224c6..3dde42994 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -314,7 +314,7 @@ bool NzOpenGL::Initialize() } } - // Framebuffer_Object + // FrameBufferObject try { glBindFramebuffer = reinterpret_cast(LoadEntry("glBindFramebuffer")); @@ -329,7 +329,7 @@ bool NzOpenGL::Initialize() glGenRenderbuffers = reinterpret_cast(LoadEntry("glGenRenderbuffers")); glRenderbufferStorage = reinterpret_cast(LoadEntry("glRenderbufferStorage")); - openGLextensions[NzOpenGL::Framebuffer_Object] = true; + openGLextensions[NzOpenGL::FrameBufferObject] = true; } catch (const std::exception& e) { @@ -352,7 +352,7 @@ bool NzOpenGL::Initialize() glGenRenderbuffers = reinterpret_cast(LoadEntry("glGenRenderbuffersEXT")); glRenderbufferStorage = reinterpret_cast(LoadEntry("glRenderbufferStorageEXT")); - openGLextensions[NzOpenGL::Framebuffer_Object] = true; + openGLextensions[NzOpenGL::FrameBufferObject] = true; } catch (const std::exception& e) { @@ -377,8 +377,24 @@ bool NzOpenGL::Initialize() } } - /****************************************Contextes****************************************/ + // VertexArrayObject + if (openGLversion >= 300 || IsSupported("GL_ARB_vertex_array_object")) + { + try + { + glBindVertexArray = reinterpret_cast(LoadEntry("glBindVertexArray", false)); + glDeleteVertexArrays = reinterpret_cast(LoadEntry("glDeleteVertexArrays", false)); + glGenVertexArrays = reinterpret_cast(LoadEntry("glGenVertexArrays", false)); + openGLextensions[NzOpenGL::VertexArrayObject] = true; + } + catch (const std::exception& e) + { + NazaraError("Failed to load ARB_vertex_array_object: " + NzString(e.what())); + } + } + + /****************************************Contextes****************************************/ NzContextParameters::defaultMajorVersion = openGLversion/100; NzContextParameters::defaultMinorVersion = (openGLversion%100)/10; @@ -427,6 +443,7 @@ PFNGLBINDBUFFERPROC glBindBuffer = nullptr; PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = nullptr; PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = nullptr; PFNGLBINDTEXTUREPROC glBindTexture = nullptr; +PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr; PFNGLBLENDFUNCPROC glBlendFunc = nullptr; PFNGLBUFFERDATAPROC glBufferData = nullptr; PFNGLBUFFERSUBDATAPROC glBufferSubData = nullptr; @@ -447,6 +464,7 @@ PFNGLDELETEQUERIESPROC glDeleteQueries = nullptr; PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = nullptr; PFNGLDELETESHADERPROC glDeleteShader = nullptr; PFNGLDELETETEXTURESPROC glDeleteTextures = nullptr; +PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = nullptr; PFNGLDEPTHFUNCPROC glDepthFunc = nullptr; PFNGLDEPTHMASKPROC glDepthMask = nullptr; PFNGLDISABLEPROC glDisable = nullptr; @@ -467,6 +485,7 @@ PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = nullptr; PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = nullptr; PFNGLGENQUERIESPROC glGenQueries = nullptr; PFNGLGENTEXTURESPROC glGenTextures = nullptr; +PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr; PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv = nullptr; PFNGLGETERRORPROC glGetError = nullptr; PFNGLGETINTEGERVPROC glGetIntegerv = nullptr; diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 6daae067c..7de849aff 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -14,13 +14,23 @@ #include #include #include +#include #include #include #include namespace { - GLenum openglPrimitive[] = { + const nzUInt8 attribIndex[] = + { + 2, // nzElementUsage_Diffuse + 1, // nzElementUsage_Normal + 0, // nzElementUsage_Position + 3, // nzElementUsage_Tangent + 4 // nzElementUsage_TexCoord + }; + + const GLenum openglPrimitive[] = { GL_LINES, // nzPrimitiveType_LineList, GL_LINE_STRIP, // nzPrimitiveType_LineStrip, GL_POINTS, // nzPrimitiveType_PointList, @@ -28,6 +38,32 @@ namespace GL_TRIANGLE_STRIP, // nzPrimitiveType_TriangleStrip, GL_TRIANGLE_FAN // nzPrimitiveType_TriangleFan }; + + const nzUInt8 openglSize[] = + { + 4, // nzElementType_Color + 1, // nzElementType_Double1 + 2, // nzElementType_Double2 + 3, // nzElementType_Double3 + 4, // nzElementType_Double4 + 1, // nzElementType_Float1 + 2, // nzElementType_Float2 + 3, // nzElementType_Float3 + 4 // nzElementType_Float4 + }; + + const GLenum openglType[] = + { + GL_UNSIGNED_BYTE, // nzElementType_Color + GL_DOUBLE, // nzElementType_Double1 + GL_DOUBLE, // nzElementType_Double2 + GL_DOUBLE, // nzElementType_Double3 + GL_DOUBLE, // nzElementType_Double4 + GL_FLOAT, // nzElementType_Float1 + GL_FLOAT, // nzElementType_Float2 + GL_FLOAT, // nzElementType_Float3 + GL_FLOAT // nzElementType_Float4 + }; } NzRenderer::NzRenderer() : @@ -36,7 +72,7 @@ m_target(nullptr), m_shader(nullptr), m_vertexBuffer(nullptr), m_vertexDeclaration(nullptr), -m_vertexBufferUpdated(false) +m_statesUpdated(false) { #if NAZARA_RENDERER_SAFE if (s_instance) @@ -91,11 +127,11 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f } #endif - if (!m_vertexBufferUpdated) + if (!m_statesUpdated) { - if (!UpdateVertexBuffer()) + if (!UpdateStates()) { - NazaraError("Failed to update vertex buffer"); + NazaraError("Failed to update states"); return; } } @@ -127,11 +163,11 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f void NzRenderer::DrawPrimitives(nzPrimitiveType primitive, unsigned int firstVertex, unsigned int vertexCount) { - if (!m_vertexBufferUpdated) + if (!m_statesUpdated) { - if (!UpdateVertexBuffer()) + if (!UpdateStates()) { - NazaraError("Failed to update vertex buffer"); + NazaraError("Failed to update states"); return; } } @@ -191,7 +227,7 @@ bool NzRenderer::Initialize() m_capabilities[nzRendererCap_FP64] = NzOpenGL::IsSupported(NzOpenGL::FP64); m_capabilities[nzRendererCap_HardwareBuffer] = true; // Natif depuis OpenGL 1.5 m_capabilities[nzRendererCap_MultipleRenderTargets] = true; // Natif depuis OpenGL 2.0 - m_capabilities[nzRendererCap_OcclusionQuery] = // Natif depuis OpenGL 1.5 + m_capabilities[nzRendererCap_OcclusionQuery] = true; // Natif depuis OpenGL 1.5 m_capabilities[nzRendererCap_SoftwareBuffer] = NzOpenGL::GetVersion() <= 300; // Déprécié en OpenGL 3 m_capabilities[nzRendererCap_Texture3D] = NzOpenGL::IsSupported(NzOpenGL::Texture3D); m_capabilities[nzRendererCap_TextureCubemap] = true; // Natif depuis OpenGL 1.3 @@ -260,12 +296,11 @@ void NzRenderer::SetClearStencil(unsigned int value) bool NzRenderer::SetIndexBuffer(const NzIndexBuffer* indexBuffer) { - if (indexBuffer == m_indexBuffer) - return true; - - // OpenGL ne nécessite pas de débinder un index buffer pour ne pas l'utiliser - if (indexBuffer) - indexBuffer->GetBuffer()->m_impl->Bind(); + if (indexBuffer != m_indexBuffer) + { + m_indexBuffer = indexBuffer; + m_statesUpdated = false; + } return true; } @@ -292,7 +327,6 @@ bool NzRenderer::SetShader(NzShader* shader) } m_shader = shader; - m_vertexBufferUpdated = false; } else if (m_shader) { @@ -339,24 +373,22 @@ bool NzRenderer::SetTarget(NzRenderTarget* target) bool NzRenderer::SetVertexBuffer(const NzVertexBuffer* vertexBuffer) { - if (m_vertexBuffer == vertexBuffer) - return true; - - if (m_vertexBuffer && vertexBuffer) + if (m_vertexBuffer != vertexBuffer) { - // Si l'ancien buffer et le nouveau sont hardware, pas besoin de mettre à jour la déclaration - if (!m_vertexBuffer->IsHardware() || !vertexBuffer->IsHardware()) - m_vertexBufferUpdated = false; + m_vertexBuffer = vertexBuffer; + m_statesUpdated = false; } - m_vertexBuffer = vertexBuffer; return true; } bool NzRenderer::SetVertexDeclaration(const NzVertexDeclaration* vertexDeclaration) { - m_vertexDeclaration = vertexDeclaration; - m_vertexBufferUpdated = false; + if (m_vertexDeclaration != vertexDeclaration) + { + m_vertexDeclaration = vertexDeclaration; + m_statesUpdated = false; + } return true; } @@ -371,10 +403,17 @@ void NzRenderer::Uninitialize() } #endif - NzOpenGL::Uninitialize(); - s_initialized = false; + // Libération des VAOs + for (auto it = m_vaos.begin(); it != m_vaos.end(); ++it) + { + GLuint vao = it->second; + glDeleteVertexArrays(1, &vao); + } + + NzOpenGL::Uninitialize(); + if (m_utilityModule) { delete m_utilityModule; @@ -397,15 +436,9 @@ bool NzRenderer::IsInitialized() return s_initialized; } -bool NzRenderer::UpdateVertexBuffer() +bool NzRenderer::UpdateStates() { #if NAZARA_RENDERER_SAFE - if (!m_shader) - { - NazaraError("No shader"); - return false; - } - if (!m_vertexBuffer) { NazaraError("No vertex buffer"); @@ -419,10 +452,78 @@ bool NzRenderer::UpdateVertexBuffer() } #endif - if (!m_shader->m_impl->UpdateVertexBuffer(m_vertexBuffer, m_vertexDeclaration)) - return false; + static const bool vaoSupported = NzOpenGL::IsSupported(NzOpenGL::VertexArrayObject); + bool update; + GLuint vao; - m_vertexBufferUpdated = true; + // Si les VAOs sont supportés, on entoure nos appels par ceux-ci + if (vaoSupported) + { + // On recherche si un VAO existe déjà avec notre configuration + // Note: Les VAOs ne sont pas partagés entre les contextes, ils font donc partie de notre configuration + + auto key = std::make_tuple(NzContext::GetCurrent(), m_indexBuffer, m_vertexBuffer, m_vertexDeclaration); + auto it = m_vaos.find(key); + if (it == m_vaos.end()) + { + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + m_vaos.insert(std::make_pair(key, static_cast(vao))); + + update = true; + } + else + { + // Notre VAO existe déjà, il est donc inutile de le reprogrammer + vao = it->second; + + update = false; + } + } + else + update = true; // Fallback si les VAOs ne sont pas supportés + + if (update) + { + m_vertexBuffer->GetBuffer()->GetImpl()->Bind(); + + const nzUInt8* buffer = reinterpret_cast(m_vertexBuffer->GetBufferPtr()); + + ///FIXME: Améliorer les déclarations pour permettre de faire ça plus simplement + for (int i = 0; i < 12; ++i) // Solution temporaire, à virer + glDisableVertexAttribArray(i); // Chaque itération tue un chaton :( + + unsigned int stride = m_vertexDeclaration->GetStride(); + unsigned int elementCount = m_vertexDeclaration->GetElementCount(); + for (unsigned int i = 0; i < elementCount; ++i) + { + const NzVertexDeclaration::Element* element = m_vertexDeclaration->GetElement(i); + + glEnableVertexAttribArray(attribIndex[element->usage]+element->usageIndex); + glVertexAttribPointer(attribIndex[element->usage]+element->usageIndex, + openglSize[element->type], + openglType[element->type], + (element->type == nzElementType_Color) ? GL_TRUE : GL_FALSE, + stride, + &buffer[element->offset]); + } + + if (m_indexBuffer) + m_indexBuffer->GetBuffer()->GetImpl()->Bind(); + } + + if (vaoSupported) + { + // Si nous venons de définir notre VAO, nous devons le débinder pour indiquer la fin de sa construction + if (update) + glBindVertexArray(0); + + // Nous (re)bindons le VAO pour définir les attributs de vertice + glBindVertexArray(vao); + } + + m_statesUpdated = true; return true; } diff --git a/src/Nazara/Renderer/ShaderImpl.hpp b/src/Nazara/Renderer/ShaderImpl.hpp index 9d30cedbc..b5b1316ec 100644 --- a/src/Nazara/Renderer/ShaderImpl.hpp +++ b/src/Nazara/Renderer/ShaderImpl.hpp @@ -47,9 +47,6 @@ class NzShaderImpl virtual void Unbind() = 0; virtual void Unlock() const = 0; - - protected: - virtual bool UpdateVertexBuffer(const NzVertexBuffer* vertexBuffer, const NzVertexDeclaration* vertexDeclaration) = 0; }; #endif // NAZARA_SHADERIMPL_HPP diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index 4e80eae9a..5e76b5ce3 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -271,6 +271,14 @@ const nzUInt8* NzImage::GetConstPixels(nzUInt8 level) const unsigned int NzImage::GetDepth(nzUInt8 level) const { + #if NAZARA_UTILITY_SAFE + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return 0; + } + #endif + return std::max(m_sharedImage->depth/(1 << level), 1U); } @@ -281,6 +289,14 @@ nzPixelFormat NzImage::GetFormat() const unsigned int NzImage::GetHeight(nzUInt8 level) const { + #if NAZARA_UTILITY_SAFE + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return 0; + } + #endif + return std::max(m_sharedImage->height/(1 << level), 1U); } @@ -422,6 +438,14 @@ unsigned int NzImage::GetSize() const unsigned int NzImage::GetSize(nzUInt8 level) const { + #if NAZARA_UTILITY_SAFE + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return 0; + } + #endif + return (std::max(m_sharedImage->width/(1 << level), 1U)) * (std::max(m_sharedImage->height/(1 << level), 1U)) * ((m_sharedImage->type == nzImageType_Cubemap) ? 6 : std::min(m_sharedImage->depth/(1 << level), 1U)) * @@ -435,6 +459,14 @@ nzImageType NzImage::GetType() const unsigned int NzImage::GetWidth(nzUInt8 level) const { + #if NAZARA_UTILITY_SAFE + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return 0; + } + #endif + return std::max(m_sharedImage->width/(1 << level), 1U); } @@ -905,4 +937,4 @@ void NzImage::ReleaseImage() m_sharedImage = &emptyImage; } -NzImage::SharedImage NzImage::emptyImage(0, nzImageType_2D, nzPixelFormat_Undefined, 0, nullptr, 0, 0, 0); +NzImage::SharedImage NzImage::emptyImage(0, nzImageType_2D, nzPixelFormat_Undefined, 1, nullptr, 0, 0, 0); From dd4cb97a37a67bd7af254291a43a0952ded22ece Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 31 May 2012 23:33:47 +0200 Subject: [PATCH 09/15] Added support for OpenGL debug mode When NzContextParameters.debugMode is true, Nazara will receive OpenGL's debug message and send them to Nazara's log NzString::Pointer now have the "0x" prefix Added support for ARB_texture_storage extension Nazara now try to load core texture 3D before trying to load EXT_texture3D Added NazaraNotice macro, writing raw text into Nazara's log Added NzContext::Destroy (called in Create) --- include/Nazara/Core/Log.hpp | 1 + include/Nazara/Renderer/Config.hpp | 3 + include/Nazara/Renderer/Context.hpp | 1 + include/Nazara/Renderer/ContextParameters.hpp | 3 + include/Nazara/Renderer/OpenGL.hpp | 15 +- src/Nazara/Core/String.cpp | 4 +- src/Nazara/Renderer/Context.cpp | 136 +++++++++++- src/Nazara/Renderer/ContextParameters.cpp | 6 + src/Nazara/Renderer/OpenGL.cpp | 196 +++++++++++++----- src/Nazara/Renderer/Renderer.cpp | 5 +- src/Nazara/Renderer/Win32/ContextImpl.cpp | 14 +- 11 files changed, 317 insertions(+), 67 deletions(-) diff --git a/include/Nazara/Core/Log.hpp b/include/Nazara/Core/Log.hpp index 8c61ffb4c..857a375b1 100644 --- a/include/Nazara/Core/Log.hpp +++ b/include/Nazara/Core/Log.hpp @@ -16,6 +16,7 @@ #include #define NazaraLog NzLog::Instance() +#define NazaraNotice(txt) NazaraLog->Write(txt) class NzFile; diff --git a/include/Nazara/Renderer/Config.hpp b/include/Nazara/Renderer/Config.hpp index 8fed18121..4c256125a 100644 --- a/include/Nazara/Renderer/Config.hpp +++ b/include/Nazara/Renderer/Config.hpp @@ -38,6 +38,9 @@ // Utilise un tracker pour repérer les éventuels leaks (Ralentit l'exécution) #define NAZARA_RENDERER_MEMORYLEAKTRACKER 0 +// Active le paramère debug des paramètres des contextes par défaut (Perte de performances mais capable de recevoir des messages d'OpenGL) +#define NAZARA_RENDERER_OPENGL_DEBUG 0 + // Active les tests de sécurité basés sur le code (Conseillé pour le développement) #define NAZARA_RENDERER_SAFE 1 diff --git a/include/Nazara/Renderer/Context.hpp b/include/Nazara/Renderer/Context.hpp index 173ae0d8b..9c489c390 100644 --- a/include/Nazara/Renderer/Context.hpp +++ b/include/Nazara/Renderer/Context.hpp @@ -24,6 +24,7 @@ class NAZARA_API NzContext ~NzContext(); bool Create(const NzContextParameters& parameters = NzContextParameters()); + void Destroy(); const NzContextParameters& GetParameters() const; bool IsActive() const; bool SetActive(bool active); diff --git a/include/Nazara/Renderer/ContextParameters.hpp b/include/Nazara/Renderer/ContextParameters.hpp index c8f312f2f..aad31d304 100644 --- a/include/Nazara/Renderer/ContextParameters.hpp +++ b/include/Nazara/Renderer/ContextParameters.hpp @@ -25,6 +25,7 @@ struct NAZARA_API NzContextParameters shareContext(defaultShareContext), window(defaultWindow), compatibilityProfile(defaultCompatibilityProfile), + debugMode(defaultDebugMode), doubleBuffered(defaultDoubleBuffered), shared(defaultShared) { @@ -39,6 +40,7 @@ struct NAZARA_API NzContextParameters const NzContext* shareContext; NzWindowHandle window; bool compatibilityProfile; + bool debugMode; bool doubleBuffered; bool shared; @@ -47,6 +49,7 @@ struct NAZARA_API NzContextParameters static const NzContext* defaultShareContext; static NzWindowHandle defaultWindow; static bool defaultCompatibilityProfile; + static bool defaultDebugMode; static bool defaultDoubleBuffered; static bool defaultShared; }; diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index 832d558a6..04623054d 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -34,9 +34,11 @@ class NAZARA_API NzOpenGL enum Extension { AnisotropicFilter, + DebugOutput, FP64, FrameBufferObject, Texture3D, + TextureStorage, VertexArrayObject, Count @@ -71,6 +73,9 @@ NAZARA_API extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; NAZARA_API extern PFNGLCOLORMASKPROC glColorMask; NAZARA_API extern PFNGLCULLFACEPROC glCullFace; NAZARA_API extern PFNGLCOMPILESHADERPROC glCompileShader; +NAZARA_API extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControl; +NAZARA_API extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsert; +NAZARA_API extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallback; NAZARA_API extern PFNGLDELETEBUFFERSPROC glDeleteBuffers; NAZARA_API extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; NAZARA_API extern PFNGLDELETEPROGRAMPROC glDeleteProgram; @@ -101,6 +106,7 @@ NAZARA_API extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; NAZARA_API extern PFNGLGENTEXTURESPROC glGenTextures; NAZARA_API extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; NAZARA_API extern PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv; +NAZARA_API extern PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLog; NAZARA_API extern PFNGLGETERRORPROC glGetError; NAZARA_API extern PFNGLGETINTEGERVPROC glGetIntegerv; NAZARA_API extern PFNGLGETPROGRAMIVPROC glGetProgramiv; @@ -126,12 +132,17 @@ NAZARA_API extern PFNGLSCISSORPROC glScissor; NAZARA_API extern PFNGLSHADERSOURCEPROC glShaderSource; NAZARA_API extern PFNGLSTENCILFUNCPROC glStencilFunc; NAZARA_API extern PFNGLSTENCILOPPROC glStencilOp; +NAZARA_API extern PFNGLTEXIMAGE1DPROC glTexImage1D; NAZARA_API extern PFNGLTEXIMAGE2DPROC glTexImage2D; -NAZARA_API extern PFNGLTEXIMAGE3DEXTPROC glTexImage3D; +NAZARA_API extern PFNGLTEXIMAGE3DPROC glTexImage3D; NAZARA_API extern PFNGLTEXPARAMETERFPROC glTexParameterf; NAZARA_API extern PFNGLTEXPARAMETERIPROC glTexParameteri; +NAZARA_API extern PFNGLTEXSTORAGE1DPROC glTexStorage1D; +NAZARA_API extern PFNGLTEXSTORAGE2DPROC glTexStorage2D; +NAZARA_API extern PFNGLTEXSTORAGE3DPROC glTexStorage3D; +NAZARA_API extern PFNGLTEXSUBIMAGE1DPROC glTexSubImage1D; NAZARA_API extern PFNGLTEXSUBIMAGE2DPROC glTexSubImage2D; -NAZARA_API extern PFNGLTEXSUBIMAGE3DEXTPROC glTexSubImage3D; +NAZARA_API extern PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D; NAZARA_API extern PFNGLUNIFORM1DPROC glUniform1d; NAZARA_API extern PFNGLUNIFORM1FPROC glUniform1f; NAZARA_API extern PFNGLUNIFORM1IPROC glUniform1i; diff --git a/src/Nazara/Core/String.cpp b/src/Nazara/Core/String.cpp index 84d7e639b..53395d609 100644 --- a/src/Nazara/Core/String.cpp +++ b/src/Nazara/Core/String.cpp @@ -4735,9 +4735,9 @@ NzString NzString::Number(unsigned long long number, nzUInt8 radix) NzString NzString::Pointer(const void* ptr) { - unsigned int size = sizeof(ptr)*2; + unsigned int size = sizeof(ptr)*2+2; char* str = new char[size+1]; - std::sprintf(str, "%p", ptr); + std::sprintf(str, "0x%p", ptr); return NzString(new SharedString(1, size, size, str)); } diff --git a/src/Nazara/Renderer/Context.cpp b/src/Nazara/Renderer/Context.cpp index 64c10c8db..3bb0b2a0c 100644 --- a/src/Nazara/Renderer/Context.cpp +++ b/src/Nazara/Renderer/Context.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #if defined(NAZARA_PLATFORM_WINDOWS) @@ -22,6 +24,108 @@ namespace ///TODO: Thread-local NzContext* currentContext = nullptr; NzContext* threadContext = nullptr; + + void CALLBACK DebugCallback(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, int length, const char* message, void* userParam) + { + NazaraUnused(length); + + NzStringStream ss; + ss << "OpenGL debug message (ID: 0x" << NzString::Number(id, 16) << "):\n"; + ss << "-Source: "; + switch (source) + { + case GL_DEBUG_SOURCE_API_ARB: + ss << "OpenGL"; + break; + + case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB: + ss << "Operating system"; + break; + + case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB: + ss << "Shader compiler"; + break; + + case GL_DEBUG_SOURCE_THIRD_PARTY_ARB: + ss << "Shader compiler"; + break; + + case GL_DEBUG_SOURCE_APPLICATION_ARB: + ss << "Application"; + break; + + case GL_DEBUG_SOURCE_OTHER_ARB: + ss << "Other"; + break; + + default: + // Peut être rajouté par une extension + ss << "Unknown"; + break; + } + ss << '\n'; + + ss << "-Type: "; + switch (type) + { + case GL_DEBUG_TYPE_ERROR_ARB: + ss << "Error"; + break; + + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB: + ss << "Deprecated behavior"; + break; + + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB: + ss << "Undefined behavior"; + break; + + case GL_DEBUG_TYPE_PORTABILITY_ARB: + ss << "Portability"; + break; + + case GL_DEBUG_TYPE_PERFORMANCE_ARB: + ss << "Performance"; + break; + + case GL_DEBUG_TYPE_OTHER_ARB: + ss << "Other"; + break; + + default: + // Peut être rajouté par une extension + ss << "Unknown"; + break; + } + ss << '\n'; + + ss << "-Severity: "; + switch (severity) + { + case GL_DEBUG_SEVERITY_HIGH_ARB: + ss << "High"; + break; + + case GL_DEBUG_SEVERITY_MEDIUM_ARB: + ss << "Medium"; + break; + + case GL_DEBUG_SEVERITY_LOW_ARB: + ss << "Low"; + break; + + default: + // Peut être rajouté par une extension + ss << "Unknown"; + break; + } + ss << '\n'; + + ss << "Message: " << message; + ss << "\n\nSent by context: " << userParam; + + NazaraNotice(ss); + } } NzContext::NzContext() : @@ -31,18 +135,13 @@ m_impl(nullptr) NzContext::~NzContext() { - if (m_impl) - { - if (currentContext == this) - NzContextImpl::Desactivate(); - - m_impl->Destroy(); - delete m_impl; - } + Destroy(); } bool NzContext::Create(const NzContextParameters& parameters) { + Destroy(); + m_parameters = parameters; if (m_parameters.shared && !m_parameters.shareContext) m_parameters.shareContext = s_reference; @@ -71,9 +170,30 @@ bool NzContext::Create(const NzContextParameters& parameters) if (m_parameters.antialiasingLevel > 0) glEnable(GL_MULTISAMPLE); + if (NzOpenGL::IsSupported(NzOpenGL::DebugOutput) && m_parameters.debugMode) + { + glDebugMessageCallback(&DebugCallback, this); + + #ifdef NAZARA_DEBUG + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + #endif + } + return true; } +void NzContext::Destroy() +{ + if (m_impl) + { + if (currentContext == this) + NzContextImpl::Desactivate(); + + m_impl->Destroy(); + delete m_impl; + } +} + const NzContextParameters& NzContext::GetParameters() const { #ifdef NAZARA_RENDERER_SAFE diff --git a/src/Nazara/Renderer/ContextParameters.cpp b/src/Nazara/Renderer/ContextParameters.cpp index 7506ecc3f..55bf0794e 100644 --- a/src/Nazara/Renderer/ContextParameters.cpp +++ b/src/Nazara/Renderer/ContextParameters.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include nzUInt8 NzContextParameters::defaultMajorVersion; // Initialisé par NzOpenGL @@ -10,5 +11,10 @@ nzUInt8 NzContextParameters::defaultMinorVersion; // Initialis const NzContext* NzContextParameters::defaultShareContext = nullptr; NzWindowHandle NzContextParameters::defaultWindow = 0; bool NzContextParameters::defaultCompatibilityProfile = false; +#if NAZARA_RENDERER_OPENGL_DEBUG || defined(NAZARA_DEBUG) +bool NzContextParameters::defaultDebugMode = true; +#else +bool NzContextParameters::defaultDebugMode = false; +#endif bool NzContextParameters::defaultDoubleBuffered = false; bool NzContextParameters::defaultShared = true; diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index 3dde42994..86ea4ae1f 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -122,10 +122,82 @@ bool NzOpenGL::Initialize() parameters.minorVersion = 0; parameters.shared = false; + /* + Note: Même le contexte de chargement nécessite quelques fonctions de base pour correctement s'initialiser + Pour cette raison, sa création est faite en deux fois, la première sert à récupérer le strict minimum, + la seconde à créer le véritable contexte de chargement. + + Non sérieusement si quelqu'un a une meilleure idée qu'il me le dise + */ + + /****************************************Initialisation****************************************/ + NzContext loadContext; if (!loadContext.Create(parameters)) { NazaraError("Failed to create load context"); + Uninitialize(); + + return false; + } + + #if defined(NAZARA_PLATFORM_WINDOWS) + wglCreateContextAttribs = reinterpret_cast(LoadEntry("wglCreateContextAttribsARB", false)); + wglChoosePixelFormat = reinterpret_cast(LoadEntry("wglChoosePixelFormatARB", false)); + if (!wglChoosePixelFormat) + wglChoosePixelFormat = reinterpret_cast(LoadEntry("wglChoosePixelFormatEXT", false)); + #elif defined(NAZARA_PLATFORM_LINUX) + glXCreateContextAttribs = reinterpret_cast(LoadEntry("glXCreateContextAttribsARB", false)); + #endif + + // Récupération de la version d'OpenGL + // Ce code se base sur le fait que la carte graphique renverra un contexte de compatibilité avec la plus haute version supportée + // Ce qui semble vrai au moins chez ATI/AMD et NVidia, mais si quelqu'un à une meilleure idée ... + glGetString = reinterpret_cast(LoadEntry("glGetString")); + if (!glGetString) + { + NazaraError("Unable to load OpenGL: failed to load glGetString"); + Uninitialize(); + + return false; + } + + const GLubyte* version = glGetString(GL_VERSION); + if (!version) + { + NazaraError("Unable to retrieve OpenGL version"); + Uninitialize(); + + return false; + } + + unsigned int major = version[0] - '0'; + unsigned int minor = version[2] - '0'; + + if (major == 0 || major > 9) + { + NazaraError("Unable to retrieve OpenGL major version"); + return false; + } + + if (minor > 9) + { + NazaraWarning("Unable to retrieve OpenGL minor version (using 0)"); + minor = 0; + } + + openGLversion = major*100 + minor*10; + + parameters.debugMode = true; // Certaines extensions n'apparaissent qu'avec un contexte de debug (e.g. ARB_debug_output) + parameters.majorVersion = NzContextParameters::defaultMajorVersion = openGLversion/100; + parameters.minorVersion = NzContextParameters::defaultMinorVersion = (openGLversion%100)/10; + + // Destruction implicite du premier contexte + if (!loadContext.Create(parameters)) + { + NazaraError("Failed to create load context"); + Uninitialize(); + return false; } @@ -182,7 +254,6 @@ bool NzOpenGL::Initialize() glGetShaderInfoLog = reinterpret_cast(LoadEntry("glGetShaderInfoLog")); glGetShaderiv = reinterpret_cast(LoadEntry("glGetShaderiv")); glGetShaderSource = reinterpret_cast(LoadEntry("glGetShaderSource")); - glGetString = reinterpret_cast(LoadEntry("glGetString")); glGetTexImage = reinterpret_cast(LoadEntry("glGetTexImage")); glGetTexParameterfv = reinterpret_cast(LoadEntry("glGetTexParameterfv")); glGetTexParameteriv = reinterpret_cast(LoadEntry("glGetTexParameteriv")); @@ -223,50 +294,13 @@ bool NzOpenGL::Initialize() glMapBufferRange = reinterpret_cast(LoadEntry("glMapBufferRange", false)); #if defined(NAZARA_PLATFORM_WINDOWS) - wglCreateContextAttribs = reinterpret_cast(LoadEntry("wglCreateContextAttribsARB", false)); - wglChoosePixelFormat = reinterpret_cast(LoadEntry("wglChoosePixelFormatARB", false)); - if (!wglChoosePixelFormat) - wglChoosePixelFormat = reinterpret_cast(LoadEntry("wglChoosePixelFormatEXT", false)); - wglGetExtensionsStringARB = reinterpret_cast(LoadEntry("wglGetExtensionsStringARB", false)); wglGetExtensionsStringEXT = reinterpret_cast(LoadEntry("wglGetExtensionsStringEXT", false)); wglSwapInterval = reinterpret_cast(LoadEntry("wglSwapIntervalEXT", false)); #elif defined(NAZARA_PLATFORM_LINUX) - glXCreateContextAttribs = reinterpret_cast(LoadEntry("glXCreateContextAttribsARB", false)); glXSwapInterval = reinterpret_cast(LoadEntry("glXSwapIntervalSGI", false)); #endif - // Récupération de la version d'OpenGL - // Ce code se base sur le fait que la carte graphique renverra un contexte de compatibilité avec la plus haute version supportée - // Ce qui semble vrai au moins chez ATI/AMD et NVidia, mais si quelqu'un à une meilleure idée ... - const GLubyte* version = glGetString(GL_VERSION); - if (!version) - { - NazaraError("Unable to retrieve OpenGL version"); - Uninitialize(); - - return false; - } - - unsigned int major = version[0] - '0'; - unsigned int minor = version[2] - '0'; - - if (major == 0 || major > 9) - { - NazaraError("Unable to retrieve OpenGL major version"); - Uninitialize(); - - return false; - } - - if (minor > 9) - { - NazaraWarning("Unable to retrieve OpenGL minor version (using 0)"); - minor = 0; - } - - openGLversion = major*100 + minor*10; - /****************************************Extensions****************************************/ if (!glGetStringi || !LoadExtensions3()) @@ -296,6 +330,24 @@ bool NzOpenGL::Initialize() // AnisotropicFilter openGLextensions[NzOpenGL::AnisotropicFilter] = IsSupported("GL_EXT_texture_filter_anisotropic"); + // DebugOutput + if (IsSupported("GL_ARB_debug_output")) + { + try + { + glDebugMessageControl = reinterpret_cast(LoadEntry("glDebugMessageControlARB")); + glDebugMessageInsert = reinterpret_cast(LoadEntry("glDebugMessageInsertARB")); + glDebugMessageCallback = reinterpret_cast(LoadEntry("glDebugMessageCallbackARB")); + glGetDebugMessageLog = reinterpret_cast(LoadEntry("glGetDebugMessageLogARB")); + + openGLextensions[NzOpenGL::DebugOutput] = true; + } + catch (const std::exception& e) + { + NazaraError("Failed to load GL_ARB_debug_output: " + NzString(e.what())); + } + } + // FP64 if (openGLversion >= 400 || IsSupported("GL_ARB_gpu_shader_fp64")) { @@ -362,18 +414,51 @@ bool NzOpenGL::Initialize() } // Texture3D - if (IsSupported("GL_EXT_texture3D")) + try + { + glTexImage3D = reinterpret_cast(LoadEntry("glTexImage3D")); + glTexSubImage3D = reinterpret_cast(LoadEntry("glTexSubImage3D")); + + openGLextensions[NzOpenGL::Texture3D] = true; + } + catch (const std::exception& e) + { + if (openGLversion >= 120) + NazaraWarning("Failed to load core texture 3D (" + NzString(e.what()) + ")"); + + if (IsSupported("GL_EXT_texture3D")) + { + try + { + // Hacky: Normalement incompatible à cause du internalFormat, GLenum pour l'extension et GLint pour le noyau + // Mais la taille du type étant la même (GLenum est un typedef équivalent à GLint) et Nazara n'utilisant pas + // Ce qui cause l'incompatibilité (les paramètres 1,2,3,4), je prends cette liberté + glTexImage3D = reinterpret_cast(LoadEntry("glTexImage3DEXT")); + glTexSubImage3D = reinterpret_cast(LoadEntry("glTexSubImage3DEXT")); + + openGLextensions[NzOpenGL::Texture3D] = true; + } + catch (const std::exception& e) + { + NazaraError("Failed to load EXT_texture3D: " + NzString(e.what())); + } + } + } + + // VertexArrayObject + if (openGLversion >= 420 || IsSupported("GL_ARB_texture_storage")) { try { - glTexImage3D = reinterpret_cast(LoadEntry("glTexImage3DEXT")); - glTexSubImage3D = reinterpret_cast(LoadEntry("glTexSubImage3DEXT")); + glTexStorage1D = reinterpret_cast(LoadEntry("glTexStorage1D")); + glTexStorage2D = reinterpret_cast(LoadEntry("glTexStorage2D")); + glTexStorage3D = reinterpret_cast(LoadEntry("glTexStorage3D")); - openGLextensions[NzOpenGL::Texture3D] = true; + openGLextensions[NzOpenGL::TextureStorage] = true; } catch (const std::exception& e) { - NazaraError("Failed to load EXT_texture3D: " + NzString(e.what())); + NazaraError("Failed to load ARB_texture_storage: " + NzString(e.what())); } } @@ -382,9 +467,9 @@ bool NzOpenGL::Initialize() { try { - glBindVertexArray = reinterpret_cast(LoadEntry("glBindVertexArray", false)); - glDeleteVertexArrays = reinterpret_cast(LoadEntry("glDeleteVertexArrays", false)); - glGenVertexArrays = reinterpret_cast(LoadEntry("glGenVertexArrays", false)); + glBindVertexArray = reinterpret_cast(LoadEntry("glBindVertexArray")); + glDeleteVertexArrays = reinterpret_cast(LoadEntry("glDeleteVertexArrays")); + glGenVertexArrays = reinterpret_cast(LoadEntry("glGenVertexArrays")); openGLextensions[NzOpenGL::VertexArrayObject] = true; } @@ -394,11 +479,9 @@ bool NzOpenGL::Initialize() } } - /****************************************Contextes****************************************/ - - NzContextParameters::defaultMajorVersion = openGLversion/100; - NzContextParameters::defaultMinorVersion = (openGLversion%100)/10; + /****************************************Contexte de référence****************************************/ + ///FIXME: Utiliser le contexte de chargement comme référence ? (Vérifier mode debug) if (!NzContext::InitializeReference()) { NazaraError("Failed to initialize reference context"); @@ -457,6 +540,9 @@ PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = nullptr; PFNGLCOLORMASKPROC glColorMask = nullptr; PFNGLCULLFACEPROC glCullFace = nullptr; PFNGLCOMPILESHADERPROC glCompileShader = nullptr; +PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControl = nullptr; +PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsert = nullptr; +PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallback = nullptr; PFNGLDELETEBUFFERSPROC glDeleteBuffers = nullptr; PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = nullptr; PFNGLDELETEPROGRAMPROC glDeleteProgram = nullptr; @@ -487,6 +573,7 @@ PFNGLGENQUERIESPROC glGenQueries = nullptr; PFNGLGENTEXTURESPROC glGenTextures = nullptr; PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr; PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv = nullptr; +PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLog = nullptr; PFNGLGETERRORPROC glGetError = nullptr; PFNGLGETINTEGERVPROC glGetIntegerv = nullptr; PFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr; @@ -512,12 +599,17 @@ PFNGLSCISSORPROC glScissor = nullptr; PFNGLSHADERSOURCEPROC glShaderSource = nullptr; PFNGLSTENCILFUNCPROC glStencilFunc = nullptr; PFNGLSTENCILOPPROC glStencilOp = nullptr; +PFNGLTEXIMAGE1DPROC glTexImage1D = nullptr; PFNGLTEXIMAGE2DPROC glTexImage2D = nullptr; -PFNGLTEXIMAGE3DEXTPROC glTexImage3D = nullptr; +PFNGLTEXIMAGE3DPROC glTexImage3D = nullptr; PFNGLTEXPARAMETERFPROC glTexParameterf = nullptr; PFNGLTEXPARAMETERIPROC glTexParameteri = nullptr; +PFNGLTEXSTORAGE1DPROC glTexStorage1D = nullptr; +PFNGLTEXSTORAGE2DPROC glTexStorage2D = nullptr; +PFNGLTEXSTORAGE3DPROC glTexStorage3D = nullptr; +PFNGLTEXSUBIMAGE1DPROC glTexSubImage1D = nullptr; PFNGLTEXSUBIMAGE2DPROC glTexSubImage2D = nullptr; -PFNGLTEXSUBIMAGE3DEXTPROC glTexSubImage3D = nullptr; +PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D = nullptr; PFNGLUNIFORM1DPROC glUniform1d = nullptr; PFNGLUNIFORM1FPROC glUniform1f = nullptr; PFNGLUNIFORM1IPROC glUniform1i = nullptr; diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 7de849aff..f545ad7cb 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -460,17 +460,20 @@ bool NzRenderer::UpdateStates() if (vaoSupported) { // On recherche si un VAO existe déjà avec notre configuration - // Note: Les VAOs ne sont pas partagés entre les contextes, ils font donc partie de notre configuration + // Note: Les VAOs ne sont pas partagés entre les contextes, ces derniers font donc partie de notre configuration auto key = std::make_tuple(NzContext::GetCurrent(), m_indexBuffer, m_vertexBuffer, m_vertexDeclaration); auto it = m_vaos.find(key); if (it == m_vaos.end()) { + // On créé notre VAO glGenVertexArrays(1, &vao); glBindVertexArray(vao); + // On l'ajoute à notre liste m_vaos.insert(std::make_pair(key, static_cast(vao))); + // Et on indique qu'on veut le programmer update = true; } else diff --git a/src/Nazara/Renderer/Win32/ContextImpl.cpp b/src/Nazara/Renderer/Win32/ContextImpl.cpp index c9abbac2c..61fdb8388 100644 --- a/src/Nazara/Renderer/Win32/ContextImpl.cpp +++ b/src/Nazara/Renderer/Win32/ContextImpl.cpp @@ -153,6 +153,8 @@ bool NzContextImpl::Create(NzContextParameters& parameters) *attrib++ = WGL_CONTEXT_MINOR_VERSION_ARB; *attrib++ = parameters.minorVersion; + int flags = 0; + if (parameters.majorVersion >= 3) { *attrib++ = WGL_CONTEXT_PROFILE_MASK_ARB; @@ -162,11 +164,19 @@ bool NzContextImpl::Create(NzContextParameters& parameters) { *attrib++ = WGL_CONTEXT_CORE_PROFILE_BIT_ARB; - *attrib++ = WGL_CONTEXT_FLAGS_ARB; - *attrib++ = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; + flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB; } } + if (parameters.debugMode) + flags |= WGL_CONTEXT_DEBUG_BIT_ARB; + + if (flags) + { + *attrib++ = WGL_CONTEXT_FLAGS_ARB; + *attrib++ = flags; + } + *attrib++ = 0; m_context = wglCreateContextAttribs(m_deviceContext, shareContext, attributes); From 49353cb636190e986a0c622db56eb1a649b4d32c Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 31 May 2012 23:42:39 +0200 Subject: [PATCH 10/15] Fixed crash with NzContext::Destroy Fixed crash when calling NzContext::Destroy two times without recreating a new context --- src/Nazara/Renderer/Context.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Nazara/Renderer/Context.cpp b/src/Nazara/Renderer/Context.cpp index 3bb0b2a0c..880aa3580 100644 --- a/src/Nazara/Renderer/Context.cpp +++ b/src/Nazara/Renderer/Context.cpp @@ -191,6 +191,7 @@ void NzContext::Destroy() m_impl->Destroy(); delete m_impl; + m_impl = nullptr; } } From a17664826510d7824dd9e7f791a75053c28add0c Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 5 Jun 2012 10:54:06 +0200 Subject: [PATCH 11/15] Added NzTexture Added levelCount parameter to NzImageParams Added NzPixelFormat::HasAlpha Reformatted OpenGL debug messages --- include/Nazara/Renderer/OpenGL.hpp | 3 + include/Nazara/Renderer/Shader.hpp | 2 + include/Nazara/Renderer/Texture.hpp | 98 ++ include/Nazara/Utility/Image.hpp | 8 +- include/Nazara/Utility/PixelFormat.hpp | 4 +- include/Nazara/Utility/PixelFormat.inl | 18 + src/Nazara/Renderer/Context.cpp | 6 +- src/Nazara/Renderer/GLSLShader.cpp | 93 +- src/Nazara/Renderer/GLSLShader.hpp | 15 +- src/Nazara/Renderer/OcclusionQuery.cpp | 5 +- src/Nazara/Renderer/OpenGL.cpp | 7 + src/Nazara/Renderer/RenderWindow.cpp | 17 + src/Nazara/Renderer/Renderer.cpp | 16 +- src/Nazara/Renderer/Shader.cpp | 13 + src/Nazara/Renderer/ShaderImpl.hpp | 6 +- src/Nazara/Renderer/Texture.cpp | 1485 ++++++++++++++++++++++++ src/Nazara/Utility/Image.cpp | 71 +- src/Nazara/Utility/Loaders/PCX.cpp | 2 +- src/Nazara/Utility/Loaders/STB.cpp | 2 +- 19 files changed, 1807 insertions(+), 64 deletions(-) create mode 100644 include/Nazara/Renderer/Texture.hpp create mode 100644 src/Nazara/Renderer/Texture.cpp diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index 04623054d..cd4c1a4d2 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -38,6 +38,7 @@ class NAZARA_API NzOpenGL FP64, FrameBufferObject, Texture3D, + TextureCompression_s3tc, TextureStorage, VertexArrayObject, @@ -120,6 +121,8 @@ NAZARA_API extern PFNGLGETSHADERSOURCEPROC glGetShaderSource; NAZARA_API extern PFNGLGETSTRINGPROC glGetString; NAZARA_API extern PFNGLGETSTRINGIPROC glGetStringi; NAZARA_API extern PFNGLGETTEXIMAGEPROC glGetTexImage; +NAZARA_API extern PFNGLGETTEXLEVELPARAMETERFVPROC glGetTexLevelParameterfv; +NAZARA_API extern PFNGLGETTEXLEVELPARAMETERIVPROC glGetTexLevelParameteriv; NAZARA_API extern PFNGLGETTEXPARAMETERFVPROC glGetTexParameterfv; NAZARA_API extern PFNGLGETTEXPARAMETERIVPROC glGetTexParameteriv; NAZARA_API extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; diff --git a/include/Nazara/Renderer/Shader.hpp b/include/Nazara/Renderer/Shader.hpp index f143d213a..79d0402de 100644 --- a/include/Nazara/Renderer/Shader.hpp +++ b/include/Nazara/Renderer/Shader.hpp @@ -32,6 +32,7 @@ enum nzShaderType class NzRenderer; class NzShaderImpl; +class NzTexture; class NAZARA_API NzShader : public NzResource, NzNonCopyable { @@ -65,6 +66,7 @@ class NAZARA_API NzShader : public NzResource, NzNonCopyable bool SendInteger(const NzString& name, int value); bool SendMatrix(const NzString& name, const NzMatrix4d& matrix); bool SendMatrix(const NzString& name, const NzMatrix4f& matrix); + bool SendTexture(const NzString& name, NzTexture* texture); void Unlock(); diff --git a/include/Nazara/Renderer/Texture.hpp b/include/Nazara/Renderer/Texture.hpp new file mode 100644 index 000000000..f038a86e9 --- /dev/null +++ b/include/Nazara/Renderer/Texture.hpp @@ -0,0 +1,98 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_TEXTURE_HPP +#define NAZARA_TEXTURE_HPP + +#include +#include +#include +#include + +enum nzTextureFilter +{ + nzTextureFilter_Bilinear, + nzTextureFilter_Nearest, + nzTextureFilter_Trilinear, + nzTextureFilter_Unknown +}; + +enum nzTextureWrap +{ + nzTextureWrap_Clamp, + nzTextureWrap_Repeat, + nzTextureWrap_Unknown +}; + +class NzRenderWindow; ///TODO: Screenshot +struct NzTextureImpl; + +class NAZARA_API NzTexture : public NzResource, NzNonCopyable +{ + friend class NzShader; + + public: + NzTexture(); + explicit NzTexture(const NzImage& image); + ~NzTexture(); + + bool Bind(); + + bool Create(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth = 1, nzUInt8 levelCount = 1, bool lock = false); + void Destroy(); + + bool Download(NzImage* image) const; + + bool EnableMipmapping(bool enable); + + unsigned int GetAnisotropyLevel() const; + nzUInt8 GetBPP() const; + unsigned int GetDepth() const; + nzTextureFilter GetFilterMode() const; + nzPixelFormat GetFormat() const; + unsigned int GetHeight() const; + nzImageType GetType() const; + unsigned int GetWidth() const; + nzTextureWrap GetWrapMode() const; + + bool IsCompressed() const; + bool IsCubemap() const; + bool IsValid() const; + + bool LoadFromFile(const NzString& filePath, const NzImageParams& params = NzImageParams()); + bool LoadFromImage(const NzImage& image); + bool LoadFromMemory(const void* data, std::size_t size, const NzImageParams& params = NzImageParams()); + bool LoadFromStream(NzInputStream& stream, const NzImageParams& params = NzImageParams()); + + bool Lock(); + + bool SetAnisotropyLevel(unsigned int anistropyLevel); + bool SetFilterMode(nzTextureFilter filter); + bool SetMipmapRange(nzUInt8 minLevel, nzUInt8 maxLevel); + bool SetWrapMode(nzTextureWrap wrap); + + bool Update(const NzImage& image, nzUInt8 level = 0); + bool Update(const NzImage& image, const NzRectui& rect, unsigned int z = 0, nzUInt8 level = 0); + //bool Update(const NzImage& image, const NzCubeui& cube, nzUInt8 level = 0); + bool Update(const nzUInt8* pixels, nzUInt8 level = 0); + bool Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z = 0, nzUInt8 level = 0); + //bool Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level = 0); + bool UpdateFace(nzCubemapFace face, const NzImage& image, nzUInt8 level = 0); + bool UpdateFace(nzCubemapFace face, const NzImage& image, const NzRectui& rect, nzUInt8 level = 0); + bool UpdateFace(nzCubemapFace face, const nzUInt8* pixels, nzUInt8 level = 0); + bool UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRectui& rect, nzUInt8 level = 0); + + void Unlock(); + + static unsigned int GetValidSize(unsigned int size); + static bool IsFormatSupported(nzPixelFormat format); + static bool IsTypeSupported(nzImageType type); + + private: + NzTextureImpl* m_impl; +}; + +#endif // NAZARA_TEXTURE_HPP diff --git a/include/Nazara/Utility/Image.hpp b/include/Nazara/Utility/Image.hpp index 272c1c7b6..359cce0a9 100644 --- a/include/Nazara/Utility/Image.hpp +++ b/include/Nazara/Utility/Image.hpp @@ -31,18 +31,22 @@ enum nzImageType nzImageType_1D, nzImageType_2D, nzImageType_3D, - nzImageType_Cubemap + nzImageType_Cubemap, + + nzImageType_Count }; struct NzImageParams { // GCC 4.7 je te veux NzImageParams() : - loadFormat(nzPixelFormat_Undefined) + loadFormat(nzPixelFormat_Undefined), + levelCount(0) { } nzPixelFormat loadFormat; + nzUInt8 levelCount; bool IsValid() const { diff --git a/include/Nazara/Utility/PixelFormat.hpp b/include/Nazara/Utility/PixelFormat.hpp index dc8b95263..4a9d45eef 100644 --- a/include/Nazara/Utility/PixelFormat.hpp +++ b/include/Nazara/Utility/PixelFormat.hpp @@ -53,6 +53,8 @@ class NzPixelFormat static nzUInt8 GetBPP(nzPixelFormat format); + static bool HasAlpha(nzPixelFormat format); + static bool IsCompressed(nzPixelFormat format); static bool IsConversionSupported(nzPixelFormat srcFormat, nzPixelFormat dstFormat); static bool IsValid(nzPixelFormat format); @@ -65,7 +67,7 @@ class NzPixelFormat static bool Initialize(); static void Uninitialize(); - static ConvertFunction s_convertFunctions[nzPixelFormat_Count][nzPixelFormat_Count]; + static NAZARA_API ConvertFunction s_convertFunctions[nzPixelFormat_Count][nzPixelFormat_Count]; }; #include diff --git a/include/Nazara/Utility/PixelFormat.inl b/include/Nazara/Utility/PixelFormat.inl index b4bcf99e7..4779b6a6b 100644 --- a/include/Nazara/Utility/PixelFormat.inl +++ b/include/Nazara/Utility/PixelFormat.inl @@ -139,6 +139,24 @@ inline nzUInt8 NzPixelFormat::GetBPP(nzPixelFormat format) return 0; } +inline bool NzPixelFormat::HasAlpha(nzPixelFormat format) +{ + switch (format) + { + case nzPixelFormat_BGRA8: + case nzPixelFormat_DXT3: + case nzPixelFormat_DXT5: + case nzPixelFormat_LA8: + case nzPixelFormat_RGB5A1: + case nzPixelFormat_RGBA4: + case nzPixelFormat_RGBA8: + return true; + + default: + return false; + } +} + inline bool NzPixelFormat::IsCompressed(nzPixelFormat format) { switch (format) diff --git a/src/Nazara/Renderer/Context.cpp b/src/Nazara/Renderer/Context.cpp index 880aa3580..dfd885ee3 100644 --- a/src/Nazara/Renderer/Context.cpp +++ b/src/Nazara/Renderer/Context.cpp @@ -31,7 +31,8 @@ namespace NzStringStream ss; ss << "OpenGL debug message (ID: 0x" << NzString::Number(id, 16) << "):\n"; - ss << "-Source: "; + ss << "Sent by context: " << userParam; + ss << "\n-Source: "; switch (source) { case GL_DEBUG_SOURCE_API_ARB: @@ -121,8 +122,7 @@ namespace } ss << '\n'; - ss << "Message: " << message; - ss << "\n\nSent by context: " << userParam; + ss << "Message: " << message << '\n'; NazaraNotice(ss); } diff --git a/src/Nazara/Renderer/GLSLShader.cpp b/src/Nazara/Renderer/GLSLShader.cpp index af9403f89..4ddc12fad 100644 --- a/src/Nazara/Renderer/GLSLShader.cpp +++ b/src/Nazara/Renderer/GLSLShader.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include @@ -26,6 +28,9 @@ namespace GL_GEOMETRY_SHADER, // nzShaderType_Geometry GL_VERTEX_SHADER // nzShaderType_Vertex }; + + GLuint lockedPrevious = 0; + nzUInt8 lockedLevel = 0; } NzGLSLShader::NzGLSLShader(NzShader* parent) : @@ -39,9 +44,24 @@ NzGLSLShader::~NzGLSLShader() bool NzGLSLShader::Bind() { + #if NAZARA_RENDERER_SAFE + if (lockedLevel > 0) + { + NazaraError("Cannot bind shader while a shader is locked"); + return false; + } + #endif + glUseProgram(m_program); - return true; ///FIXME: Comment détecter une erreur d'OpenGL sans ralentir le programme ? + for (auto it = m_textures.begin(); it != m_textures.end(); ++it) + { + glActiveTexture(GL_TEXTURE0 + it->second.unit); + if (!it->second.texture->Bind()) + NazaraWarning("Failed to bind texture"); + } + + return true; } bool NzGLSLShader::Compile() @@ -106,6 +126,8 @@ bool NzGLSLShader::Create() for (int i = 0; i < nzShaderType_Count; ++i) m_shaders[i] = 0; + m_textureFreeID = 0; + return true; } @@ -218,16 +240,16 @@ bool NzGLSLShader::Load(nzShaderType type, const NzString& source) } } -bool NzGLSLShader::Lock() const +bool NzGLSLShader::Lock() { - if (m_lockedLevel++ == 0) + if (lockedLevel++ == 0) { GLint previous; glGetIntegerv(GL_CURRENT_PROGRAM, &previous); - m_lockedPrevious = previous; + lockedPrevious = previous; - if (m_lockedPrevious != m_program) + if (lockedPrevious != m_program) glUseProgram(m_program); } @@ -288,19 +310,72 @@ bool NzGLSLShader::SendMatrix(const NzString& name, const NzMatrix4f& matrix) return true; } +bool NzGLSLShader::SendTexture(const NzString& name, NzTexture* texture) +{ + static const unsigned int maxUnits = NazaraRenderer->GetMaxTextureUnits(); + + unsigned int unitUsed = m_textures.size(); + if (unitUsed >= maxUnits) + { + NazaraError("Unable to use texture \"" + name + "\" for shader: all available texture units are used"); + return false; + } + + // À partir d'ici nous savons qu'il y a au moins un identifiant de texture libre + GLint location = GetUniformLocation(name); + if (location == -1) + { + NazaraError("Parameter name \"" + name + "\" not found in shader"); + return false; + } + + nzUInt8 unit; + if (unitUsed == 0) + // Pas d'unité utilisée, la tâche est simple + unit = 0; + else + { + auto it = m_textures.rbegin(); // Itérateur vers la fin de la map + unit = it->second.unit; + if (unit == maxUnits-1) + { + // Il y a une place libre, mais pas à la fin + for (; it != m_textures.rend(); ++it) + { + if (unit - it->second.unit > 1) // Si l'espace entre les indices est supérieur à 1, alors il y a une place libre + { + unit--; + break; + } + } + } + else + // Il y a une place libre à la fin + unit++; + } + + m_textures[location] = TextureSlot{unit, texture}; + + Lock(); + glUniform1i(location, unit); + Unlock(); + + return true; +} + void NzGLSLShader::Unbind() { glUseProgram(0); } -void NzGLSLShader::Unlock() const +void NzGLSLShader::Unlock() { - if (m_lockedLevel == 0) + if (lockedLevel == 0) { NazaraWarning("Unlock called on non-locked texture"); return; } - if (--m_lockedLevel == 0 && m_lockedPrevious != m_program) - glUseProgram(m_lockedPrevious); + if (--lockedLevel == 0 && lockedPrevious != m_program) + glUseProgram(lockedPrevious); } diff --git a/src/Nazara/Renderer/GLSLShader.hpp b/src/Nazara/Renderer/GLSLShader.hpp index 653955999..2d0287652 100644 --- a/src/Nazara/Renderer/GLSLShader.hpp +++ b/src/Nazara/Renderer/GLSLShader.hpp @@ -34,7 +34,7 @@ class NzGLSLShader : public NzShaderImpl bool IsLoaded(nzShaderType type) const; bool Load(nzShaderType type, const NzString& source); - bool Lock() const; + bool Lock(); bool SendBoolean(const NzString& name, bool value); bool SendDouble(const NzString& name, double value); @@ -42,16 +42,23 @@ class NzGLSLShader : public NzShaderImpl bool SendInteger(const NzString& name, int value); bool SendMatrix(const NzString& name, const NzMatrix4d& matrix); bool SendMatrix(const NzString& name, const NzMatrix4f& matrix); + bool SendTexture(const NzString& name, NzTexture* texture); void Unbind(); - void Unlock() const; + void Unlock(); private: + struct TextureSlot + { + nzUInt8 unit; + NzTexture* texture; + }; + mutable std::map m_idCache; - mutable GLuint m_lockedPrevious; + std::map m_textures; GLuint m_program; GLuint m_shaders[nzShaderType_Count]; - mutable nzUInt8 m_lockedLevel; + nzUInt8 m_textureFreeID; NzShader* m_parent; NzString m_log; }; diff --git a/src/Nazara/Renderer/OcclusionQuery.cpp b/src/Nazara/Renderer/OcclusionQuery.cpp index f87bca264..5ce46f719 100644 --- a/src/Nazara/Renderer/OcclusionQuery.cpp +++ b/src/Nazara/Renderer/OcclusionQuery.cpp @@ -37,7 +37,10 @@ m_id(0) NzOcclusionQuery::~NzOcclusionQuery() { if (m_id) - glDeleteQueries(1, reinterpret_cast(&m_id)); + { + GLuint query = static_cast(m_id); + glDeleteQueries(1, &query); + } } void NzOcclusionQuery::Begin() diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index 86ea4ae1f..610e8c891 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -255,6 +255,8 @@ bool NzOpenGL::Initialize() glGetShaderiv = reinterpret_cast(LoadEntry("glGetShaderiv")); glGetShaderSource = reinterpret_cast(LoadEntry("glGetShaderSource")); glGetTexImage = reinterpret_cast(LoadEntry("glGetTexImage")); + glGetTexLevelParameterfv = reinterpret_cast(LoadEntry("glGetTexLevelParameterfv")); + glGetTexLevelParameteriv = reinterpret_cast(LoadEntry("glGetTexLevelParameteriv")); glGetTexParameterfv = reinterpret_cast(LoadEntry("glGetTexParameterfv")); glGetTexParameteriv = reinterpret_cast(LoadEntry("glGetTexParameteriv")); glGetUniformLocation = reinterpret_cast(LoadEntry("glGetUniformLocation")); @@ -445,6 +447,9 @@ bool NzOpenGL::Initialize() } } + // TextureCompression_s3tc + openGLextensions[NzOpenGL::TextureCompression_s3tc] = IsSupported("GL_EXT_texture_compression_s3tc"); + // VertexArrayObject if (openGLversion >= 420 || IsSupported("GL_ARB_texture_storage")) { @@ -587,6 +592,8 @@ PFNGLGETSHADERSOURCEPROC glGetShaderSource = nullptr; PFNGLGETSTRINGPROC glGetString = nullptr; PFNGLGETSTRINGIPROC glGetStringi = nullptr; PFNGLGETTEXIMAGEPROC glGetTexImage = nullptr; +PFNGLGETTEXLEVELPARAMETERFVPROC glGetTexLevelParameterfv = nullptr; +PFNGLGETTEXLEVELPARAMETERIVPROC glGetTexLevelParameteriv = nullptr; PFNGLGETTEXPARAMETERFVPROC glGetTexParameterfv = nullptr; PFNGLGETTEXPARAMETERIVPROC glGetTexParameteriv = nullptr; PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr; diff --git a/src/Nazara/Renderer/RenderWindow.cpp b/src/Nazara/Renderer/RenderWindow.cpp index 38be6c833..6ce72547d 100644 --- a/src/Nazara/Renderer/RenderWindow.cpp +++ b/src/Nazara/Renderer/RenderWindow.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace @@ -25,12 +26,28 @@ NzRenderWindow::NzRenderWindow(NzVideoMode mode, const NzString& title, nzUInt32 m_context(nullptr) { Create(mode, title, style, parameters); + + #ifdef NAZARA_DEBUG + if (!m_impl) + { + NazaraError("Failed to create render window"); + throw std::runtime_error("Constructor failed"); + } + #endif } NzRenderWindow::NzRenderWindow(NzWindowHandle handle, const NzContextParameters& parameters) : m_context(nullptr) { Create(handle, parameters); + + #ifdef NAZARA_DEBUG + if (!m_impl) + { + NazaraError("Failed to create render window"); + throw std::runtime_error("Constructor failed"); + } + #endif } NzRenderWindow::~NzRenderWindow() diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index f545ad7cb..05627ef61 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -30,7 +30,8 @@ namespace 4 // nzElementUsage_TexCoord }; - const GLenum openglPrimitive[] = { + const GLenum openglPrimitive[] = + { GL_LINES, // nzPrimitiveType_LineList, GL_LINE_STRIP, // nzPrimitiveType_LineStrip, GL_POINTS, // nzPrimitiveType_PointList, @@ -310,6 +311,12 @@ bool NzRenderer::SetShader(NzShader* shader) if (shader == m_shader) return true; + if (m_shader) + { + m_shader->m_impl->Unbind(); + m_shader = nullptr; + } + if (shader) { #if NAZARA_RENDERER_SAFE @@ -328,11 +335,6 @@ bool NzRenderer::SetShader(NzShader* shader) m_shader = shader; } - else if (m_shader) - { - m_shader->m_impl->Unbind(); - m_shader = nullptr; - } return true; } @@ -408,7 +410,7 @@ void NzRenderer::Uninitialize() // Libération des VAOs for (auto it = m_vaos.begin(); it != m_vaos.end(); ++it) { - GLuint vao = it->second; + GLuint vao = static_cast(it->second); glDeleteVertexArrays(1, &vao); } diff --git a/src/Nazara/Renderer/Shader.cpp b/src/Nazara/Renderer/Shader.cpp index 0afb45782..6d642626b 100644 --- a/src/Nazara/Renderer/Shader.cpp +++ b/src/Nazara/Renderer/Shader.cpp @@ -371,6 +371,19 @@ bool NzShader::SendMatrix(const NzString& name, const NzMatrix4f& matrix) return m_impl->SendMatrix(name, matrix); } +bool NzShader::SendTexture(const NzString& name, NzTexture* texture) +{ + #if NAZARA_RENDERER_SAFE + if (!m_impl) + { + NazaraError("Shader not created"); + return false; + } + #endif + + return m_impl->SendTexture(name, texture); +} + void NzShader::Unlock() { #if NAZARA_RENDERER_SAFE diff --git a/src/Nazara/Renderer/ShaderImpl.hpp b/src/Nazara/Renderer/ShaderImpl.hpp index b5b1316ec..330b9dccf 100644 --- a/src/Nazara/Renderer/ShaderImpl.hpp +++ b/src/Nazara/Renderer/ShaderImpl.hpp @@ -10,6 +10,7 @@ #include class NzRenderer; +class NzTexture; class NzVertexBuffer; class NzVertexDeclaration; @@ -36,7 +37,7 @@ class NzShaderImpl virtual bool Load(nzShaderType type, const NzString& source) = 0; - virtual bool Lock() const = 0; + virtual bool Lock() = 0; virtual bool SendBoolean(const NzString& name, bool value) = 0; virtual bool SendDouble(const NzString& name, double value) = 0; @@ -44,9 +45,10 @@ class NzShaderImpl virtual bool SendInteger(const NzString& name, int value) = 0; virtual bool SendMatrix(const NzString& name, const NzMatrix4d& matrix) = 0; virtual bool SendMatrix(const NzString& name, const NzMatrix4f& matrix) = 0; + virtual bool SendTexture(const NzString& name, NzTexture* texture) = 0; virtual void Unbind() = 0; - virtual void Unlock() const = 0; + virtual void Unlock() = 0; }; #endif // NAZARA_SHADERIMPL_HPP diff --git a/src/Nazara/Renderer/Texture.cpp b/src/Nazara/Renderer/Texture.cpp new file mode 100644 index 000000000..36dad7d8f --- /dev/null +++ b/src/Nazara/Renderer/Texture.cpp @@ -0,0 +1,1485 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include + +struct NzTextureImpl +{ + // GCC 4.7 !!!!!! + NzTextureImpl() : + mipmapping(false), + mipmapsUpdated(false) + { + } + + GLuint id; + nzImageType type; + nzPixelFormat format; + nzUInt8 levelCount; + bool mipmapping; + bool mipmapsUpdated; + unsigned int depth; + unsigned int height; + unsigned int width; +}; + +namespace +{ + GLenum cubemapFace[] = + { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, // nzCubemapFace_PositiveX + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, // nzCubemapFace_NegativeX + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, // nzCubemapFace_PositiveY + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, // nzCubemapFace_NegativeY + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, // nzCubemapFace_PositiveZ + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z // nzCubemapFace_NegativeZ + }; + + GLenum openglTarget[] = + { + GL_TEXTURE_1D, // nzImageType_1D + GL_TEXTURE_2D, // nzImageType_2D + GL_TEXTURE_3D, // nzImageType_3D + GL_TEXTURE_CUBE_MAP // nzImageType_Cubemap + }; + + GLenum openglTargetBinding[] = + { + GL_TEXTURE_BINDING_1D, // nzImageType_1D + GL_TEXTURE_BINDING_2D, // nzImageType_2D + GL_TEXTURE_BINDING_3D, // nzImageType_3D + GL_TEXTURE_BINDING_CUBE_MAP // nzImageType_Cubemap + }; + + struct OpenGLFormat + { + GLint internalFormat; + GLenum dataFormat; + GLenum dataType; + }; + + bool GetOpenGLFormat(nzPixelFormat pixelFormat, OpenGLFormat* format) + { + switch (pixelFormat) + { + case nzPixelFormat_BGR8: + format->dataFormat = GL_BGR; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_RGB8; + break; + + case nzPixelFormat_BGRA8: + format->dataFormat = GL_BGRA; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_RGBA8; + break; + + case nzPixelFormat_DXT1: + format->dataFormat = GL_RGB; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + break; + + case nzPixelFormat_DXT3: + format->dataFormat = GL_RGBA; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + + case nzPixelFormat_DXT5: + format->dataFormat = GL_RGBA; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + + case nzPixelFormat_L8: + case nzPixelFormat_LA8: + NazaraError("Pixel format not supported"); + return false; + + case nzPixelFormat_RGB5A1: + format->dataFormat = GL_RGBA; + format->dataType = GL_UNSIGNED_SHORT_5_5_5_1; + format->internalFormat = GL_RGB5_A1; + break; + + case nzPixelFormat_RGB8: + format->dataFormat = GL_RGB; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_RGB8; + break; + + case nzPixelFormat_RGBA4: + format->dataFormat = GL_RGBA; + format->dataType = GL_UNSIGNED_SHORT_4_4_4_4; + format->internalFormat = GL_RGBA4; + break; + + case nzPixelFormat_RGBA8: + format->dataFormat = GL_RGBA; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_RGBA8; + break; + + default: + NazaraError("Pixel format not handled"); + return false; + } + + return true; + } + + bool CreateTexture(NzTextureImpl* impl, bool proxy) + { + OpenGLFormat openGLFormat; + if (!GetOpenGLFormat(impl->format, &openGLFormat)) + { + NazaraError("Failed to get OpenGL format"); + return false; + } + + static const bool texStorageSupported = NzOpenGL::IsSupported(NzOpenGL::TextureStorage); + + GLenum target; + switch (impl->type) + { + case nzImageType_1D: + { + target = (proxy) ? GL_TEXTURE_1D : GL_PROXY_TEXTURE_1D; + + if (texStorageSupported) + glTexStorage1D(target, impl->levelCount, openGLFormat.internalFormat, impl->width); + else + { + unsigned int w = impl->width; + for (nzUInt8 level = 0; level < impl->levelCount; ++level) + { + glTexImage1D(target, level, openGLFormat.internalFormat, w, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); + w = std::max(w/2, 1U); + } + } + break; + } + + case nzImageType_2D: + { + target = (proxy) ? GL_TEXTURE_2D : GL_PROXY_TEXTURE_2D; + + if (texStorageSupported) + glTexStorage2D(target, impl->levelCount, openGLFormat.internalFormat, impl->width, impl->height); + else + { + unsigned int w = impl->width; + unsigned int h = impl->height; + for (nzUInt8 level = 0; level < impl->levelCount; ++level) + { + glTexImage2D(target, level, openGLFormat.internalFormat, w, h, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); + w = std::max(w/2, 1U); + h = std::max(h/2, 1U); + } + } + break; + } + + case nzImageType_3D: + { + target = (proxy) ? GL_TEXTURE_3D : GL_PROXY_TEXTURE_3D; + + if (texStorageSupported) + glTexStorage3D(target, impl->levelCount, openGLFormat.internalFormat, impl->width, impl->height, impl->depth); + else + { + unsigned int w = impl->width; + unsigned int h = impl->height; + unsigned int d = impl->depth; + for (nzUInt8 level = 0; level < impl->levelCount; ++level) + { + glTexImage3D(target, level, openGLFormat.internalFormat, w, h, d, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); + w = std::max(w/2, 1U); + h = std::max(h/2, 1U); + d = std::max(d/2, 1U); + } + } + break; + } + + case nzImageType_Cubemap: + { + target = (proxy) ? GL_TEXTURE_CUBE_MAP : GL_PROXY_TEXTURE_CUBE_MAP; + + if (texStorageSupported) + glTexStorage2D(target, impl->levelCount, openGLFormat.internalFormat, impl->width, impl->height); + else + { + unsigned int size = impl->width; // Les cubemaps ont une longueur et largeur identique + for (nzUInt8 level = 0; level < impl->levelCount; ++level) + { + for (GLenum face : cubemapFace) + glTexImage2D(face, level, openGLFormat.internalFormat, size, size, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); + + size = std::max(size/2, 1U); + } + } + break; + } + + default: + NazaraInternalError("Image type not handled"); + return false; + } + + if (proxy) + { + GLint internalFormat; + glGetTexLevelParameteriv(target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat); + if (internalFormat == 0) + return false; + } + + return true; + } + + static unsigned short lockedLevel[nzImageType_Count] = {0}; + static GLuint lockedPrevious[nzImageType_Count] = {0}; + + void LockTexture(NzTextureImpl* impl) + { + if (lockedLevel[impl->type]++ == 0) + { + GLint previous; + glGetIntegerv(openglTargetBinding[impl->type], &previous); + + lockedPrevious[impl->type] = static_cast(previous); + + if (lockedPrevious[impl->type] != impl->id) + glBindTexture(openglTarget[impl->type], impl->id); + } + } + + void UnlockTexture(NzTextureImpl* impl) + { + #if NAZARA_RENDERER_SAFE + if (lockedLevel[impl->type] == 0) + { + NazaraError("Unlock called on non-locked texture"); + return; + } + #endif + + if (--lockedLevel[impl->type] == 0 && lockedPrevious[impl->type] != impl->id) + glBindTexture(openglTarget[impl->type], lockedPrevious[impl->type]); + } +} + +NzTexture::NzTexture() : +m_impl(nullptr) +{ +} + +NzTexture::NzTexture(const NzImage& image) : +m_impl(nullptr) +{ + LoadFromImage(image); + + #ifdef NAZARA_DEBUG + if (!m_impl) + { + NazaraError("Failed to create texture"); + throw std::runtime_error("Constructor failed"); + } + #endif +} + +NzTexture::~NzTexture() +{ + Destroy(); +} + +bool NzTexture::Bind() +{ + #if NAZARA_RENDERER_SAFE + if (lockedLevel[m_impl->type] > 0) + { + NazaraError("Cannot bind texture while a texture is locked"); + return false; + } + #endif + + glBindTexture(openglTarget[m_impl->type], m_impl->id); + + return true; +} + +bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth, nzUInt8 levelCount, bool lock) +{ + Destroy(); + + if (width == 0 || height == 0 || depth == 0) + return true; + + #if NAZARA_RENDERER_SAFE + if (!IsTypeSupported(type)) + { + NazaraError("Texture's type not supported"); + return false; + } + + if (!NzPixelFormat::IsValid(format)) + { + NazaraError("Invalid pixel format"); + return false; + } + + if (!IsFormatSupported(format)) + { + NazaraError("Texture's format not supported"); + return false; + } + + switch (type) + { + case nzImageType_1D: + if (height > 1) + { + NazaraError("1D textures must be 1 height"); + return false; + } + + if (depth > 1) + { + NazaraError("1D textures must be 1 depth"); + return false; + } + break; + + case nzImageType_2D: + if (depth > 1) + { + NazaraError("2D textures must be 1 depth"); + return false; + } + break; + + case nzImageType_3D: + break; + + case nzImageType_Cubemap: + if (depth > 1) + { + NazaraError("Cubemaps must be 1 depth"); + return false; + } + + if (width != height) + { + NazaraError("Cubemaps must have square dimensions"); + return false; + } + break; + + default: + NazaraInternalError("Image type not handled"); + return false; + } + #endif + + levelCount = std::min(levelCount, NzImage::GetMaxLevel(width, height, depth)); + + NzTextureImpl* impl = new NzTextureImpl; + glGenTextures(1, &impl->id); + + impl->depth = GetValidSize(depth); + impl->format = format; + impl->height = GetValidSize(height); + impl->levelCount = levelCount; + impl->type = type; + impl->width = GetValidSize(width); + + LockTexture(impl); + + // Vérification du support par la carte graphique + if (!CreateTexture(impl, true)) + { + NazaraError("Texture's parameters not supported by driver"); + UnlockTexture(impl); + glDeleteTextures(1, &impl->id); + delete impl; + + return false; + } + + // Création de la texture + if (!CreateTexture(impl, false)) + { + NazaraError("Failed to create texture"); + UnlockTexture(impl); + glDeleteTextures(1, &impl->id); + delete impl; + + return false; + } + + m_impl = impl; + + // Paramètres par défaut + SetFilterMode(nzTextureFilter_Nearest); + SetMipmapRange(0, m_impl->levelCount); + SetWrapMode(nzTextureWrap_Repeat); + + if (!lock) + UnlockTexture(impl); + + return true; +} + +void NzTexture::Destroy() +{ + if (m_impl) + { + glDeleteTextures(1, &m_impl->id); + delete m_impl; + m_impl = nullptr; + } +} + +bool NzTexture::Download(NzImage* image) const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + + if (!image) + { + NazaraError("Cannot download to a null image"); + return false; + } + #endif + + OpenGLFormat format; + if (!GetOpenGLFormat(m_impl->format, &format)) + { + NazaraError("Failed to get OpenGL format"); + return false; + } + + if (!image->Create(m_impl->type, m_impl->format, m_impl->width, m_impl->height, m_impl->depth, m_impl->levelCount)) + { + NazaraError("Failed to create image"); + return false; + } + + LockTexture(m_impl); + + // Téléchargement... + for (nzUInt8 level = 0; level < m_impl->levelCount; ++level) + glGetTexImage(openglTarget[m_impl->type], level, format.dataFormat, format.dataType, image->GetPixels(level)); + + UnlockTexture(m_impl); + + return true; +} + +bool NzTexture::EnableMipmapping(bool enable) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + #endif + + if (!glGenerateMipmap) + { + NazaraError("Mipmapping not supported"); + return false; + } + + LockTexture(m_impl); + + if (!m_impl->mipmapping && enable) + glGenerateMipmap(openglTarget[m_impl->type]); + + m_impl->mipmapping = enable; + + UnlockTexture(m_impl); + + return true; +} + +unsigned int NzTexture::GetAnisotropyLevel() const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return 1; + } + + if (!NzOpenGL::IsSupported(NzOpenGL::AnisotropicFilter)) + { + NazaraError("Anisotropic filter not supported"); + return 1; + } + #endif + + LockTexture(m_impl); + + GLfloat anisotropyLevel; + glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropyLevel); + + UnlockTexture(m_impl); + + return static_cast(anisotropyLevel); +} + +nzUInt8 NzTexture::GetBPP() const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return 0; + } + #endif + + return NzPixelFormat::GetBPP(m_impl->format); +} + +unsigned int NzTexture::GetDepth() const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return 0; + } + #endif + + return m_impl->depth; +} + +nzTextureFilter NzTexture::GetFilterMode() const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return nzTextureFilter_Unknown; + } + #endif + + LockTexture(m_impl); + + GLint value; + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &value); + + UnlockTexture(m_impl); + + GLenum filterMode = static_cast(value); + switch (filterMode) + { + case GL_LINEAR: + case GL_LINEAR_MIPMAP_NEAREST: + return nzTextureFilter_Bilinear; + + case GL_NEAREST: + case GL_NEAREST_MIPMAP_NEAREST: + return nzTextureFilter_Nearest; + + case GL_LINEAR_MIPMAP_LINEAR: + return nzTextureFilter_Trilinear; + + default: + NazaraInternalError("OpenGL filter mode not handled (0x" + NzString::Number(filterMode, 16) + ')'); + return nzTextureFilter_Unknown; + } +} + +nzPixelFormat NzTexture::GetFormat() const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return nzPixelFormat_Undefined; + } + #endif + + return m_impl->format; +} + +unsigned int NzTexture::GetHeight() const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return 0; + } + #endif + + return m_impl->height; +} + +nzImageType NzTexture::GetType() const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return nzImageType_2D; + } + #endif + + return m_impl->type; +} + +unsigned int NzTexture::GetWidth() const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return 0; + } + #endif + + return m_impl->width; +} + +nzTextureWrap NzTexture::GetWrapMode() const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return nzTextureWrap_Unknown; + } + #endif + + LockTexture(m_impl); + + GLint value; + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &value); + + UnlockTexture(m_impl); + + GLenum wrapMode = static_cast(value); + switch (wrapMode) + { + case GL_CLAMP_TO_EDGE: + return nzTextureWrap_Clamp; + + case GL_REPEAT: + return nzTextureWrap_Repeat; + + default: + NazaraInternalError("OpenGL wrap mode not handled (0x" + NzString::Number(wrapMode, 16) + ')'); + return nzTextureWrap_Unknown; + } +} + +bool NzTexture::IsCompressed() const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + #endif + + return NzPixelFormat::IsCompressed(m_impl->format); +} + +bool NzTexture::IsCubemap() const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + #endif + + return m_impl->type == nzImageType_Cubemap; +} + +bool NzTexture::IsValid() const +{ + return m_impl != nullptr; +} + +bool NzTexture::LoadFromFile(const NzString& filePath, const NzImageParams& params) +{ + NzImage image; + if (!image.LoadFromFile(filePath, params)) + { + NazaraError("Failed to load image"); + return false; + } + + return LoadFromImage(image); +} + +bool NzTexture::LoadFromImage(const NzImage& image) +{ + #if NAZARA_RENDERER_SAFE + if (!image.IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + #endif + + // Vive le Copy-On-Write + NzImage newImage(image); + + nzPixelFormat format = newImage.GetFormat(); + if (!IsFormatSupported(format)) + { + nzPixelFormat newFormat = (NzPixelFormat::HasAlpha(format)) ? nzPixelFormat_BGRA8 : nzPixelFormat_BGR8; + + NazaraWarning("Format not supported, trying to convert it to " + NzPixelFormat::ToString(newFormat) + "..."); + + if (NzPixelFormat::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; + } + } + + nzImageType type = newImage.GetType(); + nzUInt8 levelCount = newImage.GetLevelCount(); + if (!Create(type, format, newImage.GetWidth(), newImage.GetHeight(), newImage.GetDepth(), levelCount, true)) + { + NazaraError("Failed to create texture"); + return false; + } + + for (nzUInt8 level = 0; level < levelCount; ++level) + { + if (!Update(newImage.GetConstPixels(level), level)) + { + NazaraError("Failed to update texture"); + Destroy(); + + return false; + } + } + + UnlockTexture(m_impl); + + return true; +} + +bool NzTexture::LoadFromMemory(const void* data, std::size_t size, const NzImageParams& params) +{ + NzImage image; + if (!image.LoadFromMemory(data, size, params)) + { + NazaraError("Failed to load image"); + return false; + } + + return LoadFromImage(image); +} + +bool NzTexture::LoadFromStream(NzInputStream& stream, const NzImageParams& params) +{ + NzImage image; + if (!image.LoadFromStream(stream, params)) + { + NazaraError("Failed to load image"); + return false; + } + + return LoadFromImage(image); +} + +bool NzTexture::Lock() +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + #endif + + LockTexture(m_impl); + + return true; +} + +bool NzTexture::SetAnisotropyLevel(unsigned int anistropyLevel) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + + if (!NzOpenGL::IsSupported(NzOpenGL::AnisotropicFilter)) + { + NazaraError("Anisotropic filter not supported"); + return false; + } + #endif + + LockTexture(m_impl); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast(anistropyLevel)); + + UnlockTexture(m_impl); + + return true; +} + +bool NzTexture::SetFilterMode(nzTextureFilter filter) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + + if (filter == nzTextureFilter_Trilinear && m_impl->levelCount == 1) + { + NazaraError("Trilinear filter set wihout mipmaps"); + return false; + } + #endif + + LockTexture(m_impl); + + GLenum target = openglTarget[m_impl->type]; + switch (filter) + { + case nzTextureFilter_Bilinear: + if (m_impl->levelCount > 1) + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + else + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + + case nzTextureFilter_Nearest: + if (m_impl->levelCount > 1) + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST); + else + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + break; + + case nzTextureFilter_Trilinear: + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + break; + + default: + NazaraError("Texture filter not handled (0x" + NzString::Number(filter, 16) + ')'); + } + + UnlockTexture(m_impl); + + return true; +} + +bool NzTexture::SetMipmapRange(nzUInt8 minLevel, nzUInt8 maxLevel) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + + if (minLevel >= m_impl->levelCount) + { + NazaraError("Minimum level cannot be greater or equal than level count (" + NzString::Number(minLevel) + " >= " + NzString::Number(m_impl->levelCount) + ')'); + return false; + } + + if (maxLevel < minLevel) + { + NazaraError("Minimum level cannot be greater than maximum level (" + NzString::Number(minLevel) + " < " + NzString::Number(maxLevel) + ')'); + return false; + } + #endif + + LockTexture(m_impl); + glTexParameteri(openglTarget[m_impl->type], GL_TEXTURE_BASE_LEVEL, minLevel); + glTexParameteri(openglTarget[m_impl->type], GL_TEXTURE_MAX_LEVEL, std::min(m_impl->levelCount, maxLevel)); + UnlockTexture(m_impl); + + return true; +} + +bool NzTexture::SetWrapMode(nzTextureWrap wrap) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + #endif + + GLenum wrapMode; + switch (wrap) + { + case nzTextureWrap_Clamp: + wrapMode = GL_CLAMP_TO_EDGE; + break; + + case nzTextureWrap_Repeat: + wrapMode = GL_REPEAT; + break; + + default: + NazaraError("Texture wrap mode not handled (0x" + NzString::Number(wrap, 16) + ')'); + return false; + } + + LockTexture(m_impl); + + GLenum target = openglTarget[m_impl->type]; + switch (m_impl->type) + { + // Notez l'absence de "break" ici + case nzImageType_3D: + glTexParameteri(target, GL_TEXTURE_WRAP_R, wrapMode); + case nzImageType_2D: + case nzImageType_Cubemap: + glTexParameteri(target, GL_TEXTURE_WRAP_T, wrapMode); + case nzImageType_1D: + glTexParameteri(target, GL_TEXTURE_WRAP_S, wrapMode); + break; + + default: + break; + } + + UnlockTexture(m_impl); + + return true; +} + +bool NzTexture::Update(const NzImage& image, nzUInt8 level) +{ + #if NAZARA_RENDERER_SAFE + if (!image.IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (image.GetFormat() != m_impl->format) + { + NazaraError("Image format does not match texture format"); + return false; + } + #endif + + return Update(image.GetConstPixels(level), level); +} + +bool NzTexture::Update(const NzImage& image, const NzRectui& rect, unsigned int z, nzUInt8 level) +{ + #if NAZARA_RENDERER_SAFE + if (!image.IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (image.GetFormat() != m_impl->format) + { + NazaraError("Image format does not match texture format"); + return false; + } + #endif + + return Update(image.GetConstPixels(level), rect, z, level); +} +/* +bool NzTexture::Update(const NzImage& image, const NzCubeui& cube, nzUInt8 level) +{ + #if NAZARA_RENDERER_SAFE + if (!image.IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (image.GetFormat() != m_impl->format) + { + NazaraError("Image format does not match texture format"); + return false; + } + #endif + + return Update(image.GetConstPixels(level), cube, level); +} +*/ +bool NzTexture::Update(const nzUInt8* pixels, nzUInt8 level) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + + if (m_impl->type == nzImageType_Cubemap) + { + NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); + return false; + } + + if (!pixels) + { + NazaraError("Invalid pixel source"); + return false; + } + + if (level >= m_impl->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_impl->levelCount) + ')'); + return false; + } + #endif + + OpenGLFormat format; + if (!GetOpenGLFormat(m_impl->format, &format)) + { + NazaraError("Failed to get OpenGL format"); + return false; + } + + LockTexture(m_impl); + + switch (m_impl->type) + { + case nzImageType_1D: + glTexSubImage1D(GL_TEXTURE_1D, level, 0, std::max(m_impl->width >> level, 1U), format.dataFormat, format.dataType, pixels); + break; + + case nzImageType_2D: + glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, std::max(m_impl->width >> level, 1U), std::max(m_impl->height >> level, 1U), format.dataFormat, format.dataType, pixels); + break; + + case nzImageType_3D: + glTexSubImage3D(GL_TEXTURE_3D, level, 0, 0, 0, std::max(m_impl->width >> level, 1U), std::max(m_impl->height >> level, 1U), std::max(m_impl->depth >> level, 1U), format.dataFormat, format.dataType, pixels); + break; + + default: + NazaraInternalError("Image type not handled (0x" + NzString::Number(m_impl->type, 16) + ')'); + } + + UnlockTexture(m_impl); + + return true; +} + +bool NzTexture::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z, nzUInt8 level) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + + if (m_impl->type == nzImageType_Cubemap) + { + NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); + return false; + } + + if (!pixels) + { + NazaraError("Invalid pixel source"); + return false; + } + + if (!rect.IsValid()) + { + NazaraError("Invalid rectangle"); + return false; + } + + if (rect.x+rect.width > std::max(m_impl->width >> level, 1U) || rect.y+rect.height > std::max(m_impl->height >> level, 1U)) + { + NazaraError("Rectangle dimensions are out of bounds"); + return false; + } + + if (z >= std::max(m_impl->depth >> level, 1U)) + { + NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(m_impl->depth) + ')'); + return false; + } + + if (level >= m_impl->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_impl->levelCount) + ')'); + return false; + } + #endif + + OpenGLFormat format; + if (!GetOpenGLFormat(m_impl->format, &format)) + { + NazaraError("Failed to get OpenGL format"); + return false; + } + + LockTexture(m_impl); + + switch (m_impl->type) + { + case nzImageType_1D: + glTexSubImage1D(GL_TEXTURE_1D, level, rect.x, rect.width, format.dataFormat, format.dataType, pixels); + break; + + case nzImageType_2D: + glTexSubImage2D(GL_TEXTURE_2D, level, rect.x, rect.y, rect.width, rect.height, format.dataFormat, format.dataType, pixels); + break; + + case nzImageType_3D: + glTexSubImage3D(GL_TEXTURE_3D, level, rect.x, rect.y, z, rect.width, rect.height, 1, format.dataFormat, format.dataType, pixels); + break; + + default: + NazaraInternalError("Image type not handled (0x" + NzString::Number(m_impl->type, 16) + ')'); + } + + UnlockTexture(m_impl); + + return true; +} +/* +bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level = 0) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + + if (m_impl->type == nzImageType_Cubemap) + { + NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); + return false; + } + + if (!pixels) + { + NazaraError("Invalid pixel source"); + return false; + } + + if (!cube.IsValid()) + { + NazaraError("Invalid rectangle"); + return false; + } + + if (cube.x+cube.width > std::max(m_impl->width >> level, 1U) || + cube.y+cube.height > std::max(m_impl->height >> level, 1U) || + cube.z+cube.depth > std::max(m_impl->depth >> level, 1U)) + { + NazaraError("Cube dimensions are out of bounds"); + return false; + } + + if (level >= m_impl->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_impl->levelCount) + ')'); + return false; + } + #endif + + OpenGLFormat format; + if (!GetOpenGLFormat(m_impl->format, &format)) + { + NazaraError("Failed to get OpenGL format"); + return false; + } + + LockTexture(m_impl); + + switch (m_impl->type) + { + case nzImageType_1D: + glTexSubImage1D(GL_TEXTURE_1D, level, cube.x, cube.width, format->dataFormat, format->dataType, pixels); + break; + + case nzImageType_2D: + glTexSubImage1D(GL_TEXTURE_2D, level, cube.x, cube.y, cube.width, cube.height, format->dataFormat, format->dataType, pixels); + break; + + case nzImageType_3D: + glTexSubImage1D(GL_TEXTURE_3D, level, cube.x, cube.y, cube.z, cube.width, cube.height, cube.depth, format->dataFormat, format->dataType, pixels); + break; + + default: + NazaraInternalError("Image type not handled (0x" + NzString::Number(m_impl->type, 16) + ')'); + } + + UnlockTexture(m_impl); + + return true; +} +*/ +bool NzTexture::UpdateFace(nzCubemapFace face, const NzImage& image, nzUInt8 level) +{ + #if NAZARA_RENDERER_SAFE + if (!image.IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (image.GetFormat() != m_impl->format) + { + NazaraError("Image format does not match texture format"); + return false; + } + #endif + + return UpdateFace(face, image.GetConstPixels(level), level); +} + +bool NzTexture::UpdateFace(nzCubemapFace face, const NzImage& image, const NzRectui& rect, nzUInt8 level) +{ + #if NAZARA_RENDERER_SAFE + if (!image.IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (image.GetFormat() != m_impl->format) + { + NazaraError("Image format does not match texture format"); + return false; + } + #endif + + return UpdateFace(face, image.GetConstPixels(level), rect, level); +} + +bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, nzUInt8 level) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + + if (m_impl->type != nzImageType_Cubemap) + { + NazaraError("UpdateFace is designed for cubemaps, use Update instead"); + return false; + } + + if (!pixels) + { + NazaraError("Invalid pixel source"); + return false; + } + + if (level >= m_impl->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_impl->levelCount) + ')'); + return false; + } + #endif + + OpenGLFormat format; + if (!GetOpenGLFormat(m_impl->format, &format)) + { + NazaraError("Failed to get OpenGL format"); + return false; + } + + LockTexture(m_impl); + + glTexSubImage2D(cubemapFace[face], level, 0, 0, m_impl->width, m_impl->height, format.dataFormat, format.dataType, pixels); + + UnlockTexture(m_impl); + + return true; +} + +bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRectui& rect, nzUInt8 level) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + + if (m_impl->type != nzImageType_Cubemap) + { + NazaraError("UpdateFace is designed for cubemaps, use Update instead"); + return false; + } + + if (!pixels) + { + NazaraError("Invalid pixel source"); + return false; + } + + if (!rect.IsValid()) + { + NazaraError("Invalid rectangle"); + return false; + } + + if (rect.x+rect.width > std::max(m_impl->width >> level, 1U) || rect.y+rect.height > std::max(m_impl->height >> level, 1U)) + { + NazaraError("Rectangle dimensions are out of bounds"); + return false; + } + + if (level >= m_impl->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_impl->levelCount) + ')'); + return false; + } + #endif + + OpenGLFormat format; + if (!GetOpenGLFormat(m_impl->format, &format)) + { + NazaraError("Failed to get OpenGL format"); + return false; + } + + LockTexture(m_impl); + + glTexSubImage2D(cubemapFace[face], level, rect.x, rect.y, rect.width, rect.height, format.dataFormat, format.dataType, pixels); + + UnlockTexture(m_impl); + + return true; +} + +void NzTexture::Unlock() +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return; + } + #endif + + UnlockTexture(m_impl); +} + +unsigned int NzTexture::GetValidSize(unsigned int size) +{ + if (NazaraRenderer->HasCapability(nzRendererCap_TextureNPOT)) + return size; + else + { + unsigned int pot = 1; + while (pot < size) + pot <<= 1; + + return pot; + } +} + +bool NzTexture::IsFormatSupported(nzPixelFormat format) +{ + #if NAZARA_RENDERER_SAFE + if (!NzPixelFormat::IsValid(format)) + { + NazaraError("Invalid pixel format"); + return nzPixelFormat_Undefined; + } + #endif + + switch (format) + { + // Formats de base + case nzPixelFormat_BGR8: + case nzPixelFormat_BGRA8: + case nzPixelFormat_RGB8: + case nzPixelFormat_RGBA8: + return true; + + // Packed formats supportés depuis OpenGL 1.2 + case nzPixelFormat_RGB5A1: + case nzPixelFormat_RGBA4: + return true; + + // Dépréciés depuis OpenGL 3 (FIXME: Il doit bien exister des remplaçants ..) + case nzPixelFormat_L8: + case nzPixelFormat_LA8: + return false; + + case nzPixelFormat_DXT1: + case nzPixelFormat_DXT3: + case nzPixelFormat_DXT5: + { + static const bool supported = NzOpenGL::IsSupported(NzOpenGL::TextureCompression_s3tc); + return supported; + } + + default: + return false; + } +} + +bool NzTexture::IsTypeSupported(nzImageType type) +{ + switch (type) + { + case nzImageType_1D: + case nzImageType_2D: + case nzImageType_3D: + case nzImageType_Cubemap: + return true; // Tous supportés nativement dans OpenGL 2 + + default: + return false; + } +} diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index 5e76b5ce3..b9cb4d8dd 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -160,6 +160,9 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width, { ReleaseImage(); + if (width == 0 || height == 0 || depth == 0) + return true; + #if NAZARA_UTILITY_SAFE if (!NzPixelFormat::IsValid(format)) { @@ -191,6 +194,9 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width, } break; + case nzImageType_3D: + break; + case nzImageType_Cubemap: if (depth > 1) { @@ -206,13 +212,11 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width, break; default: - break; + NazaraInternalError("Image type not handled"); + return false; } #endif - if (width == 0 || height == 0 || depth == 0) - return true; - levelCount = std::min(levelCount, GetMaxLevel(width, height, depth)); nzUInt8** levels = new nzUInt8*[levelCount]; @@ -279,7 +283,7 @@ unsigned int NzImage::GetDepth(nzUInt8 level) const } #endif - return std::max(m_sharedImage->depth/(1 << level), 1U); + return std::max(m_sharedImage->depth >> level, 1U); } nzPixelFormat NzImage::GetFormat() const @@ -297,7 +301,7 @@ unsigned int NzImage::GetHeight(nzUInt8 level) const } #endif - return std::max(m_sharedImage->height/(1 << level), 1U); + return std::max(m_sharedImage->height >> level, 1U); } nzUInt8 NzImage::GetLevelCount() const @@ -446,9 +450,9 @@ unsigned int NzImage::GetSize(nzUInt8 level) const } #endif - return (std::max(m_sharedImage->width/(1 << level), 1U)) * - (std::max(m_sharedImage->height/(1 << level), 1U)) * - ((m_sharedImage->type == nzImageType_Cubemap) ? 6 : std::min(m_sharedImage->depth/(1 << level), 1U)) * + return (std::max(m_sharedImage->width >> level, 1U)) * + (std::max(m_sharedImage->height >> level, 1U)) * + ((m_sharedImage->type == nzImageType_Cubemap) ? 6 : std::max(m_sharedImage->depth >> level, 1U)) * NzPixelFormat::GetBPP(m_sharedImage->format); } @@ -467,7 +471,7 @@ unsigned int NzImage::GetWidth(nzUInt8 level) const } #endif - return std::max(m_sharedImage->width/(1 << level), 1U); + return std::max(m_sharedImage->width >> level, 1U); } bool NzImage::IsCompressed() const @@ -523,22 +527,23 @@ bool NzImage::SetLevelCount(nzUInt8 levelCount) EnsureOwnership(); + nzUInt8 oldLevelCount = m_sharedImage->levelCount; + nzUInt8 maxLevelCount = std::max(levelCount, oldLevelCount); + m_sharedImage->levelCount = levelCount; // Pour faire fonctionner GetSize + nzUInt8** pixels = new nzUInt8*[levelCount]; - for (unsigned int i = 0; i < levelCount; ++i) + for (unsigned int i = 0; i < maxLevelCount; ++i) { - if (i < m_sharedImage->levelCount) + if (i < oldLevelCount) pixels[i] = m_sharedImage->pixels[i]; + else if (i < levelCount) + pixels[i] = new nzUInt8[GetSize(i)]; else - { - unsigned int size = GetSize(i); - pixels[i] = new nzUInt8[size]; - std::memcpy(pixels[i], m_sharedImage->pixels[i], size); - } + delete[] m_sharedImage->pixels[i]; } delete[] m_sharedImage->pixels; - m_sharedImage->levelCount = levelCount; m_sharedImage->pixels = pixels; return true; @@ -702,23 +707,23 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z return false; } - if (level >= m_sharedImage->levelCount) - { - NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); - return false; - } - - if (rect.x+rect.width > (m_sharedImage->width << level) || rect.y+rect.height > (m_sharedImage->height) << level) + if (rect.x+rect.width > std::max(m_sharedImage->width >> level, 1U) || rect.y+rect.height > std::max(m_sharedImage->height >> level, 1U)) { NazaraError("Rectangle dimensions are out of bounds"); return false; } - if (z >= (m_sharedImage->depth << level)) + if (z >= std::max(m_sharedImage->depth >> level, 1U)) { NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(m_sharedImage->depth) + ')'); return false; } + + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return false; + } #endif EnsureOwnership(); @@ -749,7 +754,7 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, nzUInt8 leve if (m_sharedImage->type != nzImageType_Cubemap) { - NazaraError("Update is designed for cubemaps, use Update instead"); + NazaraError("UpdateFace is designed for cubemaps, use Update instead"); return false; } @@ -785,7 +790,7 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRect if (m_sharedImage->type != nzImageType_Cubemap) { - NazaraError("Update is designed for cubemaps, use Update instead"); + NazaraError("UpdateFace is designed for cubemaps, use Update instead"); return false; } @@ -801,15 +806,15 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRect return false; } - if (level >= m_sharedImage->levelCount) + if (rect.x+rect.width > std::max(m_sharedImage->width >> level, 1U) || rect.y+rect.height > std::max(m_sharedImage->height >> level, 1U)) { - NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + NazaraError("Rectangle dimensions are out of bounds"); return false; } - if (rect.x+rect.width > (m_sharedImage->width << level) || rect.y+rect.height > (m_sharedImage->height) << level) + if (level >= m_sharedImage->levelCount) { - NazaraError("Rectangle dimensions are out of bounds"); + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); return false; } #endif @@ -861,7 +866,7 @@ nzUInt8 NzImage::GetMaxLevel(unsigned int width, unsigned int height, unsigned i unsigned int heightLevel = std::log(height)/l2; unsigned int depthLevel = std::log(depth)/l2; - return std::max(std::max(widthLevel, heightLevel), depthLevel); + return std::max(std::max(std::max(widthLevel, heightLevel), depthLevel), 1U); } void NzImage::RegisterFileLoader(const NzString& extensions, LoadFileFunction loadFile) diff --git a/src/Nazara/Utility/Loaders/PCX.cpp b/src/Nazara/Utility/Loaders/PCX.cpp index 0eab2c186..9460ef396 100644 --- a/src/Nazara/Utility/Loaders/PCX.cpp +++ b/src/Nazara/Utility/Loaders/PCX.cpp @@ -93,7 +93,7 @@ namespace unsigned int width = header.xmax - header.xmin+1; unsigned int height = header.ymax - header.ymin+1; - if (!resource->Create(nzImageType_2D, nzPixelFormat_RGB8, width, height)) + if (!resource->Create(nzImageType_2D, nzPixelFormat_RGB8, width, height, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1)) { NazaraError("Failed to create image"); return false; diff --git a/src/Nazara/Utility/Loaders/STB.cpp b/src/Nazara/Utility/Loaders/STB.cpp index e6b42ba6f..ff0e3fbea 100644 --- a/src/Nazara/Utility/Loaders/STB.cpp +++ b/src/Nazara/Utility/Loaders/STB.cpp @@ -111,7 +111,7 @@ namespace if (format == nzPixelFormat_Undefined) format = formats[bpp-1]; - if (!resource->Create(nzImageType_2D, format, width, height)) + if (!resource->Create(nzImageType_2D, format, width, height, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1)) { NazaraError("Failed to create image"); stbi_image_free(ptr); From ddd2a2f3105fad4adadc03b071d26cae78109cf2 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 5 Jun 2012 23:06:47 +0200 Subject: [PATCH 12/15] Added CopyTo(Image/Texture) to NzRenderWindow Added several methods to NzRenderer Optimized NzRenderer::GetMax*(); Nz(Render)Window::GetSize now returns an unsigned vector Fixed textures being flipped --- include/Nazara/Renderer/OpenGL.hpp | 2 + include/Nazara/Renderer/RenderWindow.hpp | 7 + include/Nazara/Renderer/Renderer.hpp | 89 ++++- include/Nazara/Renderer/Texture.hpp | 2 +- include/Nazara/Utility/Window.hpp | 2 +- src/Nazara/Renderer/OpenGL.cpp | 4 + src/Nazara/Renderer/RenderWindow.cpp | 103 +++++- src/Nazara/Renderer/Renderer.cpp | 435 +++++++++++++++++------ src/Nazara/Renderer/Texture.cpp | 186 +++++----- src/Nazara/Utility/Image.cpp | 6 +- src/Nazara/Utility/Win32/WindowImpl.cpp | 6 +- src/Nazara/Utility/Win32/WindowImpl.hpp | 2 +- src/Nazara/Utility/Window.cpp | 4 +- 13 files changed, 619 insertions(+), 229 deletions(-) diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index cd4c1a4d2..8b2761c84 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -74,6 +74,7 @@ NAZARA_API extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; NAZARA_API extern PFNGLCOLORMASKPROC glColorMask; NAZARA_API extern PFNGLCULLFACEPROC glCullFace; NAZARA_API extern PFNGLCOMPILESHADERPROC glCompileShader; +NAZARA_API extern PFNGLCOPYTEXSUBIMAGE2DPROC glCopyTexSubImage2D; NAZARA_API extern PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControl; NAZARA_API extern PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsert; NAZARA_API extern PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallback; @@ -130,6 +131,7 @@ NAZARA_API extern PFNGLLINKPROGRAMPROC glLinkProgram; NAZARA_API extern PFNGLMAPBUFFERPROC glMapBuffer; NAZARA_API extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange; NAZARA_API extern PFNGLPOLYGONMODEPROC glPolygonMode; +NAZARA_API extern PFNGLREADPIXELSPROC glReadPixels; NAZARA_API extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; NAZARA_API extern PFNGLSCISSORPROC glScissor; NAZARA_API extern PFNGLSHADERSOURCEPROC glShaderSource; diff --git a/include/Nazara/Renderer/RenderWindow.hpp b/include/Nazara/Renderer/RenderWindow.hpp index 908cea023..2c43579ec 100644 --- a/include/Nazara/Renderer/RenderWindow.hpp +++ b/include/Nazara/Renderer/RenderWindow.hpp @@ -19,10 +19,14 @@ #endif class NzContext; +class NzImage; +class NzTexture; struct NzContextParameters; class NAZARA_API NzRenderWindow : public NzRenderTarget, public NzWindow { + friend class NzTexture; + public: NzRenderWindow(); NzRenderWindow(NzVideoMode mode, const NzString& title, nzUInt32 style = NzWindow::Default, const NzContextParameters& parameters = NzContextParameters()); @@ -31,6 +35,9 @@ class NAZARA_API NzRenderWindow : public NzRenderTarget, public NzWindow bool CanActivate() const; + bool CopyToImage(NzImage* image); ///TODO: Const + bool CopyToTexture(NzTexture* texture); ///TODO: Const + bool Create(NzVideoMode mode, const NzString& title, nzUInt32 style = NzWindow::Default, const NzContextParameters& parameters = NzContextParameters()); bool Create(NzWindowHandle handle, const NzContextParameters& parameters = NzContextParameters()); diff --git a/include/Nazara/Renderer/Renderer.hpp b/include/Nazara/Renderer/Renderer.hpp index 86cee1cba..aab95ab7c 100644 --- a/include/Nazara/Renderer/Renderer.hpp +++ b/include/Nazara/Renderer/Renderer.hpp @@ -13,6 +13,34 @@ #define NazaraRenderer NzRenderer::Instance() +enum nzBlendFunc +{ + nzBlendFunc_DestAlpha, + nzBlendFunc_DestColor, + nzBlendFunc_SrcAlpha, + nzBlendFunc_SrcColor, + nzBlendFunc_InvDestAlpha, + nzBlendFunc_InvDestColor, + nzBlendFunc_InvSrcAlpha, + nzBlendFunc_InvSrcColor, + nzBlendFunc_One, + nzBlendFunc_Zero +}; + +enum nzFaceCulling +{ + nzFaceCulling_Back, + nzFaceCulling_Front, + nzFaceCulling_FrontAndBack +}; + +enum nzFaceFilling +{ + nzFaceFilling_Point, + nzFaceFilling_Line, + nzFaceFilling_Fill +}; + enum nzPrimitiveType { nzPrimitiveType_LineList, @@ -46,6 +74,40 @@ enum nzRendererClear nzRendererClear_Stencil = 0x04 }; +enum nzRendererComparison +{ + nzRendererComparison_Always, + nzRendererComparison_Equal, + nzRendererComparison_Greater, + nzRendererComparison_GreaterOrEqual, + nzRendererComparison_Less, + nzRendererComparison_LessOrEqual, + nzRendererComparison_Never +}; + +enum nzRendererParameter +{ + nzRendererParameter_AlphaTest, + nzRendererParameter_Blend, + nzRendererParameter_ColorWrite, + nzRendererParameter_DepthTest, + nzRendererParameter_DepthWrite, + nzRendererParameter_FaceCulling, + nzRendererParameter_Stencil +}; + +enum nzStencilOperation +{ + nzStencilOperation_Decrement, + nzStencilOperation_DecrementToSaturation, + nzStencilOperation_Increment, + nzStencilOperation_IncrementToSaturation, + nzStencilOperation_Invert, + nzStencilOperation_Keep, + nzStencilOperation_Replace, + nzStencilOperation_Zero +}; + class NzColor; class NzContext; class NzIndexBuffer; @@ -66,6 +128,10 @@ class NAZARA_API NzRenderer void DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int firstIndex, unsigned int indexCount); void DrawPrimitives(nzPrimitiveType primitive, unsigned int firstVertex, unsigned int vertexCount); + void Enable(nzRendererParameter parameter, bool enable); + + unsigned int GetMaxAnisotropyLevel() const; + unsigned int GetMaxRenderTargets() const; unsigned int GetMaxTextureUnits() const; NzShader* GetShader() const; NzRenderTarget* GetTarget() const; @@ -77,8 +143,16 @@ class NAZARA_API NzRenderer void SetClearColor(nzUInt8 r, nzUInt8 g, nzUInt8 b, nzUInt8 a = 255); void SetClearDepth(double depth); void SetClearStencil(unsigned int value); + void SetFaceCulling(nzFaceCulling cullingMode); + void SetFaceFilling(nzFaceFilling fillingMode); bool SetIndexBuffer(const NzIndexBuffer* indexBuffer); bool SetShader(NzShader* shader); + void SetStencilCompareFunction(nzRendererComparison compareFunc); + void SetStencilFailOperation(nzStencilOperation failOperation); + void SetStencilMask(nzUInt32 mask); + void SetStencilPassOperation(nzStencilOperation passOperation); + void SetStencilReferenceValue(unsigned int refValue); + void SetStencilZFailOperation(nzStencilOperation zfailOperation); bool SetTarget(NzRenderTarget* target); bool SetVertexBuffer(const NzVertexBuffer* vertexBuffer); bool SetVertexDeclaration(const NzVertexDeclaration* vertexDeclaration); @@ -89,19 +163,30 @@ class NAZARA_API NzRenderer static bool IsInitialized(); private: - bool UpdateStates(); + bool EnsureStateUpdate(); typedef std::tuple VAO_Key; std::map m_vaos; + nzRendererComparison m_stencilCompare; + nzStencilOperation m_stencilFail; + nzStencilOperation m_stencilPass; + nzStencilOperation m_stencilZFail; + nzUInt32 m_stencilMask; const NzIndexBuffer* m_indexBuffer; NzRenderTarget* m_target; NzShader* m_shader; NzUtility* m_utilityModule; const NzVertexBuffer* m_vertexBuffer; const NzVertexDeclaration* m_vertexDeclaration; + bool m_vaoUpdated; bool m_capabilities[nzRendererCap_Count]; - bool m_statesUpdated; + bool m_stencilFuncUpdated; + bool m_stencilOpUpdated; + unsigned int m_maxAnisotropyLevel; + unsigned int m_maxRenderTarget; + unsigned int m_maxTextureUnit; + unsigned int m_stencilReference; static NzRenderer* s_instance; static bool s_initialized; diff --git a/include/Nazara/Renderer/Texture.hpp b/include/Nazara/Renderer/Texture.hpp index f038a86e9..01b69b115 100644 --- a/include/Nazara/Renderer/Texture.hpp +++ b/include/Nazara/Renderer/Texture.hpp @@ -27,7 +27,7 @@ enum nzTextureWrap nzTextureWrap_Unknown }; -class NzRenderWindow; ///TODO: Screenshot +class NzShader; struct NzTextureImpl; class NAZARA_API NzTexture : public NzResource, NzNonCopyable diff --git a/include/Nazara/Utility/Window.hpp b/include/Nazara/Utility/Window.hpp index e6b202df3..acd694f50 100644 --- a/include/Nazara/Utility/Window.hpp +++ b/include/Nazara/Utility/Window.hpp @@ -61,7 +61,7 @@ class NAZARA_API NzWindow : NzNonCopyable NzWindowHandle GetHandle() const; unsigned int GetHeight() const; NzVector2i GetPosition() const; - NzVector2i GetSize() const; + NzVector2ui GetSize() const; NzString GetTitle() const; unsigned int GetWidth() const; diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index 610e8c891..502cc1066 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -223,6 +223,7 @@ bool NzOpenGL::Initialize() glColorMask = reinterpret_cast(LoadEntry("glColorMask")); glCullFace = reinterpret_cast(LoadEntry("glCullFace")); glCompileShader = reinterpret_cast(LoadEntry("glCompileShader")); + glCopyTexSubImage2D = reinterpret_cast(LoadEntry("glCopyTexSubImage2D")); glDeleteBuffers = reinterpret_cast(LoadEntry("glDeleteBuffers")); glDeleteQueries = reinterpret_cast(LoadEntry("glDeleteQueries")); glDeleteProgram = reinterpret_cast(LoadEntry("glDeleteProgram")); @@ -263,6 +264,7 @@ bool NzOpenGL::Initialize() glLinkProgram = reinterpret_cast(LoadEntry("glLinkProgram")); glMapBuffer = reinterpret_cast(LoadEntry("glMapBuffer")); glPolygonMode = reinterpret_cast(LoadEntry("glPolygonMode")); + glReadPixels = reinterpret_cast(LoadEntry("glReadPixels")); glScissor = reinterpret_cast(LoadEntry("glScissor")); glShaderSource = reinterpret_cast(LoadEntry("glShaderSource")); glStencilFunc = reinterpret_cast(LoadEntry("glStencilFunc")); @@ -545,6 +547,7 @@ PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = nullptr; PFNGLCOLORMASKPROC glColorMask = nullptr; PFNGLCULLFACEPROC glCullFace = nullptr; PFNGLCOMPILESHADERPROC glCompileShader = nullptr; +PFNGLCOPYTEXSUBIMAGE2DPROC glCopyTexSubImage2D = nullptr; PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControl = nullptr; PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsert = nullptr; PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallback = nullptr; @@ -601,6 +604,7 @@ PFNGLLINKPROGRAMPROC glLinkProgram = nullptr; PFNGLMAPBUFFERPROC glMapBuffer = nullptr; PFNGLMAPBUFFERRANGEPROC glMapBufferRange = nullptr; PFNGLPOLYGONMODEPROC glPolygonMode = nullptr; +PFNGLREADPIXELSPROC glReadPixels = nullptr; PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = nullptr; PFNGLSCISSORPROC glScissor = nullptr; PFNGLSHADERSOURCEPROC glShaderSource = nullptr; diff --git a/src/Nazara/Renderer/RenderWindow.cpp b/src/Nazara/Renderer/RenderWindow.cpp index 6ce72547d..bc8c91db8 100644 --- a/src/Nazara/Renderer/RenderWindow.cpp +++ b/src/Nazara/Renderer/RenderWindow.cpp @@ -8,15 +8,10 @@ #include #include #include +#include #include #include -namespace -{ - NzContextParameters invalidContextParameters; - NzRenderTargetParameters invalidRTParameters; -} - NzRenderWindow::NzRenderWindow() : m_context(nullptr) { @@ -59,6 +54,82 @@ bool NzRenderWindow::CanActivate() const return m_impl != nullptr && m_context != nullptr; } +bool NzRenderWindow::CopyToImage(NzImage* image) +{ + #if NAZARA_RENDERER_SAFE + if (!m_context) + { + NazaraError("Window has not been created"); + return false; + } + + if (!image) + { + NazaraError("Image must be valid"); + return false; + } + #endif + + if (!m_context->SetActive(true)) + { + NazaraError("Failed to activate context"); + return false; + } + + NzVector2ui size = GetSize(); + + if (!image->Create(nzImageType_2D, nzPixelFormat_RGBA8, size.x, size.y, 1, 1)) + { + NazaraError("Failed to create image"); + return false; + } + + nzUInt8* pixels = image->GetPixels(); + glReadPixels(0, 0, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + for (unsigned int j = 0; j < size.y/2; ++j) + std::swap_ranges(&pixels[j*size.x*4], &pixels[(j+1)*size.x*4-1], &pixels[(size.y-j-1)*size.x*4]); + + return true; +} + +bool NzRenderWindow::CopyToTexture(NzTexture* texture) +{ + #if NAZARA_RENDERER_SAFE + if (!m_context) + { + NazaraError("Window has not been created"); + return false; + } + + if (!texture) + { + NazaraError("Texture must be valid"); + return false; + } + #endif + + if (!m_context->SetActive(true)) + { + NazaraError("Failed to activate context"); + return false; + } + + NzVector2ui size = GetSize(); + + if (!texture->Create(nzImageType_2D, nzPixelFormat_RGBA8, size.x, size.y, 1, 1, true)) + { + NazaraError("Failed to create texture"); + return false; + } + + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size.x, size.y); + + texture->Unlock(); + + return true; +} + bool NzRenderWindow::Create(NzVideoMode mode, const NzString& title, nzUInt32 style, const NzContextParameters& parameters) { m_parameters = parameters; @@ -81,29 +152,29 @@ void NzRenderWindow::EnableVerticalSync(bool enabled) { if (m_context) { -#if defined(NAZARA_PLATFORM_WINDOWS) + #if defined(NAZARA_PLATFORM_WINDOWS) if (!m_context->SetActive(true)) - { - NazaraError("Unable to activate context"); - return; - } + { + NazaraError("Failed to activate context"); + return; + } if (wglSwapInterval) wglSwapInterval(enabled ? 1 : 0); else -#elif defined(NAZARA_PLATFORM_LINUX) + #elif defined(NAZARA_PLATFORM_LINUX) if (!m_context->SetActive(true)) { - NazaraError("Unable to activate context"); + NazaraError("Failed to activate context"); return; } if (glXSwapInterval) glXSwapInterval(enabled ? 1 : 0); else -#else - #error Vertical Sync is not supported on this platform -#endif + #else + #error Vertical Sync is not supported on this platform + #endif NazaraError("Vertical Sync is not supported on this platform"); } else diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 05627ef61..11e18926e 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -30,6 +30,21 @@ namespace 4 // nzElementUsage_TexCoord }; + const GLenum faceCullingMode[] = + { + GL_BACK, // nzFaceCulling_Back + GL_FRONT, // nzFaceCulling_Front + GL_FRONT_AND_BACK // nzFaceCulling_FrontAndBack + }; + + const GLenum faceFillingMode[] = + { + GL_POINT, // nzFaceFilling_Point + GL_LINE, // nzFaceFilling_Line + GL_FILL // nzFaceFilling_Fill + }; + + const GLenum openglPrimitive[] = { GL_LINES, // nzPrimitiveType_LineList, @@ -65,15 +80,42 @@ namespace GL_FLOAT, // nzElementType_Float3 GL_FLOAT // nzElementType_Float4 }; + + const GLenum rendererComparison[] = + { + GL_ALWAYS, // nzRendererComparison_Always + GL_EQUAL, // nzRendererComparison_Equal + GL_GREATER, // nzRendererComparison_Greater + GL_GEQUAL, // nzRendererComparison_GreaterOrEqual + GL_LESS, // nzRendererComparison_Less + GL_LEQUAL, // nzRendererComparison_LessOrEqual + GL_NEVER // nzRendererComparison_Never + }; + + const GLenum rendererParameter[] = + { + GL_BLEND, // nzRendererParameter_Blend + GL_NONE, // nzRendererParameter_ColorWrite + GL_DEPTH_TEST, // nzRendererParameter_DepthTest + GL_NONE, // nzRendererParameter_DepthWrite + GL_CULL_FACE, // nzRendererParameter_FaceCulling + GL_STENCIL_TEST // nzRendererParameter_Stencil + }; + + const GLenum stencilOperation[] = + { + GL_DECR, // nzStencilOperation_Decrement + GL_DECR_WRAP, // nzStencilOperation_DecrementToSaturation + GL_INCR, // nzStencilOperation_Increment + GL_INCR_WRAP, // nzStencilOperation_IncrementToSaturation + GL_INVERT, // nzStencilOperation_Invert + GL_KEEP, // nzStencilOperation_Keep + GL_REPLACE, // nzStencilOperation_Replace + GL_ZERO // nzStencilOperation_Zero + }; } -NzRenderer::NzRenderer() : -m_indexBuffer(nullptr), -m_target(nullptr), -m_shader(nullptr), -m_vertexBuffer(nullptr), -m_vertexDeclaration(nullptr), -m_statesUpdated(false) +NzRenderer::NzRenderer() { #if NAZARA_RENDERER_SAFE if (s_instance) @@ -121,6 +163,12 @@ void NzRenderer::Clear(unsigned long flags) void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int firstIndex, unsigned int indexCount) { #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + if (!m_indexBuffer) { NazaraError("No index buffer"); @@ -128,13 +176,10 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f } #endif - if (!m_statesUpdated) + if (!EnsureStateUpdate()) { - if (!UpdateStates()) - { - NazaraError("Failed to update states"); - return; - } + NazaraError("Failed to update states"); + return; } nzUInt8 indexSize = m_indexBuffer->GetIndexSize(); @@ -164,30 +209,58 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f void NzRenderer::DrawPrimitives(nzPrimitiveType primitive, unsigned int firstVertex, unsigned int vertexCount) { - if (!m_statesUpdated) + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) { - if (!UpdateStates()) - { - NazaraError("Failed to update states"); - return; - } + NazaraError("No active context"); + return; + } + #endif + + if (!EnsureStateUpdate()) + { + NazaraError("Failed to update states"); + return; } glDrawArrays(openglPrimitive[primitive], firstVertex, vertexCount); } +void NzRenderer::Enable(nzRendererParameter parameter, bool enable) +{ + switch (parameter) + { + case nzRendererParameter_ColorWrite: + glColorMask(enable, enable, enable, enable); + break; + + case nzRendererParameter_DepthWrite: + glDepthMask(enable); + break; + + default: + if (enable) + glEnable(rendererParameter[parameter]); + else + glDisable(rendererParameter[parameter]); + + break; + } +} + +unsigned int NzRenderer::GetMaxAnisotropyLevel() const +{ + return m_maxAnisotropyLevel; +} + +unsigned int NzRenderer::GetMaxRenderTargets() const +{ + return m_maxRenderTarget; +} + unsigned int NzRenderer::GetMaxTextureUnits() const { - static int maxTextureUnits = -1; - if (maxTextureUnits == -1) - { - if (m_capabilities[nzRendererCap_TextureMulti]) - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); - else - maxTextureUnits = 1; - } - - return maxTextureUnits; + return m_maxTextureUnit; } NzShader* NzRenderer::GetShader() const @@ -224,6 +297,22 @@ bool NzRenderer::Initialize() if (NzOpenGL::Initialize()) { + m_vaoUpdated = false; + m_indexBuffer = nullptr; + m_shader = nullptr; + m_stencilCompare = nzRendererComparison_Always; + m_stencilFail = nzStencilOperation_Keep; + m_stencilFuncUpdated = true; + m_stencilMask = 0xFFFFFFFF; + m_stencilOpUpdated = true; + m_stencilPass = nzStencilOperation_Keep; + m_stencilReference = 0; + m_stencilZFail = nzStencilOperation_Keep; + m_target = nullptr; + m_vertexBuffer = nullptr; + m_vertexDeclaration = nullptr; + + // Récupération des capacités m_capabilities[nzRendererCap_AnisotropicFilter] = NzOpenGL::IsSupported(NzOpenGL::AnisotropicFilter); m_capabilities[nzRendererCap_FP64] = NzOpenGL::IsSupported(NzOpenGL::FP64); m_capabilities[nzRendererCap_HardwareBuffer] = true; // Natif depuis OpenGL 1.5 @@ -235,6 +324,40 @@ bool NzRenderer::Initialize() m_capabilities[nzRendererCap_TextureMulti] = true; // Natif depuis OpenGL 1.3 m_capabilities[nzRendererCap_TextureNPOT] = true; // Natif depuis OpenGL 2.0 + if (m_capabilities[nzRendererCap_AnisotropicFilter]) + { + GLint maxAnisotropy; + glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &maxAnisotropy); + + m_maxAnisotropyLevel = static_cast(maxAnisotropy); + } + else + m_maxAnisotropyLevel = 1; + + if (m_capabilities[nzRendererCap_MultipleRenderTargets]) + { + // Permettre de gérer plus de targets que de nombre de sorties dans le shader ne servirait à rien + GLint maxDrawBuffers; + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); + + GLint maxRenderTextureTargets; + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxRenderTextureTargets); + + m_maxRenderTarget = static_cast(std::min(maxDrawBuffers, maxRenderTextureTargets)); + } + else + m_maxRenderTarget = 1; + + if (m_capabilities[nzRendererCap_TextureMulti]) + { + GLint maxTextureUnits; + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); + + m_maxTextureUnit = static_cast(maxTextureUnits); + } + else + m_maxTextureUnit = 1; + s_initialized = true; return true; @@ -295,12 +418,39 @@ void NzRenderer::SetClearStencil(unsigned int value) glClearStencil(value); } +void NzRenderer::SetFaceCulling(nzFaceCulling cullingMode) +{ + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + + glCullFace(faceCullingMode[cullingMode]); +} + +void NzRenderer::SetFaceFilling(nzFaceFilling fillingMode) +{ + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + + glPolygonMode(GL_FRONT_AND_BACK, faceFillingMode[fillingMode]); +} + + bool NzRenderer::SetIndexBuffer(const NzIndexBuffer* indexBuffer) { if (indexBuffer != m_indexBuffer) { m_indexBuffer = indexBuffer; - m_statesUpdated = false; + m_vaoUpdated = false; } return true; @@ -332,13 +482,67 @@ bool NzRenderer::SetShader(NzShader* shader) NazaraError("Failed to bind shader"); return false; } - - m_shader = shader; } + m_shader = shader; + return true; } +void NzRenderer::SetStencilCompareFunction(nzRendererComparison compareFunc) +{ + if (compareFunc != m_stencilCompare) + { + m_stencilCompare = compareFunc; + m_stencilFuncUpdated = false; + } +} + +void NzRenderer::SetStencilFailOperation(nzStencilOperation failOperation) +{ + if (failOperation != m_stencilFail) + { + m_stencilFail = failOperation; + m_stencilOpUpdated = false; + } +} + +void NzRenderer::SetStencilMask(nzUInt32 mask) +{ + if (mask != m_stencilMask) + { + m_stencilMask = mask; + m_stencilFuncUpdated = false; + } +} + +void NzRenderer::SetStencilPassOperation(nzStencilOperation passOperation) +{ + if (passOperation != m_stencilPass) + { + m_stencilPass = passOperation; + m_stencilOpUpdated = false; + } +} + +void NzRenderer::SetStencilReferenceValue(unsigned int refValue) +{ + if (refValue != m_stencilReference) + { + m_stencilReference = refValue; + m_stencilFuncUpdated = false; + } +} + +void NzRenderer::SetStencilZFailOperation(nzStencilOperation zfailOperation) +{ + if (zfailOperation != m_stencilZFail) + { + m_stencilZFail = zfailOperation; + m_stencilOpUpdated = false; + } +} + bool NzRenderer::SetTarget(NzRenderTarget* target) { if (target == m_target) @@ -378,7 +582,7 @@ bool NzRenderer::SetVertexBuffer(const NzVertexBuffer* vertexBuffer) if (m_vertexBuffer != vertexBuffer) { m_vertexBuffer = vertexBuffer; - m_statesUpdated = false; + m_vaoUpdated = false; } return true; @@ -389,7 +593,7 @@ bool NzRenderer::SetVertexDeclaration(const NzVertexDeclaration* vertexDeclarati if (m_vertexDeclaration != vertexDeclaration) { m_vertexDeclaration = vertexDeclaration; - m_statesUpdated = false; + m_vaoUpdated = false; } return true; @@ -438,98 +642,113 @@ bool NzRenderer::IsInitialized() return s_initialized; } -bool NzRenderer::UpdateStates() +bool NzRenderer::EnsureStateUpdate() { - #if NAZARA_RENDERER_SAFE - if (!m_vertexBuffer) + if (!m_stencilFuncUpdated) { - NazaraError("No vertex buffer"); - return false; + glStencilFunc(rendererComparison[m_stencilCompare], m_stencilReference, m_stencilMask); + m_stencilFuncUpdated = true; } - if (!m_vertexDeclaration) + if (!m_stencilOpUpdated) { - NazaraError("No vertex declaration"); - return false; + glStencilOp(stencilOperation[m_stencilFail], stencilOperation[m_stencilZFail], stencilOperation[m_stencilPass]); + m_stencilOpUpdated = true; } - #endif - static const bool vaoSupported = NzOpenGL::IsSupported(NzOpenGL::VertexArrayObject); - bool update; - GLuint vao; - - // Si les VAOs sont supportés, on entoure nos appels par ceux-ci - if (vaoSupported) + if (!m_vaoUpdated) { - // On recherche si un VAO existe déjà avec notre configuration - // Note: Les VAOs ne sont pas partagés entre les contextes, ces derniers font donc partie de notre configuration - - auto key = std::make_tuple(NzContext::GetCurrent(), m_indexBuffer, m_vertexBuffer, m_vertexDeclaration); - auto it = m_vaos.find(key); - if (it == m_vaos.end()) + #if NAZARA_RENDERER_SAFE + if (!m_vertexBuffer) { - // On créé notre VAO - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); + NazaraError("No vertex buffer"); + return false; + } - // On l'ajoute à notre liste - m_vaos.insert(std::make_pair(key, static_cast(vao))); + if (!m_vertexDeclaration) + { + NazaraError("No vertex declaration"); + return false; + } + #endif - // Et on indique qu'on veut le programmer - update = true; + static const bool vaoSupported = NzOpenGL::IsSupported(NzOpenGL::VertexArrayObject); + bool update; + GLuint vao; + + // Si les VAOs sont supportés, on entoure nos appels par ceux-ci + if (vaoSupported) + { + // On recherche si un VAO existe déjà avec notre configuration + // Note: Les VAOs ne sont pas partagés entre les contextes, ces derniers font donc partie de notre configuration + + auto key = std::make_tuple(NzContext::GetCurrent(), m_indexBuffer, m_vertexBuffer, m_vertexDeclaration); + auto it = m_vaos.find(key); + if (it == m_vaos.end()) + { + // On créé notre VAO + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + // On l'ajoute à notre liste + m_vaos.insert(std::make_pair(key, static_cast(vao))); + + // Et on indique qu'on veut le programmer + update = true; + } + else + { + // Notre VAO existe déjà, il est donc inutile de le reprogrammer + vao = it->second; + + update = false; + } } else - { - // Notre VAO existe déjà, il est donc inutile de le reprogrammer - vao = it->second; + update = true; // Fallback si les VAOs ne sont pas supportés - update = false; - } - } - else - update = true; // Fallback si les VAOs ne sont pas supportés - - if (update) - { - m_vertexBuffer->GetBuffer()->GetImpl()->Bind(); - - const nzUInt8* buffer = reinterpret_cast(m_vertexBuffer->GetBufferPtr()); - - ///FIXME: Améliorer les déclarations pour permettre de faire ça plus simplement - for (int i = 0; i < 12; ++i) // Solution temporaire, à virer - glDisableVertexAttribArray(i); // Chaque itération tue un chaton :( - - unsigned int stride = m_vertexDeclaration->GetStride(); - unsigned int elementCount = m_vertexDeclaration->GetElementCount(); - for (unsigned int i = 0; i < elementCount; ++i) - { - const NzVertexDeclaration::Element* element = m_vertexDeclaration->GetElement(i); - - glEnableVertexAttribArray(attribIndex[element->usage]+element->usageIndex); - glVertexAttribPointer(attribIndex[element->usage]+element->usageIndex, - openglSize[element->type], - openglType[element->type], - (element->type == nzElementType_Color) ? GL_TRUE : GL_FALSE, - stride, - &buffer[element->offset]); - } - - if (m_indexBuffer) - m_indexBuffer->GetBuffer()->GetImpl()->Bind(); - } - - if (vaoSupported) - { - // Si nous venons de définir notre VAO, nous devons le débinder pour indiquer la fin de sa construction if (update) - glBindVertexArray(0); + { + m_vertexBuffer->GetBuffer()->GetImpl()->Bind(); - // Nous (re)bindons le VAO pour définir les attributs de vertice - glBindVertexArray(vao); + const nzUInt8* buffer = reinterpret_cast(m_vertexBuffer->GetBufferPtr()); + + ///FIXME: Améliorer les déclarations pour permettre de faire ça plus simplement + for (int i = 0; i < 12; ++i) // Solution temporaire, à virer + glDisableVertexAttribArray(i); // Chaque itération tue un chaton :( + + unsigned int stride = m_vertexDeclaration->GetStride(); + unsigned int elementCount = m_vertexDeclaration->GetElementCount(); + for (unsigned int i = 0; i < elementCount; ++i) + { + const NzVertexDeclaration::Element* element = m_vertexDeclaration->GetElement(i); + + glEnableVertexAttribArray(attribIndex[element->usage]+element->usageIndex); + glVertexAttribPointer(attribIndex[element->usage]+element->usageIndex, + openglSize[element->type], + openglType[element->type], + (element->type == nzElementType_Color) ? GL_TRUE : GL_FALSE, + stride, + &buffer[element->offset]); + } + + if (m_indexBuffer) + m_indexBuffer->GetBuffer()->GetImpl()->Bind(); + } + + if (vaoSupported) + { + // Si nous venons de définir notre VAO, nous devons le débinder pour indiquer la fin de sa construction + if (update) + glBindVertexArray(0); + + // Nous (re)bindons le VAO pour définir les attributs de vertice + glBindVertexArray(vao); + } + + m_vaoUpdated = true; } - m_statesUpdated = true; - return true; } diff --git a/src/Nazara/Renderer/Texture.cpp b/src/Nazara/Renderer/Texture.cpp index 36dad7d8f..a69dca501 100644 --- a/src/Nazara/Renderer/Texture.cpp +++ b/src/Nazara/Renderer/Texture.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -459,7 +460,7 @@ bool NzTexture::Download(NzImage* image) const if (!image) { - NazaraError("Cannot download to a null image"); + NazaraError("Image must be valid"); return false; } #endif @@ -479,12 +480,40 @@ bool NzTexture::Download(NzImage* image) const LockTexture(m_impl); + unsigned int width = m_impl->width; + unsigned int height = m_impl->height; + unsigned int depth = m_impl->depth; + nzUInt8 bpp = NzPixelFormat::GetBPP(m_impl->format); + + nzUInt8* mirrored = new nzUInt8[width*height*depth*bpp]; + // Téléchargement... for (nzUInt8 level = 0; level < m_impl->levelCount; ++level) - glGetTexImage(openglTarget[m_impl->type], level, format.dataFormat, format.dataType, image->GetPixels(level)); + { + glGetTexImage(openglTarget[m_impl->type], level, format.dataFormat, format.dataType, mirrored); + + // Inversion de la texture pour le repère d'OpenGL + ///FIXME: Gérer l'inversion dans NzImage, et gérer également les images compressées + unsigned int faceSize = width*height*bpp; + + nzUInt8* ptr = mirrored; + for (unsigned int d = 0; d < depth; ++d) + { + for (unsigned int j = 0; j < height/2; ++j) + std::swap_ranges(&ptr[j*width*bpp], &ptr[(j+1)*width*bpp-1], &ptr[(height-j-1)*width*bpp]); + + ptr += faceSize; + } + + width = std::max(width >> 1, 1U); + height = std::max(height >> 1, 1U); + depth = std::max(depth >> 1, 1U); + } UnlockTexture(m_impl); + delete[] mirrored; + return true; } @@ -534,12 +563,12 @@ unsigned int NzTexture::GetAnisotropyLevel() const LockTexture(m_impl); - GLfloat anisotropyLevel; - glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropyLevel); + GLint anisotropyLevel; + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropyLevel); UnlockTexture(m_impl); - return static_cast(anisotropyLevel); + return anisotropyLevel; } nzUInt8 NzTexture::GetBPP() const @@ -853,7 +882,7 @@ bool NzTexture::SetAnisotropyLevel(unsigned int anistropyLevel) LockTexture(m_impl); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast(anistropyLevel)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anistropyLevel); UnlockTexture(m_impl); @@ -1058,56 +1087,16 @@ bool NzTexture::Update(const nzUInt8* pixels, nzUInt8 level) NazaraError("Texture must be valid"); return false; } - - if (m_impl->type == nzImageType_Cubemap) - { - NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); - return false; - } - - if (!pixels) - { - NazaraError("Invalid pixel source"); - return false; - } - - if (level >= m_impl->levelCount) - { - NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_impl->levelCount) + ')'); - return false; - } #endif - OpenGLFormat format; - if (!GetOpenGLFormat(m_impl->format, &format)) + if (m_impl->type == nzImageType_3D) { - NazaraError("Failed to get OpenGL format"); + NazaraInternalError("Not implemented yet, sorry"); return false; + //return Update(pixels, NzCube(0, 0, 0, std::max(m_impl->width >> level, 1U), std::max(m_impl->height >> level, 1U), std::max(m_impl->depth >> level, 1U)), level); } - - LockTexture(m_impl); - - switch (m_impl->type) - { - case nzImageType_1D: - glTexSubImage1D(GL_TEXTURE_1D, level, 0, std::max(m_impl->width >> level, 1U), format.dataFormat, format.dataType, pixels); - break; - - case nzImageType_2D: - glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, std::max(m_impl->width >> level, 1U), std::max(m_impl->height >> level, 1U), format.dataFormat, format.dataType, pixels); - break; - - case nzImageType_3D: - glTexSubImage3D(GL_TEXTURE_3D, level, 0, 0, 0, std::max(m_impl->width >> level, 1U), std::max(m_impl->height >> level, 1U), std::max(m_impl->depth >> level, 1U), format.dataFormat, format.dataType, pixels); - break; - - default: - NazaraInternalError("Image type not handled (0x" + NzString::Number(m_impl->type, 16) + ')'); - } - - UnlockTexture(m_impl); - - return true; + else + return Update(pixels, NzRectui(0, 0, std::max(m_impl->width >> level, 1U), std::max(m_impl->height >> level, 1U)), 0, level); } bool NzTexture::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z, nzUInt8 level) @@ -1163,20 +1152,32 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int return false; } + nzUInt8 bpp = NzPixelFormat::GetBPP(m_impl->format); + + // Inversion de la texture pour le repère d'OpenGL + ///FIXME: Gérer l'inversion dans NzImage, et gérer également les images compressées + unsigned int size = rect.width*rect.height*bpp; + nzUInt8* mirrored = new nzUInt8[size]; + std::memcpy(mirrored, pixels, size); + + nzUInt8* ptr = &mirrored[size*z]; + for (unsigned int j = 0; j < rect.height/2; ++j) + std::swap_ranges(&ptr[j*rect.width*bpp], &ptr[(j+1)*rect.width*bpp-1], &ptr[(rect.height-j-1)*rect.width*bpp]); + LockTexture(m_impl); switch (m_impl->type) { case nzImageType_1D: - glTexSubImage1D(GL_TEXTURE_1D, level, rect.x, rect.width, format.dataFormat, format.dataType, pixels); + glTexSubImage1D(GL_TEXTURE_1D, level, rect.x, rect.width, format.dataFormat, format.dataType, mirrored); break; case nzImageType_2D: - glTexSubImage2D(GL_TEXTURE_2D, level, rect.x, rect.y, rect.width, rect.height, format.dataFormat, format.dataType, pixels); + glTexSubImage2D(GL_TEXTURE_2D, level, rect.x, rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored); break; case nzImageType_3D: - glTexSubImage3D(GL_TEXTURE_3D, level, rect.x, rect.y, z, rect.width, rect.height, 1, format.dataFormat, format.dataType, pixels); + glTexSubImage3D(GL_TEXTURE_3D, level, rect.x, rect.y, z, rect.width, rect.height, 1, format.dataFormat, format.dataType, mirrored); break; default: @@ -1185,6 +1186,8 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int UnlockTexture(m_impl); + delete[] mirrored; + return true; } /* @@ -1237,20 +1240,38 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 leve return false; } + nzUInt8 bpp = NzPixelFormat::GetBPP(m_impl->format); + + // Inversion de la texture pour le repère d'OpenGL + ///FIXME: Gérer l'inversion dans NzImage, et gérer également les images compressées + unsigned int faceSize = cube.width*cube.height*bpp; + unsigned int size = faceSize*cube.depth; + nzUInt8* mirrored = new nzUInt8[size]; + std::memcpy(mirrored, pixels, size); + + nzUInt8* ptr = mirrored; + for (unsigned int d = 0; d < cube.depth; ++d) + { + for (unsigned int j = 0; j < cube.height/2; ++j) + std::swap_ranges(&ptr[j*cube.width*bpp], &ptr[(j+1)*cube.width*bpp-1], &ptr[(cube.height-j-1)*cube.width*bpp]); + + ptr += faceSize; + } + LockTexture(m_impl); switch (m_impl->type) { case nzImageType_1D: - glTexSubImage1D(GL_TEXTURE_1D, level, cube.x, cube.width, format->dataFormat, format->dataType, pixels); + glTexSubImage1D(GL_TEXTURE_1D, level, cube.x, cube.width, format->dataFormat, format->dataType, mirrored); break; case nzImageType_2D: - glTexSubImage1D(GL_TEXTURE_2D, level, cube.x, cube.y, cube.width, cube.height, format->dataFormat, format->dataType, pixels); + glTexSubImage1D(GL_TEXTURE_2D, level, cube.x, cube.y, cube.width, cube.height, format->dataFormat, format->dataType, mirrored); break; case nzImageType_3D: - glTexSubImage1D(GL_TEXTURE_3D, level, cube.x, cube.y, cube.z, cube.width, cube.height, cube.depth, format->dataFormat, format->dataType, pixels); + glTexSubImage1D(GL_TEXTURE_3D, level, cube.x, cube.y, cube.z, cube.width, cube.height, cube.depth, format->dataFormat, format->dataType, mirrored); break; default: @@ -1259,6 +1280,8 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 leve UnlockTexture(m_impl); + delete[] mirrored; + return true; } */ @@ -1278,7 +1301,7 @@ bool NzTexture::UpdateFace(nzCubemapFace face, const NzImage& image, nzUInt8 lev } #endif - return UpdateFace(face, image.GetConstPixels(level), level); + return UpdateFace(face, image.GetConstPixels(level), NzRectui(0, 0, image.GetWidth(), image.GetHeight()), level); } bool NzTexture::UpdateFace(nzCubemapFace face, const NzImage& image, const NzRectui& rect, nzUInt8 level) @@ -1308,40 +1331,9 @@ bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, nzUInt8 le NazaraError("Texture must be valid"); return false; } - - if (m_impl->type != nzImageType_Cubemap) - { - NazaraError("UpdateFace is designed for cubemaps, use Update instead"); - return false; - } - - if (!pixels) - { - NazaraError("Invalid pixel source"); - return false; - } - - if (level >= m_impl->levelCount) - { - NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_impl->levelCount) + ')'); - return false; - } #endif - OpenGLFormat format; - if (!GetOpenGLFormat(m_impl->format, &format)) - { - NazaraError("Failed to get OpenGL format"); - return false; - } - - LockTexture(m_impl); - - glTexSubImage2D(cubemapFace[face], level, 0, 0, m_impl->width, m_impl->height, format.dataFormat, format.dataType, pixels); - - UnlockTexture(m_impl); - - return true; + return UpdateFace(face, pixels, NzRectui(0, 0, m_impl->width, m_impl->height), level); } bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRectui& rect, nzUInt8 level) @@ -1391,12 +1383,24 @@ bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRe return false; } + nzUInt8 bpp = NzPixelFormat::GetBPP(m_impl->format); + + // Inversion de la texture pour le repère d'OpenGL + ///FIXME: Gérer l'inversion dans NzImage, et gérer également les images compressées + unsigned int size = rect.width*rect.height*bpp; + nzUInt8* mirrored = new nzUInt8[size]; + std::memcpy(mirrored, pixels, size); + for (unsigned int j = 0; j < rect.height/2; ++j) + std::swap_ranges(&mirrored[j*rect.width*bpp], &mirrored[(j+1)*rect.width*bpp-1], &mirrored[(rect.height-j-1)*rect.width*bpp]); + LockTexture(m_impl); - glTexSubImage2D(cubemapFace[face], level, rect.x, rect.y, rect.width, rect.height, format.dataFormat, format.dataType, pixels); + glTexSubImage2D(cubemapFace[face], level, rect.x, rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored); UnlockTexture(m_impl); + delete[] mirrored; + return true; } diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index b9cb4d8dd..aeca004a7 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -729,8 +729,7 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z EnsureOwnership(); nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); - - nzUInt8* dstPixels = &m_sharedImage->pixels[level][(m_sharedImage->height*(m_sharedImage->width*z + rect.y) + rect.x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + nzUInt8* dstPixels = &m_sharedImage->pixels[level][(m_sharedImage->height*(m_sharedImage->width*z + rect.y) + rect.x) * bpp]; unsigned int srcStride = rect.width * bpp; unsigned int blockSize = m_sharedImage->width * bpp; for (unsigned int i = 0; i < rect.height; ++i) @@ -822,8 +821,7 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRect EnsureOwnership(); nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); - - nzUInt8* dstPixels = &m_sharedImage->pixels[level][(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX) + rect.y) + rect.x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + nzUInt8* dstPixels = &m_sharedImage->pixels[level][(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX) + rect.y) + rect.x) * bpp]; unsigned int srcStride = rect.width * bpp; unsigned int blockSize = m_sharedImage->width * bpp; for (unsigned int i = 0; i < rect.height; ++i) diff --git a/src/Nazara/Utility/Win32/WindowImpl.cpp b/src/Nazara/Utility/Win32/WindowImpl.cpp index f020cbdfa..946045a5c 100644 --- a/src/Nazara/Utility/Win32/WindowImpl.cpp +++ b/src/Nazara/Utility/Win32/WindowImpl.cpp @@ -202,11 +202,11 @@ NzVector2i NzWindowImpl::GetPosition() const return NzVector2i(rect.left, rect.top); } -NzVector2i NzWindowImpl::GetSize() const +NzVector2ui NzWindowImpl::GetSize() const { RECT rect; GetClientRect(m_handle, &rect); - return NzVector2i(rect.right-rect.left, rect.bottom-rect.top); + return NzVector2ui(rect.right-rect.left, rect.bottom-rect.top); } NzString NzWindowImpl::GetTitle() const @@ -689,7 +689,7 @@ bool NzWindowImpl::HandleMessage(HWND window, UINT message, WPARAM wParam, LPARA { if (wParam != SIZE_MINIMIZED) { - NzVector2i size = GetSize(); // On récupère uniquement la taille de la zone client + NzVector2ui size = GetSize(); // On récupère uniquement la taille de la zone client NzEvent event; event.type = NzEvent::Resized; diff --git a/src/Nazara/Utility/Win32/WindowImpl.hpp b/src/Nazara/Utility/Win32/WindowImpl.hpp index 48791c68c..2cc727ab0 100644 --- a/src/Nazara/Utility/Win32/WindowImpl.hpp +++ b/src/Nazara/Utility/Win32/WindowImpl.hpp @@ -45,7 +45,7 @@ class NzWindowImpl : NzNonCopyable NzWindowHandle GetHandle() const; unsigned int GetHeight() const; NzVector2i GetPosition() const; - NzVector2i GetSize() const; + NzVector2ui GetSize() const; NzString GetTitle() const; unsigned int GetWidth() const; diff --git a/src/Nazara/Utility/Window.cpp b/src/Nazara/Utility/Window.cpp index dbe29b835..1ef9c3de8 100644 --- a/src/Nazara/Utility/Window.cpp +++ b/src/Nazara/Utility/Window.cpp @@ -222,12 +222,12 @@ NzVector2i NzWindow::GetPosition() const return NzVector2i(0); } -NzVector2i NzWindow::GetSize() const +NzVector2ui NzWindow::GetSize() const { if (m_impl) return m_impl->GetSize(); else - return NzVector2i(0); + return NzVector2ui(0U); } NzString NzWindow::GetTitle() const From e2a38b37901a42c869bd447187df077e8f35b88e Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 13 Jun 2012 07:40:31 +0200 Subject: [PATCH 13/15] First part of render texture commit Added NzContext::EnsureContext and NzContext::GetThreadContext Added NzCube Added NzRect::GetCenter Added methods to send vectors to shaders Added NzRenderer::SetViewport Fixed NzRect::ExtendTo calculations Fixed NzImage::Update checks with level > 0 No longer use glTexStorage when creating a texture to prevent a bug NzBuffer's Lock and Unlock operations renamed to Map and Unmap NzVector2/3/4 can now cast implicitly to a pointer Optimized compilation time of String.hpp Optimized normalisaton of quaternions Optimized passing uniforms to shaders Quaternion now automaticaly Normalize h Removed macro definition of NAZARA_RENDERER_OPENGL from Renderer Removed implicit cast from NzVector2/3/4 to NzString Renamed nzBufferLock to nzBufferAccess Renamed NzRenderTarget::CanActivate to IsValid --- build/scripts/module/renderer.lua | 1 - include/Nazara/Core/String.hpp | 3 +- include/Nazara/Math/Cube.hpp | 58 ++++++ include/Nazara/Math/Cube.inl | 183 ++++++++++++++++++ include/Nazara/Math/Quaternion.hpp | 2 - include/Nazara/Math/Quaternion.inl | 70 +++---- include/Nazara/Math/Rect.hpp | 2 + include/Nazara/Math/Rect.inl | 12 +- include/Nazara/Math/Vector2.hpp | 3 +- include/Nazara/Math/Vector2.inl | 10 +- include/Nazara/Math/Vector3.hpp | 3 +- include/Nazara/Math/Vector3.inl | 10 +- include/Nazara/Math/Vector4.hpp | 3 +- include/Nazara/Math/Vector4.inl | 10 +- include/Nazara/Prerequesites.hpp | 5 + include/Nazara/Renderer/Buffer.hpp | 14 +- include/Nazara/Renderer/Context.hpp | 9 +- include/Nazara/Renderer/IndexBuffer.hpp | 4 +- include/Nazara/Renderer/OpenGL.hpp | 12 ++ include/Nazara/Renderer/RenderTarget.hpp | 11 +- include/Nazara/Renderer/RenderWindow.hpp | 21 +-- include/Nazara/Renderer/Renderer.hpp | 5 +- include/Nazara/Renderer/Shader.hpp | 9 + include/Nazara/Renderer/Texture.hpp | 11 +- include/Nazara/Renderer/VertexBuffer.hpp | 4 +- include/Nazara/Utility/Image.hpp | 3 +- include/Nazara/Utility/PixelFormat.hpp | 10 + include/Nazara/Utility/PixelFormat.inl | 35 ++-- src/Nazara/Core/File.cpp | 2 +- src/Nazara/Core/MemoryStream.cpp | 2 +- src/Nazara/Core/Win32/ThreadImpl.cpp | 2 +- src/Nazara/Renderer/Buffer.cpp | 16 +- src/Nazara/Renderer/BufferImpl.hpp | 4 +- src/Nazara/Renderer/Context.cpp | 57 +++++- src/Nazara/Renderer/GLSLShader.cpp | 204 +++++++++++++++++--- src/Nazara/Renderer/GLSLShader.hpp | 7 +- src/Nazara/Renderer/HardwareBuffer.cpp | 79 ++++---- src/Nazara/Renderer/HardwareBuffer.hpp | 4 +- src/Nazara/Renderer/IndexBuffer.cpp | 10 +- src/Nazara/Renderer/OcclusionQuery.cpp | 27 +++ src/Nazara/Renderer/OpenGL.cpp | 106 ++++++----- src/Nazara/Renderer/RenderTarget.cpp | 2 +- src/Nazara/Renderer/RenderWindow.cpp | 53 ++++-- src/Nazara/Renderer/Renderer.cpp | 217 +++++++++++++++------ src/Nazara/Renderer/Shader.cpp | 101 +++++++++- src/Nazara/Renderer/ShaderImpl.hpp | 6 + src/Nazara/Renderer/SoftwareBuffer.cpp | 33 ++-- src/Nazara/Renderer/SoftwareBuffer.hpp | 6 +- src/Nazara/Renderer/Texture.cpp | 231 ++++++++++++++++------- src/Nazara/Renderer/VertexBuffer.cpp | 8 +- src/Nazara/Utility/Image.cpp | 96 +++++++++- src/Nazara/Utility/Loaders/STB.cpp | 11 +- src/Nazara/Utility/PixelFormat.cpp | 2 +- src/Nazara/Utility/Win32/InputImpl.cpp | 4 +- src/Nazara/Utility/Win32/WindowImpl.cpp | 4 +- 55 files changed, 1400 insertions(+), 417 deletions(-) create mode 100644 include/Nazara/Math/Cube.hpp create mode 100644 include/Nazara/Math/Cube.inl diff --git a/build/scripts/module/renderer.lua b/build/scripts/module/renderer.lua index 872e48798..4945e717e 100644 --- a/build/scripts/module/renderer.lua +++ b/build/scripts/module/renderer.lua @@ -1,6 +1,5 @@ project "NazaraRenderer" -defines "NAZARA_RENDERER_OPENGL" links "gdi32" links "opengl32" links "winmm" diff --git a/include/Nazara/Core/String.hpp b/include/Nazara/Core/String.hpp index 0d85c4e9f..43d3d9680 100644 --- a/include/Nazara/Core/String.hpp +++ b/include/Nazara/Core/String.hpp @@ -9,8 +9,7 @@ #include #include -#include -#include +#include #include #include diff --git a/include/Nazara/Math/Cube.hpp b/include/Nazara/Math/Cube.hpp new file mode 100644 index 000000000..bbc98dae4 --- /dev/null +++ b/include/Nazara/Math/Cube.hpp @@ -0,0 +1,58 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_CUBE_HPP +#define NAZARA_CUBE_HPP + +#include +#include + +template +class NzCube +{ + public: + NzCube(); + NzCube(T X, T Y, T Z, T Width, T Height, T Depth); + NzCube(T cube[6]); + template explicit NzCube(const NzCube& rect); + NzCube(const NzCube& rect) = default; + ~NzCube() = default; + + bool Contains(T X, T Y, T Z) const; + bool Contains(const NzVector3& point) const; + bool Contains(const NzCube& rect) const; + + void ExtendTo(const NzVector3& point); + void ExtendTo(const NzCube& rect); + + NzVector3 GetCenter() const; + + bool Intersect(const NzCube& rect) const; + bool Intersect(const NzCube& rect, NzCube& intersection) const; + + bool IsValid() const; + + NzString ToString() const; + + operator NzString() const; + + T& operator[](unsigned int i); + T operator[](unsigned int i) const; + + T x, y, z, width, height, depth; +}; + +template +std::ostream& operator<<(std::ostream& out, const NzCube& vec); + +typedef NzCube NzCubed; +typedef NzCube NzCubef; +typedef NzCube NzCubei; +typedef NzCube NzCubeui; + +#include + +#endif // NAZARA_CUBE_HPP diff --git a/include/Nazara/Math/Cube.inl b/include/Nazara/Math/Cube.inl new file mode 100644 index 000000000..f281dc824 --- /dev/null +++ b/include/Nazara/Math/Cube.inl @@ -0,0 +1,183 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +template +NzCube::NzCube() +{ +} + +template +NzCube::NzCube(T X, T Y, T Z, T Width, T Height, T Depth) : +x(X), +y(Y), +z(Z), +width(Width), +height(Height), +depth(Depth) +{ +} + +template +NzCube::NzCube(T vec[6]) : +x(vec[0]), +y(vec[1]), +z(vec[2]), +width(vec[3]), +height(vec[4]), +depth(vec[5]) +{ +} + +template +template +NzCube::NzCube(const NzCube& rect) : +x(static_cast(rect.x)), +y(static_cast(rect.y)), +z(static_cast(rect.z)), +width(static_cast(rect.width)), +height(static_cast(rect.height)), +depth(static_cast(rect.depth)) +{ +} + +template +bool NzCube::Contains(T X, T Y, T Z) const +{ + return X >= x && X < x+width && + Y >= y && Y < y+height && + Z >= z && Z < z+depth; +} + +template +bool NzCube::Contains(const NzVector3& point) const +{ + return Contains(point.x, point.y, point.z); +} + +template +bool NzCube::Contains(const NzCube& rect) const +{ + return Contains(rect.x, rect.y, rect.z) && + Contains(rect.x + rect.width, rect.y + rect.height, rect.z + rect.depth); +} + +template +void NzCube::ExtendTo(const NzVector3& point) +{ + x = std::min(x, point.x); + y = std::min(y, point.y); + z = std::min(z, point.z); + width = std::max(x+width, point.x)-x; + height = std::max(y+height, point.x)-y; + depth = std::max(z+depth, point.x)-z; +} + +template +void NzCube::ExtendTo(const NzCube& rect) +{ + x = std::min(x, rect.x); + y = std::min(y, rect.y); + z = std::min(y, rect.z); + width = std::max(x+width, rect.x+rect.width)-x; + height = std::max(x+height, rect.y+rect.height)-y; + depth = std::max(x+depth, rect.z+rect.depth)-z; +} + +template +NzVector3 NzCube::GetCenter() const +{ + return NzVector3((x+width)/2, (y+height)/2, (z+depth)/2); +} + +template +bool NzCube::Intersect(const NzCube& rect) const +{ + NzCube intersection; // Optimisé par le compilateur + return Intersect(rect, intersection); +} + +template +bool NzCube::Intersect(const NzCube& rect, NzCube& intersection) const +{ + T left = std::max(x, rect.x); + T right = std::min(x+width, rect.x+rect.width); + T top = std::max(y, rect.y); + T bottom = std::min(y+height, rect.y+rect.height); + T up = std::max(z, rect.z); + T down = std::min(z+depth, rect.z+rect.depth); + + if (left < right && top < bottom && up < down) + { + intersection.x = left; + intersection.y = top; + intersection.z = up; + intersection.width = right-left; + intersection.height = bottom-top; + intersection.depth = down-up; + + return true; + } + else + return false; +} + +template +bool NzCube::IsValid() const +{ + return width > 0 && height > 0 && depth > 0; +} + +template +NzString NzCube::ToString() const +{ + NzStringStream ss; + + return ss << "Cube(" << x << ", " << y << ", " << z << ", " << width << ", " << height << ", " << depth << ')'; +} + +template +NzCube::operator NzString() const +{ + return ToString(); +} + +template +T& NzCube::operator[](unsigned int i) +{ + if (i >= 6) + { + NzStringStream ss; + ss << __FILE__ << ':' << __LINE__ << ": Index out of range (" << i << " >= 4)"; + + throw std::domain_error(ss.ToString()); + } + + return *(&x+i); +} + +template +T NzCube::operator[](unsigned int i) const +{ + if (i >= 6) + { + NzStringStream ss; + ss << __FILE__ << ':' << __LINE__ << ": Index out of range (" << i << " >= 4)"; + + throw std::domain_error(ss.ToString()); + } + + return *(&x+i); +} + +template +std::ostream& operator<<(std::ostream& out, const NzCube& rect) +{ + return out << rect.ToString(); +} + +#include diff --git a/include/Nazara/Math/Quaternion.hpp b/include/Nazara/Math/Quaternion.hpp index 4d98f8e34..a36a7c4e6 100644 --- a/include/Nazara/Math/Quaternion.hpp +++ b/include/Nazara/Math/Quaternion.hpp @@ -47,13 +47,11 @@ template class NzQuaternion //NzMatrix3 ToRotationMatrix() const; NzString ToString() const; - NzQuaternion operator+(const NzQuaternion& quat) const; NzQuaternion operator*(const NzQuaternion& quat) const; NzVector3 operator*(const NzVector3& vec) const; NzQuaternion operator*(T scale) const; NzQuaternion operator/(const NzQuaternion& quat) const; - NzQuaternion operator+=(const NzQuaternion& quat); NzQuaternion operator*=(const NzQuaternion& quat); NzQuaternion operator*=(T scale); NzQuaternion operator/=(const NzQuaternion& quat); diff --git a/include/Nazara/Math/Quaternion.inl b/include/Nazara/Math/Quaternion.inl index 09c7bd0c0..1017798df 100644 --- a/include/Nazara/Math/Quaternion.inl +++ b/include/Nazara/Math/Quaternion.inl @@ -76,17 +76,21 @@ double NzQuaternion::Magnitude() const template double NzQuaternion::Normalize() { - double length = Magnitude(); + T squaredLength = SquaredMagnitude(); - if (length != 0.0) + if (std::fabs(squaredLength) > 0.00001 && std::fabs(squaredLength - 1.0) > 0.00001) { + double length = std::sqrt(squaredLength); + w /= length; x /= length; y /= length; z /= length; - } - return length; + return length; + } + else + return std::sqrt(squaredLength); } template @@ -102,6 +106,8 @@ void NzQuaternion::Set(T W, T X, T Y, T Z) x = X; y = Y; z = Z; + + Normalize(); } template @@ -111,6 +117,8 @@ void NzQuaternion::Set(T quat[4]) x = quat[1]; y = quat[2]; z = quat[3]; + + Normalize(); } template @@ -195,35 +203,32 @@ NzString NzQuaternion::ToString() const return ss << "Quaternion(" << w << " | " << x << ", " << y << ", " << z << ')'; } -template -NzQuaternion NzQuaternion::operator+(const NzQuaternion& quat) const -{ - return NzQuaternion(w + quat.w, - x + quat.x, - y + quat.y, - z + quat.z); -} - template NzQuaternion NzQuaternion::operator*(const NzQuaternion& quat) const { - return NzQuaternion(w * quat.w - x * quat.x - y * quat.y - z * quat.z, - w * quat.x + x * quat.w + y * quat.z - z * quat.y, - w * quat.y + y * quat.w + z * quat.x - x * quat.z, - w * quat.z + z * quat.w + x * quat.y - y * quat.x); + NzQuaternion result(w * quat.w - x * quat.x - y * quat.y - z * quat.z, + w * quat.x + x * quat.w + y * quat.z - z * quat.y, + w * quat.y + y * quat.w + z * quat.x - x * quat.z, + w * quat.z + z * quat.w + x * quat.y - y * quat.x); + + result.Normalize(); + + return result; } template NzVector3 NzQuaternion::operator*(const NzVector3& vec) const { - NzVector3 uv, uuv; - NzVector3 qvec(x, y, z); - uv = qvec.CrossProduct(vec); - uuv = qvec.CrossProduct(uv); - uv *= 2.0 * w; - uuv *= 2.0; + NzVector3 normal(vec); + normal.Normalise(); + + NzQuaternion qvec(0.0, normal.x, normal.y, normal.z); + NzQuaternion result; + + result = operator*(qvec * GetConjugate()); + + return NzVector3(result.x, result.y, result.z); - return vec + uv + uuv; } template @@ -241,24 +246,12 @@ NzQuaternion NzQuaternion::operator/(const NzQuaternion& quat) const return GetConjugate(quat) * (*this); } -template -NzQuaternion NzQuaternion::operator+=(const NzQuaternion& quat) -{ - w += quat.w; - x += quat.x; - y += quat.y; - z += quat.z; - - return *this; -} - template NzQuaternion NzQuaternion::operator*=(const NzQuaternion& quat) { NzQuaternion q(*this); - operator=(q * quat); - return *this; + return operator=(q * quat); } template @@ -276,9 +269,8 @@ template NzQuaternion NzQuaternion::operator/=(const NzQuaternion& quat) { NzQuaternion q(*this); - operator=(q / quat); - return *this; + return operator=(q / quat); } template diff --git a/include/Nazara/Math/Rect.hpp b/include/Nazara/Math/Rect.hpp index b0ac31d52..4669c801d 100644 --- a/include/Nazara/Math/Rect.hpp +++ b/include/Nazara/Math/Rect.hpp @@ -28,6 +28,8 @@ class NzRect void ExtendTo(const NzVector2& point); void ExtendTo(const NzRect& rect); + NzVector2 GetCenter() const; + bool Intersect(const NzRect& rect) const; bool Intersect(const NzRect& rect, NzRect& intersection) const; diff --git a/include/Nazara/Math/Rect.inl b/include/Nazara/Math/Rect.inl index 964708361..97dab6292 100644 --- a/include/Nazara/Math/Rect.inl +++ b/include/Nazara/Math/Rect.inl @@ -65,7 +65,7 @@ void NzRect::ExtendTo(const NzVector2& point) x = std::min(x, point.x); y = std::min(y, point.y); width = std::max(x+width, point.x)-x; - height = std::max(x+width, point.x)-y; + height = std::max(y+height, point.y)-y; } template @@ -74,7 +74,13 @@ void NzRect::ExtendTo(const NzRect& rect) x = std::min(x, rect.x); y = std::min(y, rect.y); width = std::max(x+width, rect.x+rect.width)-x; - height = std::max(x+width, rect.x+rect.height)-y; + height = std::max(x+height, rect.y+rect.height)-y; +} + +template +NzVector2 NzRect::GetCenter() const +{ + return NzVector2((x+width)/2, (y+height)/2); } template @@ -97,7 +103,7 @@ bool NzRect::Intersect(const NzRect& rect, NzRect& intersection) const intersection.x = left; intersection.y = top; intersection.width = right-left; - intersection.height = top-bottom; + intersection.height = bottom-top; return true; } diff --git a/include/Nazara/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index e550890c4..bd2c54017 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -33,7 +33,8 @@ template class NzVector2 NzString ToString() const; - operator NzString() const; + operator T*(); + operator const T*() const; T& operator[](unsigned int i); T operator[](unsigned int i) const; diff --git a/include/Nazara/Math/Vector2.inl b/include/Nazara/Math/Vector2.inl index f01f14146..3026f860b 100644 --- a/include/Nazara/Math/Vector2.inl +++ b/include/Nazara/Math/Vector2.inl @@ -136,9 +136,15 @@ NzString NzVector2::ToString() const } template -NzVector2::operator NzString() const +NzVector2::operator T*() { - return ToString(); + return &x; +} + +template +NzVector2::operator const T*() const +{ + return &x; } template diff --git a/include/Nazara/Math/Vector3.hpp b/include/Nazara/Math/Vector3.hpp index b658960c3..bd0dc9b35 100644 --- a/include/Nazara/Math/Vector3.hpp +++ b/include/Nazara/Math/Vector3.hpp @@ -34,7 +34,8 @@ template class NzVector3 NzString ToString() const; - operator NzString() const; + operator T*(); + operator const T*() const; T& operator[](unsigned int i); T operator[](unsigned int i) const; diff --git a/include/Nazara/Math/Vector3.inl b/include/Nazara/Math/Vector3.inl index 91cec9fad..40e1cabb7 100644 --- a/include/Nazara/Math/Vector3.inl +++ b/include/Nazara/Math/Vector3.inl @@ -153,9 +153,15 @@ NzString NzVector3::ToString() const } template -NzVector3::operator NzString() const +NzVector3::operator T*() { - return ToString(); + return &x; +} + +template +NzVector3::operator const T*() const +{ + return &x; } template diff --git a/include/Nazara/Math/Vector4.hpp b/include/Nazara/Math/Vector4.hpp index 2f8d4860e..afd108acb 100644 --- a/include/Nazara/Math/Vector4.hpp +++ b/include/Nazara/Math/Vector4.hpp @@ -28,7 +28,8 @@ template class NzVector4 NzString ToString() const; - operator NzString() const; + operator T*(); + operator const T*() const; T& operator[](unsigned int i); T operator[](unsigned int i) const; diff --git a/include/Nazara/Math/Vector4.inl b/include/Nazara/Math/Vector4.inl index 9073d37b0..3ee1f4165 100644 --- a/include/Nazara/Math/Vector4.inl +++ b/include/Nazara/Math/Vector4.inl @@ -120,9 +120,15 @@ NzString NzVector4::ToString() const } template -NzVector4::operator NzString() const +NzVector4::operator T*() { - return ToString(); + return &x; +} + +template +NzVector4::operator const T*() const +{ + return &x; } template diff --git a/include/Nazara/Prerequesites.hpp b/include/Nazara/Prerequesites.hpp index 2a3fe5140..8acfc19f5 100644 --- a/include/Nazara/Prerequesites.hpp +++ b/include/Nazara/Prerequesites.hpp @@ -17,22 +17,27 @@ #include ///TODO: Rajouter des tests d'identification de compilateurs +// NAZARA_THREADLOCAL n'existe qu'en attendant le support complet de thread_local #if defined(_MSC_VER) #define NAZARA_COMPILER_MSVC #define NAZARA_DEPRECATED(txt) __declspec(deprecated(txt)) #define NAZARA_FUNCTION __FUNCSIG__ + #define NAZARA_THREADLOCAL __declspec(thread) #elif defined(__GNUC__) #define NAZARA_COMPILER_GCC #define NAZARA_DEPRECATED(txt) __attribute__((__deprecated__(txt))) #define NAZARA_FUNCTION __PRETTY_FUNCTION__ + #define NAZARA_THREADLOCAL __thread #elif defined(__BORLANDC__) #define NAZARA_COMPILER_BORDLAND #define NAZARA_DEPRECATED(txt) #define NAZARA_FUNCTION __FUNC__ + #define NAZARA_THREADLOCAL __declspec(thread) #else #define NAZARA_COMPILER_UNKNOWN #define NAZARA_DEPRECATED(txt) #define NAZARA_FUNCTION __func__ // __func__ est standard depuis le C++11 + #define NAZARA_THREADLOCAL thread_local #error This compiler is not fully supported #endif diff --git a/include/Nazara/Renderer/Buffer.hpp b/include/Nazara/Renderer/Buffer.hpp index 8176f1c61..c023ade1c 100644 --- a/include/Nazara/Renderer/Buffer.hpp +++ b/include/Nazara/Renderer/Buffer.hpp @@ -11,12 +11,12 @@ #include #include -enum nzBufferLock +enum nzBufferAccess { - nzBufferLock_DiscardAndWrite, - nzBufferLock_ReadOnly, - nzBufferLock_ReadWrite, - nzBufferLock_WriteOnly + nzBufferAccess_DiscardAndWrite, + nzBufferAccess_ReadOnly, + nzBufferAccess_ReadWrite, + nzBufferAccess_WriteOnly }; enum nzBufferStorage @@ -68,8 +68,8 @@ class NAZARA_API NzBuffer : public NzResource, NzNonCopyable bool IsHardware() const; - void* Lock(nzBufferLock lock, unsigned int offset = 0, unsigned int length = 0); - bool Unlock(); + void* Map(nzBufferAccess access, unsigned int offset = 0, unsigned int length = 0); + bool Unmap(); static bool IsSupported(nzBufferStorage storage); diff --git a/include/Nazara/Renderer/Context.hpp b/include/Nazara/Renderer/Context.hpp index 9c489c390..08da75937 100644 --- a/include/Nazara/Renderer/Context.hpp +++ b/include/Nazara/Renderer/Context.hpp @@ -30,11 +30,12 @@ class NAZARA_API NzContext bool SetActive(bool active); void SwapBuffers(); - static const NzContext* GetCurrent(); + static bool EnsureContext(); + static NzContext* GetCurrent(); static const NzContext* GetReference(); - static const NzContext* GetThreadContext(); - static bool InitializeReference(); - static void UninitializeReference(); + static NzContext* GetThreadContext(); + static bool Initialize(); + static void Uninitialize(); private: NzContextParameters m_parameters; diff --git a/include/Nazara/Renderer/IndexBuffer.hpp b/include/Nazara/Renderer/IndexBuffer.hpp index a7b4a9015..b3a50b1d0 100644 --- a/include/Nazara/Renderer/IndexBuffer.hpp +++ b/include/Nazara/Renderer/IndexBuffer.hpp @@ -30,8 +30,8 @@ class NAZARA_API NzIndexBuffer bool IsHardware() const; bool IsSequential() const; - void* Lock(nzBufferLock lock, unsigned int offset = 0, unsigned int length = 0); - bool Unlock(); + void* Map(nzBufferAccess access, unsigned int offset = 0, unsigned int length = 0); + bool Unmap(); private: NzBuffer* m_buffer; diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index 8b2761c84..0deb0b068 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -37,6 +37,7 @@ class NAZARA_API NzOpenGL DebugOutput, FP64, FrameBufferObject, + SeparateShaderObjects, Texture3D, TextureCompression_s3tc, TextureStorage, @@ -131,6 +132,17 @@ NAZARA_API extern PFNGLLINKPROGRAMPROC glLinkProgram; NAZARA_API extern PFNGLMAPBUFFERPROC glMapBuffer; NAZARA_API extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange; NAZARA_API extern PFNGLPOLYGONMODEPROC glPolygonMode; +NAZARA_API extern PFNGLPROGRAMUNIFORM1DPROC glProgramUniform1d; +NAZARA_API extern PFNGLPROGRAMUNIFORM1FPROC glProgramUniform1f; +NAZARA_API extern PFNGLPROGRAMUNIFORM1IPROC glProgramUniform1i; +NAZARA_API extern PFNGLPROGRAMUNIFORM2DVPROC glProgramUniform2dv; +NAZARA_API extern PFNGLPROGRAMUNIFORM2FVPROC glProgramUniform2fv; +NAZARA_API extern PFNGLPROGRAMUNIFORM3DVPROC glProgramUniform3dv; +NAZARA_API extern PFNGLPROGRAMUNIFORM3FVPROC glProgramUniform3fv; +NAZARA_API extern PFNGLPROGRAMUNIFORM4DVPROC glProgramUniform4dv; +NAZARA_API extern PFNGLPROGRAMUNIFORM4FVPROC glProgramUniform4fv; +NAZARA_API extern PFNGLPROGRAMUNIFORMMATRIX4DVPROC glProgramUniformMatrix4dv; +NAZARA_API extern PFNGLPROGRAMUNIFORMMATRIX4FVPROC glProgramUniformMatrix4fv; NAZARA_API extern PFNGLREADPIXELSPROC glReadPixels; NAZARA_API extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; NAZARA_API extern PFNGLSCISSORPROC glScissor; diff --git a/include/Nazara/Renderer/RenderTarget.hpp b/include/Nazara/Renderer/RenderTarget.hpp index 1b5ce9858..8a065a31c 100644 --- a/include/Nazara/Renderer/RenderTarget.hpp +++ b/include/Nazara/Renderer/RenderTarget.hpp @@ -21,15 +21,16 @@ class NAZARA_API NzRenderTarget NzRenderTarget() = default; virtual ~NzRenderTarget(); - virtual bool CanActivate() const = 0; - - virtual NzRenderTargetParameters GetRenderTargetParameters() const = 0; - - #ifdef NAZARA_RENDERER_OPENGL + #ifndef NAZARA_RENDERER_COMMON virtual bool HasContext() const = 0; #endif + virtual unsigned int GetHeight() const = 0; + virtual NzRenderTargetParameters GetParameters() const = 0; + virtual unsigned int GetWidth() const = 0; + bool IsActive() const; + virtual bool IsValid() const = 0; bool SetActive(bool active); diff --git a/include/Nazara/Renderer/RenderWindow.hpp b/include/Nazara/Renderer/RenderWindow.hpp index 2c43579ec..fabd16265 100644 --- a/include/Nazara/Renderer/RenderWindow.hpp +++ b/include/Nazara/Renderer/RenderWindow.hpp @@ -10,13 +10,10 @@ #define NAZARA_RENDERWINDOW_HPP #include -#include #include -#include - -#ifndef NAZARA_RENDERER_COMMON #include -#endif +#include +#include class NzContext; class NzImage; @@ -25,16 +22,12 @@ struct NzContextParameters; class NAZARA_API NzRenderWindow : public NzRenderTarget, public NzWindow { - friend class NzTexture; - public: NzRenderWindow(); NzRenderWindow(NzVideoMode mode, const NzString& title, nzUInt32 style = NzWindow::Default, const NzContextParameters& parameters = NzContextParameters()); NzRenderWindow(NzWindowHandle handle, const NzContextParameters& parameters = NzContextParameters()); virtual ~NzRenderWindow(); - bool CanActivate() const; - bool CopyToImage(NzImage* image); ///TODO: Const bool CopyToTexture(NzTexture* texture); ///TODO: Const @@ -45,14 +38,20 @@ class NAZARA_API NzRenderWindow : public NzRenderTarget, public NzWindow void EnableVerticalSync(bool enabled); - NzRenderTargetParameters GetRenderTargetParameters() const; - #ifndef NAZARA_RENDERER_COMMON NzContextParameters GetContextParameters() const; + #endif + unsigned int GetHeight() const; + NzRenderTargetParameters GetParameters() const; + unsigned int GetWidth() const; + + #ifndef NAZARA_RENDERER_COMMON bool HasContext() const; #endif + bool IsValid() const; + protected: bool Activate(); diff --git a/include/Nazara/Renderer/Renderer.hpp b/include/Nazara/Renderer/Renderer.hpp index aab95ab7c..6296f22f5 100644 --- a/include/Nazara/Renderer/Renderer.hpp +++ b/include/Nazara/Renderer/Renderer.hpp @@ -8,6 +8,7 @@ #define NAZARA_RENDERER_HPP #include +#include #include #include @@ -87,7 +88,6 @@ enum nzRendererComparison enum nzRendererParameter { - nzRendererParameter_AlphaTest, nzRendererParameter_Blend, nzRendererParameter_ColorWrite, nzRendererParameter_DepthTest, @@ -135,10 +135,12 @@ class NAZARA_API NzRenderer unsigned int GetMaxTextureUnits() const; NzShader* GetShader() const; NzRenderTarget* GetTarget() const; + NzRectui GetViewport() const; bool HasCapability(nzRendererCap capability) const; bool Initialize(); + void SetBlendFunc(nzBlendFunc src, nzBlendFunc dest); void SetClearColor(const NzColor& color); void SetClearColor(nzUInt8 r, nzUInt8 g, nzUInt8 b, nzUInt8 a = 255); void SetClearDepth(double depth); @@ -156,6 +158,7 @@ class NAZARA_API NzRenderer bool SetTarget(NzRenderTarget* target); bool SetVertexBuffer(const NzVertexBuffer* vertexBuffer); bool SetVertexDeclaration(const NzVertexDeclaration* vertexDeclaration); + void SetViewport(const NzRectui& viewport); void Uninitialize(); diff --git a/include/Nazara/Renderer/Shader.hpp b/include/Nazara/Renderer/Shader.hpp index 79d0402de..b060c9bde 100644 --- a/include/Nazara/Renderer/Shader.hpp +++ b/include/Nazara/Renderer/Shader.hpp @@ -11,6 +11,9 @@ #include #include #include +#include +#include +#include #include enum nzShaderLanguage @@ -66,6 +69,12 @@ class NAZARA_API NzShader : public NzResource, NzNonCopyable bool SendInteger(const NzString& name, int value); bool SendMatrix(const NzString& name, const NzMatrix4d& matrix); bool SendMatrix(const NzString& name, const NzMatrix4f& matrix); + bool SendVector(const NzString& name, const NzVector2d& vector); + bool SendVector(const NzString& name, const NzVector2f& vector); + bool SendVector(const NzString& name, const NzVector3d& vector); + bool SendVector(const NzString& name, const NzVector3f& vector); + bool SendVector(const NzString& name, const NzVector4d& vector); + bool SendVector(const NzString& name, const NzVector4f& vector); bool SendTexture(const NzString& name, NzTexture* texture); void Unlock(); diff --git a/include/Nazara/Renderer/Texture.hpp b/include/Nazara/Renderer/Texture.hpp index 01b69b115..98df54f38 100644 --- a/include/Nazara/Renderer/Texture.hpp +++ b/include/Nazara/Renderer/Texture.hpp @@ -39,7 +39,9 @@ class NAZARA_API NzTexture : public NzResource, NzNonCopyable explicit NzTexture(const NzImage& image); ~NzTexture(); - bool Bind(); + #ifndef NAZARA_RENDERER_COMMON + bool Bind() const; + #endif bool Create(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth = 1, nzUInt8 levelCount = 1, bool lock = false); void Destroy(); @@ -60,6 +62,7 @@ class NAZARA_API NzTexture : public NzResource, NzNonCopyable bool IsCompressed() const; bool IsCubemap() const; + bool IsTarget() const; bool IsValid() const; bool LoadFromFile(const NzString& filePath, const NzImageParams& params = NzImageParams()); @@ -76,10 +79,10 @@ class NAZARA_API NzTexture : public NzResource, NzNonCopyable bool Update(const NzImage& image, nzUInt8 level = 0); bool Update(const NzImage& image, const NzRectui& rect, unsigned int z = 0, nzUInt8 level = 0); - //bool Update(const NzImage& image, const NzCubeui& cube, nzUInt8 level = 0); + bool Update(const NzImage& image, const NzCubeui& cube, nzUInt8 level = 0); bool Update(const nzUInt8* pixels, nzUInt8 level = 0); bool Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z = 0, nzUInt8 level = 0); - //bool Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level = 0); + bool Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level = 0); bool UpdateFace(nzCubemapFace face, const NzImage& image, nzUInt8 level = 0); bool UpdateFace(nzCubemapFace face, const NzImage& image, const NzRectui& rect, nzUInt8 level = 0); bool UpdateFace(nzCubemapFace face, const nzUInt8* pixels, nzUInt8 level = 0); @@ -92,6 +95,8 @@ class NAZARA_API NzTexture : public NzResource, NzNonCopyable static bool IsTypeSupported(nzImageType type); private: + void SetTarget(bool isTarget); + NzTextureImpl* m_impl; }; diff --git a/include/Nazara/Renderer/VertexBuffer.hpp b/include/Nazara/Renderer/VertexBuffer.hpp index 721b32ee4..a4634d78a 100644 --- a/include/Nazara/Renderer/VertexBuffer.hpp +++ b/include/Nazara/Renderer/VertexBuffer.hpp @@ -29,8 +29,8 @@ class NAZARA_API NzVertexBuffer bool IsHardware() const; - void* Lock(nzBufferLock lock, unsigned int offset = 0, unsigned int length = 0); - bool Unlock(); + void* Map(nzBufferAccess access, unsigned int offset = 0, unsigned int length = 0); + bool Unmap(); private: NzBuffer* m_buffer; diff --git a/include/Nazara/Utility/Image.hpp b/include/Nazara/Utility/Image.hpp index 359cce0a9..296179ae5 100644 --- a/include/Nazara/Utility/Image.hpp +++ b/include/Nazara/Utility/Image.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -104,7 +105,7 @@ class NAZARA_API NzImage : public NzResource, public NzResourceLoader(src), static_cast(src) + GetBPP(srcFormat), static_cast(dst))) + if (!func(reinterpret_cast(src), reinterpret_cast(src) + GetBPP(srcFormat), reinterpret_cast(dst))) { NazaraError("Pixel format conversion from " + ToString(srcFormat) + " to " + ToString(dstFormat) + " failed"); return false; @@ -48,7 +48,7 @@ inline bool NzPixelFormat::Convert(nzPixelFormat srcFormat, nzPixelFormat dstFor { if (srcFormat == dstFormat) { - std::memcpy(dst, start, static_cast(end)-static_cast(start)); + std::memcpy(dst, start, reinterpret_cast(end)-reinterpret_cast(start)); return true; } @@ -59,7 +59,7 @@ inline bool NzPixelFormat::Convert(nzPixelFormat srcFormat, nzPixelFormat dstFor return false; } - if (!func(static_cast(start), static_cast(end), static_cast(dst))) + if (!func(reinterpret_cast(start), reinterpret_cast(end), reinterpret_cast(dst))) { NazaraError("Pixel format conversion from " + ToString(srcFormat) + " to " + ToString(dstFormat) + " failed"); return false; @@ -72,10 +72,6 @@ inline nzUInt8 NzPixelFormat::GetBPP(nzPixelFormat format) { switch (format) { - case nzPixelFormat_Count: - case nzPixelFormat_Undefined: - return 0; - case nzPixelFormat_BGR8: return 3; @@ -132,6 +128,11 @@ inline nzUInt8 NzPixelFormat::GetBPP(nzPixelFormat format) case nzPixelFormat_RGBA8: return 4; + + case nzPixelFormat_Count: + case nzPixelFormat_Undefined: + NazaraError("Invalid pixel format"); + return 0; } NazaraInternalError("Invalid pixel format"); @@ -152,9 +153,19 @@ inline bool NzPixelFormat::HasAlpha(nzPixelFormat format) case nzPixelFormat_RGBA8: return true; - default: + case nzPixelFormat_BGR8: + case nzPixelFormat_DXT1: + case nzPixelFormat_L8: + case nzPixelFormat_RGB8: return false; + + case nzPixelFormat_Count: + case nzPixelFormat_Undefined: + break; } + + NazaraError("Invalid pixel format"); + return false; } inline bool NzPixelFormat::IsCompressed(nzPixelFormat format) @@ -258,13 +269,13 @@ inline NzString NzPixelFormat::ToString(nzPixelFormat format) case nzPixelFormat_RGBA8: return "RGBA8"; - default: - NazaraInternalError("Invalid pixel format"); - case nzPixelFormat_Count: case nzPixelFormat_Undefined: - return "Invalid format"; + break; } + + NazaraError("Invalid pixel format"); + return "Invalid format"; } #include diff --git a/src/Nazara/Core/File.cpp b/src/Nazara/Core/File.cpp index d50cbae27..c7b21bab7 100644 --- a/src/Nazara/Core/File.cpp +++ b/src/Nazara/Core/File.cpp @@ -313,7 +313,7 @@ std::size_t NzFile::Read(void* buffer, std::size_t typeSize, unsigned int count) { unsigned int typeCount = byteRead/typeSize; for (unsigned int i = 0; i < typeCount; ++i) - NzByteSwap(static_cast(buffer) + i*typeSize, typeSize); + NzByteSwap(reinterpret_cast(buffer) + i*typeSize, typeSize); } return byteRead; diff --git a/src/Nazara/Core/MemoryStream.cpp b/src/Nazara/Core/MemoryStream.cpp index 17d223e6c..182d7f12e 100644 --- a/src/Nazara/Core/MemoryStream.cpp +++ b/src/Nazara/Core/MemoryStream.cpp @@ -8,7 +8,7 @@ #include NzMemoryStream::NzMemoryStream(const void* ptr, nzUInt64 size) : -m_ptr(static_cast(ptr)), +m_ptr(reinterpret_cast(ptr)), m_pos(0), m_size(size) { diff --git a/src/Nazara/Core/Win32/ThreadImpl.cpp b/src/Nazara/Core/Win32/ThreadImpl.cpp index e6a627e0b..6e8db44c6 100644 --- a/src/Nazara/Core/Win32/ThreadImpl.cpp +++ b/src/Nazara/Core/Win32/ThreadImpl.cpp @@ -67,7 +67,7 @@ void NzThreadImpl::Terminate() unsigned int _stdcall NzThreadImpl::ThreadProc(void* userdata) { - NzThread* owner = static_cast(userdata); + NzThread* owner = reinterpret_cast(userdata); NzFunctor* func = owner->m_func; HANDLE myHandle = owner->m_impl->m_thread; func->Run(); diff --git a/src/Nazara/Renderer/Buffer.cpp b/src/Nazara/Renderer/Buffer.cpp index 804d26eb0..335d13e7e 100644 --- a/src/Nazara/Renderer/Buffer.cpp +++ b/src/Nazara/Renderer/Buffer.cpp @@ -50,17 +50,17 @@ NzBuffer::~NzBuffer() bool NzBuffer::CopyContent(NzBuffer& buffer) { - void* ptr = buffer.Lock(nzBufferLock_ReadOnly); + void* ptr = buffer.Map(nzBufferAccess_ReadOnly); if (!ptr) { - NazaraError("Unable to lock source buffer"); + NazaraError("Failed to map source buffer"); return false; } bool r = Fill(ptr, 0, m_length); - if (!buffer.Unlock()) - NazaraWarning("Unable to unlock source buffer"); + if (!buffer.Unmap()) + NazaraWarning("Failed to unmap source buffer"); return r; } @@ -205,7 +205,7 @@ bool NzBuffer::IsHardware() const return m_storage == nzBufferStorage_Hardware; } -void* NzBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned int length) +void* NzBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned int length) { #if NAZARA_RENDERER_SAFE if (!m_impl) @@ -221,10 +221,10 @@ void* NzBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned int length } #endif - return m_impl->Lock(lock, offset*m_typeSize, length*m_typeSize); + return m_impl->Map(access, offset*m_typeSize, length*m_typeSize); } -bool NzBuffer::Unlock() +bool NzBuffer::Unmap() { #if NAZARA_RENDERER_SAFE if (!m_impl) @@ -234,7 +234,7 @@ bool NzBuffer::Unlock() } #endif - return m_impl->Unlock(); + return m_impl->Unmap(); } bool NzBuffer::IsSupported(nzBufferStorage storage) diff --git a/src/Nazara/Renderer/BufferImpl.hpp b/src/Nazara/Renderer/BufferImpl.hpp index 74b8d835a..74795abe9 100644 --- a/src/Nazara/Renderer/BufferImpl.hpp +++ b/src/Nazara/Renderer/BufferImpl.hpp @@ -26,8 +26,8 @@ class NzBufferImpl virtual bool IsHardware() const = 0; - virtual void* Lock(nzBufferLock lock, unsigned int offset = 0, unsigned int size = 0) = 0; - virtual bool Unlock() = 0; + virtual void* Map(nzBufferAccess access, unsigned int offset = 0, unsigned int size = 0) = 0; + virtual bool Unmap() = 0; }; #endif // NAZARA_BUFFERIMPL_INCLUDED diff --git a/src/Nazara/Renderer/Context.cpp b/src/Nazara/Renderer/Context.cpp index dfd885ee3..520586671 100644 --- a/src/Nazara/Renderer/Context.cpp +++ b/src/Nazara/Renderer/Context.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #if defined(NAZARA_PLATFORM_WINDOWS) #include @@ -21,9 +22,10 @@ namespace { - ///TODO: Thread-local - NzContext* currentContext = nullptr; - NzContext* threadContext = nullptr; + NAZARA_THREADLOCAL NzContext* currentContext = nullptr; + NAZARA_THREADLOCAL NzContext* threadContext = nullptr; + + std::vector contexts; void CALLBACK DebugCallback(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, int length, const char* message, void* userParam) { @@ -269,7 +271,36 @@ void NzContext::SwapBuffers() m_impl->SwapBuffers(); } -const NzContext* NzContext::GetCurrent() +bool NzContext::EnsureContext() +{ + if (!currentContext) + { + if (!threadContext) + { + NzContext* context = new NzContext; + if (!context->Create()) + { + NazaraError("Failed to create context"); + delete context; + + return false; + } + + contexts.push_back(context); + + threadContext = context; + } + else if (!threadContext->SetActive(true)) + { + NazaraError("Failed to active thread context"); + return false; + } + } + + return true; +} + +NzContext* NzContext::GetCurrent() { return currentContext; } @@ -279,12 +310,14 @@ const NzContext* NzContext::GetReference() return s_reference; } -const NzContext* NzContext::GetThreadContext() +NzContext* NzContext::GetThreadContext() { + EnsureContext(); + return threadContext; } -bool NzContext::InitializeReference() +bool NzContext::Initialize() { NzContextParameters parameters; // parameters.compatibilityProfile = true; @@ -299,11 +332,21 @@ bool NzContext::InitializeReference() return false; } + // Le contexte de référence doit rester désactivé pour le partage + s_reference->SetActive(false); + + NzContextParameters::defaultShareContext = s_reference; + return true; } -void NzContext::UninitializeReference() +void NzContext::Uninitialize() { + for (NzContext* context : contexts) + delete context; + + contexts.clear(); // On supprime tous les contextes créés + delete s_reference; s_reference = nullptr; } diff --git a/src/Nazara/Renderer/GLSLShader.cpp b/src/Nazara/Renderer/GLSLShader.cpp index 4ddc12fad..7518a3643 100644 --- a/src/Nazara/Renderer/GLSLShader.cpp +++ b/src/Nazara/Renderer/GLSLShader.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,14 @@ bool NzGLSLShader::Bind() } #endif + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return false; + } + #endif + glUseProgram(m_program); for (auto it = m_textures.begin(); it != m_textures.end(); ++it) @@ -66,6 +75,8 @@ bool NzGLSLShader::Bind() bool NzGLSLShader::Compile() { + NzContext::EnsureContext(); + m_idCache.clear(); glLinkProgram(m_program); @@ -104,6 +115,8 @@ bool NzGLSLShader::Compile() bool NzGLSLShader::Create() { + NzContext::EnsureContext(); + m_program = glCreateProgram(); if (!m_program) { @@ -126,13 +139,13 @@ bool NzGLSLShader::Create() for (int i = 0; i < nzShaderType_Count; ++i) m_shaders[i] = 0; - m_textureFreeID = 0; - return true; } void NzGLSLShader::Destroy() { + NzContext::EnsureContext(); + for (GLuint shader : m_shaders) if (shader) glDeleteShader(shader); @@ -153,6 +166,8 @@ nzShaderLanguage NzGLSLShader::GetLanguage() const NzString NzGLSLShader::GetSourceCode(nzShaderType type) const { + NzContext::EnsureContext(); + NzString source; GLint length; @@ -172,6 +187,8 @@ GLint NzGLSLShader::GetUniformLocation(const NzString& name) const GLint id; if (it == m_idCache.end()) { + NzContext::EnsureContext(); + id = glGetUniformLocation(m_program, name.GetConstBuffer()); m_idCache[name] = id; } @@ -188,6 +205,8 @@ bool NzGLSLShader::IsLoaded(nzShaderType type) const bool NzGLSLShader::Load(nzShaderType type, const NzString& source) { + NzContext::EnsureContext(); + GLuint shader = glCreateShader(shaderType[type]); if (!shader) { @@ -244,6 +263,8 @@ bool NzGLSLShader::Lock() { if (lockedLevel++ == 0) { + NzContext::EnsureContext(); + GLint previous; glGetIntegerv(GL_CURRENT_PROGRAM, &previous); @@ -258,54 +279,168 @@ bool NzGLSLShader::Lock() bool NzGLSLShader::SendBoolean(const NzString& name, bool value) { - Lock(); - glUniform1i(GetUniformLocation(name), value); - Unlock(); + if (glProgramUniform1i) + glProgramUniform1i(m_program, GetUniformLocation(name), value); + else + { + Lock(); + glUniform1i(GetUniformLocation(name), value); + Unlock(); + } return true; } bool NzGLSLShader::SendDouble(const NzString& name, double value) { - Lock(); - glUniform1d(GetUniformLocation(name), value); - Unlock(); + if (glProgramUniform1d) + glProgramUniform1d(m_program, GetUniformLocation(name), value); + else + { + Lock(); + glUniform1d(GetUniformLocation(name), value); + Unlock(); + } return true; } bool NzGLSLShader::SendFloat(const NzString& name, float value) { - Lock(); - glUniform1f(GetUniformLocation(name), value); - Unlock(); + if (glProgramUniform1f) + glProgramUniform1f(m_program, GetUniformLocation(name), value); + else + { + Lock(); + glUniform1f(GetUniformLocation(name), value); + Unlock(); + } return true; } bool NzGLSLShader::SendInteger(const NzString& name, int value) { - Lock(); - glUniform1i(GetUniformLocation(name), value); - Unlock(); + if (glProgramUniform1i) + glProgramUniform1i(m_program, GetUniformLocation(name), value); + else + { + Lock(); + glUniform1i(GetUniformLocation(name), value); + Unlock(); + } return true; } bool NzGLSLShader::SendMatrix(const NzString& name, const NzMatrix4d& matrix) { - Lock(); - glUniformMatrix4dv(GetUniformLocation(name), 1, GL_FALSE, matrix); - Unlock(); + if (glProgramUniformMatrix4dv) + glProgramUniformMatrix4dv(m_program, GetUniformLocation(name), 1, GL_FALSE, matrix); + else + { + Lock(); + glUniformMatrix4dv(GetUniformLocation(name), 1, GL_FALSE, matrix); + Unlock(); + } return true; } bool NzGLSLShader::SendMatrix(const NzString& name, const NzMatrix4f& matrix) { - Lock(); - glUniformMatrix4fv(GetUniformLocation(name), 1, GL_FALSE, matrix); - Unlock(); + if (glProgramUniformMatrix4fv) + glProgramUniformMatrix4fv(m_program, GetUniformLocation(name), 1, GL_FALSE, matrix); + else + { + Lock(); + glUniformMatrix4fv(GetUniformLocation(name), 1, GL_FALSE, matrix); + Unlock(); + } + + return true; +} + +bool NzGLSLShader::SendVector(const NzString& name, const NzVector2d& vector) +{ + if (glProgramUniform2dv) + glProgramUniform2dv(m_program, GetUniformLocation(name), 1, vector); + else + { + Lock(); + glUniform2dv(GetUniformLocation(name), 1, vector); + Unlock(); + } + + return true; +} + +bool NzGLSLShader::SendVector(const NzString& name, const NzVector2f& vector) +{ + if (glProgramUniform2fv) + glProgramUniform2fv(m_program, GetUniformLocation(name), 1, vector); + else + { + Lock(); + glUniform2fv(GetUniformLocation(name), 1, vector); + Unlock(); + } + + return true; +} + +bool NzGLSLShader::SendVector(const NzString& name, const NzVector3d& vector) +{ + if (glProgramUniform3dv) + glProgramUniform3dv(m_program, GetUniformLocation(name), 1, vector); + else + { + Lock(); + glUniform3dv(GetUniformLocation(name), 1, vector); + Unlock(); + } + + return true; +} + +bool NzGLSLShader::SendVector(const NzString& name, const NzVector3f& vector) +{ + if (glProgramUniform3fv) + glProgramUniform3fv(m_program, GetUniformLocation(name), 1, vector); + else + { + Lock(); + glUniform3fv(GetUniformLocation(name), 1, vector); + Unlock(); + } + + return true; +} + +bool NzGLSLShader::SendVector(const NzString& name, const NzVector4d& vector) +{ + if (glProgramUniform4dv) + glProgramUniform4dv(m_program, GetUniformLocation(name), 1, vector); + else + { + Lock(); + glUniform4dv(GetUniformLocation(name), 1, vector); + Unlock(); + } + + return true; +} + +bool NzGLSLShader::SendVector(const NzString& name, const NzVector4f& vector) +{ + if (glProgramUniform4fv) + glProgramUniform4fv(m_program, GetUniformLocation(name), 1, vector); + else + { + Lock(); + glUniform4fv(GetUniformLocation(name), 1, vector); + Unlock(); + } return true; } @@ -356,25 +491,48 @@ bool NzGLSLShader::SendTexture(const NzString& name, NzTexture* texture) m_textures[location] = TextureSlot{unit, texture}; - Lock(); - glUniform1i(location, unit); - Unlock(); + if (glProgramUniform1i) + glProgramUniform1i(m_program, location, unit); + else + { + Lock(); + glUniform1i(location, unit); + Unlock(); + } return true; } void NzGLSLShader::Unbind() { + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + glUseProgram(0); } void NzGLSLShader::Unlock() { + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + + #if NAZARA_RENDERER_SAFE if (lockedLevel == 0) { NazaraWarning("Unlock called on non-locked texture"); return; } + #endif if (--lockedLevel == 0 && lockedPrevious != m_program) glUseProgram(lockedPrevious); diff --git a/src/Nazara/Renderer/GLSLShader.hpp b/src/Nazara/Renderer/GLSLShader.hpp index 2d0287652..658e6e67d 100644 --- a/src/Nazara/Renderer/GLSLShader.hpp +++ b/src/Nazara/Renderer/GLSLShader.hpp @@ -42,6 +42,12 @@ class NzGLSLShader : public NzShaderImpl bool SendInteger(const NzString& name, int value); bool SendMatrix(const NzString& name, const NzMatrix4d& matrix); bool SendMatrix(const NzString& name, const NzMatrix4f& matrix); + bool SendVector(const NzString& name, const NzVector2d& vector); + bool SendVector(const NzString& name, const NzVector2f& vector); + bool SendVector(const NzString& name, const NzVector3d& vector); + bool SendVector(const NzString& name, const NzVector3f& vector); + bool SendVector(const NzString& name, const NzVector4d& vector); + bool SendVector(const NzString& name, const NzVector4f& vector); bool SendTexture(const NzString& name, NzTexture* texture); void Unbind(); @@ -58,7 +64,6 @@ class NzGLSLShader : public NzShaderImpl std::map m_textures; GLuint m_program; GLuint m_shaders[nzShaderType_Count]; - nzUInt8 m_textureFreeID; NzShader* m_parent; NzString m_log; }; diff --git a/src/Nazara/Renderer/HardwareBuffer.cpp b/src/Nazara/Renderer/HardwareBuffer.cpp index d42db2593..c017967be 100644 --- a/src/Nazara/Renderer/HardwareBuffer.cpp +++ b/src/Nazara/Renderer/HardwareBuffer.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -12,17 +13,17 @@ namespace { GLenum bufferLock[] = { - GL_WRITE_ONLY, // nzBufferLock_DiscardAndWrite - GL_READ_ONLY, // nzBufferLock_ReadOnly - GL_READ_WRITE, // nzBufferLock_ReadWrite - GL_WRITE_ONLY // nzBufferLock_WriteOnly + GL_WRITE_ONLY, // nzBufferAccess_DiscardAndWrite + GL_READ_ONLY, // nzBufferAccess_ReadOnly + GL_READ_WRITE, // nzBufferAccess_ReadWrite + GL_WRITE_ONLY // nzBufferAccess_WriteOnly }; GLenum bufferLockRange[] = { - GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_WRITE_BIT, // nzBufferLock_DiscardAndWrite - GL_MAP_READ_BIT, // nzBufferLock_ReadOnly - GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, // nzBufferLock_ReadWrite - GL_MAP_WRITE_BIT // nzBufferLock_WriteOnly + GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_DiscardAndWrite + GL_MAP_READ_BIT, // nzBufferAccess_ReadOnly + GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_ReadWrite + GL_MAP_WRITE_BIT // nzBufferAccess_WriteOnly }; GLenum bufferTarget[] = { @@ -43,13 +44,13 @@ namespace GL_STATIC_DRAW // nzBufferUsage_Static }; - typedef nzUInt8* (*LockRoutine)(nzBufferType type, nzBufferLock lock, unsigned int offset, unsigned int size); + typedef nzUInt8* (*LockRoutine)(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size); - nzUInt8* LockBuffer(nzBufferType type, nzBufferLock lock, unsigned int offset, unsigned int size) + nzUInt8* LockBuffer(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size) { NazaraUnused(size); - if (lock == nzBufferLock_DiscardAndWrite) + if (access == nzBufferAccess_DiscardAndWrite) { GLint size; glGetBufferParameteriv(bufferTargetBinding[type], GL_BUFFER_SIZE, &size); @@ -61,30 +62,30 @@ namespace glBufferData(bufferTargetBinding[type], size, nullptr, usage); } - void* ptr = glMapBuffer(bufferTarget[type], bufferLock[lock]); + void* ptr = glMapBuffer(bufferTarget[type], bufferLock[access]); if (ptr) return reinterpret_cast(ptr) + offset; else return nullptr; } - nzUInt8* LockBufferRange(nzBufferType type, nzBufferLock lock, unsigned int offset, unsigned int size) + nzUInt8* LockBufferRange(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size) { - return reinterpret_cast(glMapBufferRange(bufferTarget[type], offset, size, bufferLockRange[lock])); + return reinterpret_cast(glMapBufferRange(bufferTarget[type], offset, size, bufferLockRange[access])); } - nzUInt8* LockBufferFirstRun(nzBufferType type, nzBufferLock lock, unsigned int offset, unsigned int size); + nzUInt8* LockBufferFirstRun(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size); - LockRoutine lockBuffer = LockBufferFirstRun; + LockRoutine mapBuffer = LockBufferFirstRun; - nzUInt8* LockBufferFirstRun(nzBufferType type, nzBufferLock lock, unsigned int offset, unsigned int size) + nzUInt8* LockBufferFirstRun(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size) { if (glMapBufferRange) - lockBuffer = LockBufferRange; + mapBuffer = LockBufferRange; else - lockBuffer = LockBuffer; + mapBuffer = LockBuffer; - return lockBuffer(type, lock, offset, size); + return mapBuffer(type, access, offset, size); } } @@ -100,20 +101,24 @@ NzHardwareBuffer::~NzHardwareBuffer() void NzHardwareBuffer::Bind() { + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + glBindBuffer(bufferTarget[m_type], m_buffer); } bool NzHardwareBuffer::Create(unsigned int size, nzBufferUsage usage) { + NzContext::EnsureContext(); + m_buffer = 0; glGenBuffers(1, &m_buffer); - if (!m_buffer) - { - NazaraError("Failed to create buffer"); - return false; - } - GLint previous; glGetIntegerv(bufferTargetBinding[m_type], &previous); @@ -129,11 +134,15 @@ bool NzHardwareBuffer::Create(unsigned int size, nzBufferUsage usage) void NzHardwareBuffer::Destroy() { + NzContext::EnsureContext(); + glDeleteBuffers(1, &m_buffer); } bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int size) { + NzContext::EnsureContext(); + GLuint previous; glGetIntegerv(bufferTargetBinding[m_type], reinterpret_cast(&previous)); @@ -152,10 +161,10 @@ bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int } else { - nzUInt8* ptr = lockBuffer(m_type, (size == m_parent->GetSize()) ? nzBufferLock_DiscardAndWrite : nzBufferLock_WriteOnly, offset, size); + nzUInt8* ptr = mapBuffer(m_type, (size == m_parent->GetSize()) ? nzBufferAccess_DiscardAndWrite : nzBufferAccess_WriteOnly, offset, size); if (!ptr) { - NazaraError("Failed to lock buffer"); + NazaraError("Failed to map buffer"); return false; } @@ -164,7 +173,7 @@ bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int if (glUnmapBuffer(bufferTarget[m_type]) != GL_TRUE) { // Une erreur rare est survenue, nous devons réinitialiser le buffer - NazaraError("Failed to unlock buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')'); + NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')'); glBufferData(bufferTarget[m_type], m_parent->GetSize(), nullptr, bufferUsage[m_parent->GetStorage()]); @@ -189,8 +198,10 @@ bool NzHardwareBuffer::IsHardware() const return true; } -void* NzHardwareBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned int length) +void* NzHardwareBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned int length) { + NzContext::EnsureContext(); + // Pour ne pas perturber le rendu, on interfère pas avec le binding déjà présent GLuint previous; glGetIntegerv(bufferTargetBinding[m_type], reinterpret_cast(&previous)); @@ -198,7 +209,7 @@ void* NzHardwareBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned in if (previous != m_buffer) glBindBuffer(bufferTarget[m_type], m_buffer); - void* ptr = lockBuffer(m_type, lock, offset, length); + void* ptr = mapBuffer(m_type, access, offset, length); // Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérrations chaînées) if (previous != m_buffer && previous != 0) @@ -207,8 +218,10 @@ void* NzHardwareBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned in return ptr; } -bool NzHardwareBuffer::Unlock() +bool NzHardwareBuffer::Unmap() { + NzContext::EnsureContext(); + GLuint previous; glGetIntegerv(bufferTargetBinding[m_type], reinterpret_cast(&previous)); @@ -218,7 +231,7 @@ bool NzHardwareBuffer::Unlock() if (glUnmapBuffer(bufferTarget[m_type]) != GL_TRUE) { // Une erreur rare est survenue, nous devons réinitialiser le buffer - NazaraError("Failed to unlock buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')'); + NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')'); glBufferData(bufferTarget[m_type], m_parent->GetSize(), nullptr, bufferUsage[m_parent->GetStorage()]); diff --git a/src/Nazara/Renderer/HardwareBuffer.hpp b/src/Nazara/Renderer/HardwareBuffer.hpp index 044633634..f1652098e 100644 --- a/src/Nazara/Renderer/HardwareBuffer.hpp +++ b/src/Nazara/Renderer/HardwareBuffer.hpp @@ -28,8 +28,8 @@ class NzHardwareBuffer : public NzBufferImpl bool IsHardware() const; - void* Lock(nzBufferLock lock, unsigned int offset = 0, unsigned int length = 0); - bool Unlock(); + void* Map(nzBufferAccess access, unsigned int offset = 0, unsigned int length = 0); + bool Unmap(); private: GLuint m_buffer; diff --git a/src/Nazara/Renderer/IndexBuffer.cpp b/src/Nazara/Renderer/IndexBuffer.cpp index 7eb0a5c68..2e822d5d9 100644 --- a/src/Nazara/Renderer/IndexBuffer.cpp +++ b/src/Nazara/Renderer/IndexBuffer.cpp @@ -172,12 +172,12 @@ bool NzIndexBuffer::IsSequential() const return m_buffer == nullptr; } -void* NzIndexBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned int length) +void* NzIndexBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned int length) { #if NAZARA_RENDERER_SAFE if (!m_buffer) { - NazaraError("Impossible to lock sequential index buffer"); + NazaraError("Impossible to map sequential index buffer"); return nullptr; } @@ -188,10 +188,10 @@ void* NzIndexBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned int l } #endif - return m_buffer->Lock(lock, m_startIndex+offset, (length) ? length : m_indexCount-offset); + return m_buffer->Map(access, m_startIndex+offset, (length) ? length : m_indexCount-offset); } -bool NzIndexBuffer::Unlock() +bool NzIndexBuffer::Unmap() { #if NAZARA_RENDERER_SAFE if (!m_buffer) @@ -201,5 +201,5 @@ bool NzIndexBuffer::Unlock() } #endif - return m_buffer->Unlock(); + return m_buffer->Unmap(); } diff --git a/src/Nazara/Renderer/OcclusionQuery.cpp b/src/Nazara/Renderer/OcclusionQuery.cpp index 5ce46f719..50901e190 100644 --- a/src/Nazara/Renderer/OcclusionQuery.cpp +++ b/src/Nazara/Renderer/OcclusionQuery.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -15,9 +16,13 @@ m_id(0) { #if NAZARA_RENDERER_SAFE if (IsSupported()) + { #endif + NzContext::EnsureContext(); + glGenQueries(1, reinterpret_cast(&m_id)); #if NAZARA_RENDERER_SAFE + } else { NazaraError("Occlusion queries not supported"); @@ -38,6 +43,8 @@ NzOcclusionQuery::~NzOcclusionQuery() { if (m_id) { + NzContext::EnsureContext(); + GLuint query = static_cast(m_id); glDeleteQueries(1, &query); } @@ -45,16 +52,34 @@ NzOcclusionQuery::~NzOcclusionQuery() void NzOcclusionQuery::Begin() { + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + glBeginQuery(GL_SAMPLES_PASSED, m_id); } void NzOcclusionQuery::End() { + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + glEndQuery(GL_SAMPLES_PASSED); } unsigned int NzOcclusionQuery::GetResult() const { + NzContext::EnsureContext(); + GLuint result; glGetQueryObjectuiv(m_id, GL_QUERY_RESULT, &result); @@ -63,6 +88,8 @@ unsigned int NzOcclusionQuery::GetResult() const bool NzOcclusionQuery::IsResultAvailable() const { + NzContext::EnsureContext(); + GLint available; glGetQueryObjectiv(m_id, GL_QUERY_RESULT_AVAILABLE, &available); diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index 502cc1066..401499ef6 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -116,7 +116,6 @@ bool NzOpenGL::Initialize() } // Le chargement des fonctions OpenGL nécessite un contexte OpenGL - // Le contexte de chargement ne peut pas être partagé car le contexte de référence n'existe pas encore NzContextParameters parameters; parameters.majorVersion = 2; parameters.minorVersion = 0; @@ -124,8 +123,8 @@ bool NzOpenGL::Initialize() /* Note: Même le contexte de chargement nécessite quelques fonctions de base pour correctement s'initialiser - Pour cette raison, sa création est faite en deux fois, la première sert à récupérer le strict minimum, - la seconde à créer le véritable contexte de chargement. + Pour cette raison, deux contextes sont créés, le premier sert à récupérer les fonctions permetttant + de créer le second avec les bons paramètres.s Non sérieusement si quelqu'un a une meilleure idée qu'il me le dise */ @@ -371,50 +370,50 @@ bool NzOpenGL::Initialize() } // FrameBufferObject - try + if (openGLversion >= 300 || IsSupported("GL_ARB_framebuffer_object")) { - glBindFramebuffer = reinterpret_cast(LoadEntry("glBindFramebuffer")); - glBindRenderbuffer = reinterpret_cast(LoadEntry("glBindRenderbuffer")); - glCheckFramebufferStatus = reinterpret_cast(LoadEntry("glCheckFramebufferStatus")); - glDeleteFramebuffers = reinterpret_cast(LoadEntry("glDeleteFramebuffers")); - glDeleteRenderbuffers = reinterpret_cast(LoadEntry("glDeleteRenderbuffers")); - glFramebufferRenderbuffer = reinterpret_cast(LoadEntry("glFramebufferRenderbuffer")); - glFramebufferTexture2D = reinterpret_cast(LoadEntry("glFramebufferTexture2D")); - glGenerateMipmap = reinterpret_cast(LoadEntry("glGenerateMipmap")); - glGenFramebuffers = reinterpret_cast(LoadEntry("glGenFramebuffers")); - glGenRenderbuffers = reinterpret_cast(LoadEntry("glGenRenderbuffers")); - glRenderbufferStorage = reinterpret_cast(LoadEntry("glRenderbufferStorage")); - - openGLextensions[NzOpenGL::FrameBufferObject] = true; - } - catch (const std::exception& e) - { - if (openGLversion >= 300) - NazaraWarning("Failed to load core FBOs (" + NzString(e.what()) + ")"); - - if (IsSupported("GL_EXT_framebuffer_object")) + try { - try - { - glBindFramebuffer = reinterpret_cast(LoadEntry("glBindFramebufferEXT")); - glBindRenderbuffer = reinterpret_cast(LoadEntry("glBindRenderbufferEXT")); - glCheckFramebufferStatus = reinterpret_cast(LoadEntry("glCheckFramebufferStatusEXT")); - glDeleteFramebuffers = reinterpret_cast(LoadEntry("glDeleteFramebuffersEXT")); - glDeleteRenderbuffers = reinterpret_cast(LoadEntry("glDeleteRenderbuffersEXT")); - glFramebufferRenderbuffer = reinterpret_cast(LoadEntry("glFramebufferRenderbufferEXT")); - glFramebufferTexture2D = reinterpret_cast(LoadEntry("glFramebufferTexture2DEXT")); - glGenerateMipmap = reinterpret_cast(LoadEntry("glGenerateMipmapEXT")); - glGenFramebuffers = reinterpret_cast(LoadEntry("glGenFramebuffersEXT")); - glGenRenderbuffers = reinterpret_cast(LoadEntry("glGenRenderbuffersEXT")); - glRenderbufferStorage = reinterpret_cast(LoadEntry("glRenderbufferStorageEXT")); + glBindFramebuffer = reinterpret_cast(LoadEntry("glBindFramebuffer")); + glBindRenderbuffer = reinterpret_cast(LoadEntry("glBindRenderbuffer")); + glCheckFramebufferStatus = reinterpret_cast(LoadEntry("glCheckFramebufferStatus")); + glDeleteFramebuffers = reinterpret_cast(LoadEntry("glDeleteFramebuffers")); + glDeleteRenderbuffers = reinterpret_cast(LoadEntry("glDeleteRenderbuffers")); + glFramebufferRenderbuffer = reinterpret_cast(LoadEntry("glFramebufferRenderbuffer")); + glFramebufferTexture2D = reinterpret_cast(LoadEntry("glFramebufferTexture2D")); + glGenerateMipmap = reinterpret_cast(LoadEntry("glGenerateMipmap")); + glGenFramebuffers = reinterpret_cast(LoadEntry("glGenFramebuffers")); + glGenRenderbuffers = reinterpret_cast(LoadEntry("glGenRenderbuffers")); + glRenderbufferStorage = reinterpret_cast(LoadEntry("glRenderbufferStorage")); - openGLextensions[NzOpenGL::FrameBufferObject] = true; - } - catch (const std::exception& e) - { - NazaraError("Failed to load EXT_framebuffer_object: " + NzString(e.what())); - } + openGLextensions[NzOpenGL::FrameBufferObject] = true; } + catch (const std::exception& e) + { + NazaraError("Failed to load ARB_framebuffer_object: (" + NzString(e.what()) + ")"); + } + } + + // SeparateShaderObjects + if (openGLversion >= 400 || IsSupported("GL_ARB_gpu_shader_fp64")) + { + glProgramUniform1f = reinterpret_cast(LoadEntry("glProgramUniform1f")); + glProgramUniform1i = reinterpret_cast(LoadEntry("glProgramUniform1i")); + glProgramUniform2fv = reinterpret_cast(LoadEntry("glProgramUniform2fv")); + glProgramUniform3fv = reinterpret_cast(LoadEntry("glProgramUniform3fv")); + glProgramUniform4fv = reinterpret_cast(LoadEntry("glProgramUniform4fv")); + glProgramUniformMatrix4fv = reinterpret_cast(LoadEntry("glProgramUniformMatrix4fv")); + + if (openGLextensions[NzOpenGL::FP64]) + { + glProgramUniform1d = reinterpret_cast(LoadEntry("glProgramUniform1d")); + glProgramUniform2dv = reinterpret_cast(LoadEntry("glProgramUniform2dv")); + glProgramUniform3dv = reinterpret_cast(LoadEntry("glProgramUniform3dv")); + glProgramUniform4dv = reinterpret_cast(LoadEntry("glProgramUniform4dv")); + glProgramUniformMatrix4dv = reinterpret_cast(LoadEntry("glProgramUniformMatrix4dv")); + } + + openGLextensions[NzOpenGL::SeparateShaderObjects] = true; } // Texture3D @@ -452,7 +451,7 @@ bool NzOpenGL::Initialize() // TextureCompression_s3tc openGLextensions[NzOpenGL::TextureCompression_s3tc] = IsSupported("GL_EXT_texture_compression_s3tc"); - // VertexArrayObject + // TextureStorage if (openGLversion >= 420 || IsSupported("GL_ARB_texture_storage")) { try @@ -489,16 +488,14 @@ bool NzOpenGL::Initialize() /****************************************Contexte de référence****************************************/ ///FIXME: Utiliser le contexte de chargement comme référence ? (Vérifier mode debug) - if (!NzContext::InitializeReference()) + if (!NzContext::Initialize()) { - NazaraError("Failed to initialize reference context"); + NazaraError("Failed to initialize contexts"); Uninitialize(); return false; } - NzContextParameters::defaultShareContext = NzContext::GetReference(); - return true; } @@ -514,7 +511,7 @@ bool NzOpenGL::IsSupported(const NzString& string) void NzOpenGL::Uninitialize() { - NzContext::UninitializeReference(); + NzContext::Uninitialize(); for (bool& ext : openGLextensions) ext = false; @@ -604,6 +601,17 @@ PFNGLLINKPROGRAMPROC glLinkProgram = nullptr; PFNGLMAPBUFFERPROC glMapBuffer = nullptr; PFNGLMAPBUFFERRANGEPROC glMapBufferRange = nullptr; PFNGLPOLYGONMODEPROC glPolygonMode = nullptr; +PFNGLPROGRAMUNIFORM1DPROC glProgramUniform1d = nullptr; +PFNGLPROGRAMUNIFORM1FPROC glProgramUniform1f = nullptr; +PFNGLPROGRAMUNIFORM1IPROC glProgramUniform1i = nullptr; +PFNGLPROGRAMUNIFORM2DVPROC glProgramUniform2dv = nullptr; +PFNGLPROGRAMUNIFORM2FVPROC glProgramUniform2fv = nullptr; +PFNGLPROGRAMUNIFORM3DVPROC glProgramUniform3dv = nullptr; +PFNGLPROGRAMUNIFORM3FVPROC glProgramUniform3fv = nullptr; +PFNGLPROGRAMUNIFORM4DVPROC glProgramUniform4dv = nullptr; +PFNGLPROGRAMUNIFORM4FVPROC glProgramUniform4fv = nullptr; +PFNGLPROGRAMUNIFORMMATRIX4DVPROC glProgramUniformMatrix4dv = nullptr; +PFNGLPROGRAMUNIFORMMATRIX4FVPROC glProgramUniformMatrix4fv = nullptr; PFNGLREADPIXELSPROC glReadPixels = nullptr; PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = nullptr; PFNGLSCISSORPROC glScissor = nullptr; diff --git a/src/Nazara/Renderer/RenderTarget.cpp b/src/Nazara/Renderer/RenderTarget.cpp index 8ac1905a7..2954e61ca 100644 --- a/src/Nazara/Renderer/RenderTarget.cpp +++ b/src/Nazara/Renderer/RenderTarget.cpp @@ -25,5 +25,5 @@ bool NzRenderTarget::SetActive(bool active) void NzRenderTarget::Desactivate() { - // Seuls les target sans contextes (ex: RenderTexture) nécessitent une désactivation + // Seuls les target sans contextes (ex: NzRenderTexture) nécessitent une désactivation } diff --git a/src/Nazara/Renderer/RenderWindow.cpp b/src/Nazara/Renderer/RenderWindow.cpp index bc8c91db8..6891e3aba 100644 --- a/src/Nazara/Renderer/RenderWindow.cpp +++ b/src/Nazara/Renderer/RenderWindow.cpp @@ -5,9 +5,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -49,11 +47,6 @@ NzRenderWindow::~NzRenderWindow() { } -bool NzRenderWindow::CanActivate() const -{ - return m_impl != nullptr && m_context != nullptr; -} - bool NzRenderWindow::CopyToImage(NzImage* image) { #if NAZARA_RENDERER_SAFE @@ -144,7 +137,7 @@ bool NzRenderWindow::Create(NzWindowHandle handle, const NzContextParameters& pa void NzRenderWindow::Display() { - if (m_context) + if (m_context && m_parameters.doubleBuffered) m_context->SwapBuffers(); } @@ -181,7 +174,23 @@ void NzRenderWindow::EnableVerticalSync(bool enabled) NazaraError("No context"); } -NzRenderTargetParameters NzRenderWindow::GetRenderTargetParameters() const +NzContextParameters NzRenderWindow::GetContextParameters() const +{ + if (m_context) + return m_context->GetParameters(); + else + { + NazaraError("Window not created/context not initialized"); + return NzContextParameters(); + } +} + +unsigned int NzRenderWindow::GetHeight() const +{ + return NzWindow::GetHeight(); +} + +NzRenderTargetParameters NzRenderWindow::GetParameters() const { if (m_context) { @@ -195,15 +204,9 @@ NzRenderTargetParameters NzRenderWindow::GetRenderTargetParameters() const } } -NzContextParameters NzRenderWindow::GetContextParameters() const +unsigned int NzRenderWindow::GetWidth() const { - if (m_context) - return m_context->GetParameters(); - else - { - NazaraError("Window not created/context not initialized"); - return NzContextParameters(); - } + return NzWindow::GetWidth(); } bool NzRenderWindow::HasContext() const @@ -211,9 +214,23 @@ bool NzRenderWindow::HasContext() const return true; } +bool NzRenderWindow::IsValid() const +{ + return m_impl != nullptr && m_context != nullptr; +} + bool NzRenderWindow::Activate() { - return m_context->SetActive(true); + if (m_context->SetActive(true)) + { + glDrawBuffer((m_parameters.doubleBuffered) ? GL_BACK : GL_FRONT); + return true; + } + else + { + NazaraError("Failed to activate window's context"); + return false; + } } void NzRenderWindow::OnClose() diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 11e18926e..ce8e0ab53 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -23,17 +23,32 @@ namespace { const nzUInt8 attribIndex[] = { - 2, // nzElementUsage_Diffuse - 1, // nzElementUsage_Normal - 0, // nzElementUsage_Position - 3, // nzElementUsage_Tangent - 4 // nzElementUsage_TexCoord + 2, // nzElementUsage_Diffuse + 1, // nzElementUsage_Normal + 0, // nzElementUsage_Position + 3, // nzElementUsage_Tangent + 4 // nzElementUsage_TexCoord + }; + + + const GLenum blendFunc[] = + { + GL_DST_ALPHA, // nzBlendFunc_DestAlpha + GL_DST_COLOR, // nzBlendFunc_DestColor + GL_SRC_ALPHA, // nzBlendFunc_SrcAlpha + GL_SRC_COLOR, // nzBlendFunc_SrcColor + GL_ONE_MINUS_DST_ALPHA, // nzBlendFunc_InvDestAlpha + GL_ONE_MINUS_DST_COLOR, // nzBlendFunc_InvDestColor + GL_ONE_MINUS_SRC_ALPHA, // nzBlendFunc_InvSrcAlpha + GL_ONE_MINUS_SRC_COLOR, // nzBlendFunc_InvSrcColor + GL_ONE, // nzBlendFunc_One + GL_ZERO // nzBlendFunc_Zero }; const GLenum faceCullingMode[] = { - GL_BACK, // nzFaceCulling_Back - GL_FRONT, // nzFaceCulling_Front + GL_BACK, // nzFaceCulling_Back + GL_FRONT, // nzFaceCulling_Front GL_FRONT_AND_BACK // nzFaceCulling_FrontAndBack }; @@ -41,18 +56,18 @@ namespace { GL_POINT, // nzFaceFilling_Point GL_LINE, // nzFaceFilling_Line - GL_FILL // nzFaceFilling_Fill + GL_FILL // nzFaceFilling_Fill }; const GLenum openglPrimitive[] = { - GL_LINES, // nzPrimitiveType_LineList, - GL_LINE_STRIP, // nzPrimitiveType_LineStrip, - GL_POINTS, // nzPrimitiveType_PointList, - GL_TRIANGLES, // nzPrimitiveType_TriangleList, + GL_LINES, // nzPrimitiveType_LineList, + GL_LINE_STRIP, // nzPrimitiveType_LineStrip, + GL_POINTS, // nzPrimitiveType_PointList, + GL_TRIANGLES, // nzPrimitiveType_TriangleList, GL_TRIANGLE_STRIP, // nzPrimitiveType_TriangleStrip, - GL_TRIANGLE_FAN // nzPrimitiveType_TriangleFan + GL_TRIANGLE_FAN // nzPrimitiveType_TriangleFan }; const nzUInt8 openglSize[] = @@ -71,47 +86,47 @@ namespace const GLenum openglType[] = { GL_UNSIGNED_BYTE, // nzElementType_Color - GL_DOUBLE, // nzElementType_Double1 - GL_DOUBLE, // nzElementType_Double2 - GL_DOUBLE, // nzElementType_Double3 - GL_DOUBLE, // nzElementType_Double4 - GL_FLOAT, // nzElementType_Float1 - GL_FLOAT, // nzElementType_Float2 - GL_FLOAT, // nzElementType_Float3 - GL_FLOAT // nzElementType_Float4 + GL_DOUBLE, // nzElementType_Double1 + GL_DOUBLE, // nzElementType_Double2 + GL_DOUBLE, // nzElementType_Double3 + GL_DOUBLE, // nzElementType_Double4 + GL_FLOAT, // nzElementType_Float1 + GL_FLOAT, // nzElementType_Float2 + GL_FLOAT, // nzElementType_Float3 + GL_FLOAT // nzElementType_Float4 }; const GLenum rendererComparison[] = { - GL_ALWAYS, // nzRendererComparison_Always - GL_EQUAL, // nzRendererComparison_Equal - GL_GREATER, // nzRendererComparison_Greater - GL_GEQUAL, // nzRendererComparison_GreaterOrEqual - GL_LESS, // nzRendererComparison_Less - GL_LEQUAL, // nzRendererComparison_LessOrEqual - GL_NEVER // nzRendererComparison_Never + GL_ALWAYS, // nzRendererComparison_Always + GL_EQUAL, // nzRendererComparison_Equal + GL_GREATER, // nzRendererComparison_Greater + GL_GEQUAL, // nzRendererComparison_GreaterOrEqual + GL_LESS, // nzRendererComparison_Less + GL_LEQUAL, // nzRendererComparison_LessOrEqual + GL_NEVER // nzRendererComparison_Never }; const GLenum rendererParameter[] = { - GL_BLEND, // nzRendererParameter_Blend - GL_NONE, // nzRendererParameter_ColorWrite - GL_DEPTH_TEST, // nzRendererParameter_DepthTest - GL_NONE, // nzRendererParameter_DepthWrite - GL_CULL_FACE, // nzRendererParameter_FaceCulling - GL_STENCIL_TEST // nzRendererParameter_Stencil + GL_BLEND, // nzRendererParameter_Blend + GL_NONE, // nzRendererParameter_ColorWrite + GL_DEPTH_TEST, // nzRendererParameter_DepthTest + GL_NONE, // nzRendererParameter_DepthWrite + GL_CULL_FACE, // nzRendererParameter_FaceCulling + GL_STENCIL_TEST // nzRendererParameter_Stencil }; const GLenum stencilOperation[] = { - GL_DECR, // nzStencilOperation_Decrement + GL_DECR, // nzStencilOperation_Decrement GL_DECR_WRAP, // nzStencilOperation_DecrementToSaturation - GL_INCR, // nzStencilOperation_Increment + GL_INCR, // nzStencilOperation_Increment GL_INCR_WRAP, // nzStencilOperation_IncrementToSaturation - GL_INVERT, // nzStencilOperation_Invert - GL_KEEP, // nzStencilOperation_Keep - GL_REPLACE, // nzStencilOperation_Replace - GL_ZERO // nzStencilOperation_Zero + GL_INVERT, // nzStencilOperation_Invert + GL_KEEP, // nzStencilOperation_Keep + GL_REPLACE, // nzStencilOperation_Replace + GL_ZERO // nzStencilOperation_Zero }; } @@ -228,6 +243,14 @@ void NzRenderer::DrawPrimitives(nzPrimitiveType primitive, unsigned int firstVer void NzRenderer::Enable(nzRendererParameter parameter, bool enable) { + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + switch (parameter) { case nzRendererParameter_ColorWrite: @@ -273,6 +296,22 @@ NzRenderTarget* NzRenderer::GetTarget() const return m_target; } +NzRectui NzRenderer::GetViewport() const +{ + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return NzRectui(); + } + #endif + + GLint params[4]; + glGetIntegerv(GL_VIEWPORT, ¶ms[0]); + + return NzRectui(params[0], params[1], params[2], params[3]); +} + bool NzRenderer::HasCapability(nzRendererCap capability) const { return m_capabilities[capability]; @@ -297,6 +336,11 @@ bool NzRenderer::Initialize() if (NzOpenGL::Initialize()) { + NzContext::EnsureContext(); + + const NzContext* context = NzContext::GetReference(); + bool compatibility = context->GetParameters().compatibilityProfile; + m_vaoUpdated = false; m_indexBuffer = nullptr; m_shader = nullptr; @@ -318,7 +362,7 @@ bool NzRenderer::Initialize() m_capabilities[nzRendererCap_HardwareBuffer] = true; // Natif depuis OpenGL 1.5 m_capabilities[nzRendererCap_MultipleRenderTargets] = true; // Natif depuis OpenGL 2.0 m_capabilities[nzRendererCap_OcclusionQuery] = true; // Natif depuis OpenGL 1.5 - m_capabilities[nzRendererCap_SoftwareBuffer] = NzOpenGL::GetVersion() <= 300; // Déprécié en OpenGL 3 + m_capabilities[nzRendererCap_SoftwareBuffer] = compatibility || NzOpenGL::GetVersion() <= 300; // Déprécié en OpenGL 3 m_capabilities[nzRendererCap_Texture3D] = NzOpenGL::IsSupported(NzOpenGL::Texture3D); m_capabilities[nzRendererCap_TextureCubemap] = true; // Natif depuis OpenGL 1.3 m_capabilities[nzRendererCap_TextureMulti] = true; // Natif depuis OpenGL 1.3 @@ -336,14 +380,10 @@ bool NzRenderer::Initialize() if (m_capabilities[nzRendererCap_MultipleRenderTargets]) { - // Permettre de gérer plus de targets que de nombre de sorties dans le shader ne servirait à rien GLint maxDrawBuffers; glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); - GLint maxRenderTextureTargets; - glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxRenderTextureTargets); - - m_maxRenderTarget = static_cast(std::min(maxDrawBuffers, maxRenderTextureTargets)); + m_maxRenderTarget = static_cast(maxDrawBuffers); } else m_maxRenderTarget = 1; @@ -366,6 +406,19 @@ bool NzRenderer::Initialize() return false; } +void NzRenderer::SetBlendFunc(nzBlendFunc src, nzBlendFunc dest) +{ + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + + glBlendFunc(blendFunc[src], blendFunc[dest]); +} + void NzRenderer::SetClearColor(const NzColor& color) { #ifdef NAZARA_DEBUG @@ -462,10 +515,7 @@ bool NzRenderer::SetShader(NzShader* shader) return true; if (m_shader) - { m_shader->m_impl->Unbind(); - m_shader = nullptr; - } if (shader) { @@ -473,6 +523,8 @@ bool NzRenderer::SetShader(NzShader* shader) if (!shader->IsCompiled()) { NazaraError("Shader is not compiled"); + m_shader = nullptr; + return false; } #endif @@ -480,9 +532,13 @@ bool NzRenderer::SetShader(NzShader* shader) if (!shader->m_impl->Bind()) { NazaraError("Failed to bind shader"); + m_shader = nullptr; + return false; } } + else + m_shader = nullptr; m_shader = shader; @@ -548,19 +604,19 @@ bool NzRenderer::SetTarget(NzRenderTarget* target) if (target == m_target) return true; - #if NAZARA_RENDERER_SAFE - if (target && !target->CanActivate()) - { - NazaraError("Target cannot be activated"); - return false; - } - #endif - if (m_target && !m_target->HasContext()) m_target->Desactivate(); if (target) { + #if NAZARA_RENDERER_SAFE + if (!target->IsValid()) + { + NazaraError("Target not valid"); + return false; + } + #endif + if (target->Activate()) m_target = target; else @@ -599,6 +655,43 @@ bool NzRenderer::SetVertexDeclaration(const NzVertexDeclaration* vertexDeclarati return true; } +void NzRenderer::SetViewport(const NzRectui& viewport) +{ + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + + unsigned int height = m_target->GetHeight(); + + #if NAZARA_RENDERER_SAFE + if (!m_target) + { + NazaraError("Renderer has no target"); + return; + } + + unsigned int width = m_target->GetWidth(); + if (viewport.x+viewport.width >= width) + { + NazaraError("Rectangle dimensions are out of bounds"); + return; + } + + if (viewport.y+viewport.height >= height) + { + NazaraError("Rectangle dimensions are out of bounds"); + return; + } + #endif + + glViewport(viewport.x, height-viewport.height-viewport.y, viewport.width, viewport.height); + glScissor(viewport.x, height-viewport.height-viewport.y, viewport.width, viewport.height); +} + void NzRenderer::Uninitialize() { #if NAZARA_RENDERER_SAFE @@ -609,6 +702,8 @@ void NzRenderer::Uninitialize() } #endif + NzContext::EnsureContext(); + s_initialized = false; // Libération des VAOs @@ -644,6 +739,14 @@ bool NzRenderer::IsInitialized() bool NzRenderer::EnsureStateUpdate() { + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return false; + } + #endif + if (!m_stencilFuncUpdated) { glStencilFunc(rendererComparison[m_stencilCompare], m_stencilReference, m_stencilMask); diff --git a/src/Nazara/Renderer/Shader.cpp b/src/Nazara/Renderer/Shader.cpp index 6d642626b..f3e635089 100644 --- a/src/Nazara/Renderer/Shader.cpp +++ b/src/Nazara/Renderer/Shader.cpp @@ -253,11 +253,12 @@ bool NzShader::LoadFromFile(nzShaderType type, const NzString& filePath) return false; } - NzString source; unsigned int length = file.GetSize(); + + NzString source; source.Resize(length); - if (file.Read(&source[0], sizeof(char), length) != length*sizeof(char)) + if (file.Read(&source[0], length) != length) { NazaraError("Failed to read shader file"); return false; @@ -371,6 +372,102 @@ bool NzShader::SendMatrix(const NzString& name, const NzMatrix4f& matrix) return m_impl->SendMatrix(name, matrix); } +bool NzShader::SendVector(const NzString& name, const NzVector2d& vector) +{ + #if NAZARA_RENDERER_SAFE + if (!m_impl) + { + NazaraError("Shader not created"); + return false; + } + + if (!NazaraRenderer->HasCapability(nzRendererCap_FP64)) + { + NazaraError("FP64 is not supported"); + return false; + } + #endif + + return m_impl->SendVector(name, vector); +} + +bool NzShader::SendVector(const NzString& name, const NzVector2f& vector) +{ + #if NAZARA_RENDERER_SAFE + if (!m_impl) + { + NazaraError("Shader not created"); + return false; + } + #endif + + return m_impl->SendVector(name, vector); +} + +bool NzShader::SendVector(const NzString& name, const NzVector3d& vector) +{ + #if NAZARA_RENDERER_SAFE + if (!m_impl) + { + NazaraError("Shader not created"); + return false; + } + + if (!NazaraRenderer->HasCapability(nzRendererCap_FP64)) + { + NazaraError("FP64 is not supported"); + return false; + } + #endif + + return m_impl->SendVector(name, vector); +} + +bool NzShader::SendVector(const NzString& name, const NzVector3f& vector) +{ + #if NAZARA_RENDERER_SAFE + if (!m_impl) + { + NazaraError("Shader not created"); + return false; + } + #endif + + return m_impl->SendVector(name, vector); +} + +bool NzShader::SendVector(const NzString& name, const NzVector4d& vector) +{ + #if NAZARA_RENDERER_SAFE + if (!m_impl) + { + NazaraError("Shader not created"); + return false; + } + + if (!NazaraRenderer->HasCapability(nzRendererCap_FP64)) + { + NazaraError("FP64 is not supported"); + return false; + } + #endif + + return m_impl->SendVector(name, vector); +} + +bool NzShader::SendVector(const NzString& name, const NzVector4f& vector) +{ + #if NAZARA_RENDERER_SAFE + if (!m_impl) + { + NazaraError("Shader not created"); + return false; + } + #endif + + return m_impl->SendVector(name, vector); +} + bool NzShader::SendTexture(const NzString& name, NzTexture* texture) { #if NAZARA_RENDERER_SAFE diff --git a/src/Nazara/Renderer/ShaderImpl.hpp b/src/Nazara/Renderer/ShaderImpl.hpp index 330b9dccf..504f59853 100644 --- a/src/Nazara/Renderer/ShaderImpl.hpp +++ b/src/Nazara/Renderer/ShaderImpl.hpp @@ -45,6 +45,12 @@ class NzShaderImpl virtual bool SendInteger(const NzString& name, int value) = 0; virtual bool SendMatrix(const NzString& name, const NzMatrix4d& matrix) = 0; virtual bool SendMatrix(const NzString& name, const NzMatrix4f& matrix) = 0; + virtual bool SendVector(const NzString& name, const NzVector2d& vector) = 0; + virtual bool SendVector(const NzString& name, const NzVector2f& vector) = 0; + virtual bool SendVector(const NzString& name, const NzVector3d& vector) = 0; + virtual bool SendVector(const NzString& name, const NzVector3f& vector) = 0; + virtual bool SendVector(const NzString& name, const NzVector4d& vector) = 0; + virtual bool SendVector(const NzString& name, const NzVector4f& vector) = 0; virtual bool SendTexture(const NzString& name, NzTexture* texture) = 0; virtual void Unbind() = 0; diff --git a/src/Nazara/Renderer/SoftwareBuffer.cpp b/src/Nazara/Renderer/SoftwareBuffer.cpp index a234ac00c..c579a7e40 100644 --- a/src/Nazara/Renderer/SoftwareBuffer.cpp +++ b/src/Nazara/Renderer/SoftwareBuffer.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -30,6 +31,14 @@ NzSoftwareBuffer::~NzSoftwareBuffer() void NzSoftwareBuffer::Bind() { + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + glBindBuffer(bufferTarget[m_type], 0); } @@ -48,7 +57,7 @@ bool NzSoftwareBuffer::Create(unsigned int size, nzBufferUsage usage) return false; } - m_locked = false; + m_mapped = false; return true; } @@ -61,9 +70,9 @@ void NzSoftwareBuffer::Destroy() bool NzSoftwareBuffer::Fill(const void* data, unsigned int offset, unsigned int size) { #if NAZARA_RENDERER_SAFE - if (m_locked) + if (m_mapped) { - NazaraError("Buffer already locked"); + NazaraError("Buffer already mapped"); return false; } #endif @@ -83,35 +92,35 @@ bool NzSoftwareBuffer::IsHardware() const return false; } -void* NzSoftwareBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned int size) +void* NzSoftwareBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned int size) { - NazaraUnused(lock); + NazaraUnused(access); NazaraUnused(size); #if NAZARA_RENDERER_SAFE - if (m_locked) + if (m_mapped) { - NazaraError("Buffer already locked"); + NazaraError("Buffer already mapped"); return nullptr; } #endif - m_locked = true; + m_mapped = true; return &m_buffer[offset]; } -bool NzSoftwareBuffer::Unlock() +bool NzSoftwareBuffer::Unmap() { #if NAZARA_RENDERER_SAFE - if (!m_locked) + if (!m_mapped) { - NazaraError("Buffer not locked"); + NazaraError("Buffer not mapped"); return true; } #endif - m_locked = false; + m_mapped = false; return true; } diff --git a/src/Nazara/Renderer/SoftwareBuffer.hpp b/src/Nazara/Renderer/SoftwareBuffer.hpp index 865b7d6d2..704f8e65f 100644 --- a/src/Nazara/Renderer/SoftwareBuffer.hpp +++ b/src/Nazara/Renderer/SoftwareBuffer.hpp @@ -27,13 +27,13 @@ class NzSoftwareBuffer : public NzBufferImpl bool IsHardware() const; - void* Lock(nzBufferLock lock, unsigned int offset = 0, unsigned int length = 0); - bool Unlock(); + void* Map(nzBufferAccess access, unsigned int offset = 0, unsigned int length = 0); + bool Unmap(); private: nzBufferType m_type; nzUInt8* m_buffer; - bool m_locked; + bool m_mapped; }; #endif // NAZARA_SOFTWAREBUFFER_HPP diff --git a/src/Nazara/Renderer/Texture.cpp b/src/Nazara/Renderer/Texture.cpp index a69dca501..c5eb3e639 100644 --- a/src/Nazara/Renderer/Texture.cpp +++ b/src/Nazara/Renderer/Texture.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -14,8 +15,9 @@ struct NzTextureImpl { // GCC 4.7 !!!!!! NzTextureImpl() : + isTarget(false), mipmapping(false), - mipmapsUpdated(false) + mipmapsUpdated(true) { } @@ -23,6 +25,7 @@ struct NzTextureImpl nzImageType type; nzPixelFormat format; nzUInt8 levelCount; + bool isTarget; bool mipmapping; bool mipmapsUpdated; unsigned int depth; @@ -73,31 +76,31 @@ namespace format->dataFormat = GL_BGR; format->dataType = GL_UNSIGNED_BYTE; format->internalFormat = GL_RGB8; - break; + return true; case nzPixelFormat_BGRA8: format->dataFormat = GL_BGRA; format->dataType = GL_UNSIGNED_BYTE; format->internalFormat = GL_RGBA8; - break; + return true; case nzPixelFormat_DXT1: format->dataFormat = GL_RGB; format->dataType = GL_UNSIGNED_BYTE; format->internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; - break; + return true; case nzPixelFormat_DXT3: format->dataFormat = GL_RGBA; format->dataType = GL_UNSIGNED_BYTE; format->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; - break; + return true; case nzPixelFormat_DXT5: format->dataFormat = GL_RGBA; format->dataType = GL_UNSIGNED_BYTE; format->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; - break; + return true; case nzPixelFormat_L8: case nzPixelFormat_LA8: @@ -108,32 +111,35 @@ namespace format->dataFormat = GL_RGBA; format->dataType = GL_UNSIGNED_SHORT_5_5_5_1; format->internalFormat = GL_RGB5_A1; - break; + return true; case nzPixelFormat_RGB8: format->dataFormat = GL_RGB; format->dataType = GL_UNSIGNED_BYTE; format->internalFormat = GL_RGB8; - break; + return true; case nzPixelFormat_RGBA4: format->dataFormat = GL_RGBA; format->dataType = GL_UNSIGNED_SHORT_4_4_4_4; format->internalFormat = GL_RGBA4; - break; + return true; case nzPixelFormat_RGBA8: format->dataFormat = GL_RGBA; format->dataType = GL_UNSIGNED_BYTE; format->internalFormat = GL_RGBA8; - break; + return true; - default: - NazaraError("Pixel format not handled"); + case nzPixelFormat_Undefined: + case nzPixelFormat_Count: + NazaraInternalError("Invalid pixel format"); return false; } - return true; + NazaraError("Pixel format not handled"); + + return false; } bool CreateTexture(NzTextureImpl* impl, bool proxy) @@ -145,8 +151,6 @@ namespace return false; } - static const bool texStorageSupported = NzOpenGL::IsSupported(NzOpenGL::TextureStorage); - GLenum target; switch (impl->type) { @@ -154,15 +158,16 @@ namespace { target = (proxy) ? GL_TEXTURE_1D : GL_PROXY_TEXTURE_1D; - if (texStorageSupported) + /*if (glTexStorage1D) glTexStorage1D(target, impl->levelCount, openGLFormat.internalFormat, impl->width); - else + else*/ { unsigned int w = impl->width; for (nzUInt8 level = 0; level < impl->levelCount; ++level) { glTexImage1D(target, level, openGLFormat.internalFormat, w, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); - w = std::max(w/2, 1U); + if (w > 1U) + w >>= 1; } } break; @@ -172,17 +177,20 @@ namespace { target = (proxy) ? GL_TEXTURE_2D : GL_PROXY_TEXTURE_2D; - if (texStorageSupported) + /*if (glTexStorage2D) glTexStorage2D(target, impl->levelCount, openGLFormat.internalFormat, impl->width, impl->height); - else + else*/ { unsigned int w = impl->width; unsigned int h = impl->height; for (nzUInt8 level = 0; level < impl->levelCount; ++level) { glTexImage2D(target, level, openGLFormat.internalFormat, w, h, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); - w = std::max(w/2, 1U); - h = std::max(h/2, 1U); + if (w > 1U) + w >>= 1; + + if (h > 1U) + h >>= 1; } } break; @@ -192,9 +200,9 @@ namespace { target = (proxy) ? GL_TEXTURE_3D : GL_PROXY_TEXTURE_3D; - if (texStorageSupported) + /*if (glTexStorage3D) glTexStorage3D(target, impl->levelCount, openGLFormat.internalFormat, impl->width, impl->height, impl->depth); - else + else*/ { unsigned int w = impl->width; unsigned int h = impl->height; @@ -202,9 +210,14 @@ namespace for (nzUInt8 level = 0; level < impl->levelCount; ++level) { glTexImage3D(target, level, openGLFormat.internalFormat, w, h, d, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); - w = std::max(w/2, 1U); - h = std::max(h/2, 1U); - d = std::max(d/2, 1U); + if (w > 1U) + w >>= 1; + + if (h > 1U) + h >>= 1; + + if (d > 1U) + d >>= 1; } } break; @@ -214,9 +227,9 @@ namespace { target = (proxy) ? GL_TEXTURE_CUBE_MAP : GL_PROXY_TEXTURE_CUBE_MAP; - if (texStorageSupported) + /*if (glTexStorage2D) glTexStorage2D(target, impl->levelCount, openGLFormat.internalFormat, impl->width, impl->height); - else + else*/ { unsigned int size = impl->width; // Les cubemaps ont une longueur et largeur identique for (nzUInt8 level = 0; level < impl->levelCount; ++level) @@ -224,7 +237,8 @@ namespace for (GLenum face : cubemapFace) glTexImage2D(face, level, openGLFormat.internalFormat, size, size, 0, openGLFormat.dataFormat, openGLFormat.dataType, nullptr); - size = std::max(size/2, 1U); + if (size > 1U) + size >>= 1; } } break; @@ -253,6 +267,8 @@ namespace { if (lockedLevel[impl->type]++ == 0) { + NzContext::EnsureContext(); + GLint previous; glGetIntegerv(openglTargetBinding[impl->type], &previous); @@ -265,6 +281,14 @@ namespace void UnlockTexture(NzTextureImpl* impl) { + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + #if NAZARA_RENDERER_SAFE if (lockedLevel[impl->type] == 0) { @@ -302,7 +326,7 @@ NzTexture::~NzTexture() Destroy(); } -bool NzTexture::Bind() +bool NzTexture::Bind() const { #if NAZARA_RENDERER_SAFE if (lockedLevel[m_impl->type] > 0) @@ -314,11 +338,25 @@ bool NzTexture::Bind() glBindTexture(openglTarget[m_impl->type], m_impl->id); + if (!m_impl->mipmapsUpdated) + { + glGenerateMipmap(openglTarget[m_impl->type]); + m_impl->mipmapsUpdated = true; + } + return true; } bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth, nzUInt8 levelCount, bool lock) { + #if NAZARA_RENDERER_SAFE + if (m_impl && m_impl->isTarget) + { + NazaraError("Texture is a target, it cannot be recreated"); + return false; + } + #endif + Destroy(); if (width == 0 || height == 0 || depth == 0) @@ -348,7 +386,7 @@ bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int widt case nzImageType_1D: if (height > 1) { - NazaraError("1D textures must be 1 height"); + NazaraError("One dimensional texture's height must be 1"); return false; } @@ -390,6 +428,8 @@ bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int widt } #endif + NzContext::EnsureContext(); + levelCount = std::min(levelCount, NzImage::GetMaxLevel(width, height, depth)); NzTextureImpl* impl = new NzTextureImpl; @@ -433,6 +473,12 @@ bool NzTexture::Create(nzImageType type, nzPixelFormat format, unsigned int widt SetMipmapRange(0, m_impl->levelCount); SetWrapMode(nzTextureWrap_Repeat); + if (m_impl->levelCount > 1U) + { + m_impl->mipmapping = true; + m_impl->mipmapsUpdated = false; + } + if (!lock) UnlockTexture(impl); @@ -443,6 +489,16 @@ void NzTexture::Destroy() { if (m_impl) { + #if NAZARA_RENDERER_SAFE + if (m_impl->isTarget) + { + NazaraError("Texture is a target, it cannot be destroyed"); + return; + } + #endif + + NzContext::EnsureContext(); + glDeleteTextures(1, &m_impl->id); delete m_impl; m_impl = nullptr; @@ -505,9 +561,14 @@ bool NzTexture::Download(NzImage* image) const ptr += faceSize; } - width = std::max(width >> 1, 1U); - height = std::max(height >> 1, 1U); - depth = std::max(depth >> 1, 1U); + if (width > 1) + width >>= 1; + + if (height > 1) + height >>= 1; + + if (depth > 1) + depth >>= 1; } UnlockTexture(m_impl); @@ -533,15 +594,22 @@ bool NzTexture::EnableMipmapping(bool enable) return false; } - LockTexture(m_impl); - if (!m_impl->mipmapping && enable) - glGenerateMipmap(openglTarget[m_impl->type]); + { + GLint tex; + glGetIntegerv(openglTargetBinding[m_impl->type], &tex); + + if (m_impl->id == static_cast(tex)) + { + glGenerateMipmap(openglTarget[m_impl->type]); + m_impl->mipmapsUpdated = true; + } + else + m_impl->mipmapsUpdated = false; + } m_impl->mipmapping = enable; - UnlockTexture(m_impl); - return true; } @@ -744,6 +812,19 @@ bool NzTexture::IsCubemap() const return m_impl->type == nzImageType_Cubemap; } +bool NzTexture::IsTarget() const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + #endif + + return m_impl->isTarget; +} + bool NzTexture::IsValid() const { return m_impl != nullptr; @@ -1059,7 +1140,7 @@ bool NzTexture::Update(const NzImage& image, const NzRectui& rect, unsigned int return Update(image.GetConstPixels(level), rect, z, level); } -/* + bool NzTexture::Update(const NzImage& image, const NzCubeui& cube, nzUInt8 level) { #if NAZARA_RENDERER_SAFE @@ -1078,7 +1159,7 @@ bool NzTexture::Update(const NzImage& image, const NzCubeui& cube, nzUInt8 level return Update(image.GetConstPixels(level), cube, level); } -*/ + bool NzTexture::Update(const nzUInt8* pixels, nzUInt8 level) { #if NAZARA_RENDERER_SAFE @@ -1090,11 +1171,7 @@ bool NzTexture::Update(const nzUInt8* pixels, nzUInt8 level) #endif if (m_impl->type == nzImageType_3D) - { - NazaraInternalError("Not implemented yet, sorry"); - return false; - //return Update(pixels, NzCube(0, 0, 0, std::max(m_impl->width >> level, 1U), std::max(m_impl->height >> level, 1U), std::max(m_impl->depth >> level, 1U)), level); - } + return Update(pixels, NzCubeui(0, 0, 0, std::max(m_impl->width >> level, 1U), std::max(m_impl->height >> level, 1U), std::max(m_impl->depth >> level, 1U)), level); else return Update(pixels, NzRectui(0, 0, std::max(m_impl->width >> level, 1U), std::max(m_impl->height >> level, 1U)), 0, level); } @@ -1108,6 +1185,12 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int return false; } + if (m_impl->isTarget) + { + NazaraError("Texture is a target, it cannot be updated"); + return false; + } + if (m_impl->type == nzImageType_Cubemap) { NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); @@ -1190,8 +1273,8 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int return true; } -/* -bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level = 0) + +bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level) { #if NAZARA_RENDERER_SAFE if (!IsValid()) @@ -1200,6 +1283,12 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 leve return false; } + if (m_impl->isTarget) + { + NazaraError("Texture is a target, it cannot be updated"); + return false; + } + if (m_impl->type == nzImageType_Cubemap) { NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); @@ -1263,15 +1352,15 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 leve switch (m_impl->type) { case nzImageType_1D: - glTexSubImage1D(GL_TEXTURE_1D, level, cube.x, cube.width, format->dataFormat, format->dataType, mirrored); + glTexSubImage1D(GL_TEXTURE_1D, level, cube.x, cube.width, format.dataFormat, format.dataType, mirrored); break; case nzImageType_2D: - glTexSubImage1D(GL_TEXTURE_2D, level, cube.x, cube.y, cube.width, cube.height, format->dataFormat, format->dataType, mirrored); + glTexSubImage2D(GL_TEXTURE_2D, level, cube.x, cube.y, cube.width, cube.height, format.dataFormat, format.dataType, mirrored); break; case nzImageType_3D: - glTexSubImage1D(GL_TEXTURE_3D, level, cube.x, cube.y, cube.z, cube.width, cube.height, cube.depth, format->dataFormat, format->dataType, mirrored); + glTexSubImage3D(GL_TEXTURE_3D, level, cube.x, cube.y, cube.z, cube.width, cube.height, cube.depth, format.dataFormat, format.dataType, mirrored); break; default: @@ -1284,7 +1373,7 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 leve return true; } -*/ + bool NzTexture::UpdateFace(nzCubemapFace face, const NzImage& image, nzUInt8 level) { #if NAZARA_RENDERER_SAFE @@ -1345,6 +1434,12 @@ bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRe return false; } + if (m_impl->isTarget) + { + NazaraError("Texture is a target, it cannot be updated"); + return false; + } + if (m_impl->type != nzImageType_Cubemap) { NazaraError("UpdateFace is designed for cubemaps, use Update instead"); @@ -1433,14 +1528,6 @@ unsigned int NzTexture::GetValidSize(unsigned int size) bool NzTexture::IsFormatSupported(nzPixelFormat format) { - #if NAZARA_RENDERER_SAFE - if (!NzPixelFormat::IsValid(format)) - { - NazaraError("Invalid pixel format"); - return nzPixelFormat_Undefined; - } - #endif - switch (format) { // Formats de base @@ -1468,9 +1555,14 @@ bool NzTexture::IsFormatSupported(nzPixelFormat format) return supported; } - default: - return false; + case nzPixelFormat_Undefined: + case nzPixelFormat_Count: + break; } + + NazaraError("Invalid pixel format"); + + return false; } bool NzTexture::IsTypeSupported(nzImageType type) @@ -1487,3 +1579,16 @@ bool NzTexture::IsTypeSupported(nzImageType type) return false; } } + +void NzTexture::SetTarget(bool isTarget) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraInternalError("Texture must be valid"); + return; + } + #endif + + m_impl->isTarget = isTarget; +} diff --git a/src/Nazara/Renderer/VertexBuffer.cpp b/src/Nazara/Renderer/VertexBuffer.cpp index 62bdac667..fed64316b 100644 --- a/src/Nazara/Renderer/VertexBuffer.cpp +++ b/src/Nazara/Renderer/VertexBuffer.cpp @@ -97,7 +97,7 @@ bool NzVertexBuffer::IsHardware() const return m_buffer->IsHardware(); } -void* NzVertexBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned int length) +void* NzVertexBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned int length) { #if NAZARA_RENDERER_SAFE if (offset+length > m_vertexCount) @@ -107,10 +107,10 @@ void* NzVertexBuffer::Lock(nzBufferLock lock, unsigned int offset, unsigned int } #endif - return m_buffer->Lock(lock, m_startVertex+offset, (length) ? length : m_vertexCount-offset); + return m_buffer->Map(access, m_startVertex+offset, (length) ? length : m_vertexCount-offset); } -bool NzVertexBuffer::Unlock() +bool NzVertexBuffer::Unmap() { - return m_buffer->Unlock(); + return m_buffer->Unmap(); } diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index aeca004a7..d5a1f08b6 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -701,21 +701,72 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z return false; } + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return false; + } + #endif + + unsigned int width = std::max(m_sharedImage->width >> level, 1U); + unsigned int height = std::max(m_sharedImage->height >> level, 1U); + + #if NAZARA_UTILITY_SAFE if (!rect.IsValid()) { NazaraError("Invalid rectangle"); return false; } - if (rect.x+rect.width > std::max(m_sharedImage->width >> level, 1U) || rect.y+rect.height > std::max(m_sharedImage->height >> level, 1U)) + if (rect.x+rect.width > width || rect.y+rect.height > height) { NazaraError("Rectangle dimensions are out of bounds"); return false; } - if (z >= std::max(m_sharedImage->depth >> level, 1U)) + unsigned int depth = std::max(m_sharedImage->depth >> level, 1U); + if (z >= depth) { - NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(m_sharedImage->depth) + ')'); + NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(depth) + ')'); + return false; + } + #endif + + EnsureOwnership(); + + nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); + nzUInt8* dstPixels = &m_sharedImage->pixels[level][(height*(width*z + rect.y) + rect.x) * bpp]; + unsigned int srcStride = rect.width * bpp; + unsigned int blockSize = width * bpp; + for (unsigned int i = 0; i < rect.height; ++i) + { + std::memcpy(dstPixels, pixels, blockSize); + pixels += srcStride; + dstPixels += blockSize; + } + + return true; +} + +bool NzImage::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level) +{ + ///FIXME: Vérifier que ça fonctionne correctement + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (m_sharedImage->type == nzImageType_Cubemap) + { + NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); + return false; + } + + if (!pixels) + { + NazaraError("Invalid pixel source"); return false; } @@ -726,17 +777,42 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z } #endif + unsigned int width = std::max(m_sharedImage->width >> level, 1U); + unsigned int height = std::max(m_sharedImage->height >> level, 1U); + unsigned int depth = std::max(m_sharedImage->height >> level, 1U); + + #if NAZARA_UTILITY_SAFE + if (!cube.IsValid()) + { + NazaraError("Invalid cube"); + return false; + } + + if (cube.x+cube.width > width || cube.y+cube.height > height || cube.z+cube.depth > depth) + { + NazaraError("Cube dimensions are out of bounds"); + return false; + } + #endif + EnsureOwnership(); nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); - nzUInt8* dstPixels = &m_sharedImage->pixels[level][(m_sharedImage->height*(m_sharedImage->width*z + rect.y) + rect.x) * bpp]; - unsigned int srcStride = rect.width * bpp; - unsigned int blockSize = m_sharedImage->width * bpp; - for (unsigned int i = 0; i < rect.height; ++i) + nzUInt8* dstPixels = &m_sharedImage->pixels[level][(height*(width*cube.z + cube.y) + cube.x) * bpp]; + unsigned int srcStride = cube.width * bpp; + unsigned int blockSize = width * bpp; + unsigned int faceSize = width * height * bpp; + for (unsigned int z = 0; z < cube.depth; ++z) { - std::memcpy(dstPixels, pixels, blockSize); - pixels += srcStride; - dstPixels += blockSize; + nzUInt8* facePixels = dstPixels; + for (unsigned int i = 0; i < cube.height; ++i) + { + std::memcpy(dstPixels, pixels, blockSize); + pixels += srcStride; + facePixels += blockSize; + } + + dstPixels += faceSize; } return true; diff --git a/src/Nazara/Utility/Loaders/STB.cpp b/src/Nazara/Utility/Loaders/STB.cpp index ff0e3fbea..1b6ed1c6b 100644 --- a/src/Nazara/Utility/Loaders/STB.cpp +++ b/src/Nazara/Utility/Loaders/STB.cpp @@ -21,19 +21,19 @@ namespace { int Read(void* userdata, char* data, int size) { - NzInputStream* stream = static_cast(userdata); + NzInputStream* stream = reinterpret_cast(userdata); return static_cast(stream->Read(data, size)); } void Skip(void* userdata, unsigned int size) { - NzInputStream* stream = static_cast(userdata); + NzInputStream* stream = reinterpret_cast(userdata); stream->Read(nullptr, size); } int Eof(void* userdata) { - NzInputStream* stream = static_cast(userdata); + NzInputStream* stream = reinterpret_cast(userdata); return stream->GetCursorPos() >= stream->GetSize(); } @@ -63,7 +63,8 @@ namespace { NazaraUnused(parameters); - static nzPixelFormat formats[4] = { + static const nzPixelFormat formats[4] = + { nzPixelFormat_L8, nzPixelFormat_LA8, nzPixelFormat_RGB8, @@ -134,7 +135,7 @@ namespace NazaraUnused(parameters); int width, height, bpp; - return stbi_info_from_memory(static_cast(data), size, &width, &height, &bpp); + return stbi_info_from_memory(reinterpret_cast(data), size, &width, &height, &bpp); } bool NzLoader_STB_IsStreamLoadingSupported(NzInputStream& stream, const NzImageParams& parameters) diff --git a/src/Nazara/Utility/PixelFormat.cpp b/src/Nazara/Utility/PixelFormat.cpp index 84685f296..1a189181e 100644 --- a/src/Nazara/Utility/PixelFormat.cpp +++ b/src/Nazara/Utility/PixelFormat.cpp @@ -1317,4 +1317,4 @@ void NzPixelFormat::Uninitialize() std::memset(s_convertFunctions, 0, nzPixelFormat_Count*nzPixelFormat_Count*sizeof(NzPixelFormat::ConvertFunction)); } -NzPixelFormat::ConvertFunction NzPixelFormat::s_convertFunctions[nzPixelFormat_Count][nzPixelFormat_Count] = {{0}}; +NzPixelFormat::ConvertFunction NzPixelFormat::s_convertFunctions[nzPixelFormat_Count][nzPixelFormat_Count] = {{0}}; ///FIXME: Fonctionne correctement ? diff --git a/src/Nazara/Utility/Win32/InputImpl.cpp b/src/Nazara/Utility/Win32/InputImpl.cpp index 3423b16c8..4d44710db 100644 --- a/src/Nazara/Utility/Win32/InputImpl.cpp +++ b/src/Nazara/Utility/Win32/InputImpl.cpp @@ -18,7 +18,7 @@ NzVector2i NzEventImpl::GetMousePosition() NzVector2i NzEventImpl::GetMousePosition(const NzWindow& relativeTo) { - HWND handle = static_cast(relativeTo.GetHandle()); + HWND handle = reinterpret_cast(relativeTo.GetHandle()); if (handle) { POINT pos; @@ -229,7 +229,7 @@ void NzEventImpl::SetMousePosition(int x, int y) void NzEventImpl::SetMousePosition(int x, int y, const NzWindow& relativeTo) { - HWND handle = static_cast(relativeTo.GetHandle()); + HWND handle = reinterpret_cast(relativeTo.GetHandle()); if (handle) { POINT pos = {x, y}; diff --git a/src/Nazara/Utility/Win32/WindowImpl.cpp b/src/Nazara/Utility/Win32/WindowImpl.cpp index 946045a5c..8ce9a18b7 100644 --- a/src/Nazara/Utility/Win32/WindowImpl.cpp +++ b/src/Nazara/Utility/Win32/WindowImpl.cpp @@ -166,7 +166,7 @@ bool NzWindowImpl::Create(NzWindowHandle handle) return false; } - m_handle = static_cast(handle); + m_handle = reinterpret_cast(handle); m_eventListener = false; m_ownsWindow = false; @@ -354,7 +354,7 @@ void NzWindowImpl::ShowMouseCursor(bool show) // http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045(v=vs.85).aspx if (show) - m_cursor = static_cast(LoadImage(nullptr, MAKEINTRESOURCE(OCR_NORMAL), IMAGE_CURSOR, 0, 0, LR_SHARED)); + m_cursor = reinterpret_cast(LoadImage(nullptr, MAKEINTRESOURCE(OCR_NORMAL), IMAGE_CURSOR, 0, 0, LR_SHARED)); else m_cursor = nullptr; From 0f84f8eda84d2f4a02cbcce32d2754c8b7f34e29 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 13 Jun 2012 17:54:07 +0200 Subject: [PATCH 14/15] Added Quaternion spheric interpolation Fixed NzVector(2/3)::Length() and NzQuaternion::Magnitude() returning double instead of template type Added quaternion dot product Added gitignore --- .gitignore | 151 +++++++++++++++++++++++++++++ include/Nazara/Math/Quaternion.hpp | 16 ++- include/Nazara/Math/Quaternion.inl | 108 +++++++++++++++------ include/Nazara/Math/Vector2.hpp | 6 +- include/Nazara/Math/Vector2.inl | 8 +- include/Nazara/Math/Vector3.hpp | 6 +- include/Nazara/Math/Vector3.inl | 8 +- 7 files changed, 254 insertions(+), 49 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..44729e355 --- /dev/null +++ b/.gitignore @@ -0,0 +1,151 @@ +# Codeblocks +*.cbp +*.cscope_file_list +*.depend +*.layout +*.workspace + +# Compiled Object files +*.slo +*.lo +*.o + +# Compiled Dynamic libraries +*.so + +# Compiled Static libraries +*.lai +*.la +*.a + +# Object files +*.o + +# Libraries +*.lib + +# Shared objects (inc. Windows DLLs) +*.dll +*.so + +# Executables +*.exe +*.out + +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results + +[Dd]ebug*/ +[Rr]elease/ + +build/ + + +[Tt]est[Rr]esult +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.vspscc +*.vssscc +.builds + +*.pidb + +*.log +*.scc +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ + +*.[Rr]e[Ss]harper + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish + +# Publish Web Output +*.Publish.xml + +# Others +[Bb]in +[Oo]bj +sql +TestResults +[Tt]est[Rr]esult* +*.Cache +ClientBin +[Ss]tyle[Cc]op.* +~$* +*.dbmdl + +*.[Pp]ublish.xml + +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML + +# NuGet +packages/ \ No newline at end of file diff --git a/include/Nazara/Math/Quaternion.hpp b/include/Nazara/Math/Quaternion.hpp index a36a7c4e6..a5e892f2a 100644 --- a/include/Nazara/Math/Quaternion.hpp +++ b/include/Nazara/Math/Quaternion.hpp @@ -26,11 +26,13 @@ template class NzQuaternion NzQuaternion(const NzQuaternion& quat) = default; ~NzQuaternion() = default; + T DotProduct(const NzQuaternion& vec) const; + NzQuaternion GetConjugate() const; NzQuaternion GetNormalized() const; - double Magnitude() const; - double Normalize(); + T Magnitude() const; + T Normalize(); T SquaredMagnitude() const; void Set(T W, T X, T Y, T Z); @@ -47,14 +49,16 @@ template class NzQuaternion //NzMatrix3 ToRotationMatrix() const; NzString ToString() const; + NzQuaternion operator+(const NzQuaternion& quat) const; NzQuaternion operator*(const NzQuaternion& quat) const; NzVector3 operator*(const NzVector3& vec) const; NzQuaternion operator*(T scale) const; NzQuaternion operator/(const NzQuaternion& quat) const; - NzQuaternion operator*=(const NzQuaternion& quat); - NzQuaternion operator*=(T scale); - NzQuaternion operator/=(const NzQuaternion& quat); + NzQuaternion& operator+=(const NzQuaternion& quat); + NzQuaternion& operator*=(const NzQuaternion& quat); + NzQuaternion& operator*=(T scale); + NzQuaternion& operator/=(const NzQuaternion& quat); bool operator==(const NzQuaternion& quat) const; bool operator!=(const NzQuaternion& quat) const; @@ -63,6 +67,8 @@ template class NzQuaternion bool operator>(const NzQuaternion& quat) const; bool operator>=(const NzQuaternion& quat) const; + static NzQuaternion Slerp(const NzQuaternion& quatA, const NzQuaternion& quatB, T interp); + T w, x, y, z; }; diff --git a/include/Nazara/Math/Quaternion.inl b/include/Nazara/Math/Quaternion.inl index 1017798df..a49fbde81 100644 --- a/include/Nazara/Math/Quaternion.inl +++ b/include/Nazara/Math/Quaternion.inl @@ -52,6 +52,12 @@ NzQuaternion::NzQuaternion(const NzQuaternion& quat) Set(quat); } +template +T NzQuaternion::DotProduct(const NzQuaternion& vec) const +{ + return w*vec.w + x*vec.x + y*vec.y + z.vec.z; +} + template NzQuaternion NzQuaternion::GetConjugate() const { @@ -68,19 +74,19 @@ NzQuaternion NzQuaternion::GetNormalized() const } template -double NzQuaternion::Magnitude() const +T NzQuaternion::Magnitude() const { return std::sqrt(SquaredMagnitude()); } template -double NzQuaternion::Normalize() +T NzQuaternion::Normalize() { T squaredLength = SquaredMagnitude(); if (std::fabs(squaredLength) > 0.00001 && std::fabs(squaredLength - 1.0) > 0.00001) { - double length = std::sqrt(squaredLength); + T length = std::sqrt(squaredLength); w /= length; x /= length; @@ -90,7 +96,7 @@ double NzQuaternion::Normalize() return length; } else - return std::sqrt(squaredLength); + return 1.0; // Le quaternion est déjà normalisé } template @@ -106,8 +112,6 @@ void NzQuaternion::Set(T W, T X, T Y, T Z) x = X; y = Y; z = Z; - - Normalize(); } template @@ -117,8 +121,6 @@ void NzQuaternion::Set(T quat[4]) x = quat[1]; y = quat[2]; z = quat[3]; - - Normalize(); } template @@ -175,6 +177,52 @@ void NzQuaternion::SetZero() Set(0.0, 0.0, 0.0, 0.0); } +template +NzQuaternion NzQuaternion::Slerp(const NzQuaternion& quatA, const NzQuaternion& quatB, T interp) +{ + if (interp <= 0.0) + return quatA; + + if (interp >= 1.0) + return quatB; + + NzQuaternion q; + + T cosOmega = quatA.DotProduct(quatB); + if (cosOmega < 0.0) + { + // On inverse tout + q.Set(-quatB.w, -quatB.x, -quatB.y, -quatB.z); + cosOmega = -cosOmega; + } + else + q.Set(quatB); + + T k0, k1; + if (cosOmega > 0.9999) + { + // Interpolation linéaire pour éviter une division par zéro + k0 = 1.0 - interp; + k1 = interp; + } + else + { + T sinOmega = std::sqrt(1.0f - (cosOmega * cosOmega)); + T omega = std::atan2(sinOmega, cosOmega); + + // Pour éviter deux divisions + sinOmega = 1/sinOmega; + + k0 = std::sin((1.0 - interp) * omega) * sinOmega; + k1 = std::sin(interp * omega) * sinOmega; + } + + /* interpolate and return new quaternion */ + NzQuaternion result(k0 * quatA.w, k0 * quatA.x, k0 * quatA.y, k0 * quatA.z); + + return result += q; +} + template NzEulerAngles NzQuaternion::ToEulerAngles() const { @@ -203,17 +251,22 @@ NzString NzQuaternion::ToString() const return ss << "Quaternion(" << w << " | " << x << ", " << y << ", " << z << ')'; } +template +NzQuaternion NzQuaternion::operator+(const NzQuaternion& quat) const +{ + return NzQuaternion(w + quat.w, + x + quat.x, + y + quat.y, + z + quat.z); +} + template NzQuaternion NzQuaternion::operator*(const NzQuaternion& quat) const { - NzQuaternion result(w * quat.w - x * quat.x - y * quat.y - z * quat.z, + return NzQuaternion(w * quat.w - x * quat.x - y * quat.y - z * quat.z, w * quat.x + x * quat.w + y * quat.z - z * quat.y, w * quat.y + y * quat.w + z * quat.x - x * quat.z, w * quat.z + z * quat.w + x * quat.y - y * quat.x); - - result.Normalize(); - - return result; } template @@ -223,9 +276,7 @@ NzVector3 NzQuaternion::operator*(const NzVector3& vec) const normal.Normalise(); NzQuaternion qvec(0.0, normal.x, normal.y, normal.z); - NzQuaternion result; - - result = operator*(qvec * GetConjugate()); + NzQuaternion result = operator*(qvec * GetConjugate()); return NzVector3(result.x, result.y, result.z); @@ -247,30 +298,27 @@ NzQuaternion NzQuaternion::operator/(const NzQuaternion& quat) const } template -NzQuaternion NzQuaternion::operator*=(const NzQuaternion& quat) +NzQuaternion& NzQuaternion::operator+=(const NzQuaternion& quat) { - NzQuaternion q(*this); - - return operator=(q * quat); + return operator=(operator+(quat)); } template -NzQuaternion NzQuaternion::operator*=(T scale) +NzQuaternion& NzQuaternion::operator*=(const NzQuaternion& quat) { - w *= scale; - x *= scale; - y *= scale; - z *= scale; - - return *this; + return operator=(operator*(quat)); } template -NzQuaternion NzQuaternion::operator/=(const NzQuaternion& quat) +NzQuaternion& NzQuaternion::operator*=(T scale) { - NzQuaternion q(*this); + return operator=(operator*(scale)); +} - return operator=(q / quat); +template +NzQuaternion& NzQuaternion::operator/=(const NzQuaternion& quat) +{ + return operator=(operator/(quat)); } template diff --git a/include/Nazara/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index bd2c54017..ec12330c0 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -21,13 +21,13 @@ template class NzVector2 ~NzVector2() = default; T AbsDotProduct(const NzVector2& vec) const; - double Distance(const NzVector2& vec) const; + T Distance(const NzVector2& vec) const; T DotProduct(const NzVector2& vec) const; NzVector2 GetNormal() const; void MakeCeil(const NzVector2& vec); void MakeFloor(const NzVector2& vec); - double Length() const; - double Normalize(); + T Length() const; + T Normalize(); T SquaredDistance(const NzVector2& vec) const; T SquaredLength() const; diff --git a/include/Nazara/Math/Vector2.inl b/include/Nazara/Math/Vector2.inl index 3026f860b..d8214981c 100644 --- a/include/Nazara/Math/Vector2.inl +++ b/include/Nazara/Math/Vector2.inl @@ -55,7 +55,7 @@ template<> inline int NzVector2::AbsDotProduct(const NzVector2& vec) c } template -double NzVector2::Distance(const NzVector2& vec) const +T NzVector2::Distance(const NzVector2& vec) const { return std::sqrt(SquaredDistance(vec)); } @@ -96,15 +96,15 @@ void NzVector2::MakeFloor(const NzVector2& vec) } template -double NzVector2::Length() const +T NzVector2::Length() const { return std::sqrt(SquaredLength()); } template -double NzVector2::Normalize() +T NzVector2::Normalize() { - double length = Length(); + T length = Length(); if (length != 0.f) { diff --git a/include/Nazara/Math/Vector3.hpp b/include/Nazara/Math/Vector3.hpp index bd0dc9b35..563ec83c8 100644 --- a/include/Nazara/Math/Vector3.hpp +++ b/include/Nazara/Math/Vector3.hpp @@ -22,13 +22,13 @@ template class NzVector3 T AbsDotProduct(const NzVector3& vec) const; NzVector3 CrossProduct(const NzVector3& vec) const; - double Distance(const NzVector3& vec) const; + T Distance(const NzVector3& vec) const; T DotProduct(const NzVector3& vec) const; NzVector3 GetNormal() const; void MakeCeil(const NzVector3& vec); void MakeFloor(const NzVector3& vec); - double Length() const; - double Normalize(); + T Length() const; + T Normalize(); T SquaredDistance(const NzVector3& vec) const; T SquaredLength() const; diff --git a/include/Nazara/Math/Vector3.inl b/include/Nazara/Math/Vector3.inl index 40e1cabb7..30c1e15e4 100644 --- a/include/Nazara/Math/Vector3.inl +++ b/include/Nazara/Math/Vector3.inl @@ -65,7 +65,7 @@ NzVector3 NzVector3::CrossProduct(const NzVector3& vec) const } template -double NzVector3::Distance(const NzVector3& vec) const +T NzVector3::Distance(const NzVector3& vec) const { return std::sqrt(SquaredDistance(vec)); } @@ -112,15 +112,15 @@ void NzVector3::MakeFloor(const NzVector3& vec) } template -double NzVector3::Length() const +T NzVector3::Length() const { return std::sqrt(SquaredLength()); } template -double NzVector3::Normalize() +T NzVector3::Normalize() { - double length = Length(); + T length = Length(); if (length != 0.f) { From be0a5d2819166cffcf77894abeb2a818f04e4365 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 15 Jun 2012 11:03:43 +0200 Subject: [PATCH 15/15] Fixed many bugs Added NzOpenGL::GetEntry Activated preprocessor error if not compiling with a C++11 compliant compiler Cube can now be constructed with a Rect Desactived utility option "threaded window" (bugged) Epured Image interface (No more UpdateFace, use Update with z = the face you are targetting) Fixed compilation errors (Thanks to RafBill) Fixed predefined colors not exported Fixed uplading pixels not aligned by 4 bytes Fixed Thumbs.db files not ignored by git NzImage now supports Filling and Flipping (Horizontally and vertically) NzImage::Get(Const)Pixels now support pixel location NzVector(2/3) can now return floatting distance/length with all types NzVector(2/3/4) can now be constructed by a vector of smaller dimension Premake now set "-std=c++11" build option for GCC Renamed NzImage::(Get/Set)Pixel to (Get/Set)PixelColor Updated new([])/delete([]) in the leaks tracker to the new C++11 signatures --- .gitignore | 2 +- .../src/Nazara/ModuleName/Debug/Leaks.cpp | 8 +- build/scripts/common.lua | 3 + include/Nazara/Core/Color.hpp | 18 +- include/Nazara/Math/Cube.hpp | 2 + include/Nazara/Math/Cube.inl | 11 + include/Nazara/Math/Matrix4.hpp | 7 +- include/Nazara/Math/Matrix4.inl | 2 +- include/Nazara/Math/Quaternion.inl | 4 +- include/Nazara/Math/Vector2.hpp | 4 +- include/Nazara/Math/Vector2.inl | 39 +- include/Nazara/Math/Vector3.hpp | 7 +- include/Nazara/Math/Vector3.inl | 45 +- include/Nazara/Math/Vector4.hpp | 2 + include/Nazara/Math/Vector4.inl | 34 +- include/Nazara/Prerequesites.hpp | 5 +- include/Nazara/Renderer/OpenGL.hpp | 2 + include/Nazara/Utility/Config.hpp | 2 +- include/Nazara/Utility/Image.hpp | 53 +- readme.txt | 5 +- readme_fr.txt | 5 +- src/Nazara/Audio/Debug/Leaks.cpp | 8 +- src/Nazara/Core/Debug/Leaks.cpp | 8 +- src/Nazara/Core/Debug/MemoryLeakTracker.cpp | 2 +- src/Nazara/Core/Win32/ThreadImpl.cpp | 2 +- src/Nazara/Core/Win32/ThreadImpl.hpp | 2 +- src/Nazara/Network/Debug/Leaks.cpp | 8 +- src/Nazara/Noise/Debug/Leaks.cpp | 8 +- src/Nazara/Renderer/Buffer.cpp | 4 +- src/Nazara/Renderer/Debug/Leaks.cpp | 8 +- src/Nazara/Renderer/OpenGL.cpp | 7 + src/Nazara/Renderer/RenderWindow.cpp | 3 +- src/Nazara/Renderer/Texture.cpp | 178 +++-- src/Nazara/Utility/Debug/Leaks.cpp | 8 +- src/Nazara/Utility/Image.cpp | 681 +++++++++++------- src/Nazara/Utility/Loaders/STB.cpp | 2 +- .../STB/{stb_image.c => stb_image.cpp} | 0 src/Nazara/Utility/Win32/WindowImpl.cpp | 11 +- src/Nazara/Utility/Window.cpp | 1 + 39 files changed, 739 insertions(+), 462 deletions(-) rename src/Nazara/Utility/Loaders/STB/{stb_image.c => stb_image.cpp} (100%) diff --git a/.gitignore b/.gitignore index 44729e355..fd6451f19 100644 --- a/.gitignore +++ b/.gitignore @@ -33,7 +33,7 @@ *.out # Windows image file caches -Thumbs.db +Thumbs.db # Folder config file Desktop.ini diff --git a/NazaraModuleTemplate/src/Nazara/ModuleName/Debug/Leaks.cpp b/NazaraModuleTemplate/src/Nazara/ModuleName/Debug/Leaks.cpp index 13e396e67..6c4fc1d7d 100644 --- a/NazaraModuleTemplate/src/Nazara/ModuleName/Debug/Leaks.cpp +++ b/NazaraModuleTemplate/src/Nazara/ModuleName/Debug/Leaks.cpp @@ -7,22 +7,22 @@ #include #include -void* operator new(std::size_t size) throw(std::bad_alloc) +void* operator new(std::size_t size) { return NzMemoryManager::Allocate(size, false); } -void* operator new[](std::size_t size) throw(std::bad_alloc) +void* operator new[](std::size_t size) { return NzMemoryManager::Allocate(size, true); } -void operator delete(void* pointer) throw() +void operator delete(void* pointer) noexcept { NzMemoryManager::Free(pointer, false); } -void operator delete[](void* pointer) throw() +void operator delete[](void* pointer) noexcept { NzMemoryManager::Free(pointer, true); } diff --git a/build/scripts/common.lua b/build/scripts/common.lua index 220bd104c..d2df3aa9a 100644 --- a/build/scripts/common.lua +++ b/build/scripts/common.lua @@ -32,5 +32,8 @@ configuration "*Static" configuration "*DLL" kind "SharedLib" +configuration "gmake" + buildoptions "-std=c++11" + configuration { "linux or bsd or macosx", "gmake" } buildoptions "-fvisibility=hidden" \ No newline at end of file diff --git a/include/Nazara/Core/Color.hpp b/include/Nazara/Core/Color.hpp index 7a3b59f42..609fae5ae 100644 --- a/include/Nazara/Core/Color.hpp +++ b/include/Nazara/Core/Color.hpp @@ -47,15 +47,15 @@ class NzColor nzUInt8 r, g, b, a; - static const NzColor Black; - static const NzColor Blue; - static const NzColor Cyan; - static const NzColor Green; - static const NzColor Magenta; - static const NzColor Orange; - static const NzColor Red; - static const NzColor Yellow; - static const NzColor White; + static NAZARA_API const NzColor Black; + static NAZARA_API const NzColor Blue; + static NAZARA_API const NzColor Cyan; + static NAZARA_API const NzColor Green; + static NAZARA_API const NzColor Magenta; + static NAZARA_API const NzColor Orange; + static NAZARA_API const NzColor Red; + static NAZARA_API const NzColor Yellow; + static NAZARA_API const NzColor White; private: static float Hue2RGB(float v1, float v2, float vH); diff --git a/include/Nazara/Math/Cube.hpp b/include/Nazara/Math/Cube.hpp index bbc98dae4..57aacdf77 100644 --- a/include/Nazara/Math/Cube.hpp +++ b/include/Nazara/Math/Cube.hpp @@ -8,6 +8,7 @@ #define NAZARA_CUBE_HPP #include +#include #include template @@ -17,6 +18,7 @@ class NzCube NzCube(); NzCube(T X, T Y, T Z, T Width, T Height, T Depth); NzCube(T cube[6]); + NzCube(const NzRect& rect); template explicit NzCube(const NzCube& rect); NzCube(const NzCube& rect) = default; ~NzCube() = default; diff --git a/include/Nazara/Math/Cube.inl b/include/Nazara/Math/Cube.inl index f281dc824..5fc3b0c2d 100644 --- a/include/Nazara/Math/Cube.inl +++ b/include/Nazara/Math/Cube.inl @@ -33,6 +33,17 @@ depth(vec[5]) { } +template +NzCube::NzCube(const NzRect& rect) : +x(rect.x), +y(rect.y), +z(0), +width(rect.width), +height(rect.height), +depth(1) +{ +} + template template NzCube::NzCube(const NzCube& rect) : diff --git a/include/Nazara/Math/Matrix4.hpp b/include/Nazara/Math/Matrix4.hpp index f53ad1499..5b6e5878c 100644 --- a/include/Nazara/Math/Matrix4.hpp +++ b/include/Nazara/Math/Matrix4.hpp @@ -96,17 +96,12 @@ template class NzMatrix4 struct SharedMatrix { - SharedMatrix() : // Vivement GCC 4.7 sur Windows - refCount(1) - { - } - T m11, m12, m13, m14; T m21, m22, m23, m24; T m31, m32, m33, m34; T m41, m42, m43, m44; - unsigned short refCount; + unsigned short refCount = 1; NazaraMutex(mutex) }; diff --git a/include/Nazara/Math/Matrix4.inl b/include/Nazara/Math/Matrix4.inl index fca54c880..708190ad8 100644 --- a/include/Nazara/Math/Matrix4.inl +++ b/include/Nazara/Math/Matrix4.inl @@ -107,7 +107,7 @@ NzMatrix4 NzMatrix4::GetInverse() const NzMatrix4 matrix; T det = GetDeterminant(); - if (det != 0.0) + if (!NzNumberEquals(det, static_cast(0.0))) { matrix(0, 0) = (m_sharedMatrix->m22 * (m_sharedMatrix->m33 * m_sharedMatrix->m44 - m_sharedMatrix->m34 * m_sharedMatrix->m43) - m_sharedMatrix->m32 * (m_sharedMatrix->m23 * m_sharedMatrix->m44 - m_sharedMatrix->m43 * m_sharedMatrix->m24) + m_sharedMatrix->m42 * (m_sharedMatrix->m23 * m_sharedMatrix->m34 - m_sharedMatrix->m33 * m_sharedMatrix->m24)) / det; matrix(0, 1) = -(m_sharedMatrix->m12 * (m_sharedMatrix->m33 * m_sharedMatrix->m44 - m_sharedMatrix->m43 * m_sharedMatrix->m34) - m_sharedMatrix->m32 * (m_sharedMatrix->m13 * m_sharedMatrix->m44 - m_sharedMatrix->m43 * m_sharedMatrix->m14) + m_sharedMatrix->m42 * (m_sharedMatrix->m13 * m_sharedMatrix->m34 - m_sharedMatrix->m33 * m_sharedMatrix->m14)) / det; diff --git a/include/Nazara/Math/Quaternion.inl b/include/Nazara/Math/Quaternion.inl index a49fbde81..afba1dd72 100644 --- a/include/Nazara/Math/Quaternion.inl +++ b/include/Nazara/Math/Quaternion.inl @@ -217,15 +217,15 @@ NzQuaternion NzQuaternion::Slerp(const NzQuaternion& quatA, const NzQuater k1 = std::sin(interp * omega) * sinOmega; } - /* interpolate and return new quaternion */ NzQuaternion result(k0 * quatA.w, k0 * quatA.x, k0 * quatA.y, k0 * quatA.z); - return result += q; } template NzEulerAngles NzQuaternion::ToEulerAngles() const { + Normalize(); + T test = x*y + z*w; if (test > 0.499) // singularity at north pole diff --git a/include/Nazara/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index ec12330c0..6473d7206 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -22,12 +22,14 @@ template class NzVector2 T AbsDotProduct(const NzVector2& vec) const; T Distance(const NzVector2& vec) const; + float Distancef(const NzVector2& vec) const; T DotProduct(const NzVector2& vec) const; NzVector2 GetNormal() const; void MakeCeil(const NzVector2& vec); void MakeFloor(const NzVector2& vec); T Length() const; - T Normalize(); + float Lengthf() const; + void Normalize(); T SquaredDistance(const NzVector2& vec) const; T SquaredLength() const; diff --git a/include/Nazara/Math/Vector2.inl b/include/Nazara/Math/Vector2.inl index d8214981c..3889aaa78 100644 --- a/include/Nazara/Math/Vector2.inl +++ b/include/Nazara/Math/Vector2.inl @@ -49,7 +49,14 @@ T NzVector2::AbsDotProduct(const NzVector2& vec) const return std::fabs(x * vec.x) + std::fabs(y * vec.y); } -template<> inline int NzVector2::AbsDotProduct(const NzVector2& vec) const +template<> +inline int NzVector2::AbsDotProduct(const NzVector2& vec) const +{ + return std::labs(x * vec.x) + std::labs(y * vec.y); +} + +template<> +inline unsigned int NzVector2::AbsDotProduct(const NzVector2& vec) const { return std::labs(x * vec.x) + std::labs(y * vec.y); } @@ -60,6 +67,12 @@ T NzVector2::Distance(const NzVector2& vec) const return std::sqrt(SquaredDistance(vec)); } +template +float NzVector2::Distancef(const NzVector2& vec) const +{ + return std::sqrt(static_cast(SquaredDistance(vec))); +} + template T NzVector2::DotProduct(const NzVector2& vec) const { @@ -102,17 +115,21 @@ T NzVector2::Length() const } template -T NzVector2::Normalize() +float NzVector2::Lengthf() const { - T length = Length(); + return std::sqrt(static_cast(SquaredLength())); +} - if (length != 0.f) +template +void NzVector2::Normalize() +{ + auto length = Length(); + + if (!NzNumberEquals(length, static_cast(0.0))) { x /= length; y /= length; } - - return length; } template @@ -214,7 +231,7 @@ NzVector2 NzVector2::operator*(T scale) const template NzVector2 NzVector2::operator/(const NzVector2& vec) const { - if (vec.x == 0.f || vec.y == 0.f) + if (NzNumberEquals(vec.x, static_cast(0.0)) || NzNumberEquals(vec.y, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; @@ -228,7 +245,7 @@ NzVector2 NzVector2::operator/(const NzVector2& vec) const template NzVector2 NzVector2::operator/(T scale) const { - if (scale == 0.f) + if (NzNumberEquals(scale, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; @@ -278,7 +295,7 @@ NzVector2& NzVector2::operator*=(T scale) template NzVector2& NzVector2::operator/=(const NzVector2& vec) { - if (vec.x == 0.f || vec.y == 0.f) + if (NzNumberEquals(vec.x, static_cast(0.0)) || NzNumberEquals(vec.y, static_cast(0.0)) || NzNumberEquals(vec.z, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; @@ -295,7 +312,7 @@ NzVector2& NzVector2::operator/=(const NzVector2& vec) template NzVector2& NzVector2::operator/=(T scale) { - if (scale == 0.f) + if (NzNumberEquals(scale, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; @@ -361,7 +378,7 @@ NzVector2 operator*(T scale, const NzVector2& vec) template NzVector2 operator/(T scale, const NzVector2& vec) { - if (vec.x == 0.f || vec.y == 0.f) + if (NzNumberEquals(vec.x, static_cast(0.0)) || NzNumberEquals(vec.y, static_cast(0.0)) || NzNumberEquals(vec.z, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; diff --git a/include/Nazara/Math/Vector3.hpp b/include/Nazara/Math/Vector3.hpp index 563ec83c8..04e3834c2 100644 --- a/include/Nazara/Math/Vector3.hpp +++ b/include/Nazara/Math/Vector3.hpp @@ -8,6 +8,7 @@ #define NAZARA_VECTOR3_HPP #include +#include template class NzVector3 { @@ -16,6 +17,7 @@ template class NzVector3 NzVector3(T X, T Y, T Z); explicit NzVector3(T scale); NzVector3(T vec[3]); + NzVector3(const NzVector2& vec); template explicit NzVector3(const NzVector3& vec); NzVector3(const NzVector3& vec) = default; ~NzVector3() = default; @@ -23,12 +25,14 @@ template class NzVector3 T AbsDotProduct(const NzVector3& vec) const; NzVector3 CrossProduct(const NzVector3& vec) const; T Distance(const NzVector3& vec) const; + float Distancef(const NzVector3& vec) const; T DotProduct(const NzVector3& vec) const; NzVector3 GetNormal() const; void MakeCeil(const NzVector3& vec); void MakeFloor(const NzVector3& vec); T Length() const; - T Normalize(); + float Lengthf() const; + void Normalize(); T SquaredDistance(const NzVector3& vec) const; T SquaredLength() const; @@ -77,6 +81,7 @@ template NzVector3 operator/(T scale, const NzVector3& vec); typedef NzVector3 NzVector3d; typedef NzVector3 NzVector3f; typedef NzVector3 NzVector3i; +typedef NzVector3 NzVector3ui; #include diff --git a/include/Nazara/Math/Vector3.inl b/include/Nazara/Math/Vector3.inl index 30c1e15e4..73eff32fe 100644 --- a/include/Nazara/Math/Vector3.inl +++ b/include/Nazara/Math/Vector3.inl @@ -38,6 +38,14 @@ z(vec[2]) { } +template +NzVector3::NzVector3(const NzVector2& vec) : +x(vec.x), +y(vec.y), +z(0) +{ +} + template template NzVector3::NzVector3(const NzVector3& vec) : @@ -53,7 +61,14 @@ T NzVector3::AbsDotProduct(const NzVector3& vec) const return std::fabs(x * vec.x) + std::fabs(y * vec.y) + std::fabs(z * vec.z); } -template<> inline int NzVector3::AbsDotProduct(const NzVector3& vec) const +template<> +inline int NzVector3::AbsDotProduct(const NzVector3& vec) const +{ + return std::labs(x * vec.x) + std::labs(y * vec.y) + std::labs(z * vec.z); +} + +template<> +inline unsigned int NzVector3::AbsDotProduct(const NzVector3& vec) const { return std::labs(x * vec.x) + std::labs(y * vec.y) + std::labs(z * vec.z); } @@ -70,6 +85,12 @@ T NzVector3::Distance(const NzVector3& vec) const return std::sqrt(SquaredDistance(vec)); } +template +float NzVector3::Distancef(const NzVector3& vec) const +{ + return std::sqrt(static_cast(SquaredDistance())); +} + template T NzVector3::DotProduct(const NzVector3& vec) const { @@ -118,18 +139,22 @@ T NzVector3::Length() const } template -T NzVector3::Normalize() +float NzVector3::Lengthf() const +{ + return std::sqrt(static_cast(SquaredLength())); +} + +template +void NzVector3::Normalize() { T length = Length(); - if (length != 0.f) + if (!NzNumberEquals(length, static_cast(0.0))) { x /= length; y /= length; z /= length; } - - return length; } template @@ -231,7 +256,7 @@ NzVector3 NzVector3::operator*(T scale) const template NzVector3 NzVector3::operator/(const NzVector3& vec) const { - if (vec.x == 0.f || vec.y == 0.f || vec.z == 0.f) + if (NzNumberEquals(vec.x, static_cast(0.0)) || NzNumberEquals(vec.y, static_cast(0.0)) || NzNumberEquals(vec.z, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; @@ -245,7 +270,7 @@ NzVector3 NzVector3::operator/(const NzVector3& vec) const template NzVector3 NzVector3::operator/(T scale) const { - if (scale == 0.f) + if (NzNumberEquals(scale, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; @@ -299,7 +324,7 @@ NzVector3& NzVector3::operator*=(T scale) template NzVector3& NzVector3::operator/=(const NzVector3& vec) { - if (vec.x == 0.f || vec.y == 0.f || vec.z == 0.f) + if (NzNumberEquals(vec.x, static_cast(0.0)) || NzNumberEquals(vec.y, static_cast(0.0)) || NzNumberEquals(vec.z, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; @@ -317,7 +342,7 @@ NzVector3& NzVector3::operator/=(const NzVector3& vec) template NzVector3& NzVector3::operator/=(T scale) { - if (scale == 0.f) + if (NzNumberEquals(scale, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; @@ -385,7 +410,7 @@ NzVector3 operator*(T scale, const NzVector3& vec) template NzVector3 operator/(T scale, const NzVector3& vec) { - if (vec.x == 0.f || vec.y == 0.f || vec.z == 0.f) + if (NzNumberEquals(vec.x, static_cast(0.0)) || NzNumberEquals(vec.y, static_cast(0.0)) || NzNumberEquals(vec.z, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; diff --git a/include/Nazara/Math/Vector4.hpp b/include/Nazara/Math/Vector4.hpp index afd108acb..872ac16c0 100644 --- a/include/Nazara/Math/Vector4.hpp +++ b/include/Nazara/Math/Vector4.hpp @@ -8,6 +8,7 @@ #define NAZARA_VECTOR4_HPP #include +#include template class NzVector4 { @@ -17,6 +18,7 @@ template class NzVector4 explicit NzVector4(T scale); NzVector4(T vec[4]); template explicit NzVector4(const NzVector4& vec); + NzVector4(const NzVector3& vec, T W = 1.0); NzVector4(const NzVector4& vec) = default; ~NzVector4() = default; diff --git a/include/Nazara/Math/Vector4.inl b/include/Nazara/Math/Vector4.inl index 3ee1f4165..6620c7f35 100644 --- a/include/Nazara/Math/Vector4.inl +++ b/include/Nazara/Math/Vector4.inl @@ -51,13 +51,29 @@ w(static_cast(vec.w)) { } +template +NzVector4::NzVector4(const NzVector3& vec, T W) : +x(vec.x), +y(vec.y), +z(vec.z), +w(W) +{ +} + template T NzVector4::AbsDotProduct(const NzVector4& vec) const { return std::fabs(x * vec.x) + std::fabs(y * vec.y) + std::fabs(z * vec.z) + std::fabs(w * vec.w); } -template<> inline int NzVector4::AbsDotProduct(const NzVector4& vec) const +template<> +inline int NzVector4::AbsDotProduct(const NzVector4& vec) const +{ + return std::labs(x * vec.x) + std::labs(y * vec.y) + std::labs(z * vec.z) + std::labs(w * vec.w); +} + +template<> +inline unsigned int NzVector4::AbsDotProduct(const NzVector4& vec) const { return std::labs(x * vec.x) + std::labs(y * vec.y) + std::labs(z * vec.z) + std::labs(w * vec.w); } @@ -103,7 +119,7 @@ void NzVector4::MakeFloor(const NzVector4& vec) template void NzVector4::Normalize() { - if (w != 0.f) + if (!NzNumberEquals(w, static_cast(0.0))) { x /= w; y /= w; @@ -116,7 +132,7 @@ NzString NzVector4::ToString() const { NzStringStream ss; - return ss << "Vector4(" << x << ", " << y << ", " << z <<')'; + return ss << "Vector4(" << x << ", " << y << ", " << z << ", " << w << ')'; } template @@ -180,7 +196,7 @@ NzVector4 NzVector4::operator+(const NzVector4& vec) const template NzVector4 NzVector4::operator-(const NzVector4& vec) const { - return NzVector4(x - vec.x, y - vec.y, z - vec.z); + return NzVector4(x - vec.x, y - vec.y, z - vec.z, w - vec.w); } template @@ -198,7 +214,7 @@ NzVector4 NzVector4::operator*(T scale) const template NzVector4 NzVector4::operator/(const NzVector4& vec) const { - if (vec.x == 0.f || vec.y == 0.f || vec.z == 0.f || vec.w == 0.f) + if (NzNumberEquals(vec.x, static_cast(0.0)) || NzNumberEquals(vec.y, static_cast(0.0)) || NzNumberEquals(vec.z, static_cast(0.0)) || NzNumberEquals(vec.w, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; @@ -212,7 +228,7 @@ NzVector4 NzVector4::operator/(const NzVector4& vec) const template NzVector4 NzVector4::operator/(T scale) const { - if (scale == 0.f) + if (NzNumberEquals(scale, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; @@ -270,7 +286,7 @@ NzVector4& NzVector4::operator*=(T scale) template NzVector4& NzVector4::operator/=(const NzVector4& vec) { - if (vec.x == 0.f || vec.y == 0.f || vec.z == 0.f || vec.w == 0.f) + if (NzNumberEquals(vec.x, static_cast(0.0)) || NzNumberEquals(vec.y, static_cast(0.0)) || NzNumberEquals(vec.z, static_cast(0.0)) || NzNumberEquals(vec.w, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; @@ -289,7 +305,7 @@ NzVector4& NzVector4::operator/=(const NzVector4& vec) template NzVector4& NzVector4::operator/=(T scale) { - if (scale == 0.f) + if (NzNumberEquals(scale, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; @@ -359,7 +375,7 @@ NzVector4 operator*(T scale, const NzVector4& vec) template NzVector4 operator/(T scale, const NzVector4& vec) { - if (vec.x == 0.f || vec.y == 0.f || vec.z == 0.f || vec.w == 0.f) + if (NzNumberEquals(vec.x, static_cast(0.0)) || NzNumberEquals(vec.y, static_cast(0.0)) || NzNumberEquals(vec.z, static_cast(0.0)) || NzNumberEquals(vec.w, static_cast(0.0))) { NzStringStream ss; ss << __FILE__ << ':' << __LINE__ << ": Division by zero"; diff --git a/include/Nazara/Prerequesites.hpp b/include/Nazara/Prerequesites.hpp index 8acfc19f5..0691fc975 100644 --- a/include/Nazara/Prerequesites.hpp +++ b/include/Nazara/Prerequesites.hpp @@ -5,10 +5,9 @@ #ifndef NAZARA_PREREQUESITES_HPP #define NAZARA_PREREQUESITES_HPP -// (Commenté en attendant GCC 4.7) -/*#if __cplusplus < 201103L +#if __cplusplus < 201103L #error Nazara requires a C++11 compliant compiler -#endif*/ +#endif // Version du moteur #define NAZARA_VERSION_MAJOR 0 diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index 0deb0b068..8f5e92d85 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -46,6 +46,7 @@ class NAZARA_API NzOpenGL Count }; + static NzOpenGLFunc GetEntry(const NzString& entryPoint); static unsigned int GetVersion(); static bool Initialize(); static bool IsSupported(Extension extension); @@ -131,6 +132,7 @@ NAZARA_API extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; NAZARA_API extern PFNGLLINKPROGRAMPROC glLinkProgram; NAZARA_API extern PFNGLMAPBUFFERPROC glMapBuffer; NAZARA_API extern PFNGLMAPBUFFERRANGEPROC glMapBufferRange; +NAZARA_API extern PFNGLPIXELSTOREIPROC glPixelStorei; NAZARA_API extern PFNGLPOLYGONMODEPROC glPolygonMode; NAZARA_API extern PFNGLPROGRAMUNIFORM1DPROC glProgramUniform1d; NAZARA_API extern PFNGLPROGRAMUNIFORM1FPROC glProgramUniform1f; diff --git a/include/Nazara/Utility/Config.hpp b/include/Nazara/Utility/Config.hpp index be9b3a8bf..a7d025626 100644 --- a/include/Nazara/Utility/Config.hpp +++ b/include/Nazara/Utility/Config.hpp @@ -36,6 +36,6 @@ #define NAZARA_UTILITY_SAFE 1 // Fait tourner chaque fenêtre dans un thread séparé si le système le supporte -#define NAZARA_UTILITY_THREADED_WINDOW 1 +#define NAZARA_UTILITY_THREADED_WINDOW 0 ///FIXME: Buggé depuis GCC 4.7 #endif // NAZARA_CONFIG_UTILITY_HPP diff --git a/include/Nazara/Utility/Image.hpp b/include/Nazara/Utility/Image.hpp index 296179ae5..71cddbaa3 100644 --- a/include/Nazara/Utility/Image.hpp +++ b/include/Nazara/Utility/Image.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -19,12 +20,12 @@ enum nzCubemapFace { - nzCubemapFace_PositiveX, - nzCubemapFace_NegativeX, - nzCubemapFace_PositiveY, - nzCubemapFace_NegativeY, - nzCubemapFace_PositiveZ, - nzCubemapFace_NegativeZ + nzCubemapFace_PositiveX = 0, + nzCubemapFace_NegativeX = 1, + nzCubemapFace_PositiveY = 2, + nzCubemapFace_NegativeY = 3, + nzCubemapFace_PositiveZ = 4, + nzCubemapFace_NegativeZ = 5 }; enum nzImageType @@ -39,15 +40,8 @@ enum nzImageType struct NzImageParams { - // GCC 4.7 je te veux - NzImageParams() : - loadFormat(nzPixelFormat_Undefined), - levelCount(0) - { - } - - nzPixelFormat loadFormat; - nzUInt8 levelCount; + nzPixelFormat loadFormat = nzPixelFormat_Undefined; + nzUInt8 levelCount = 0; bool IsValid() const { @@ -70,22 +64,27 @@ class NAZARA_API NzImage : public NzResource, public NzResourceLoader #include -void* operator new(std::size_t size) throw(std::bad_alloc) +void* operator new(std::size_t size) { return NzMemoryManager::Allocate(size, false); } -void* operator new[](std::size_t size) throw(std::bad_alloc) +void* operator new[](std::size_t size) { return NzMemoryManager::Allocate(size, true); } -void operator delete(void* pointer) throw() +void operator delete(void* pointer) noexcept { NzMemoryManager::Free(pointer, false); } -void operator delete[](void* pointer) throw() +void operator delete[](void* pointer) noexcept { NzMemoryManager::Free(pointer, true); } diff --git a/src/Nazara/Core/Debug/Leaks.cpp b/src/Nazara/Core/Debug/Leaks.cpp index 97811836a..732b99a20 100644 --- a/src/Nazara/Core/Debug/Leaks.cpp +++ b/src/Nazara/Core/Debug/Leaks.cpp @@ -7,22 +7,22 @@ #include #include -void* operator new(std::size_t size) throw(std::bad_alloc) +void* operator new(std::size_t size) { return NzMemoryManager::Allocate(size, false); } -void* operator new[](std::size_t size) throw(std::bad_alloc) +void* operator new[](std::size_t size) { return NzMemoryManager::Allocate(size, true); } -void operator delete(void* pointer) throw() +void operator delete(void* pointer) noexcept { NzMemoryManager::Free(pointer, false); } -void operator delete[](void* pointer) throw() +void operator delete[](void* pointer) noexcept { NzMemoryManager::Free(pointer, true); } diff --git a/src/Nazara/Core/Debug/MemoryLeakTracker.cpp b/src/Nazara/Core/Debug/MemoryLeakTracker.cpp index bdf0daba2..08fce3532 100644 --- a/src/Nazara/Core/Debug/MemoryLeakTracker.cpp +++ b/src/Nazara/Core/Debug/MemoryLeakTracker.cpp @@ -73,7 +73,7 @@ void* NzMemoryManager::Allocate(std::size_t size, bool multi, const char* file, Block* ptr = reinterpret_cast(std::malloc(size+sizeof(Block))); if (!ptr) - return nullptr; + return nullptr; // Impossible d'envoyer une exception car cela allouerait de la mémoire avec new (boucle infinie) ptr->array = multi; ptr->file = file; diff --git a/src/Nazara/Core/Win32/ThreadImpl.cpp b/src/Nazara/Core/Win32/ThreadImpl.cpp index 6e8db44c6..b38b6304f 100644 --- a/src/Nazara/Core/Win32/ThreadImpl.cpp +++ b/src/Nazara/Core/Win32/ThreadImpl.cpp @@ -65,7 +65,7 @@ void NzThreadImpl::Terminate() TerminateThread(m_thread, 0); } -unsigned int _stdcall NzThreadImpl::ThreadProc(void* userdata) +unsigned int __stdcall NzThreadImpl::ThreadProc(void* userdata) { NzThread* owner = reinterpret_cast(userdata); NzFunctor* func = owner->m_func; diff --git a/src/Nazara/Core/Win32/ThreadImpl.hpp b/src/Nazara/Core/Win32/ThreadImpl.hpp index eed45a31b..2e7cbd8ce 100644 --- a/src/Nazara/Core/Win32/ThreadImpl.hpp +++ b/src/Nazara/Core/Win32/ThreadImpl.hpp @@ -29,7 +29,7 @@ class NzThreadImpl void Terminate(); private: - static unsigned int _stdcall ThreadProc(void* userdata); + static unsigned int __stdcall ThreadProc(void* userdata); HANDLE m_thread; unsigned int m_threadId; diff --git a/src/Nazara/Network/Debug/Leaks.cpp b/src/Nazara/Network/Debug/Leaks.cpp index a6b378ab2..403a969d7 100644 --- a/src/Nazara/Network/Debug/Leaks.cpp +++ b/src/Nazara/Network/Debug/Leaks.cpp @@ -7,22 +7,22 @@ #include #include -void* operator new(std::size_t size) throw(std::bad_alloc) +void* operator new(std::size_t size) { return NzMemoryManager::Allocate(size, false); } -void* operator new[](std::size_t size) throw(std::bad_alloc) +void* operator new[](std::size_t size) { return NzMemoryManager::Allocate(size, true); } -void operator delete(void* pointer) throw() +void operator delete(void* pointer) noexcept { NzMemoryManager::Free(pointer, false); } -void operator delete[](void* pointer) throw() +void operator delete[](void* pointer) noexcept { NzMemoryManager::Free(pointer, true); } diff --git a/src/Nazara/Noise/Debug/Leaks.cpp b/src/Nazara/Noise/Debug/Leaks.cpp index 3e65ef142..aaba6c452 100644 --- a/src/Nazara/Noise/Debug/Leaks.cpp +++ b/src/Nazara/Noise/Debug/Leaks.cpp @@ -7,22 +7,22 @@ #include #include -void* operator new(std::size_t size) throw(std::bad_alloc) +void* operator new(std::size_t size) { return NzMemoryManager::Allocate(size, false); } -void* operator new[](std::size_t size) throw(std::bad_alloc) +void* operator new[](std::size_t size) { return NzMemoryManager::Allocate(size, true); } -void operator delete(void* pointer) throw() +void operator delete(void* pointer) noexcept { NzMemoryManager::Free(pointer, false); } -void operator delete[](void* pointer) throw() +void operator delete[](void* pointer) noexcept { NzMemoryManager::Free(pointer, true); } diff --git a/src/Nazara/Renderer/Buffer.cpp b/src/Nazara/Renderer/Buffer.cpp index 335d13e7e..d5fa5b961 100644 --- a/src/Nazara/Renderer/Buffer.cpp +++ b/src/Nazara/Renderer/Buffer.cpp @@ -145,7 +145,7 @@ void* NzBuffer::GetBufferPtr() if (!m_impl) { NazaraError("Buffer not created"); - return false; + return nullptr; } #endif @@ -158,7 +158,7 @@ const void* NzBuffer::GetBufferPtr() const if (!m_impl) { NazaraError("Buffer not created"); - return false; + return nullptr; } #endif diff --git a/src/Nazara/Renderer/Debug/Leaks.cpp b/src/Nazara/Renderer/Debug/Leaks.cpp index 9fb75777f..ee8f4be88 100644 --- a/src/Nazara/Renderer/Debug/Leaks.cpp +++ b/src/Nazara/Renderer/Debug/Leaks.cpp @@ -7,22 +7,22 @@ #include #include -void* operator new(std::size_t size) throw(std::bad_alloc) +void* operator new(std::size_t size) { return NzMemoryManager::Allocate(size, false); } -void* operator new[](std::size_t size) throw(std::bad_alloc) +void* operator new[](std::size_t size) { return NzMemoryManager::Allocate(size, true); } -void operator delete(void* pointer) throw() +void operator delete(void* pointer) noexcept { NzMemoryManager::Free(pointer, false); } -void operator delete[](void* pointer) throw() +void operator delete[](void* pointer) noexcept { NzMemoryManager::Free(pointer, true); } diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index 401499ef6..d6144728d 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -102,6 +102,11 @@ namespace } } +NzOpenGLFunc NzOpenGL::GetEntry(const NzString& entryPoint) +{ + return LoadEntry(entryPoint.GetConstBuffer(), false); +} + unsigned int NzOpenGL::GetVersion() { return openGLversion; @@ -262,6 +267,7 @@ bool NzOpenGL::Initialize() glGetUniformLocation = reinterpret_cast(LoadEntry("glGetUniformLocation")); glLinkProgram = reinterpret_cast(LoadEntry("glLinkProgram")); glMapBuffer = reinterpret_cast(LoadEntry("glMapBuffer")); + glPixelStorei = reinterpret_cast(LoadEntry("glPixelStorei")); glPolygonMode = reinterpret_cast(LoadEntry("glPolygonMode")); glReadPixels = reinterpret_cast(LoadEntry("glReadPixels")); glScissor = reinterpret_cast(LoadEntry("glScissor")); @@ -600,6 +606,7 @@ PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr; PFNGLLINKPROGRAMPROC glLinkProgram = nullptr; PFNGLMAPBUFFERPROC glMapBuffer = nullptr; PFNGLMAPBUFFERRANGEPROC glMapBufferRange = nullptr; +PFNGLPIXELSTOREIPROC glPixelStorei = nullptr; PFNGLPOLYGONMODEPROC glPolygonMode = nullptr; PFNGLPROGRAMUNIFORM1DPROC glProgramUniform1d = nullptr; PFNGLPROGRAMUNIFORM1FPROC glProgramUniform1f = nullptr; diff --git a/src/Nazara/Renderer/RenderWindow.cpp b/src/Nazara/Renderer/RenderWindow.cpp index 6891e3aba..1af1c2174 100644 --- a/src/Nazara/Renderer/RenderWindow.cpp +++ b/src/Nazara/Renderer/RenderWindow.cpp @@ -80,8 +80,7 @@ bool NzRenderWindow::CopyToImage(NzImage* image) nzUInt8* pixels = image->GetPixels(); glReadPixels(0, 0, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - for (unsigned int j = 0; j < size.y/2; ++j) - std::swap_ranges(&pixels[j*size.x*4], &pixels[(j+1)*size.x*4-1], &pixels[(size.y-j-1)*size.x*4]); + image->FlipVertically(); return true; } diff --git a/src/Nazara/Renderer/Texture.cpp b/src/Nazara/Renderer/Texture.cpp index c5eb3e639..8283fc32c 100644 --- a/src/Nazara/Renderer/Texture.cpp +++ b/src/Nazara/Renderer/Texture.cpp @@ -13,21 +13,13 @@ struct NzTextureImpl { - // GCC 4.7 !!!!!! - NzTextureImpl() : - isTarget(false), - mipmapping(false), - mipmapsUpdated(true) - { - } - GLuint id; nzImageType type; nzPixelFormat format; nzUInt8 levelCount; - bool isTarget; - bool mipmapping; - bool mipmapsUpdated; + bool isTarget = false; + bool mipmapping = false; + bool mipmapsUpdated = true; unsigned int depth; unsigned int height; unsigned int width; @@ -279,6 +271,18 @@ namespace } } + inline void SetUnpackAlignement(nzUInt8 bpp) + { + if (bpp % 8 == 0) + glPixelStorei(GL_UNPACK_ALIGNMENT, 8); + else if (bpp % 4 == 0) + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + else if (bpp % 2 == 0) + glPixelStorei(GL_UNPACK_ALIGNMENT, 2); + else + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + } + void UnlockTexture(NzTextureImpl* impl) { #ifdef NAZARA_DEBUG @@ -539,27 +543,11 @@ bool NzTexture::Download(NzImage* image) const unsigned int width = m_impl->width; unsigned int height = m_impl->height; unsigned int depth = m_impl->depth; - nzUInt8 bpp = NzPixelFormat::GetBPP(m_impl->format); - - nzUInt8* mirrored = new nzUInt8[width*height*depth*bpp]; // Téléchargement... for (nzUInt8 level = 0; level < m_impl->levelCount; ++level) { - glGetTexImage(openglTarget[m_impl->type], level, format.dataFormat, format.dataType, mirrored); - - // Inversion de la texture pour le repère d'OpenGL - ///FIXME: Gérer l'inversion dans NzImage, et gérer également les images compressées - unsigned int faceSize = width*height*bpp; - - nzUInt8* ptr = mirrored; - for (unsigned int d = 0; d < depth; ++d) - { - for (unsigned int j = 0; j < height/2; ++j) - std::swap_ranges(&ptr[j*width*bpp], &ptr[(j+1)*width*bpp-1], &ptr[(height-j-1)*width*bpp]); - - ptr += faceSize; - } + glGetTexImage(openglTarget[m_impl->type], level, format.dataFormat, format.dataType, image->GetPixels(level)); if (width > 1) width >>= 1; @@ -573,7 +561,9 @@ bool NzTexture::Download(NzImage* image) const UnlockTexture(m_impl); - delete[] mirrored; + // Inversion de la texture pour le repère d'OpenGL + if (!image->FlipVertically()) + NazaraWarning("Failed to flip image"); return true; } @@ -1138,7 +1128,20 @@ bool NzTexture::Update(const NzImage& image, const NzRectui& rect, unsigned int } #endif - return Update(image.GetConstPixels(level), rect, z, level); + const nzUInt8* pixels = image.GetConstPixels(level, rect.x, rect.y, z); + if (!pixels) + { + NazaraError("Failed to access image's pixels"); + return false; + } + + glPixelStorei(GL_UNPACK_ROW_LENGTH, image.GetWidth(level)); + + bool success = Update(pixels, rect, z, level); + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + return success; } bool NzTexture::Update(const NzImage& image, const NzCubeui& cube, nzUInt8 level) @@ -1157,7 +1160,22 @@ bool NzTexture::Update(const NzImage& image, const NzCubeui& cube, nzUInt8 level } #endif - return Update(image.GetConstPixels(level), cube, level); + const nzUInt8* pixels = image.GetConstPixels(level, cube.x, cube.y, cube.z); + if (!pixels) + { + NazaraError("Failed to access image's pixels"); + return false; + } + + glPixelStorei(GL_UNPACK_ROW_LENGTH, image.GetWidth(level)); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, image.GetHeight(level)); + + bool success = Update(pixels, cube, level); + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); + + return success; } bool NzTexture::Update(const nzUInt8* pixels, nzUInt8 level) @@ -1208,8 +1226,12 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int NazaraError("Invalid rectangle"); return false; } + #endif - if (rect.x+rect.width > std::max(m_impl->width >> level, 1U) || rect.y+rect.height > std::max(m_impl->height >> level, 1U)) + unsigned int height = std::max(m_impl->height >> level, 1U); + + #if NAZARA_RENDERER_SAFE + if (rect.x+rect.width > std::max(m_impl->width >> level, 1U) || rect.y+rect.height > height) { NazaraError("Rectangle dimensions are out of bounds"); return false; @@ -1238,39 +1260,35 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int nzUInt8 bpp = NzPixelFormat::GetBPP(m_impl->format); // Inversion de la texture pour le repère d'OpenGL - ///FIXME: Gérer l'inversion dans NzImage, et gérer également les images compressées - unsigned int size = rect.width*rect.height*bpp; - nzUInt8* mirrored = new nzUInt8[size]; - std::memcpy(mirrored, pixels, size); + NzImage mirrored; + mirrored.Create(m_impl->type, m_impl->format, rect.width, rect.height); + mirrored.Update(pixels); - nzUInt8* ptr = &mirrored[size*z]; - for (unsigned int j = 0; j < rect.height/2; ++j) - std::swap_ranges(&ptr[j*rect.width*bpp], &ptr[(j+1)*rect.width*bpp-1], &ptr[(rect.height-j-1)*rect.width*bpp]); + if (!mirrored.FlipVertically()) + NazaraWarning("Failed to flip image"); + + SetUnpackAlignement(bpp); LockTexture(m_impl); - switch (m_impl->type) { case nzImageType_1D: - glTexSubImage1D(GL_TEXTURE_1D, level, rect.x, rect.width, format.dataFormat, format.dataType, mirrored); + glTexSubImage1D(GL_TEXTURE_1D, level, rect.x, rect.width, format.dataFormat, format.dataType, mirrored.GetConstPixels()); break; case nzImageType_2D: - glTexSubImage2D(GL_TEXTURE_2D, level, rect.x, rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored); + glTexSubImage2D(GL_TEXTURE_2D, level, rect.x, height-rect.height-rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored.GetConstPixels()); break; case nzImageType_3D: - glTexSubImage3D(GL_TEXTURE_3D, level, rect.x, rect.y, z, rect.width, rect.height, 1, format.dataFormat, format.dataType, mirrored); + glTexSubImage3D(GL_TEXTURE_3D, level, rect.x, height-rect.height-rect.y, z, rect.width, rect.height, 1, format.dataFormat, format.dataType, mirrored.GetConstPixels()); break; default: NazaraInternalError("Image type not handled (0x" + NzString::Number(m_impl->type, 16) + ')'); } - UnlockTexture(m_impl); - delete[] mirrored; - return true; } @@ -1306,9 +1324,13 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 leve NazaraError("Invalid rectangle"); return false; } + #endif + unsigned int height = std::max(m_impl->height >> level, 1U); + + #if NAZARA_RENDERER_SAFE if (cube.x+cube.width > std::max(m_impl->width >> level, 1U) || - cube.y+cube.height > std::max(m_impl->height >> level, 1U) || + cube.y+cube.height > height || cube.z+cube.depth > std::max(m_impl->depth >> level, 1U)) { NazaraError("Cube dimensions are out of bounds"); @@ -1332,45 +1354,35 @@ bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 leve nzUInt8 bpp = NzPixelFormat::GetBPP(m_impl->format); // Inversion de la texture pour le repère d'OpenGL - ///FIXME: Gérer l'inversion dans NzImage, et gérer également les images compressées - unsigned int faceSize = cube.width*cube.height*bpp; - unsigned int size = faceSize*cube.depth; - nzUInt8* mirrored = new nzUInt8[size]; - std::memcpy(mirrored, pixels, size); + NzImage mirrored; + mirrored.Create(m_impl->type, m_impl->format, cube.width, cube.height, cube.depth); + mirrored.Update(pixels); - nzUInt8* ptr = mirrored; - for (unsigned int d = 0; d < cube.depth; ++d) - { - for (unsigned int j = 0; j < cube.height/2; ++j) - std::swap_ranges(&ptr[j*cube.width*bpp], &ptr[(j+1)*cube.width*bpp-1], &ptr[(cube.height-j-1)*cube.width*bpp]); + if (!mirrored.FlipVertically()) + NazaraWarning("Failed to flip image"); - ptr += faceSize; - } + SetUnpackAlignement(bpp); LockTexture(m_impl); - switch (m_impl->type) { case nzImageType_1D: - glTexSubImage1D(GL_TEXTURE_1D, level, cube.x, cube.width, format.dataFormat, format.dataType, mirrored); + glTexSubImage1D(GL_TEXTURE_1D, level, cube.x, cube.width, format.dataFormat, format.dataType, mirrored.GetConstPixels()); break; case nzImageType_2D: - glTexSubImage2D(GL_TEXTURE_2D, level, cube.x, cube.y, cube.width, cube.height, format.dataFormat, format.dataType, mirrored); + glTexSubImage2D(GL_TEXTURE_2D, level, cube.x, height-cube.height-cube.y, cube.width, cube.height, format.dataFormat, format.dataType, mirrored.GetConstPixels()); break; case nzImageType_3D: - glTexSubImage3D(GL_TEXTURE_3D, level, cube.x, cube.y, cube.z, cube.width, cube.height, cube.depth, format.dataFormat, format.dataType, mirrored); + glTexSubImage3D(GL_TEXTURE_3D, level, cube.x, height-cube.height-cube.y, cube.z, cube.width, cube.height, cube.depth, format.dataFormat, format.dataType, mirrored.GetConstPixels()); break; default: NazaraInternalError("Image type not handled (0x" + NzString::Number(m_impl->type, 16) + ')'); } - UnlockTexture(m_impl); - delete[] mirrored; - return true; } @@ -1409,7 +1421,13 @@ bool NzTexture::UpdateFace(nzCubemapFace face, const NzImage& image, const NzRec } #endif - return UpdateFace(face, image.GetConstPixels(level), rect, level); + glPixelStorei(GL_UNPACK_ROW_LENGTH, image.GetWidth(level)); + + bool success = UpdateFace(face, image.GetConstPixels(level), rect, level); + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + return success; } bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, nzUInt8 level) @@ -1457,8 +1475,12 @@ bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRe NazaraError("Invalid rectangle"); return false; } + #endif - if (rect.x+rect.width > std::max(m_impl->width >> level, 1U) || rect.y+rect.height > std::max(m_impl->height >> level, 1U)) + unsigned int height = std::max(m_impl->height >> level, 1U); + + #if NAZARA_RENDERER_SAFE + if (rect.x+rect.width > std::max(m_impl->width >> level, 1U) || rect.y+rect.height > height) { NazaraError("Rectangle dimensions are out of bounds"); return false; @@ -1481,21 +1503,19 @@ bool NzTexture::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRe nzUInt8 bpp = NzPixelFormat::GetBPP(m_impl->format); // Inversion de la texture pour le repère d'OpenGL - ///FIXME: Gérer l'inversion dans NzImage, et gérer également les images compressées - unsigned int size = rect.width*rect.height*bpp; - nzUInt8* mirrored = new nzUInt8[size]; - std::memcpy(mirrored, pixels, size); - for (unsigned int j = 0; j < rect.height/2; ++j) - std::swap_ranges(&mirrored[j*rect.width*bpp], &mirrored[(j+1)*rect.width*bpp-1], &mirrored[(rect.height-j-1)*rect.width*bpp]); + NzImage mirrored; + mirrored.Create(m_impl->type, m_impl->format, rect.width, rect.height); + mirrored.Update(pixels); + + if (!mirrored.FlipVertically()) + NazaraWarning("Failed to flip image"); + + SetUnpackAlignement(bpp); LockTexture(m_impl); - - glTexSubImage2D(cubemapFace[face], level, rect.x, rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored); - + glTexSubImage2D(cubemapFace[face], level, rect.x, height-rect.height-rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored.GetConstPixels()); UnlockTexture(m_impl); - delete[] mirrored; - return true; } diff --git a/src/Nazara/Utility/Debug/Leaks.cpp b/src/Nazara/Utility/Debug/Leaks.cpp index dfb2f33a7..46b4e1abf 100644 --- a/src/Nazara/Utility/Debug/Leaks.cpp +++ b/src/Nazara/Utility/Debug/Leaks.cpp @@ -7,22 +7,22 @@ #include #include -void* operator new(std::size_t size) throw(std::bad_alloc) +void* operator new(std::size_t size) { return NzMemoryManager::Allocate(size, false); } -void* operator new[](std::size_t size) throw(std::bad_alloc) +void* operator new[](std::size_t size) { return NzMemoryManager::Allocate(size, true); } -void operator delete(void* pointer) throw() +void operator delete(void* pointer) noexcept { NzMemoryManager::Free(pointer, false); } -void operator delete[](void* pointer) throw() +void operator delete[](void* pointer) noexcept { NzMemoryManager::Free(pointer, true); } diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index d5a1f08b6..11284bd52 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -9,6 +9,19 @@ #include #include +namespace +{ + inline unsigned int GetLevelSize(unsigned int size, nzUInt8 level) + { + return std::max(size >> level, 1U); + } + + inline nzUInt8* GetPixelPtr(nzUInt8* base, nzUInt8 bpp, unsigned int x, unsigned int y, unsigned int z, unsigned int width, unsigned int height) + { + return &base[(width*(height*z+y) + x) * bpp]; + } +} + NzImage::NzImage() : m_sharedImage(&emptyImage) { @@ -98,13 +111,13 @@ bool NzImage::Convert(nzPixelFormat format) } if (width > 1) - width /= 2; + width >>= 1; if (height > 1) - height /= 2; + height >>= 1; if (depth > 1 && m_sharedImage->type != nzImageType_Cubemap) - depth /= 2; + depth >>= 1; } SharedImage* newImage = new SharedImage(1, m_sharedImage->type, format, m_sharedImage->levelCount, levels, m_sharedImage->width, m_sharedImage->height, m_sharedImage->depth); @@ -115,7 +128,7 @@ bool NzImage::Convert(nzPixelFormat format) return true; } -bool NzImage::Copy(const NzImage& source, const NzRectui& srcRect, const NzVector2ui& dstPos) +bool NzImage::Copy(const NzImage& source, const NzCubeui& srcCube, const NzVector3ui& dstPos) { #if NAZARA_UTILITY_SAFE if (!source.IsValid()) @@ -131,29 +144,49 @@ bool NzImage::Copy(const NzImage& source, const NzRectui& srcRect, const NzVecto } #endif - return Update(&source.GetConstPixels()[(srcRect.x + srcRect.y * source.GetHeight()) * source.GetBPP()], - NzRectui(dstPos.x, dstPos.y, srcRect.width, srcRect.height)); -} - -bool NzImage::CopyToFace(nzCubemapFace face, const NzImage& source, const NzRectui& srcRect, const NzVector2ui& dstPos) -{ - #if NAZARA_UTILITY_SAFE - if (!source.IsValid()) + const nzUInt8* pixels = source.GetConstPixels(0, srcCube.x, srcCube.y, srcCube.z); + if (!pixels) { - NazaraError("Source image must be valid"); + NazaraError("Failed to access pixels"); return false; } - if (source.GetFormat() != m_sharedImage->format) - { - NazaraError("Source image format does not match destination image format"); - return false; - } - #endif + /* + Correctif temporaire : Update veut de la mémoire contigüe + Il est donc nécessaire de prendre la partie de la texture que nous voulons mettre à jour - return UpdateFace(face, - &source.GetConstPixels()[(srcRect.x + srcRect.y * source.GetHeight()) * source.GetBPP()], - NzRectui(dstPos.x, dstPos.y, srcRect.width, srcRect.height)); + FIXME: Trouver une interface pour gérer ce genre de problème (Façon OpenGL?) + (Appliquer l'interface à NzTexture également) + */ + nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); + unsigned int dstLineStride = srcCube.width*bpp; + unsigned int dstFaceStride = dstLineStride*srcCube.height; + unsigned int srcLineStride = m_sharedImage->width*bpp; + unsigned int srcFaceStride = srcLineStride*m_sharedImage->height; + + nzUInt8* cube = new nzUInt8[dstFaceStride*srcCube.depth]; + nzUInt8* ptr = cube; + + for (unsigned int z = 0; z < srcCube.depth; ++z) + { + nzUInt8* facePixels = ptr; + for (unsigned int y = 0; y < srcCube.height; ++y) + { + std::memcpy(facePixels, pixels, dstLineStride); + + facePixels += dstLineStride; + pixels += srcLineStride; + } + + ptr += dstFaceStride; + pixels += srcFaceStride; + } + + bool success = Update(cube, NzCubeui(dstPos.x, dstPos.y, dstPos.z, srcCube.width, srcCube.height, srcCube.depth)); + + delete[] cube; + + return success; } bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth, nzUInt8 levelCount) @@ -233,13 +266,13 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width, levels[i] = new nzUInt8[w * h * d * NzPixelFormat::GetBPP(format)]; if (w > 1) - w /= 2; + w >>= 1; if (h > 1) - h /= 2; + h >>= 1; if (d > 1 && type != nzImageType_Cubemap) - d /= 2; + d >>= 1; } catch (const std::exception& e) { @@ -263,14 +296,323 @@ void NzImage::Destroy() ReleaseImage(); } +bool NzImage::Fill(const NzColor& color) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (NzPixelFormat::IsCompressed(m_sharedImage->format)) + { + NazaraError("Cannot access pixels from compressed image"); + return false; + } + #endif + + EnsureOwnership(); + + nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); + nzUInt8* pixels = new nzUInt8[bpp]; + if (!NzPixelFormat::Convert(nzPixelFormat_RGBA8, m_sharedImage->format, &color.r, pixels)) + { + NazaraError("Failed to convert RGBA8 to " + NzPixelFormat::ToString(m_sharedImage->format)); + delete[] pixels; + + return false; + } + + unsigned int width = m_sharedImage->width; + unsigned int height = m_sharedImage->height; + unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth; + + for (unsigned int level = 0; level < m_sharedImage->levelCount; ++level) + { + nzUInt8* ptr = &m_sharedImage->pixels[level][0]; + nzUInt8* end = &m_sharedImage->pixels[level][width*height*depth*bpp]; + + while (ptr < end) + { + std::memcpy(ptr, pixels, bpp); + ptr += bpp; + } + + if (width > 1U) + width >>= 1; + + if (height > 1U) + height >>= 1; + + if (depth > 1U && m_sharedImage->type != nzImageType_Cubemap) + depth >>= 1; + } + + delete[] pixels; + + return true; +} + +bool NzImage::Fill(const NzColor& color, const NzRectui& rect, unsigned int z) +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (!rect.IsValid()) + { + NazaraError("Invalid rectangle"); + return false; + } + + if (rect.x+rect.width > m_sharedImage->width || rect.y+rect.height > m_sharedImage->height) + { + NazaraError("Rectangle dimensions are out of bounds"); + return false; + } + + unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth; + if (z >= depth) + { + NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(depth) + ')'); + return false; + } + #endif + + EnsureOwnership(); + + nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); + nzUInt8* pixels = new nzUInt8[bpp]; + if (!NzPixelFormat::Convert(nzPixelFormat_RGBA8, m_sharedImage->format, &color.r, pixels)) + { + NazaraError("Failed to convert RGBA8 to " + NzPixelFormat::ToString(m_sharedImage->format)); + delete[] pixels; + + return false; + } + + nzUInt8* dstPixels = GetPixelPtr(m_sharedImage->pixels[0], bpp, rect.x, rect.y, z, m_sharedImage->width, m_sharedImage->height); + unsigned int srcStride = rect.width * bpp; + unsigned int dstStride = m_sharedImage->width * bpp; + for (unsigned int y = 0; y < rect.height; ++y) + { + nzUInt8* start = dstPixels; + nzUInt8* end = dstPixels + srcStride; + while (start < end) + { + std::memcpy(start, pixels, bpp); + start += bpp; + } + + dstPixels += dstStride; + } + + return true; +} + +bool NzImage::Fill(const NzColor& color, const NzCubeui& cube) +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (!cube.IsValid()) + { + NazaraError("Invalid rectangle"); + return false; + } + + if (cube.x+cube.width > m_sharedImage->width || cube.y+cube.height > m_sharedImage->height || cube.z+cube.depth > m_sharedImage->depth) + { + NazaraError("Cube dimensions are out of bounds"); + return false; + } + #endif + + EnsureOwnership(); + + nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); + nzUInt8* pixels = new nzUInt8[bpp]; + if (!NzPixelFormat::Convert(nzPixelFormat_RGBA8, m_sharedImage->format, &color.r, pixels)) + { + NazaraError("Failed to convert RGBA8 to " + NzPixelFormat::ToString(m_sharedImage->format)); + delete[] pixels; + + return false; + } + + nzUInt8* dstPixels = GetPixelPtr(m_sharedImage->pixels[0], bpp, cube.x, cube.y, cube.z, m_sharedImage->width, m_sharedImage->height); + unsigned int srcStride = cube.width * bpp; + unsigned int dstStride = m_sharedImage->width * bpp; + unsigned int faceSize = dstStride * m_sharedImage->height; + for (unsigned int z = 0; z < cube.depth; ++z) + { + nzUInt8* facePixels = dstPixels; + for (unsigned int y = 0; y < cube.height; ++y) + { + nzUInt8* start = facePixels; + nzUInt8* end = facePixels + srcStride; + while (start < end) + { + std::memcpy(start, pixels, bpp); + start += bpp; + } + + facePixels += dstStride; + } + + dstPixels += faceSize; + } + + delete[] pixels; + + return true; +} + +bool NzImage::FlipHorizontally() +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (NzPixelFormat::IsCompressed(m_sharedImage->format)) + { + NazaraError("Cannot flip compressed image"); + return false; + } + #endif + + EnsureOwnership(); + + nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); + unsigned int width = m_sharedImage->width; + unsigned int height = m_sharedImage->height; + unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth; + for (unsigned int level = 0; level < m_sharedImage->levelCount; ++level) + { + for (unsigned int z = 0; z < depth; ++z) + { + nzUInt8* ptr = &m_sharedImage->pixels[level][width*height*z]; + unsigned int lineStride = width*bpp; + for (unsigned int y = 0; y < height; ++y) + { + for (unsigned int x = 0; x < width/2; ++x) + std::swap_ranges(&ptr[x*bpp], &ptr[(x+1)*bpp], &ptr[(width-x)*bpp]); + + ptr += lineStride; + } + } + + if (width > 1U) + width >>= 1; + + if (height > 1U) + height >>= 1; + + if (depth > 1U && m_sharedImage->type != nzImageType_Cubemap) + depth >>= 1; + } + + return true; +} + + +bool NzImage::FlipVertically() +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (NzPixelFormat::IsCompressed(m_sharedImage->format)) + { + NazaraError("Cannot flip compressed image"); + return false; + } + #endif + + EnsureOwnership(); + + nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); + unsigned int width = m_sharedImage->width; + unsigned int height = m_sharedImage->height; + unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth; + for (unsigned int level = 0; level < m_sharedImage->levelCount; ++level) + { + for (unsigned int z = 0; z < depth; ++z) + { + nzUInt8* ptr = &m_sharedImage->pixels[level][width*height*z]; + unsigned int lineStride = width*bpp; + for (unsigned int y = 0; y < height/2; ++y) + std::swap_ranges(&ptr[y*lineStride], &ptr[(y+1)*lineStride-1], &ptr[(height-y-1)*lineStride]); + } + + if (width > 1U) + width >>= 1; + + if (height > 1U) + height >>= 1; + + if (depth > 1U && m_sharedImage->type != nzImageType_Cubemap) + depth >>= 1; + } + + return true; +} + nzUInt8 NzImage::GetBPP() const { return NzPixelFormat::GetBPP(m_sharedImage->format); } -const nzUInt8* NzImage::GetConstPixels(nzUInt8 level) const +const nzUInt8* NzImage::GetConstPixels(nzUInt8 level, unsigned int x, unsigned int y, unsigned int z) const { - return m_sharedImage->pixels[level]; + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return nullptr; + } + + if (level >= m_sharedImage->levelCount) + { + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return nullptr; + } + + if (x >= m_sharedImage->width) + { + NazaraError("X value exceeds width (" + NzString::Number(x) + " >= (" + NzString::Number(m_sharedImage->width) + ')'); + return nullptr; + } + + if (y >= m_sharedImage->height) + { + NazaraError("Y value exceeds width (" + NzString::Number(y) + " >= (" + NzString::Number(m_sharedImage->height) + ')'); + return nullptr; + } + + unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth; + if (z >= depth) + { + NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(depth) + ')'); + return nullptr; + } + #endif + + return GetPixelPtr(m_sharedImage->pixels[level], NzPixelFormat::GetBPP(m_sharedImage->format), x, y, z, m_sharedImage->width, m_sharedImage->height); } unsigned int NzImage::GetDepth(nzUInt8 level) const @@ -283,7 +625,7 @@ unsigned int NzImage::GetDepth(nzUInt8 level) const } #endif - return std::max(m_sharedImage->depth >> level, 1U); + return GetLevelSize(m_sharedImage->depth, level); } nzPixelFormat NzImage::GetFormat() const @@ -301,7 +643,7 @@ unsigned int NzImage::GetHeight(nzUInt8 level) const } #endif - return std::max(m_sharedImage->height >> level, 1U); + return GetLevelSize(m_sharedImage->height, level); } nzUInt8 NzImage::GetLevelCount() const @@ -314,7 +656,7 @@ nzUInt8 NzImage::GetMaxLevel() const return GetMaxLevel(m_sharedImage->width, m_sharedImage->height, m_sharedImage->depth); } -NzColor NzImage::GetPixel(unsigned int x, unsigned int y, unsigned int z) const +NzColor NzImage::GetPixelColor(unsigned int x, unsigned int y, unsigned int z) const { #if NAZARA_UTILITY_SAFE if (!IsValid()) @@ -323,12 +665,6 @@ NzColor NzImage::GetPixel(unsigned int x, unsigned int y, unsigned int z) const return NzColor(); } - if (m_sharedImage->type == nzImageType_Cubemap) - { - NazaraError("GetPixel is not designed for cubemaps, use GetPixelFace instead"); - return NzColor(); - } - if (NzPixelFormat::IsCompressed(m_sharedImage->format)) { NazaraError("Cannot access pixels from compressed image"); @@ -347,14 +683,15 @@ NzColor NzImage::GetPixel(unsigned int x, unsigned int y, unsigned int z) const return NzColor(); } - if (z >= m_sharedImage->depth) + unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth; + if (z >= depth) { - NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(m_sharedImage->depth) + ')'); + NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(depth) + ')'); return NzColor(); } #endif - const nzUInt8* pixel = &m_sharedImage->pixels[0][(m_sharedImage->height*(m_sharedImage->width*z+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + const nzUInt8* pixel = GetPixelPtr(m_sharedImage->pixels[0], NzPixelFormat::GetBPP(m_sharedImage->format), x, y, z, m_sharedImage->width, m_sharedImage->height); NzColor color; if (!NzPixelFormat::Convert(m_sharedImage->format, nzPixelFormat_RGBA8, pixel, &color.r)) @@ -363,54 +700,44 @@ NzColor NzImage::GetPixel(unsigned int x, unsigned int y, unsigned int z) const return color; } -NzColor NzImage::GetPixelFace(nzCubemapFace face, unsigned int x, unsigned int y) const +nzUInt8* NzImage::GetPixels(nzUInt8 level, unsigned int x, unsigned int y, unsigned int z) { #if NAZARA_UTILITY_SAFE if (!IsValid()) { NazaraError("Image must be valid"); - return NzColor(); + return nullptr; } - if (m_sharedImage->type != nzImageType_Cubemap) + if (level >= m_sharedImage->levelCount) { - NazaraError("GetPixelFace is designed for cubemaps, use GetPixel instead"); - return NzColor(); - } - - if (NzPixelFormat::IsCompressed(m_sharedImage->format)) - { - NazaraError("Cannot access pixels from compressed image"); - return NzColor(); + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return nullptr; } if (x >= m_sharedImage->width) { NazaraError("X value exceeds width (" + NzString::Number(x) + " >= (" + NzString::Number(m_sharedImage->width) + ')'); - return NzColor(); + return nullptr; } if (y >= m_sharedImage->height) { NazaraError("Y value exceeds width (" + NzString::Number(y) + " >= (" + NzString::Number(m_sharedImage->height) + ')'); - return NzColor(); + return nullptr; + } + + unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth; + if (z >= depth) + { + NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(depth) + ')'); + return nullptr; } #endif - const nzUInt8* pixel = &m_sharedImage->pixels[0][(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX)+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; - - NzColor color; - if (!NzPixelFormat::Convert(m_sharedImage->format, nzPixelFormat_RGBA8, pixel, &color.r)) - NazaraError("Failed to convert image's format to RGBA8"); - - return color; -} - -nzUInt8* NzImage::GetPixels(nzUInt8 level) -{ EnsureOwnership(); - return m_sharedImage->pixels[level]; + return GetPixelPtr(m_sharedImage->pixels[level], NzPixelFormat::GetBPP(m_sharedImage->format), x, y, z, m_sharedImage->width, m_sharedImage->height); } unsigned int NzImage::GetSize() const @@ -425,13 +752,13 @@ unsigned int NzImage::GetSize() const size += width * height * depth; if (width > 1) - width /= 2; + width >>= 1; if (height > 1) - height /= 2; + height >>= 1; if (depth > 1) - depth /= 2; + depth >>= 1; } if (m_sharedImage->type == nzImageType_Cubemap) @@ -450,9 +777,9 @@ unsigned int NzImage::GetSize(nzUInt8 level) const } #endif - return (std::max(m_sharedImage->width >> level, 1U)) * - (std::max(m_sharedImage->height >> level, 1U)) * - ((m_sharedImage->type == nzImageType_Cubemap) ? 6 : std::max(m_sharedImage->depth >> level, 1U)) * + return (GetLevelSize(m_sharedImage->width, level)) * + (GetLevelSize(m_sharedImage->height, level)) * + ((m_sharedImage->type == nzImageType_Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level)) * NzPixelFormat::GetBPP(m_sharedImage->format); } @@ -471,7 +798,7 @@ unsigned int NzImage::GetWidth(nzUInt8 level) const } #endif - return std::max(m_sharedImage->width >> level, 1U); + return GetLevelSize(m_sharedImage->width, level); } bool NzImage::IsCompressed() const @@ -549,7 +876,7 @@ bool NzImage::SetLevelCount(nzUInt8 levelCount) return true; } -bool NzImage::SetPixel(const NzColor& color, unsigned int x, unsigned int y, unsigned int z) +bool NzImage::SetPixelColor(const NzColor& color, unsigned int x, unsigned int y, unsigned int z) { #if NAZARA_UTILITY_SAFE if (!IsValid()) @@ -558,12 +885,6 @@ bool NzImage::SetPixel(const NzColor& color, unsigned int x, unsigned int y, uns return false; } - if (m_sharedImage->type == nzImageType_Cubemap) - { - NazaraError("SetPixel is not designed for cubemaps, use SetPixelFace instead"); - return false; - } - if (NzPixelFormat::IsCompressed(m_sharedImage->format)) { NazaraError("Cannot access pixels from compressed image"); @@ -582,59 +903,15 @@ bool NzImage::SetPixel(const NzColor& color, unsigned int x, unsigned int y, uns return false; } - if (z >= m_sharedImage->depth) + unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : m_sharedImage->depth; + if (z >= depth) { - NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(m_sharedImage->depth) + ')'); + NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(depth) + ')'); return false; } #endif - nzUInt8* pixel = &m_sharedImage->pixels[0][(m_sharedImage->height*(m_sharedImage->width*z+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; - - if (!NzPixelFormat::Convert(nzPixelFormat_RGBA8, m_sharedImage->format, &color.r, pixel)) - { - NazaraError("Failed to convert RGBA8 to image's format"); - return false; - } - - return true; -} - -bool NzImage::SetPixelFace(nzCubemapFace face, const NzColor& color, unsigned int x, unsigned int y) -{ - #if NAZARA_UTILITY_SAFE - if (!IsValid()) - { - NazaraError("Image must be valid"); - return false; - } - - if (m_sharedImage->type != nzImageType_Cubemap) - { - NazaraError("SetPixelFace is designed for cubemaps, use SetPixel instead"); - return false; - } - - if (NzPixelFormat::IsCompressed(m_sharedImage->format)) - { - NazaraError("Cannot access pixels from compressed image"); - return false; - } - - if (x >= m_sharedImage->width) - { - NazaraError("X value exceeds width (" + NzString::Number(x) + " >= (" + NzString::Number(m_sharedImage->width) + ')'); - return false; - } - - if (y >= m_sharedImage->height) - { - NazaraError("Y value exceeds width (" + NzString::Number(y) + " >= (" + NzString::Number(m_sharedImage->height) + ')'); - return false; - } - #endif - - nzUInt8* pixel = &m_sharedImage->pixels[0][(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX)+y) + x) * NzPixelFormat::GetBPP(m_sharedImage->format)]; + nzUInt8* pixel = GetPixelPtr(m_sharedImage->pixels[0], NzPixelFormat::GetBPP(m_sharedImage->format), x, y, z, m_sharedImage->width, m_sharedImage->height); if (!NzPixelFormat::Convert(nzPixelFormat_RGBA8, m_sharedImage->format, &color.r, pixel)) { @@ -654,12 +931,6 @@ bool NzImage::Update(const nzUInt8* pixels, nzUInt8 level) return false; } - if (m_sharedImage->type == nzImageType_Cubemap) - { - NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); - return false; - } - if (!pixels) { NazaraError("Invalid pixel source"); @@ -689,12 +960,6 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z return false; } - if (m_sharedImage->type == nzImageType_Cubemap) - { - NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); - return false; - } - if (!pixels) { NazaraError("Invalid pixel source"); @@ -706,25 +971,25 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); return false; } - #endif - unsigned int width = std::max(m_sharedImage->width >> level, 1U); - unsigned int height = std::max(m_sharedImage->height >> level, 1U); - - #if NAZARA_UTILITY_SAFE if (!rect.IsValid()) { NazaraError("Invalid rectangle"); return false; } + #endif + unsigned int width = GetLevelSize(m_sharedImage->width, level); + unsigned int height = GetLevelSize(m_sharedImage->height, level); + + #if NAZARA_UTILITY_SAFE if (rect.x+rect.width > width || rect.y+rect.height > height) { NazaraError("Rectangle dimensions are out of bounds"); return false; } - unsigned int depth = std::max(m_sharedImage->depth >> level, 1U); + unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : GetLevelSize(m_sharedImage->depth, level); if (z >= depth) { NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(depth) + ')'); @@ -735,14 +1000,14 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z EnsureOwnership(); nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); - nzUInt8* dstPixels = &m_sharedImage->pixels[level][(height*(width*z + rect.y) + rect.x) * bpp]; + nzUInt8* dstPixels = GetPixelPtr(m_sharedImage->pixels[level], bpp, rect.x, rect.y, z, width, height); unsigned int srcStride = rect.width * bpp; - unsigned int blockSize = width * bpp; - for (unsigned int i = 0; i < rect.height; ++i) + unsigned int dstStride = m_sharedImage->width * bpp; + for (unsigned int y = 0; y < rect.height; ++y) { - std::memcpy(dstPixels, pixels, blockSize); + std::memcpy(dstPixels, pixels, srcStride); pixels += srcStride; - dstPixels += blockSize; + dstPixels += dstStride; } return true; @@ -758,12 +1023,6 @@ bool NzImage::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level) return false; } - if (m_sharedImage->type == nzImageType_Cubemap) - { - NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); - return false; - } - if (!pixels) { NazaraError("Invalid pixel source"); @@ -777,9 +1036,9 @@ bool NzImage::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level) } #endif - unsigned int width = std::max(m_sharedImage->width >> level, 1U); - unsigned int height = std::max(m_sharedImage->height >> level, 1U); - unsigned int depth = std::max(m_sharedImage->height >> level, 1U); + unsigned int width = GetLevelSize(m_sharedImage->width, level); + unsigned int height = GetLevelSize(m_sharedImage->height, level); + unsigned int depth = (m_sharedImage->type == nzImageType_Cubemap) ? 6 : GetLevelSize(m_sharedImage->height, level); #if NAZARA_UTILITY_SAFE if (!cube.IsValid()) @@ -798,18 +1057,18 @@ bool NzImage::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level) EnsureOwnership(); nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); - nzUInt8* dstPixels = &m_sharedImage->pixels[level][(height*(width*cube.z + cube.y) + cube.x) * bpp]; + nzUInt8* dstPixels = GetPixelPtr(m_sharedImage->pixels[level], bpp, cube.x, cube.y, cube.z, width, height); unsigned int srcStride = cube.width * bpp; - unsigned int blockSize = width * bpp; - unsigned int faceSize = width * height * bpp; + unsigned int dstStride = width * bpp; + unsigned int faceSize = dstStride * height; for (unsigned int z = 0; z < cube.depth; ++z) { nzUInt8* facePixels = dstPixels; - for (unsigned int i = 0; i < cube.height; ++i) + for (unsigned int y = 0; y < cube.height; ++y) { - std::memcpy(dstPixels, pixels, blockSize); + std::memcpy(facePixels, pixels, srcStride); pixels += srcStride; - facePixels += blockSize; + facePixels += dstStride; } dstPixels += faceSize; @@ -818,98 +1077,6 @@ bool NzImage::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level) return true; } -bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, nzUInt8 level) -{ - #if NAZARA_UTILITY_SAFE - if (!IsValid()) - { - NazaraError("Image must be valid"); - return false; - } - - if (m_sharedImage->type != nzImageType_Cubemap) - { - NazaraError("UpdateFace is designed for cubemaps, use Update instead"); - return false; - } - - if (!pixels) - { - NazaraError("Invalid pixel source"); - return false; - } - - if (level >= m_sharedImage->levelCount) - { - NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); - return false; - } - #endif - - EnsureOwnership(); - - unsigned int size = GetSize(level); - std::memcpy(&m_sharedImage->pixels[level][size*(face-nzCubemapFace_PositiveX)], pixels, size); - - return true; -} - -bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRectui& rect, nzUInt8 level) -{ - #if NAZARA_UTILITY_SAFE - if (!IsValid()) - { - NazaraError("Image must be valid"); - return false; - } - - if (m_sharedImage->type != nzImageType_Cubemap) - { - NazaraError("UpdateFace is designed for cubemaps, use Update instead"); - return false; - } - - if (!pixels) - { - NazaraError("Invalid pixel source"); - return false; - } - - if (!rect.IsValid()) - { - NazaraError("Invalid rectangle"); - return false; - } - - if (rect.x+rect.width > std::max(m_sharedImage->width >> level, 1U) || rect.y+rect.height > std::max(m_sharedImage->height >> level, 1U)) - { - NazaraError("Rectangle dimensions are out of bounds"); - return false; - } - - if (level >= m_sharedImage->levelCount) - { - NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); - return false; - } - #endif - - EnsureOwnership(); - - nzUInt8 bpp = NzPixelFormat::GetBPP(m_sharedImage->format); - nzUInt8* dstPixels = &m_sharedImage->pixels[level][(m_sharedImage->height*(m_sharedImage->width*(face-nzCubemapFace_PositiveX) + rect.y) + rect.x) * bpp]; - unsigned int srcStride = rect.width * bpp; - unsigned int blockSize = m_sharedImage->width * bpp; - for (unsigned int i = 0; i < rect.height; ++i) - { - std::memcpy(dstPixels, pixels, blockSize); - pixels += srcStride; - dstPixels += blockSize; - } - - return true; -} - NzImage& NzImage::operator=(const NzImage& image) { ReleaseImage(); @@ -988,7 +1155,7 @@ void NzImage::EnsureOwnership() { unsigned int size = GetSize(i); pixels[i] = new nzUInt8[size]; - std::memcpy(pixels[i], &m_sharedImage->pixels[i], size); + std::memcpy(pixels[i], m_sharedImage->pixels[i], size); } m_sharedImage = new SharedImage(1, m_sharedImage->type, m_sharedImage->format, m_sharedImage->levelCount, pixels, m_sharedImage->width, m_sharedImage->height, m_sharedImage->depth); diff --git a/src/Nazara/Utility/Loaders/STB.cpp b/src/Nazara/Utility/Loaders/STB.cpp index 1b6ed1c6b..e031fa4b1 100644 --- a/src/Nazara/Utility/Loaders/STB.cpp +++ b/src/Nazara/Utility/Loaders/STB.cpp @@ -11,7 +11,7 @@ #include #define STBI_HEADER_FILE_ONLY -#include +#include #include diff --git a/src/Nazara/Utility/Loaders/STB/stb_image.c b/src/Nazara/Utility/Loaders/STB/stb_image.cpp similarity index 100% rename from src/Nazara/Utility/Loaders/STB/stb_image.c rename to src/Nazara/Utility/Loaders/STB/stb_image.cpp diff --git a/src/Nazara/Utility/Win32/WindowImpl.cpp b/src/Nazara/Utility/Win32/WindowImpl.cpp index 8ce9a18b7..d241ef1ab 100644 --- a/src/Nazara/Utility/Win32/WindowImpl.cpp +++ b/src/Nazara/Utility/Win32/WindowImpl.cpp @@ -4,6 +4,8 @@ // Un grand merci à Laurent Gomila pour la SFML qui m'aura bien aidé à réaliser cette implémentation +#define OEMRESOURCE + #include #include #include @@ -14,6 +16,11 @@ #include #include +#ifdef _WIN64 + #define GWL_USERDATA GWLP_USERDATA + #define GCL_HCURSOR GCLP_HCURSOR +#endif + // N'est pas définit avec MinGW apparemment #ifndef MAPVK_VK_TO_VSC #define MAPVK_VK_TO_VSC 0 @@ -116,7 +123,7 @@ bool NzWindowImpl::Create(NzVideoMode mode, const NzString& title, nzUInt32 styl win32StyleEx = 0; - RECT rect = {0, 0, width, height}; + RECT rect = {0, 0, static_cast(width), static_cast(height)}; AdjustWindowRect(&rect, win32Style, false); width = rect.right-rect.left; height = rect.bottom-rect.top; @@ -330,7 +337,7 @@ void NzWindowImpl::SetPosition(int x, int y) void NzWindowImpl::SetSize(unsigned int width, unsigned int height) { // SetWindowPos demande la taille totale de la fenêtre - RECT rect = {0, 0, width, height}; + RECT rect = {0, 0, static_cast(width), static_cast(height)}; AdjustWindowRect(&rect, GetWindowLongPtr(m_handle, GWL_STYLE), false); SetWindowPos(m_handle, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER); diff --git a/src/Nazara/Utility/Window.cpp b/src/Nazara/Utility/Window.cpp index 1ef9c3de8..5f83ff6f2 100644 --- a/src/Nazara/Utility/Window.cpp +++ b/src/Nazara/Utility/Window.cpp @@ -308,6 +308,7 @@ void NzWindow::SetEventListener(bool listener) m_impl->SetEventListener(listener); if (!listener) { + // On vide la pile des évènements NzLockGuard lock(m_eventMutex); while (!m_events.empty()) m_events.pop();