diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..fd6451f19 --- /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/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/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/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/Color.hpp b/include/Nazara/Core/Color.hpp new file mode 100644 index 000000000..609fae5ae --- /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 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; + + 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); +}; + +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/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/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/Log.hpp b/include/Nazara/Core/Log.hpp index 71e69c418..857a375b1 100644 --- a/include/Nazara/Core/Log.hpp +++ b/include/Nazara/Core/Log.hpp @@ -9,13 +9,14 @@ #include #include +#include #include -#include #define NAZARA_CLASS_LOG #include #define NazaraLog NzLog::Instance() +#define NazaraNotice(txt) NazaraLog->Write(txt) class NzFile; 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/String.hpp b/include/Nazara/Core/String.hpp index 4451433d1..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 @@ -25,9 +24,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/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/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/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/Math/Cube.hpp b/include/Nazara/Math/Cube.hpp new file mode 100644 index 000000000..57aacdf77 --- /dev/null +++ b/include/Nazara/Math/Cube.hpp @@ -0,0 +1,60 @@ +// 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 +#include + +template +class NzCube +{ + public: + 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; + + 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..5fc3b0c2d --- /dev/null +++ b/include/Nazara/Math/Cube.inl @@ -0,0 +1,194 @@ +// 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 +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) : +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/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.hpp b/include/Nazara/Math/Quaternion.hpp index 4d98f8e34..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); @@ -53,10 +55,10 @@ template class NzQuaternion 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); + 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; @@ -65,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 09c7bd0c0..afba1dd72 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,25 +74,29 @@ NzQuaternion NzQuaternion::GetNormalized() const } template -double NzQuaternion::Magnitude() const +T NzQuaternion::Magnitude() const { return std::sqrt(SquaredMagnitude()); } template -double NzQuaternion::Normalize() +T 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) { + T length = std::sqrt(squaredLength); + w /= length; x /= length; y /= length; z /= length; - } - return length; + return length; + } + else + return 1.0; // Le quaternion est déjà normalisé } template @@ -167,9 +177,55 @@ 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; + } + + 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 @@ -199,31 +255,31 @@ template NzQuaternion NzQuaternion::operator+(const NzQuaternion& quat) const { return NzQuaternion(w + quat.w, - x + quat.x, - y + quat.y, - z + quat.z); + 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); + 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); } 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 = operator*(qvec * GetConjugate()); + + return NzVector3(result.x, result.y, result.z); - return vec + uv + uuv; } template @@ -242,43 +298,27 @@ NzQuaternion NzQuaternion::operator/(const NzQuaternion& quat) const } template -NzQuaternion NzQuaternion::operator+=(const NzQuaternion& quat) +NzQuaternion& NzQuaternion::operator+=(const NzQuaternion& quat) { - w += quat.w; - x += quat.x; - y += quat.y; - z += quat.z; - - return *this; + return operator=(operator+(quat)); } template -NzQuaternion NzQuaternion::operator*=(const NzQuaternion& quat) +NzQuaternion& NzQuaternion::operator*=(const NzQuaternion& quat) { - NzQuaternion q(*this); - operator=(q * quat); - - return *this; + return operator=(operator*(quat)); } template -NzQuaternion NzQuaternion::operator*=(T scale) +NzQuaternion& NzQuaternion::operator*=(T scale) { - w *= scale; - x *= scale; - y *= scale; - z *= scale; - - return *this; + return operator=(operator*(scale)); } template -NzQuaternion NzQuaternion::operator/=(const NzQuaternion& quat) +NzQuaternion& NzQuaternion::operator/=(const NzQuaternion& quat) { - NzQuaternion q(*this); - operator=(q / quat); - - return *this; + return operator=(operator/(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..6473d7206 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -21,19 +21,22 @@ template class NzVector2 ~NzVector2() = default; T AbsDotProduct(const NzVector2& vec) const; - double Distance(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); - double Length() const; - double Normalize(); + T Length() const; + float Lengthf() const; + void Normalize(); T SquaredDistance(const NzVector2& vec) const; T SquaredLength() const; 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..3889aaa78 100644 --- a/include/Nazara/Math/Vector2.inl +++ b/include/Nazara/Math/Vector2.inl @@ -49,17 +49,30 @@ 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); } template -double NzVector2::Distance(const NzVector2& vec) const +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 { @@ -96,23 +109,27 @@ void NzVector2::MakeFloor(const NzVector2& vec) } template -double NzVector2::Length() const +T NzVector2::Length() const { return std::sqrt(SquaredLength()); } template -double NzVector2::Normalize() +float NzVector2::Lengthf() const { - double 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 @@ -136,9 +153,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 @@ -208,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"; @@ -222,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"; @@ -272,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"; @@ -289,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"; @@ -355,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 b658960c3..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,25 +17,29 @@ 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; T AbsDotProduct(const NzVector3& vec) const; NzVector3 CrossProduct(const NzVector3& vec) const; - double Distance(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); - double Length() const; - double Normalize(); + T Length() const; + float Lengthf() const; + void Normalize(); T SquaredDistance(const NzVector3& vec) const; T SquaredLength() const; NzString ToString() const; - operator NzString() const; + operator T*(); + operator const T*() const; T& operator[](unsigned int i); T operator[](unsigned int i) const; @@ -76,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 91cec9fad..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); } @@ -65,11 +80,17 @@ 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)); } +template +float NzVector3::Distancef(const NzVector3& vec) const +{ + return std::sqrt(static_cast(SquaredDistance())); +} + template T NzVector3::DotProduct(const NzVector3& vec) const { @@ -112,24 +133,28 @@ void NzVector3::MakeFloor(const NzVector3& vec) } template -double NzVector3::Length() const +T NzVector3::Length() const { return std::sqrt(SquaredLength()); } template -double NzVector3::Normalize() +float NzVector3::Lengthf() const { - double length = Length(); + return std::sqrt(static_cast(SquaredLength())); +} - if (length != 0.f) +template +void NzVector3::Normalize() +{ + T length = Length(); + + if (!NzNumberEquals(length, static_cast(0.0))) { x /= length; y /= length; z /= length; } - - return length; } template @@ -153,9 +178,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 @@ -225,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"; @@ -239,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"; @@ -293,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"; @@ -311,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"; @@ -379,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 2f8d4860e..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; @@ -28,7 +30,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 168fb6714..e5ec906fd 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,13 +132,19 @@ NzString NzVector4::ToString() const { NzStringStream ss; - return ss << "Vector4(" << x << ", " << y << ", " << z <<')'; + return ss << "Vector4(" << x << ", " << y << ", " << z << ", " << w << ')'; } template -NzVector4::operator NzString() const +NzVector4::operator T*() { - return ToString(); + return &x; +} + +template +NzVector4::operator const T*() const +{ + return &x; } template @@ -174,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 @@ -192,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"; @@ -206,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"; @@ -264,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"; @@ -283,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"; @@ -353,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 71bbfeff5..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 @@ -17,23 +16,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_FUNCTION __PRETTY_FUNCTION__ - #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 @@ -63,24 +66,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/Buffer.hpp b/include/Nazara/Renderer/Buffer.hpp index 285a6774b..c023ade1c 100644 --- a/include/Nazara/Renderer/Buffer.hpp +++ b/include/Nazara/Renderer/Buffer.hpp @@ -8,15 +8,15 @@ #define NAZARA_BUFFER_HPP #include -#include +#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/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..08da75937 100644 --- a/include/Nazara/Renderer/Context.hpp +++ b/include/Nazara/Renderer/Context.hpp @@ -24,16 +24,18 @@ class NAZARA_API NzContext ~NzContext(); bool Create(const NzContextParameters& parameters = NzContextParameters()); + void Destroy(); const NzContextParameters& GetParameters() const; bool IsActive() const; 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/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/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/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/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index fc229991f..8f5e92d85 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -34,13 +34,19 @@ class NAZARA_API NzOpenGL enum Extension { AnisotropicFilter, + DebugOutput, FP64, - Framebuffer_Object, + FrameBufferObject, + SeparateShaderObjects, Texture3D, + TextureCompression_s3tc, + TextureStorage, + VertexArrayObject, Count }; + static NzOpenGLFunc GetEntry(const NzString& entryPoint); static unsigned int GetVersion(); static bool Initialize(); static bool IsSupported(Extension extension); @@ -56,6 +62,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; @@ -69,6 +76,10 @@ 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; NAZARA_API extern PFNGLDELETEBUFFERSPROC glDeleteBuffers; NAZARA_API extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; NAZARA_API extern PFNGLDELETEPROGRAMPROC glDeleteProgram; @@ -76,6 +87,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,7 +108,9 @@ 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 PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLog; NAZARA_API extern PFNGLGETERRORPROC glGetError; NAZARA_API extern PFNGLGETINTEGERVPROC glGetIntegerv; NAZARA_API extern PFNGLGETPROGRAMIVPROC glGetProgramiv; @@ -110,24 +124,44 @@ 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; 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; +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; 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/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 908cea023..fabd16265 100644 --- a/include/Nazara/Renderer/RenderWindow.hpp +++ b/include/Nazara/Renderer/RenderWindow.hpp @@ -10,15 +10,14 @@ #define NAZARA_RENDERWINDOW_HPP #include -#include #include +#include +#include #include -#ifndef NAZARA_RENDERER_COMMON -#include -#endif - class NzContext; +class NzImage; +class NzTexture; struct NzContextParameters; class NAZARA_API NzRenderWindow : public NzRenderTarget, public NzWindow @@ -29,7 +28,8 @@ class NAZARA_API NzRenderWindow : public NzRenderTarget, public NzWindow NzRenderWindow(NzWindowHandle handle, const NzContextParameters& parameters = NzContextParameters()); virtual ~NzRenderWindow(); - 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()); @@ -38,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 f2aa3d76c..6296f22f5 100644 --- a/include/Nazara/Renderer/Renderer.hpp +++ b/include/Nazara/Renderer/Renderer.hpp @@ -8,9 +8,40 @@ #define NAZARA_RENDERER_HPP #include +#include +#include +#include #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, @@ -44,6 +75,41 @@ enum nzRendererClear nzRendererClear_Stencil = 0x04 }; +enum nzRendererComparison +{ + nzRendererComparison_Always, + nzRendererComparison_Equal, + nzRendererComparison_Greater, + nzRendererComparison_GreaterOrEqual, + nzRendererComparison_Less, + nzRendererComparison_LessOrEqual, + nzRendererComparison_Never +}; + +enum nzRendererParameter +{ + 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; class NzRenderTarget; class NzShader; @@ -57,26 +123,42 @@ 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); + void Enable(nzRendererParameter parameter, bool enable); + + unsigned int GetMaxAnisotropyLevel() const; + unsigned int GetMaxRenderTargets() const; 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); 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); + void SetViewport(const NzRectui& viewport); void Uninitialize(); @@ -84,16 +166,30 @@ class NAZARA_API NzRenderer static bool IsInitialized(); private: - bool UpdateVertexBuffer(); + 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_vertexBufferUpdated; + 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/Shader.hpp b/include/Nazara/Renderer/Shader.hpp index e54de851d..b060c9bde 100644 --- a/include/Nazara/Renderer/Shader.hpp +++ b/include/Nazara/Renderer/Shader.hpp @@ -8,9 +8,12 @@ #define NAZARA_SHADER_HPP #include +#include #include #include -#include +#include +#include +#include #include enum nzShaderLanguage @@ -32,6 +35,7 @@ enum nzShaderType class NzRenderer; class NzShaderImpl; +class NzTexture; class NAZARA_API NzShader : public NzResource, NzNonCopyable { @@ -65,6 +69,13 @@ 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 new file mode 100644 index 000000000..98df54f38 --- /dev/null +++ b/include/Nazara/Renderer/Texture.hpp @@ -0,0 +1,103 @@ +// 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 NzShader; +struct NzTextureImpl; + +class NAZARA_API NzTexture : public NzResource, NzNonCopyable +{ + friend class NzShader; + + public: + NzTexture(); + explicit NzTexture(const NzImage& image); + ~NzTexture(); + + #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(); + + 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 IsTarget() 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: + void SetTarget(bool isTarget); + + NzTextureImpl* m_impl; +}; + +#endif // NAZARA_TEXTURE_HPP 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/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 0273249a0..71cddbaa3 100644 --- a/include/Nazara/Utility/Image.hpp +++ b/include/Nazara/Utility/Image.hpp @@ -8,8 +8,11 @@ #define NAZARA_IMAGE_HPP #include +#include #include +#include #include +#include #include #include #include @@ -17,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 @@ -30,19 +33,23 @@ enum nzImageType nzImageType_1D, nzImageType_2D, nzImageType_3D, - nzImageType_Cubemap + nzImageType_Cubemap, + + nzImageType_Count }; struct NzImageParams { + nzPixelFormat loadFormat = nzPixelFormat_Undefined; + nzUInt8 levelCount = 0; + bool IsValid() const { - return true; + return loadFormat == nzPixelFormat_Undefined || NzPixelFormat::IsValid(loadFormat); } }; ///TODO: Filtres -///TODO: Mipmaps class NAZARA_API NzImage : public NzResource, public NzResourceLoader { @@ -55,21 +62,33 @@ class NAZARA_API NzImage : public NzResource, public NzResourceLoader +#include enum nzPixelFormat { nzPixelFormat_Undefined, - nzPixelFormat_B8G8R8, - nzPixelFormat_B8G8R8A8, + nzPixelFormat_BGR8, // 3*nzUInt8 + nzPixelFormat_BGRA8, // 4*nzUInt8 nzPixelFormat_DXT1, nzPixelFormat_DXT3, nzPixelFormat_DXT5, - nzPixelFormat_L8, - nzPixelFormat_L8A8, - nzPixelFormat_R4G4A4A4, - nzPixelFormat_R5G5A5A1, - nzPixelFormat_R8, - nzPixelFormat_R8G8, - nzPixelFormat_R8G8B8, - nzPixelFormat_R8G8B8A8 + nzPixelFormat_L8, // 1*nzUInt8 + nzPixelFormat_LA8, // 2*nzUInt8 + /* + nzPixelFormat_RGB16F, + nzPixelFormat_RGB16I, // 4*nzUInt16 + nzPixelFormat_RGB32F, + nzPixelFormat_RGB32I, // 4*nzUInt32 + nzPixelFormat_RGBA16F, + nzPixelFormat_RGBA16I, // 4*nzUInt16 + nzPixelFormat_RGBA32F, + nzPixelFormat_RGBA32I, // 4*nzUInt32 + */ + nzPixelFormat_RGBA4, // 1*nzUInt16 + nzPixelFormat_RGB5A1, // 1*nzUInt16 + nzPixelFormat_RGB8, // 3*nzUInt8 + nzPixelFormat_RGBA8, // 4*nzUInt8 + /* + nzPixelFormat_Depth16, + nzPixelFormat_Depth24, + nzPixelFormat_Depth24Stencil8, + nzPixelFormat_Depth32, + nzPixelFormat_Stencil1, + nzPixelFormat_Stencil4, + nzPixelFormat_Stencil8, + nzPixelFormat_Stencil16, + */ + + 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 HasAlpha(nzPixelFormat format); + static bool IsCompressed(nzPixelFormat format); + static bool IsConversionSupported(nzPixelFormat srcFormat, nzPixelFormat dstFormat); + 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 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 f89ca81ab..2ea636d04 100644 --- a/include/Nazara/Utility/PixelFormat.inl +++ b/include/Nazara/Utility/PixelFormat.inl @@ -2,19 +2,80 @@ // 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) + " is not supported"); + return false; + } + + 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; + } + + 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, reinterpret_cast(end)-reinterpret_cast(start)); + return true; + } + + ConvertFunction func = s_convertFunctions[srcFormat][dstFormat]; + if (!func) + { + NazaraError("Pixel format conversion from " + ToString(srcFormat) + " to " + ToString(dstFormat) + " is not supported"); + return false; + } + + if (!func(reinterpret_cast(start), reinterpret_cast(end), reinterpret_cast(dst))) + { + NazaraError("Pixel format conversion from " + ToString(srcFormat) + " to " + ToString(dstFormat) + " failed"); + return false; + } + + return true; +} inline nzUInt8 NzPixelFormat::GetBPP(nzPixelFormat format) { switch (format) { - 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,31 +90,84 @@ 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; + + case nzPixelFormat_Count: + case nzPixelFormat_Undefined: + NazaraError("Invalid pixel format"); + return 0; } + NazaraInternalError("Invalid pixel 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; + + 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) { switch (format) @@ -68,4 +182,100 @@ inline bool NzPixelFormat::IsCompressed(nzPixelFormat format) } } -#include +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) + { + 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"; + + case nzPixelFormat_Count: + case nzPixelFormat_Undefined: + break; + } + + NazaraError("Invalid pixel format"); + return "Invalid format"; +} + +#include 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/include/Nazara/Utility/Window.hpp b/include/Nazara/Utility/Window.hpp index b51239f52..acd694f50 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 @@ -24,10 +24,12 @@ #include #endif +class NzUtility; class NzWindowImpl; class NAZARA_API NzWindow : NzNonCopyable { + friend class NzUtility; friend class NzWindowImpl; public: @@ -59,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; @@ -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/readme.txt b/readme.txt index 02814821f..baa55a86f 100644 --- a/readme.txt +++ b/readme.txt @@ -40,4 +40,7 @@ Links Website : http://www.digitalpulsesoftware.com Wiki : http://wiki.digitalpulsesoftware.com/index.php?title=Nazara -Forum : http://forum.digitalpulsesoftware.com \ No newline at end of file +Forum : http://forum.digitalpulsesoftware.com + +Thanks to +-RafBill: Finding bugs diff --git a/readme_fr.txt b/readme_fr.txt index a31c39eca..7e2408b0e 100644 --- a/readme_fr.txt +++ b/readme_fr.txt @@ -40,4 +40,7 @@ Liens Site web : http://www.digitalpulsesoftware.com Wiki : http://wiki.digitalpulsesoftware.com/index.php?title=Nazara -Forum : http://forum.digitalpulsesoftware.com \ No newline at end of file +Forum : http://forum.digitalpulsesoftware.com + +Merci à +-RafBill: Recherche de bugs diff --git a/src/Nazara/Audio/Debug/Leaks.cpp b/src/Nazara/Audio/Debug/Leaks.cpp index 6938eacda..e28e0794e 100644 --- a/src/Nazara/Audio/Debug/Leaks.cpp +++ b/src/Nazara/Audio/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/Color.cpp b/src/Nazara/Core/Color.cpp new file mode 100644 index 000000000..e7e583f2d --- /dev/null +++ b/src/Nazara/Core/Color.cpp @@ -0,0 +1,16 @@ +// 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 + +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/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/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/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/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/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/String.cpp b/src/Nazara/Core/String.cpp index d55bbdb08..53395d609 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; + } } } @@ -4703,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/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..b38b6304f 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 @@ -65,9 +65,9 @@ void NzThreadImpl::Terminate() TerminateThread(m_thread, 0); } -unsigned int _stdcall NzThreadImpl::ThreadProc(void* userdata) +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/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 804d26eb0..d5fa5b961 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; } @@ -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 @@ -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 64c10c8db..520586671 100644 --- a/src/Nazara/Renderer/Context.cpp +++ b/src/Nazara/Renderer/Context.cpp @@ -5,7 +5,10 @@ #include #include #include +#include +#include #include +#include #if defined(NAZARA_PLATFORM_WINDOWS) #include @@ -19,9 +22,112 @@ 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) + { + NazaraUnused(length); + + NzStringStream ss; + ss << "OpenGL debug message (ID: 0x" << NzString::Number(id, 16) << "):\n"; + ss << "Sent by context: " << userParam; + ss << "\n-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 << '\n'; + + NazaraNotice(ss); + } } NzContext::NzContext() : @@ -31,18 +137,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 +172,31 @@ 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; + m_impl = nullptr; + } +} + const NzContextParameters& NzContext::GetParameters() const { #ifdef NAZARA_RENDERER_SAFE @@ -148,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; } @@ -158,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; @@ -178,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/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/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/GLSLShader.cpp b/src/Nazara/Renderer/GLSLShader.cpp index 624c33fc9..7518a3643 100644 --- a/src/Nazara/Renderer/GLSLShader.cpp +++ b/src/Nazara/Renderer/GLSLShader.cpp @@ -6,14 +6,16 @@ #include #include #include -#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 @@ -28,31 +30,8 @@ namespace 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 - }; + GLuint lockedPrevious = 0; + nzUInt8 lockedLevel = 0; } NzGLSLShader::NzGLSLShader(NzShader* parent) : @@ -66,13 +45,38 @@ NzGLSLShader::~NzGLSLShader() bool NzGLSLShader::Bind() { + #if NAZARA_RENDERER_SAFE + if (lockedLevel > 0) + { + NazaraError("Cannot bind shader while a shader is locked"); + return false; + } + #endif + + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + 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() { + NzContext::EnsureContext(); + m_idCache.clear(); glLinkProgram(m_program); @@ -111,6 +115,8 @@ bool NzGLSLShader::Compile() bool NzGLSLShader::Create() { + NzContext::EnsureContext(); + m_program = glCreateProgram(); if (!m_program) { @@ -123,7 +129,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; @@ -138,6 +144,8 @@ bool NzGLSLShader::Create() void NzGLSLShader::Destroy() { + NzContext::EnsureContext(); + for (GLuint shader : m_shaders) if (shader) glDeleteShader(shader); @@ -158,6 +166,8 @@ nzShaderLanguage NzGLSLShader::GetLanguage() const NzString NzGLSLShader::GetSourceCode(nzShaderType type) const { + NzContext::EnsureContext(); + NzString source; GLint length; @@ -177,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; } @@ -193,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) { @@ -245,16 +259,18 @@ bool NzGLSLShader::Load(nzShaderType type, const NzString& source) } } -bool NzGLSLShader::Lock() const +bool NzGLSLShader::Lock() { - if (m_lockedLevel++ == 0) + if (lockedLevel++ == 0) { + NzContext::EnsureContext(); + GLint previous; glGetIntegerv(GL_CURRENT_PROGRAM, &previous); - m_lockedPrevious = previous; + lockedPrevious = previous; - if (m_lockedPrevious != m_program) + if (lockedPrevious != m_program) glUseProgram(m_program); } @@ -263,97 +279,261 @@ bool NzGLSLShader::Lock() const 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; +} + +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}; + + 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() const +void NzGLSLShader::Unlock() { - if (m_lockedLevel == 0) + #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 (--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; + if (--lockedLevel == 0 && lockedPrevious != m_program) + glUseProgram(lockedPrevious); } diff --git a/src/Nazara/Renderer/GLSLShader.hpp b/src/Nazara/Renderer/GLSLShader.hpp index 86efaabaf..658e6e67d 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,18 +42,28 @@ 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(); - void Unlock() const; + void Unlock(); private: - bool UpdateVertexBuffer(const NzVertexBuffer* vertexBuffer, const NzVertexDeclaration* vertexDeclaration); + 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; 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 f87bca264..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"); @@ -37,21 +42,44 @@ m_id(0) NzOcclusionQuery::~NzOcclusionQuery() { if (m_id) - glDeleteQueries(1, reinterpret_cast(&m_id)); + { + NzContext::EnsureContext(); + + GLuint query = static_cast(m_id); + glDeleteQueries(1, &query); + } } 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); @@ -60,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 9e863a952..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; @@ -116,16 +121,87 @@ 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; parameters.shared = false; + /* + Note: Même le contexte de chargement nécessite quelques fonctions de base pour correctement s'initialiser + 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 + */ + + /****************************************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; } @@ -151,6 +227,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")); @@ -182,14 +259,17 @@ 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")); + 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")); 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")); glShaderSource = reinterpret_cast(LoadEntry("glShaderSource")); glStencilFunc = reinterpret_cast(LoadEntry("glStencilFunc")); @@ -223,50 +303,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 +339,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")) { @@ -314,89 +375,133 @@ bool NzOpenGL::Initialize() } } - // Framebuffer_Object - try - { - 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::Framebuffer_Object] = 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 - { - 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")); - - openGLextensions[NzOpenGL::Framebuffer_Object] = true; - } - catch (const std::exception& e) - { - NazaraError("Failed to load EXT_framebuffer_object: " + NzString(e.what())); - } - } - } - - // Texture3D - if (IsSupported("GL_EXT_texture3D")) + // FrameBufferObject + if (openGLversion >= 300 || IsSupported("GL_ARB_framebuffer_object")) { try { - glTexImage3D = reinterpret_cast(LoadEntry("glTexImage3DEXT")); - glTexSubImage3D = reinterpret_cast(LoadEntry("glTexSubImage3DEXT")); + 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::Texture3D] = true; + openGLextensions[NzOpenGL::FrameBufferObject] = true; } catch (const std::exception& e) { - NazaraError("Failed to load EXT_texture3D: " + NzString(e.what())); + NazaraError("Failed to load ARB_framebuffer_object: (" + NzString(e.what()) + ")"); } } - /****************************************Contextes****************************************/ - - - 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()) + // SeparateShaderObjects + if (openGLversion >= 400 || IsSupported("GL_ARB_gpu_shader_fp64")) { - NazaraError("Failed to initialize reference context"); + 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 + 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())); + } + } + } + + // TextureCompression_s3tc + openGLextensions[NzOpenGL::TextureCompression_s3tc] = IsSupported("GL_EXT_texture_compression_s3tc"); + + // TextureStorage + if (openGLversion >= 420 || IsSupported("GL_ARB_texture_storage")) + { + try + { + glTexStorage1D = reinterpret_cast(LoadEntry("glTexStorage1D")); + glTexStorage2D = reinterpret_cast(LoadEntry("glTexStorage2D")); + glTexStorage3D = reinterpret_cast(LoadEntry("glTexStorage3D")); + + openGLextensions[NzOpenGL::TextureStorage] = true; + } + catch (const std::exception& e) + { + NazaraError("Failed to load ARB_texture_storage: " + NzString(e.what())); + } + } + + // VertexArrayObject + if (openGLversion >= 300 || IsSupported("GL_ARB_vertex_array_object")) + { + try + { + glBindVertexArray = reinterpret_cast(LoadEntry("glBindVertexArray")); + glDeleteVertexArrays = reinterpret_cast(LoadEntry("glDeleteVertexArrays")); + glGenVertexArrays = reinterpret_cast(LoadEntry("glGenVertexArrays")); + + openGLextensions[NzOpenGL::VertexArrayObject] = true; + } + catch (const std::exception& e) + { + NazaraError("Failed to load ARB_vertex_array_object: " + NzString(e.what())); + } + } + + /****************************************Contexte de référence****************************************/ + + ///FIXME: Utiliser le contexte de chargement comme référence ? (Vérifier mode debug) + if (!NzContext::Initialize()) + { + NazaraError("Failed to initialize contexts"); Uninitialize(); return false; } - NzContextParameters::defaultShareContext = NzContext::GetReference(); - return true; } @@ -412,7 +517,7 @@ bool NzOpenGL::IsSupported(const NzString& string) void NzOpenGL::Uninitialize() { - NzContext::UninitializeReference(); + NzContext::Uninitialize(); for (bool& ext : openGLextensions) ext = false; @@ -431,6 +536,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; @@ -444,6 +550,10 @@ PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = nullptr; PFNGLCOLORMASKPROC glColorMask = nullptr; PFNGLCULLFACEPROC glCullFace = nullptr; PFNGLCOMPILESHADERPROC glCompileShader = nullptr; +PFNGLCOPYTEXSUBIMAGE2DPROC glCopyTexSubImage2D = nullptr; +PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControl = nullptr; +PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsert = nullptr; +PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallback = nullptr; PFNGLDELETEBUFFERSPROC glDeleteBuffers = nullptr; PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = nullptr; PFNGLDELETEPROGRAMPROC glDeleteProgram = nullptr; @@ -451,6 +561,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; @@ -471,7 +582,9 @@ PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = nullptr; PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = nullptr; PFNGLGENQUERIESPROC glGenQueries = nullptr; PFNGLGENTEXTURESPROC glGenTextures = nullptr; +PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr; PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv = nullptr; +PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLog = nullptr; PFNGLGETERRORPROC glGetError = nullptr; PFNGLGETINTEGERVPROC glGetIntegerv = nullptr; PFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr; @@ -485,24 +598,44 @@ 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; PFNGLLINKPROGRAMPROC glLinkProgram = nullptr; PFNGLMAPBUFFERPROC glMapBuffer = nullptr; PFNGLMAPBUFFERRANGEPROC glMapBufferRange = nullptr; +PFNGLPIXELSTOREIPROC glPixelStorei = 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; 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/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 5d3bf24f2..1af1c2174 100644 --- a/src/Nazara/Renderer/RenderWindow.cpp +++ b/src/Nazara/Renderer/RenderWindow.cpp @@ -5,17 +5,11 @@ #include #include #include -#include #include -#include +#include +#include #include -namespace -{ - NzContextParameters invalidContextParameters; - NzRenderTargetParameters invalidRTParameters; -} - NzRenderWindow::NzRenderWindow() : m_context(nullptr) { @@ -25,21 +19,107 @@ 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() { } -bool NzRenderWindow::CanActivate() const +bool NzRenderWindow::CopyToImage(NzImage* image) { - return m_impl != nullptr && m_context != nullptr; + #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); + + image->FlipVertically(); + + 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) @@ -56,7 +136,7 @@ bool NzRenderWindow::Create(NzWindowHandle handle, const NzContextParameters& pa void NzRenderWindow::Display() { - if (m_context) + if (m_context && m_parameters.doubleBuffered) m_context->SwapBuffers(); } @@ -64,49 +144,35 @@ 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 NazaraError("No context"); } -NzRenderTargetParameters NzRenderWindow::GetRenderTargetParameters() const -{ - if (m_context) - { - const NzContextParameters& parameters = m_context->GetParameters(); - return NzRenderTargetParameters(parameters.antialiasingLevel, parameters.depthBits, parameters.stencilBits); - } - else - { - NazaraError("Window not created/context not initialized"); - return NzRenderTargetParameters(); - } -} - NzContextParameters NzRenderWindow::GetContextParameters() const { if (m_context) @@ -118,14 +184,52 @@ NzContextParameters NzRenderWindow::GetContextParameters() const } } +unsigned int NzRenderWindow::GetHeight() const +{ + return NzWindow::GetHeight(); +} + +NzRenderTargetParameters NzRenderWindow::GetParameters() const +{ + if (m_context) + { + const NzContextParameters& parameters = m_context->GetParameters(); + return NzRenderTargetParameters(parameters.antialiasingLevel, parameters.depthBits, parameters.stencilBits); + } + else + { + NazaraError("Window not created/context not initialized"); + return NzRenderTargetParameters(); + } +} + +unsigned int NzRenderWindow::GetWidth() const +{ + return NzWindow::GetWidth(); +} + 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() @@ -137,6 +241,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..ce8e0ab53 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 @@ -13,29 +14,123 @@ #include #include #include +#include #include #include #include namespace { - GLenum openglPrimitive[] = { - GL_LINES, // nzPrimitiveType_LineList, - GL_LINE_STRIP, // nzPrimitiveType_LineStrip, - GL_POINTS, // nzPrimitiveType_PointList, - GL_TRIANGLES, // nzPrimitiveType_TriangleList, + const nzUInt8 attribIndex[] = + { + 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_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, + 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[] = + { + 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 + }; + + 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_vertexBufferUpdated(false) +NzRenderer::NzRenderer() { #if NAZARA_RENDERER_SAFE if (s_instance) @@ -53,7 +148,7 @@ NzRenderer::~NzRenderer() s_instance = nullptr; } -void NzRenderer::Clear(nzRendererClear flags) +void NzRenderer::Clear(unsigned long flags) { #ifdef NAZARA_DEBUG if (NzContext::GetCurrent() == nullptr) @@ -83,6 +178,12 @@ void NzRenderer::Clear(nzRendererClear 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"); @@ -90,13 +191,10 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f } #endif - if (!m_vertexBufferUpdated) + if (!EnsureStateUpdate()) { - if (!UpdateVertexBuffer()) - { - NazaraError("Failed to update vertex buffer"); - return; - } + NazaraError("Failed to update states"); + return; } nzUInt8 indexSize = m_indexBuffer->GetIndexSize(); @@ -126,30 +224,66 @@ void NzRenderer::DrawIndexedPrimitives(nzPrimitiveType primitive, unsigned int f void NzRenderer::DrawPrimitives(nzPrimitiveType primitive, unsigned int firstVertex, unsigned int vertexCount) { - if (!m_vertexBufferUpdated) + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) { - if (!UpdateVertexBuffer()) - { - NazaraError("Failed to update vertex buffer"); - 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) +{ + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + + 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 @@ -162,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]; @@ -186,17 +336,68 @@ 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; + 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 m_capabilities[nzRendererCap_MultipleRenderTargets] = true; // Natif depuis OpenGL 2.0 - m_capabilities[nzRendererCap_OcclusionQuery] = // Natif depuis OpenGL 1.5 - m_capabilities[nzRendererCap_SoftwareBuffer] = NzOpenGL::GetVersion() <= 300; // Déprécié en OpenGL 3 + m_capabilities[nzRendererCap_OcclusionQuery] = true; // Natif depuis OpenGL 1.5 + 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 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]) + { + GLint maxDrawBuffers; + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); + + m_maxRenderTarget = static_cast(maxDrawBuffers); + } + 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; @@ -205,6 +406,32 @@ 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 + 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 @@ -244,14 +471,40 @@ 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) - 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_vaoUpdated = false; + } return true; } @@ -261,12 +514,17 @@ bool NzRenderer::SetShader(NzShader* shader) if (shader == m_shader) return true; + if (m_shader) + m_shader->m_impl->Unbind(); + if (shader) { #if NAZARA_RENDERER_SAFE if (!shader->IsCompiled()) { NazaraError("Shader is not compiled"); + m_shader = nullptr; + return false; } #endif @@ -274,39 +532,91 @@ bool NzRenderer::SetShader(NzShader* shader) if (!shader->m_impl->Bind()) { NazaraError("Failed to bind shader"); + m_shader = nullptr; + return false; } - - m_shader = shader; - m_vertexBufferUpdated = false; } - else if (m_shader) - { - m_shader->m_impl->Unbind(); + else m_shader = nullptr; - } + + 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) 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 @@ -325,28 +635,63 @@ 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_vaoUpdated = 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_vaoUpdated = false; + } 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 @@ -357,10 +702,19 @@ void NzRenderer::Uninitialize() } #endif - NzOpenGL::Uninitialize(); + NzContext::EnsureContext(); s_initialized = false; + // Libération des VAOs + for (auto it = m_vaos.begin(); it != m_vaos.end(); ++it) + { + GLuint vao = static_cast(it->second); + glDeleteVertexArrays(1, &vao); + } + + NzOpenGL::Uninitialize(); + if (m_utilityModule) { delete m_utilityModule; @@ -383,32 +737,120 @@ bool NzRenderer::IsInitialized() return s_initialized; } -bool NzRenderer::UpdateVertexBuffer() +bool NzRenderer::EnsureStateUpdate() { - #if NAZARA_RENDERER_SAFE - if (!m_shader) + #ifdef NAZARA_DEBUG + if (NzContext::GetCurrent() == nullptr) { - NazaraError("No shader"); - return false; - } - - if (!m_vertexBuffer) - { - NazaraError("No vertex buffer"); - return false; - } - - if (!m_vertexDeclaration) - { - NazaraError("No vertex declaration"); + NazaraError("No active context"); return false; } #endif - if (!m_shader->m_impl->UpdateVertexBuffer(m_vertexBuffer, m_vertexDeclaration)) - return false; + if (!m_stencilFuncUpdated) + { + glStencilFunc(rendererComparison[m_stencilCompare], m_stencilReference, m_stencilMask); + m_stencilFuncUpdated = true; + } - m_vertexBufferUpdated = true; + if (!m_stencilOpUpdated) + { + glStencilOp(stencilOperation[m_stencilFail], stencilOperation[m_stencilZFail], stencilOperation[m_stencilPass]); + m_stencilOpUpdated = true; + } + + if (!m_vaoUpdated) + { + #if NAZARA_RENDERER_SAFE + if (!m_vertexBuffer) + { + NazaraError("No vertex buffer"); + return false; + } + + if (!m_vertexDeclaration) + { + NazaraError("No vertex declaration"); + return false; + } + #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) + { + // 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 + 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_vaoUpdated = true; + } return true; } diff --git a/src/Nazara/Renderer/Shader.cpp b/src/Nazara/Renderer/Shader.cpp index 0afb45782..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,115 @@ 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 + 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 9d30cedbc..504f59853 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,12 +45,16 @@ 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; - virtual void Unlock() const = 0; - - protected: - virtual bool UpdateVertexBuffer(const NzVertexBuffer* vertexBuffer, const NzVertexDeclaration* vertexDeclaration) = 0; + virtual void Unlock() = 0; }; #endif // NAZARA_SHADERIMPL_HPP 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 new file mode 100644 index 000000000..8283fc32c --- /dev/null +++ b/src/Nazara/Renderer/Texture.cpp @@ -0,0 +1,1614 @@ +// 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 +#include +#include + +struct NzTextureImpl +{ + GLuint id; + nzImageType type; + nzPixelFormat format; + nzUInt8 levelCount; + bool isTarget = false; + bool mipmapping = false; + bool mipmapsUpdated = true; + 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; + return true; + + case nzPixelFormat_BGRA8: + format->dataFormat = GL_BGRA; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_RGBA8; + return true; + + case nzPixelFormat_DXT1: + format->dataFormat = GL_RGB; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; + return true; + + case nzPixelFormat_DXT3: + format->dataFormat = GL_RGBA; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + return true; + + case nzPixelFormat_DXT5: + format->dataFormat = GL_RGBA; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + return true; + + 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; + return true; + + case nzPixelFormat_RGB8: + format->dataFormat = GL_RGB; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_RGB8; + return true; + + case nzPixelFormat_RGBA4: + format->dataFormat = GL_RGBA; + format->dataType = GL_UNSIGNED_SHORT_4_4_4_4; + format->internalFormat = GL_RGBA4; + return true; + + case nzPixelFormat_RGBA8: + format->dataFormat = GL_RGBA; + format->dataType = GL_UNSIGNED_BYTE; + format->internalFormat = GL_RGBA8; + return true; + + case nzPixelFormat_Undefined: + case nzPixelFormat_Count: + NazaraInternalError("Invalid pixel format"); + return false; + } + + NazaraError("Pixel format not handled"); + + return false; + } + + bool CreateTexture(NzTextureImpl* impl, bool proxy) + { + OpenGLFormat openGLFormat; + if (!GetOpenGLFormat(impl->format, &openGLFormat)) + { + NazaraError("Failed to get OpenGL format"); + return false; + } + + GLenum target; + switch (impl->type) + { + case nzImageType_1D: + { + target = (proxy) ? GL_TEXTURE_1D : GL_PROXY_TEXTURE_1D; + + /*if (glTexStorage1D) + 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); + if (w > 1U) + w >>= 1; + } + } + break; + } + + case nzImageType_2D: + { + target = (proxy) ? GL_TEXTURE_2D : GL_PROXY_TEXTURE_2D; + + /*if (glTexStorage2D) + 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); + if (w > 1U) + w >>= 1; + + if (h > 1U) + h >>= 1; + } + } + break; + } + + case nzImageType_3D: + { + target = (proxy) ? GL_TEXTURE_3D : GL_PROXY_TEXTURE_3D; + + /*if (glTexStorage3D) + 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); + if (w > 1U) + w >>= 1; + + if (h > 1U) + h >>= 1; + + if (d > 1U) + d >>= 1; + } + } + break; + } + + case nzImageType_Cubemap: + { + target = (proxy) ? GL_TEXTURE_CUBE_MAP : GL_PROXY_TEXTURE_CUBE_MAP; + + /*if (glTexStorage2D) + 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); + + if (size > 1U) + size >>= 1; + } + } + 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) + { + NzContext::EnsureContext(); + + 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); + } + } + + 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 + if (NzContext::GetCurrent() == nullptr) + { + NazaraError("No active context"); + return; + } + #endif + + #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() const +{ + #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); + + 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) + 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("One dimensional texture's height must be 1"); + 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 + + NzContext::EnsureContext(); + + 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 (m_impl->levelCount > 1U) + { + m_impl->mipmapping = true; + m_impl->mipmapsUpdated = false; + } + + if (!lock) + UnlockTexture(impl); + + return true; +} + +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; + } +} + +bool NzTexture::Download(NzImage* image) const +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + + if (!image) + { + NazaraError("Image must be valid"); + 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); + + unsigned int width = m_impl->width; + unsigned int height = m_impl->height; + unsigned int depth = m_impl->depth; + + // 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)); + + if (width > 1) + width >>= 1; + + if (height > 1) + height >>= 1; + + if (depth > 1) + depth >>= 1; + } + + UnlockTexture(m_impl); + + // Inversion de la texture pour le repère d'OpenGL + if (!image->FlipVertically()) + NazaraWarning("Failed to flip image"); + + 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; + } + + if (!m_impl->mipmapping && enable) + { + 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; + + 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); + + GLint anisotropyLevel; + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropyLevel); + + UnlockTexture(m_impl); + + return 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::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; +} + +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); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 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 + + 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) +{ + #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 + + 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) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + #endif + + if (m_impl->type == nzImageType_3D) + 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); +} + +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->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"); + return false; + } + + if (!pixels) + { + NazaraError("Invalid pixel source"); + return false; + } + + if (!rect.IsValid()) + { + NazaraError("Invalid rectangle"); + return false; + } + #endif + + 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; + } + + 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; + } + + nzUInt8 bpp = NzPixelFormat::GetBPP(m_impl->format); + + // Inversion de la texture pour le repère d'OpenGL + 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); + switch (m_impl->type) + { + case nzImageType_1D: + 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, 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, 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); + + return true; +} + +bool NzTexture::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + 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"); + return false; + } + + if (!pixels) + { + NazaraError("Invalid pixel source"); + return false; + } + + if (!cube.IsValid()) + { + 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 > height || + 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; + } + + nzUInt8 bpp = NzPixelFormat::GetBPP(m_impl->format); + + // Inversion de la texture pour le repère d'OpenGL + NzImage mirrored; + mirrored.Create(m_impl->type, m_impl->format, cube.width, cube.height, cube.depth); + mirrored.Update(pixels); + + 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, cube.x, cube.width, format.dataFormat, format.dataType, mirrored.GetConstPixels()); + break; + + case nzImageType_2D: + 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, 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); + + 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), NzRectui(0, 0, image.GetWidth(), image.GetHeight()), 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 + + 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) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + return false; + } + #endif + + 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) +{ + #if NAZARA_RENDERER_SAFE + if (!IsValid()) + { + NazaraError("Texture must be valid"); + 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"); + return false; + } + + if (!pixels) + { + NazaraError("Invalid pixel source"); + return false; + } + + if (!rect.IsValid()) + { + NazaraError("Invalid rectangle"); + return false; + } + #endif + + 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; + } + + 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; + } + + nzUInt8 bpp = NzPixelFormat::GetBPP(m_impl->format); + + // Inversion de la texture pour le repère d'OpenGL + 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, height-rect.height-rect.y, rect.width, rect.height, format.dataFormat, format.dataType, mirrored.GetConstPixels()); + 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) +{ + 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; + } + + case nzPixelFormat_Undefined: + case nzPixelFormat_Count: + break; + } + + NazaraError("Invalid pixel format"); + + 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; + } +} + +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/Renderer/Win32/ContextImpl.cpp b/src/Nazara/Renderer/Win32/ContextImpl.cpp index 071545de5..61fdb8388 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 @@ -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); @@ -180,7 +190,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/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 04c753094..11284bd52 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -6,8 +6,22 @@ #include #include #include +#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) { @@ -36,7 +50,85 @@ NzImage::~NzImage() ReleaseImage(); } -bool NzImage::Copy(const NzImage& source, const NzRectui& srcRect, const NzVector2ui& dstPos) +bool NzImage::Convert(nzPixelFormat format) +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + return false; + } + + if (!NzPixelFormat::IsValid(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; + + for (unsigned int i = 0; i < m_sharedImage->levelCount; ++i) + { + 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); + + 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; + } + + if (width > 1) + width >>= 1; + + if (height > 1) + height >>= 1; + + if (depth > 1 && m_sharedImage->type != nzImageType_Cubemap) + depth >>= 1; + } + + 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; + + return true; +} + +bool NzImage::Copy(const NzImage& source, const NzCubeui& srcCube, const NzVector3ui& dstPos) { #if NAZARA_UTILITY_SAFE if (!source.IsValid()) @@ -52,37 +144,65 @@ 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) +bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width, unsigned int height, unsigned int depth, nzUInt8 levelCount) { ReleaseImage(); - unsigned int size = width*height*depth*NzPixelFormat::GetBPP(format); - if (size == 0) + if (width == 0 || height == 0 || depth == 0) return true; #if NAZARA_UTILITY_SAFE + if (!NzPixelFormat::IsValid(format)) + { + NazaraError("Invalid pixel format"); + return false; + } + switch (type) { case nzImageType_1D: @@ -107,6 +227,9 @@ bool NzImage::Create(nzImageType type, nzPixelFormat format, unsigned int width, } break; + case nzImageType_3D: + break; + case nzImageType_Cubemap: if (depth > 1) { @@ -119,19 +242,51 @@ 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; + NazaraInternalError("Image type not handled"); + return false; } - #else - if (type == nzImageType_Cubemap) - size *= 6; // Les cubemaps ont six faces #endif - m_sharedImage = new SharedImage(1, type, format, new nzUInt8[size], width, height, depth); + 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) + { + // 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 >>= 1; + + if (h > 1) + h >>= 1; + + if (d > 1 && type != nzImageType_Cubemap) + d >>= 1; + } + 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, levelCount, levels, width, height, depth); return true; } @@ -141,19 +296,336 @@ 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() const +const nzUInt8* NzImage::GetConstPixels(nzUInt8 level, unsigned int x, unsigned int y, unsigned int z) const { - return m_sharedImage->pixels; + #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() const +unsigned int NzImage::GetDepth(nzUInt8 level) const { - return m_sharedImage->depth; + #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 GetLevelSize(m_sharedImage->depth, level); } nzPixelFormat NzImage::GetFormat() const @@ -161,21 +633,154 @@ nzPixelFormat NzImage::GetFormat() const return m_sharedImage->format; } -unsigned int NzImage::GetHeight() const +unsigned int NzImage::GetHeight(nzUInt8 level) const { - return m_sharedImage->height; + #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 GetLevelSize(m_sharedImage->height, level); } -nzUInt8* NzImage::GetPixels() +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::GetPixelColor(unsigned int x, unsigned int y, unsigned int z) const +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); + 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(); + } + + 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 NzColor(); + } + #endif + + 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)) + NazaraError("Failed to convert image's format to RGBA8"); + + return color; +} + +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 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 + EnsureOwnership(); - return m_sharedImage->pixels; + 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 { - return m_sharedImage->width * m_sharedImage->height * 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 >>= 1; + + if (height > 1) + height >>= 1; + + if (depth > 1) + depth >>= 1; + } + + if (m_sharedImage->type == nzImageType_Cubemap) + size *= 6; + + return size * NzPixelFormat::GetBPP(m_sharedImage->format); +} + +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 (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); } nzImageType NzImage::GetType() const @@ -183,9 +788,17 @@ nzImageType NzImage::GetType() const return m_sharedImage->type; } -unsigned int NzImage::GetWidth() const +unsigned int NzImage::GetWidth(nzUInt8 level) const { - return m_sharedImage->width; + #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 GetLevelSize(m_sharedImage->width, level); } bool NzImage::IsCompressed() const @@ -218,7 +831,7 @@ bool NzImage::LoadFromStream(NzInputStream& stream, const NzImageParams& params) return NzResourceLoader::LoadResourceFromStream(this, stream, params); } -bool NzImage::Update(const nzUInt8* pixels) +bool NzImage::SetLevelCount(nzUInt8 levelCount) { #if NAZARA_UTILITY_SAFE if (!IsValid()) @@ -227,9 +840,94 @@ bool NzImage::Update(const nzUInt8* pixels) return false; } - if (IsCubemap()) + if (levelCount == 0) { - NazaraError("Update is not designed for cubemaps, use UpdateFace instead"); + 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 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 < maxLevelCount; ++i) + { + if (i < oldLevelCount) + pixels[i] = m_sharedImage->pixels[i]; + else if (i < levelCount) + pixels[i] = new nzUInt8[GetSize(i)]; + else + delete[] m_sharedImage->pixels[i]; + } + + delete[] m_sharedImage->pixels; + + m_sharedImage->pixels = pixels; + + return true; +} + +bool NzImage::SetPixelColor(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 (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; + } + + 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 + + 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)) + { + NazaraError("Failed to convert RGBA8 to image's format"); + return false; + } + + return true; +} + +bool NzImage::Update(const nzUInt8* pixels, nzUInt8 level) +{ + #if NAZARA_UTILITY_SAFE + if (!IsValid()) + { + NazaraError("Image must be valid"); return false; } @@ -238,16 +936,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) +bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect, unsigned int z, nzUInt8 level) { #if NAZARA_UTILITY_SAFE if (!IsValid()) @@ -256,43 +960,52 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect) return false; } - if (IsCubemap()) - { - NazaraError("Update is not designed for cubemaps, use UpdateFace 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; + } + if (!rect.IsValid()) { NazaraError("Invalid rectangle"); return false; } + #endif - if (rect.width > m_sharedImage->width || rect.height > m_sharedImage->height) + 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 = (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) + ')'); + 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 = GetPixelPtr(m_sharedImage->pixels[level], bpp, rect.x, rect.y, z, width, height); 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) + for (unsigned int y = 0; y < rect.height; ++y) { - std::memcpy(dstPixels, pixels, blockSize); + std::memcpy(dstPixels, pixels, srcStride); pixels += srcStride; dstPixels += dstStride; } @@ -300,8 +1013,9 @@ bool NzImage::Update(const nzUInt8* pixels, const NzRectui& rect) return true; } -bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels) +bool NzImage::Update(const nzUInt8* pixels, const NzCubeui& cube, nzUInt8 level) { + ///FIXME: Vérifier que ça fonctionne correctement #if NAZARA_UTILITY_SAFE if (!IsValid()) { @@ -309,57 +1023,33 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels) return false; } - if (!IsCubemap()) - { - NazaraError("Update is only designed for cubemaps, use Update instead"); - return false; - } - - if (!pixels) - { - NazaraError("Invalid pixel source"); - return false; - } - #endif - - EnsureOwnership(); - - unsigned int size = GetSize(); - std::memcpy(&m_sharedImage->pixels[size*(face-nzCubemapFace_PositiveX)], pixels, size); - - return true; -} - -bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRectui& rect) -{ - #if NAZARA_UTILITY_SAFE - if (!IsValid()) - { - NazaraError("Image must be valid"); - return false; - } - - if (!IsCubemap()) - { - NazaraError("Update is only designed for cubemaps, use Update instead"); - return false; - } - if (!pixels) { NazaraError("Invalid pixel source"); return false; } - if (!rect.IsValid()) + if (level >= m_sharedImage->levelCount) { - NazaraError("Invalid rectangle"); + NazaraError("Level out of bounds (" + NzString::Number(level) + " >= " + NzString::Number(m_sharedImage->levelCount) + ')'); + return false; + } + #endif + + 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()) + { + NazaraError("Invalid cube"); return false; } - if (rect.width > m_sharedImage->width || rect.height > m_sharedImage->height) + if (cube.x+cube.width > width || cube.y+cube.height > height || cube.z+cube.depth > depth) { - NazaraError("Rectangle dimensions are out of bounds"); + NazaraError("Cube dimensions are out of bounds"); return false; } #endif @@ -367,17 +1057,21 @@ bool NzImage::UpdateFace(nzCubemapFace face, const nzUInt8* pixels, const NzRect EnsureOwnership(); 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; - 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) + nzUInt8* dstPixels = GetPixelPtr(m_sharedImage->pixels[level], bpp, cube.x, cube.y, cube.z, width, height); + unsigned int srcStride = cube.width * bpp; + unsigned int dstStride = width * bpp; + unsigned int faceSize = dstStride * height; + for (unsigned int z = 0; z < cube.depth; ++z) { - std::memcpy(dstPixels, pixels, blockSize); - pixels += srcStride; - dstPixels += dstStride; + nzUInt8* facePixels = dstPixels; + for (unsigned int y = 0; y < cube.height; ++y) + { + std::memcpy(facePixels, pixels, srcStride); + pixels += srcStride; + facePixels += dstStride; + } + + dstPixels += faceSize; } return true; @@ -405,6 +1099,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(std::max(widthLevel, heightLevel), depthLevel), 1U); +} + void NzImage::RegisterFileLoader(const NzString& extensions, LoadFileFunction loadFile) { return RegisterResourceFileLoader(extensions, loadFile); @@ -445,12 +1150,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); } } @@ -465,6 +1173,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; } @@ -472,4 +1183,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, 1, nullptr, 0, 0, 0); diff --git a/src/Nazara/Utility/Loaders/PCX.cpp b/src/Nazara/Utility/Loaders/PCX.cpp index 67f8a803e..9460ef396 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, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1)) { 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..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 @@ -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,15 +63,45 @@ namespace { NazaraUnused(parameters); - static nzPixelFormat format[4] = { + static const 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 +109,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, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1)) { NazaraError("Failed to create image"); stbi_image_free(ptr); @@ -88,8 +121,12 @@ namespace } resource->Update(ptr); + stbi_image_free(ptr); + if (stbiFormat == STBI_default && parameters.loadFormat != nzPixelFormat_Undefined) + resource->Convert(parameters.loadFormat); + return true; } @@ -98,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/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/PixelFormat.cpp b/src/Nazara/Utility/PixelFormat.cpp new file mode 100644 index 000000000..1a189181e --- /dev/null +++ b/src/Nazara/Utility/PixelFormat.cpp @@ -0,0 +1,1320 @@ +// 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 + +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); + } + + 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) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + *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; + } + + 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; + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; + 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) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + *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; + } + + 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); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; + 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) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + nzUInt16 l = static_cast(c8to4(start[0])); + + *ptr = (l << 12) | + (l << 8) | + (l << 4) | + 0x0F; + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; + 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; + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; + 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) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + nzUInt16 l = static_cast(c8to4(start[0])); + + *ptr = (l << 12) | (l << 8) | (l << 4) | c8to4(start[1]); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; + 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); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; + 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) + { + 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; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + 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; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + 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); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + 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(pixel & 0x000F); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + nzUInt16 pixel = *reinterpret_cast(start); + + #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; + } + + return reinterpret_cast(ptr); + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + 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; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + 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; + } + + return dst; + } + + /*********************************RGB5A1**********************************/ + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + 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); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + 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); + *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); + + #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); + + *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); + + #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); + + *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) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + nzUInt16 pixel = *reinterpret_cast(start); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(&pixel, sizeof(nzUInt16)); + #endif + + 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; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + 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); + + start += 2; + } + + return dst; + } + + template<> + nzUInt8* ConvertPixels(const nzUInt8* start, const nzUInt8* end, nzUInt8* dst) + { + while (start < end) + { + 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); + *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) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + *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; + } + + 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) | + 0x1; + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; + 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) + { + nzUInt16* ptr = reinterpret_cast(dst); + while (start < end) + { + *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; + } + + 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); + + #ifdef NAZARA_BIG_ENDIAN + NzByteSwap(ptr, sizeof(nzUInt16)); + #endif + + ptr++; + 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: Décompresseur DXT1 +/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); +*/ + + /**********************************DXT3***********************************/ + ///TODO: Décompresseur DXT3 +/* + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); + RegisterConverter(); +*/ + + /**********************************DXT5***********************************/ + ///TODO: Décompresseur DXT5 +/* + 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(); + + /*********************************RGB5A1**********************************/ + 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}}; ///FIXME: Fonctionne correctement ? diff --git a/src/Nazara/Utility/Utility.cpp b/src/Nazara/Utility/Utility.cpp index 02bc5576e..3d1bfe716 100644 --- a/src/Nazara/Utility/Utility.cpp +++ b/src/Nazara/Utility/Utility.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include NzUtility::NzUtility() @@ -29,6 +31,20 @@ bool NzUtility::Initialize() } #endif + if (!NzPixelFormat::Initialize()) + { + NazaraError("Failed to initialize pixel format"); + 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) @@ -53,6 +69,10 @@ void NzUtility::Uninitialize() NzLoaders_STB_Unregister(); NzLoaders_PCX_Unregister(); + NzWindow::Uninitialize(); + + NzPixelFormat::Uninitialize(); + s_initialized = false; } 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 937b1c311..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 @@ -25,7 +32,6 @@ namespace { const wchar_t* className = L"Nazara Window"; NzWindowImpl* fullscreenWindow = nullptr; - unsigned int windowCount = 0; } NzWindowImpl::NzWindowImpl(NzWindow* parent) : @@ -62,19 +68,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; @@ -126,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; @@ -165,15 +162,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) @@ -184,7 +173,7 @@ bool NzWindowImpl::Create(NzWindowHandle handle) return false; } - m_handle = static_cast(handle); + m_handle = reinterpret_cast(handle); m_eventListener = false; m_ownsWindow = false; @@ -220,11 +209,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 @@ -348,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); @@ -372,7 +361,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; @@ -707,7 +696,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; @@ -776,6 +765,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 +811,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 +943,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 99a6025c9..2cc727ab0 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 @@ -24,6 +24,7 @@ class NzMutex; class NzThread; class NzThreadCondition; #endif +class NzWindow; #undef IsMinimized // Conflit avec la méthode du même nom @@ -44,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; @@ -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..5f83ff6f2 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) @@ -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 @@ -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,8 @@ void NzWindow::SetEventListener(bool listener) m_impl->SetEventListener(listener); if (!listener) { - NzLock lock(m_eventMutex); + // On vide la pile des évènements + NzLockGuard lock(m_eventMutex); while (!m_events.empty()) m_events.pop(); } @@ -408,7 +409,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()) { @@ -473,3 +474,13 @@ void NzWindow::PushEvent(const NzEvent& event) } #endif } + +bool NzWindow::Initialize() +{ + return NzWindowImpl::Initialize(); +} + +void NzWindow::Uninitialize() +{ + NzWindowImpl::Uninitialize(); +}