Documentation for the rest

Former-commit-id: b6f401370127679db397da0039cb5e98477e90db
This commit is contained in:
Gawaboumga 2016-02-21 14:42:38 +01:00
parent b62b694af8
commit 2a28d8863c
7 changed files with 851 additions and 43 deletions

View File

@ -7,17 +7,38 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::CallOnExit
* \brief Core class that represents a function to call at the end of the scope
*/
/*!
* \brief Constructs a CallOnExit object with a function
*
* \param func Function to call on exit
*/
inline CallOnExit::CallOnExit(Func func) : inline CallOnExit::CallOnExit(Func func) :
m_func(func) m_func(func)
{ {
} }
/*!
* \brief Destructs the object and calls the function
*/
inline CallOnExit::~CallOnExit() inline CallOnExit::~CallOnExit()
{ {
if (m_func) if (m_func)
m_func(); m_func();
} }
/*!
* \brief Calls the function and sets the new callback
*
* \param func Function to call on exit
*/
inline void CallOnExit::CallAndReset(Func func) inline void CallOnExit::CallAndReset(Func func)
{ {
if (m_func) if (m_func)
@ -26,6 +47,12 @@ namespace Nz
Reset(func); Reset(func);
} }
/*!
* \brief Resets the function
*
* \param func Function to call on exit
*/
inline void CallOnExit::Reset(Func func) inline void CallOnExit::Reset(Func func)
{ {
m_func = func; m_func = func;

View File

@ -11,10 +11,28 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::Color
* \brief Core class that represents a color
*/
/*!
* \brief Constructs a Color object by default
*/
inline Color::Color() inline Color::Color()
{ {
} }
/*!
* \brief Constructs a Color object with values
*
* \param red Red value
* \param green Green value
* \param blue Blue value
* \param alpha Alpha value
*/
inline Color::Color(UInt8 red, UInt8 green, UInt8 blue, UInt8 alpha) : inline Color::Color(UInt8 red, UInt8 green, UInt8 blue, UInt8 alpha) :
r(red), r(red),
g(green), g(green),
@ -23,6 +41,12 @@ namespace Nz
{ {
} }
/*!
* \brief Constructs a Color object with a light level
*
* \param lightness Value for r, g and b
*/
inline Color::Color(UInt8 lightness) : inline Color::Color(UInt8 lightness) :
r(lightness), r(lightness),
g(lightness), g(lightness),
@ -31,6 +55,13 @@ namespace Nz
{ {
} }
/*!
* \brief Constructs a Color object with values
*
* \param vec[3] vec[0] = red value, vec[1] = green value, vec[2] = blue value
* \param alpha Alpha value
*/
inline Color::Color(UInt8 vec[3], UInt8 alpha) : inline Color::Color(UInt8 vec[3], UInt8 alpha) :
r(vec[0]), r(vec[0]),
g(vec[1]), g(vec[1]),
@ -39,6 +70,11 @@ namespace Nz
{ {
} }
/*!
* \brief Converts this to string
* \return String representation of the object "Color(r, g, b[, a])"
*/
inline String Color::ToString() const inline String Color::ToString() const
{ {
StringStream ss; StringStream ss;
@ -52,6 +88,13 @@ namespace Nz
return ss; return ss;
} }
/*!
* \brief Adds two colors together
* \return Color which is the sum
*
* \param color Other color
*/
inline Color Color::operator+(const Color& color) const inline Color Color::operator+(const Color& color) const
{ {
///TODO: Improve this shit ///TODO: Improve this shit
@ -64,6 +107,13 @@ namespace Nz
return c; return c;
} }
/*!
* \brief Multiplies two colors together
* \return Color which is the product
*
* \param color Other color
*/
inline Color Color::operator*(const Color& color) const inline Color Color::operator*(const Color& color) const
{ {
///TODO: Improve this shit ///TODO: Improve this shit
@ -76,48 +126,104 @@ namespace Nz
return c; return c;
} }
/*!
* \brief Adds the color to this
* \return Color which is the sum
*
* \param color Other color
*/
inline Color Color::operator+=(const Color& color) inline Color Color::operator+=(const Color& color)
{ {
return operator=(operator+(color)); return operator=(operator+(color));
} }
/*!
* \brief Multiplies the color to this
* \return Color which is the product
*
* \param color Other color
*/
inline Color Color::operator*=(const Color& color) inline Color Color::operator*=(const Color& color)
{ {
return operator=(operator*(color)); return operator=(operator*(color));
} }
/*!
* \brief Checks whether the two colors are equal
* \return true if it is the case
*
* \param color Color to compare
*/
inline bool Color::operator==(const Color& color) const inline bool Color::operator==(const Color& color) const
{ {
return r == color.r && g == color.g && b == color.b && a == color.a; return r == color.r && g == color.g && b == color.b && a == color.a;
} }
/*!
* \brief Checks whether the two colors are equal
* \return false if it is the case
*
* \param color Color to compare
*/
inline bool Color::operator!=(const Color& color) const inline bool Color::operator!=(const Color& color) const
{ {
return !operator==(color); return !operator==(color);
} }
// Algorithmes venant de http://www.easyrgb.com/index.php?X=MATH // Algorithm coming from http://www.easyrgb.com/index.php?X=MATH
/*!
* \brief Converts CMY representation to RGB
* \return Color resulting
*
* \param cyan Cyan component
* \param magenta Magenta component
* \param yellow Yellow component
*/
inline Color Color::FromCMY(float cyan, float magenta, float yellow) inline Color Color::FromCMY(float cyan, float magenta, float yellow)
{ {
return Color(static_cast<UInt8>((1.f-cyan)*255.f), static_cast<UInt8>((1.f-magenta)*255.f), static_cast<UInt8>((1.f-yellow)*255.f)); return Color(static_cast<UInt8>((1.f-cyan)*255.f), static_cast<UInt8>((1.f-magenta)*255.f), static_cast<UInt8>((1.f-yellow)*255.f));
} }
/*!
* \brief Converts CMYK representation to RGB
* \return Color resulting
*
* \param cyan Cyan component
* \param magenta Magenta component
* \param yellow Yellow component
* \param black Black component
*/
inline Color Color::FromCMYK(float cyan, float magenta, float yellow, float black) inline Color Color::FromCMYK(float cyan, float magenta, float yellow, float black)
{ {
return FromCMY(cyan * (1.f - black) + black, return FromCMY(cyan * (1.f - black) + black,
magenta * (1.f - black) + black, magenta * (1.f - black) + black,
yellow * (1.f - black) + black); yellow * (1.f - black) + black);
} }
/*!
* \brief Converts HSL representation to RGB
* \return Color resulting
*
* \param hue Hue component
* \param saturation Saturation component
* \param lightness Lightness component
*/
inline Color Color::FromHSL(UInt8 hue, UInt8 saturation, UInt8 lightness) inline Color Color::FromHSL(UInt8 hue, UInt8 saturation, UInt8 lightness)
{ {
if (saturation == 0) if (saturation == 0)
{ {
// RGB results from 0 to 255 // RGB results from 0 to 255
return Color(lightness * 255, return Color(lightness * 255,
lightness * 255, lightness * 255,
lightness * 255); lightness * 255);
} }
else else
{ {
@ -135,11 +241,20 @@ namespace Nz
float v1 = 2.f * l - v2; float v1 = 2.f * l - v2;
return Color(static_cast<UInt8>(255.f * Hue2RGB(v1, v2, h + (1.f/3.f))), return Color(static_cast<UInt8>(255.f * Hue2RGB(v1, v2, h + (1.f/3.f))),
static_cast<UInt8>(255.f * Hue2RGB(v1, v2, h)), static_cast<UInt8>(255.f * Hue2RGB(v1, v2, h)),
static_cast<UInt8>(255.f * Hue2RGB(v1, v2, h - (1.f/3.f)))); static_cast<UInt8>(255.f * Hue2RGB(v1, v2, h - (1.f/3.f))));
} }
} }
/*!
* \brief Converts HSV representation to RGB
* \return Color resulting
*
* \param hue Hue component
* \param saturation Saturation component
* \param value Value component
*/
inline Color Color::FromHSV(float hue, float saturation, float value) inline Color Color::FromHSV(float hue, float saturation, float value)
{ {
if (NumberEquals(saturation, 0.f)) if (NumberEquals(saturation, 0.f))
@ -201,11 +316,28 @@ namespace Nz
return Color(static_cast<UInt8>(r*255.f), static_cast<UInt8>(g*255.f), static_cast<UInt8>(b*255.f)); return Color(static_cast<UInt8>(r*255.f), static_cast<UInt8>(g*255.f), static_cast<UInt8>(b*255.f));
} }
} }
/*!
* \brief Converts XYZ representation to RGB
* \return Color resulting
*
* \param vec Vector3 representing the space color
*/
inline Color Color::FromXYZ(const Vector3f& vec) inline Color Color::FromXYZ(const Vector3f& vec)
{ {
return FromXYZ(vec.x, vec.y, vec.z); return FromXYZ(vec.x, vec.y, vec.z);
} }
/*!
* \brief Converts XYZ representation to RGB
* \return Color resulting
*
* \param x X component
* \param y Y component
* \param z Z component
*/
inline Color Color::FromXYZ(float x, float y, float z) inline Color Color::FromXYZ(float x, float y, float z)
{ {
x /= 100.f; // X from 0 to 95.047 x /= 100.f; // X from 0 to 95.047
@ -234,6 +366,15 @@ namespace Nz
return Color(static_cast<UInt8>(r * 255.f), static_cast<UInt8>(g * 255.f), static_cast<UInt8>(b * 255.f)); return Color(static_cast<UInt8>(r * 255.f), static_cast<UInt8>(g * 255.f), static_cast<UInt8>(b * 255.f));
} }
/*!
* \brief Converts RGB representation to CMYK
*
* \param color Color to transform
* \param cyan Cyan component
* \param magenta Magenta component
* \param yellow Yellow component
*/
inline void Color::ToCMY(const Color& color, float* cyan, float* magenta, float* yellow) inline void Color::ToCMY(const Color& color, float* cyan, float* magenta, float* yellow)
{ {
*cyan = 1.f - color.r/255.f; *cyan = 1.f - color.r/255.f;
@ -241,6 +382,15 @@ namespace Nz
*yellow = 1.f - color.b/255.f; *yellow = 1.f - color.b/255.f;
} }
/*!
* \brief Converts RGB representation to CMYK
*
* \param color Color to transform
* \param cyan Cyan component
* \param magenta Magenta component
* \param yellow Yellow component
*/
inline void Color::ToCMYK(const Color& color, float* cyan, float* magenta, float* yellow, float* black) inline void Color::ToCMYK(const Color& color, float* cyan, float* magenta, float* yellow, float* black)
{ {
float c, m, y; float c, m, y;
@ -265,6 +415,15 @@ namespace Nz
*black = k; *black = k;
} }
/*!
* \brief Converts RGB representation to HSL
*
* \param color Color to transform
* \param hue Hue component
* \param saturation Saturation component
* \param lightness Lightness component
*/
inline void Color::ToHSL(const Color& color, UInt8* hue, UInt8* saturation, UInt8* lightness) inline void Color::ToHSL(const Color& color, UInt8* hue, UInt8* saturation, UInt8* lightness)
{ {
float r = color.r / 255.f; float r = color.r / 255.f;
@ -315,6 +474,15 @@ namespace Nz
} }
} }
/*!
* \brief Converts RGB representation to HSV
*
* \param color Color to transform
* \param hue Hue component
* \param saturation Saturation component
* \param value Value component
*/
inline void Color::ToHSV(const Color& color, float* hue, float* saturation, float* value) inline void Color::ToHSV(const Color& color, float* hue, float* saturation, float* value)
{ {
float r = color.r / 255.f; float r = color.r / 255.f;
@ -361,11 +529,27 @@ namespace Nz
} }
} }
/*!
* \brief Converts RGB representation to XYZ
*
* \param color Color to transform
* \param vec Vector3 representing the space color
*/
inline void Color::ToXYZ(const Color& color, Vector3f* vec) inline void Color::ToXYZ(const Color& color, Vector3f* vec)
{ {
return ToXYZ(color, &vec->x, &vec->y, &vec->z); return ToXYZ(color, &vec->x, &vec->y, &vec->z);
} }
/*!
* \brief Converts RGB representation to XYZ
*
* \param color Color to transform
* \param x X component
* \param y Y component
* \param z Z component
*/
inline void Color::ToXYZ(const Color& color, float* x, float* y, float* z) inline void Color::ToXYZ(const Color& color, float* x, float* y, float* z)
{ {
float r = color.r/255.f; //R from 0 to 255 float r = color.r/255.f; //R from 0 to 255
@ -397,6 +581,15 @@ namespace Nz
*z = r*0.0193f + g*0.1192f + b*0.9505f; *z = r*0.0193f + g*0.1192f + b*0.9505f;
} }
/*!
* \brief Converts HUE representation to RGV
* \return RGB corresponding
*
* \param v1 V1 component
* \param v2 V2 component
* \param vH VH component
*/
inline float Color::Hue2RGB(float v1, float v2, float vH) inline float Color::Hue2RGB(float v1, float v2, float vH)
{ {
if (vH < 0.f) if (vH < 0.f)
@ -415,8 +608,16 @@ namespace Nz
return v1 + (v2 - v1)*(2.f/3.f - vH)*6; return v1 + (v2 - v1)*(2.f/3.f - vH)*6;
return v1; return v1;
}
} }
}
/*!
* \brief Output operator
* \return The stream
*
* \param out The stream
* \param color The color to output
*/
inline std::ostream& operator<<(std::ostream& out, const Nz::Color& color) inline std::ostream& operator<<(std::ostream& out, const Nz::Color& color)
{ {

View File

@ -7,6 +7,20 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::ObjectRef
* \brief Core class that represents a reference to an object
*/
/*!
* \brief Gets the ObjectRef object by name
* \return Optional reference
*
* \param name Name of the object
*
* \remark Produces a NazaraError if object not found
*/
template<typename Type> template<typename Type>
ObjectRef<Type> ObjectLibrary<Type>::Get(const String& name) ObjectRef<Type> ObjectLibrary<Type>::Get(const String& name)
{ {
@ -17,18 +31,37 @@ namespace Nz
return ref; return ref;
} }
/*!
* \brief Checks whether the library has the object with that name
* \return true if it the case
*/
template<typename Type> template<typename Type>
bool ObjectLibrary<Type>::Has(const String& name) bool ObjectLibrary<Type>::Has(const String& name)
{ {
return Type::s_library.find(name) != Type::s_library.end(); return Type::s_library.find(name) != Type::s_library.end();
} }
/*!
* \brief Registers the ObjectRef object with that name
*
* \param name Name of the object
* \param object Object to stock
*/
template<typename Type> template<typename Type>
void ObjectLibrary<Type>::Register(const String& name, ObjectRef<Type> object) void ObjectLibrary<Type>::Register(const String& name, ObjectRef<Type> object)
{ {
Type::s_library.emplace(name, object); Type::s_library.emplace(name, object);
} }
/*!
* \brief Gets the ObjectRef object by name
* \return Optional reference
*
* \param name Name of the object
*/
template<typename Type> template<typename Type>
ObjectRef<Type> ObjectLibrary<Type>::Query(const String& name) ObjectRef<Type> ObjectLibrary<Type>::Query(const String& name)
{ {
@ -39,6 +72,12 @@ namespace Nz
return nullptr; return nullptr;
} }
/*!
* \brief Unregisters the ObjectRef object with that name
*
* \param name Name of the object
*/
template<typename Type> template<typename Type>
void ObjectLibrary<Type>::Unregister(const String& name) void ObjectLibrary<Type>::Unregister(const String& name)
{ {

View File

@ -16,13 +16,36 @@
namespace Nz namespace Nz
{ {
/*!
* \class Nz::GuillotineBinPack
* \brief Core class that represents the "Guillotine problem", combination of the "Bin packing problem" and the "cutting stock"
*/
namespace namespace
{ {
/*!
* \brief Gets the score for fitting the area
* \return Score of the fitting
*
* \param width Width
* \param height Height
* \param freeRectSize Free area
*/
int ScoreBestAreaFit(int width, int height, const Rectui& freeRectSize) int ScoreBestAreaFit(int width, int height, const Rectui& freeRectSize)
{ {
return freeRectSize.width * freeRectSize.height - width * height; return freeRectSize.width * freeRectSize.height - width * height;
} }
/*!
* \brief Gets the score for fitting the area following long side
* \return Score of the fitting following long side
*
* \param width Width
* \param height Height
* \param freeRectSize Free area
*/
int ScoreBestLongSideFit(int width, int height, const Rectui& freeRectSize) int ScoreBestLongSideFit(int width, int height, const Rectui& freeRectSize)
{ {
int leftoverHoriz = std::abs(static_cast<int>(freeRectSize.width - width)); int leftoverHoriz = std::abs(static_cast<int>(freeRectSize.width - width));
@ -32,6 +55,15 @@ namespace Nz
return leftover; return leftover;
} }
/*!
* \brief Gets the score for fitting the area following short side
* \return Score of the fitting following short side
*
* \param width Width
* \param height Height
* \param freeRectSize Free area
*/
int ScoreBestShortSideFit(int width, int height, const Rectui& freeRectSize) int ScoreBestShortSideFit(int width, int height, const Rectui& freeRectSize)
{ {
int leftoverHoriz = std::abs(static_cast<int>(freeRectSize.width - width)); int leftoverHoriz = std::abs(static_cast<int>(freeRectSize.width - width));
@ -41,37 +73,85 @@ namespace Nz
return leftover; return leftover;
} }
/*!
* \brief Gets the worst score for fitting the area
* \return Worst score of the fitting
*
* \param width Width
* \param height Height
* \param freeRectSize Free area
*/
int ScoreWorstAreaFit(int width, int height, const Rectui& freeRectSize) int ScoreWorstAreaFit(int width, int height, const Rectui& freeRectSize)
{ {
return -ScoreBestAreaFit(width, height, freeRectSize); return -ScoreBestAreaFit(width, height, freeRectSize);
} }
/*!
* \brief Gets the worst score for fitting the area following long side
* \return Worst score of the fitting following long side
*
* \param width Width
* \param height Height
* \param freeRectSize Free area
*/
int ScoreWorstLongSideFit(int width, int height, const Rectui& freeRectSize) int ScoreWorstLongSideFit(int width, int height, const Rectui& freeRectSize)
{ {
return -ScoreBestLongSideFit(width, height, freeRectSize); return -ScoreBestLongSideFit(width, height, freeRectSize);
} }
/*!
* \brief Gets the worst score for fitting the area following short side
* \return Worst score of the fitting following short side
*
* \param width Width
* \param height Height
* \param freeRectSize Free area
*/
int ScoreWorstShortSideFit(int width, int height, const Rectui& freeRectSize) int ScoreWorstShortSideFit(int width, int height, const Rectui& freeRectSize)
{ {
return -ScoreBestShortSideFit(width, height, freeRectSize); return -ScoreBestShortSideFit(width, height, freeRectSize);
} }
} }
/*!
* \brief Constructs a GuillotineBinPack object by default
*/
GuillotineBinPack::GuillotineBinPack() GuillotineBinPack::GuillotineBinPack()
{ {
Reset(); Reset();
} }
/*!
* \brief Constructs a GuillotineBinPack object with width and height
*
* \param width Width
* \param height Height
*/
GuillotineBinPack::GuillotineBinPack(unsigned int width, unsigned int height) GuillotineBinPack::GuillotineBinPack(unsigned int width, unsigned int height)
{ {
Reset(width, height); Reset(width, height);
} }
/*!
* \brief Constructs a GuillotineBinPack object with area
*
* \param size Vector2 representing the area (width, height)
*/
GuillotineBinPack::GuillotineBinPack(const Vector2ui& size) GuillotineBinPack::GuillotineBinPack(const Vector2ui& size)
{ {
Reset(size); Reset(size);
} }
/*!
* \brief Clears the content
*/
void GuillotineBinPack::Clear() void GuillotineBinPack::Clear()
{ {
m_freeRectangles.clear(); m_freeRectangles.clear();
@ -80,6 +160,15 @@ namespace Nz
m_usedArea = 0; m_usedArea = 0;
} }
/*!
* \brief Expands the content
*
* \param newWidth New width for the expansion
* \param newHeight New height for the expansion
*
* \see Expand
*/
void GuillotineBinPack::Expand(unsigned int newWidth, unsigned newHeight) void GuillotineBinPack::Expand(unsigned int newWidth, unsigned newHeight)
{ {
unsigned int oldWidth = m_width; unsigned int oldWidth = m_width;
@ -98,52 +187,123 @@ namespace Nz
while (MergeFreeRectangles()); while (MergeFreeRectangles());
} }
/*!
* \brief Expands the content
*
* \param newSize New area for the expansion
*
* \see Expand
*/
void GuillotineBinPack::Expand(const Vector2ui& newSize) void GuillotineBinPack::Expand(const Vector2ui& newSize)
{ {
Expand(newSize.x, newSize.y); Expand(newSize.x, newSize.y);
} }
/*!
* \brief Frees the rectangle
*
* \param rect Area to free
*
* \remark This method should only be called with computed rectangles by the method Insert and can produce fragmentation
*/
void GuillotineBinPack::FreeRectangle(const Rectui& rect) void GuillotineBinPack::FreeRectangle(const Rectui& rect)
{ {
///DOC: Cette méthode ne devrait recevoir que des rectangles calculés par la méthode Insert et peut provoquer de la fragmentation
m_freeRectangles.push_back(rect); m_freeRectangles.push_back(rect);
m_usedArea -= rect.width * rect.height; m_usedArea -= rect.width * rect.height;
} }
/*!
* \brief Gets the height
* \return Height of the area
*/
unsigned int GuillotineBinPack::GetHeight() const unsigned int GuillotineBinPack::GetHeight() const
{ {
return m_height; return m_height;
} }
/*!
* \brief Gets percentage of occupation
* \return Percentage of the already occupied area
*/
float GuillotineBinPack::GetOccupancy() const float GuillotineBinPack::GetOccupancy() const
{ {
return static_cast<float>(m_usedArea)/(m_width*m_height); return static_cast<float>(m_usedArea)/(m_width*m_height);
} }
/*!
* \brief Gets the size of the area
* \return Size of the area
*/
Vector2ui GuillotineBinPack::GetSize() const Vector2ui GuillotineBinPack::GetSize() const
{ {
return Vector2ui(m_width, m_height); return Vector2ui(m_width, m_height);
} }
/*!
* \brief Gets the width
* \return Width of the area
*/
unsigned int GuillotineBinPack::GetWidth() const unsigned int GuillotineBinPack::GetWidth() const
{ {
return m_width; return m_width;
} }
/*!
* \brief Inserts rectangles in the area
* \return true if each rectangle could be inserted
*
* \param rects List of rectangles
* \param count Count of rectangles
* \param merge Merge possible
* \param rectChoice Heuristic to use to free
* \param splitMethod Heuristic to use to split
*/
bool GuillotineBinPack::Insert(Rectui* rects, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod) bool GuillotineBinPack::Insert(Rectui* rects, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
{ {
return Insert(rects, nullptr, nullptr, count, merge, rectChoice, splitMethod); return Insert(rects, nullptr, nullptr, count, merge, rectChoice, splitMethod);
} }
/*!
* \brief Inserts rectangles in the area
* \return true if each rectangle could be inserted
*
* \param rects List of rectangles
* \param flipped List of flipped rectangles
* \param count Count of rectangles
* \param merge Merge possible
* \param rectChoice Heuristic to use to free
* \param splitMethod Heuristic to use to split
*/
bool GuillotineBinPack::Insert(Rectui* rects, bool* flipped, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod) bool GuillotineBinPack::Insert(Rectui* rects, bool* flipped, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
{ {
return Insert(rects, flipped, nullptr, count, merge, rectChoice, splitMethod); return Insert(rects, flipped, nullptr, count, merge, rectChoice, splitMethod);
} }
/*!
* \brief Inserts rectangles in the area
* \return true if each rectangle could be inserted
*
* \param rects List of rectangles
* \param flipped List of flipped rectangles
* \param flipped List of inserted rectangles
* \param count Count of rectangles
* \param merge Merge possible
* \param rectChoice Heuristic to use to free
* \param splitMethod Heuristic to use to split
*/
bool GuillotineBinPack::Insert(Rectui* rects, bool* flipped, bool* inserted, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod) bool GuillotineBinPack::Insert(Rectui* rects, bool* flipped, bool* inserted, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
{ {
std::vector<Rectui*> remainingRects(count); // La position du rectangle std::vector<Rectui*> remainingRects(count); // Position of the rectangle
for (unsigned int i = 0; i < count; ++i) for (unsigned int i = 0; i < count; ++i)
remainingRects[i] = &rects[i]; remainingRects[i] = &rects[i];
@ -214,7 +374,7 @@ namespace Nz
// If we didn't manage to find any rectangle to pack, abort. // If we didn't manage to find any rectangle to pack, abort.
if (bestScore == std::numeric_limits<int>::max()) if (bestScore == std::numeric_limits<int>::max())
{ {
// Si nous le pouvons, on marque les rectangles n'ayant pas pu être insérés // If we can do it, we mark the rectangle could be inserted
if (inserted) if (inserted)
{ {
for (Rectui* rect : remainingRects) for (Rectui* rect : remainingRects)
@ -259,9 +419,13 @@ namespace Nz
return true; return true;
} }
/*!
* \brief Merges free rectangles together
* \return true if there was a merge (and thus if a merge is still possible)
*/
bool GuillotineBinPack::MergeFreeRectangles() bool GuillotineBinPack::MergeFreeRectangles()
{ {
///DOC: Renvoie true s'il y a eu fusion (et donc si une fusion est encore possible)
std::size_t oriSize = m_freeRectangles.size(); std::size_t oriSize = m_freeRectangles.size();
// Do a Theta(n^2) loop to see if any pair of free rectangles could me merged into one. // Do a Theta(n^2) loop to see if any pair of free rectangles could me merged into one.
@ -312,6 +476,10 @@ namespace Nz
return m_freeRectangles.size() < oriSize; return m_freeRectangles.size() < oriSize;
} }
/*!
* \brief Resets the area
*/
void GuillotineBinPack::Reset() void GuillotineBinPack::Reset()
{ {
m_height = 0; m_height = 0;
@ -320,6 +488,13 @@ namespace Nz
Clear(); Clear();
} }
/*!
* \brief Resets the area
*
* \param width Width
* \param height Height
*/
void GuillotineBinPack::Reset(unsigned int width, unsigned int height) void GuillotineBinPack::Reset(unsigned int width, unsigned int height)
{ {
m_height = height; m_height = height;
@ -328,11 +503,25 @@ namespace Nz
Clear(); Clear();
} }
/*!
* \brief Resets the area
*
* \param size Size of the area
*/
void GuillotineBinPack::Reset(const Vector2ui& size) void GuillotineBinPack::Reset(const Vector2ui& size)
{ {
Reset(size.x, size.y); Reset(size.x, size.y);
} }
/*!
* \brief Splits the free rectangle along axis
*
* \param freeRect Free rectangle to split
* \param placedRect Already placed rectangle
* \param splitHorizontal Split horizontally (or vertically)
*/
void GuillotineBinPack::SplitFreeRectAlongAxis(const Rectui& freeRect, const Rectui& placedRect, bool splitHorizontal) void GuillotineBinPack::SplitFreeRectAlongAxis(const Rectui& freeRect, const Rectui& placedRect, bool splitHorizontal)
{ {
// Form the two new rectangles. // Form the two new rectangles.
@ -365,50 +554,60 @@ namespace Nz
m_freeRectangles.push_back(right); m_freeRectangles.push_back(right);
} }
/*!
* \brief Splits the free rectangle using the heuristic
*
* \param freeRect Free rectangle to split
* \param placedRect Already placed rectangle
* \param method Method used to split
*
* \remark Produces a NazaraError if enumeration GuillotineSplitHeuristic is invalid
*/
void GuillotineBinPack::SplitFreeRectByHeuristic(const Rectui& freeRect, const Rectui& placedRect, GuillotineSplitHeuristic method) void GuillotineBinPack::SplitFreeRectByHeuristic(const Rectui& freeRect, const Rectui& placedRect, GuillotineSplitHeuristic method)
{ {
// Compute the lengths of the leftover area. // Compute the lengths of the leftover area
const int w = freeRect.width - placedRect.width; const int w = freeRect.width - placedRect.width;
const int h = freeRect.height - placedRect.height; const int h = freeRect.height - placedRect.height;
// Placing placedRect into freeRect results in an L-shaped free area, which must be split into // Placing placedRect into freeRect results in an L-shaped free area, which must be split into
// two disjoint rectangles. This can be achieved with by splitting the L-shape using a single line. // two disjoint rectangles. This can be achieved with by splitting the L-shape using a single line
// We have two choices: horizontal or vertical. // We have two choices: horizontal or vertical
// Use the given heuristic to decide which choice to make. // Use the given heuristic to decide which choice to make
bool splitHorizontal; bool splitHorizontal;
switch (method) switch (method)
{ {
case SplitLongerAxis: case SplitLongerAxis:
// Split along the longer total axis. // Split along the longer total axis
splitHorizontal = (freeRect.width > freeRect.height); splitHorizontal = (freeRect.width > freeRect.height);
break; break;
case SplitLongerLeftoverAxis: case SplitLongerLeftoverAxis:
// Split along the longer leftover axis. // Split along the longer leftover axis
splitHorizontal = (w > h); splitHorizontal = (w > h);
break; break;
case SplitMaximizeArea: case SplitMaximizeArea:
// Maximize the smaller area == minimize the larger area. // Maximize the smaller area == minimize the larger area
// Tries to make the rectangles more even-sized. // Tries to make the rectangles more even-sized
splitHorizontal = (placedRect.width * h <= w * placedRect.height); splitHorizontal = (placedRect.width * h <= w * placedRect.height);
break; break;
case SplitMinimizeArea: case SplitMinimizeArea:
// Maximize the larger area == minimize the smaller area. // Maximize the larger area == minimize the smaller area
// Tries to make the single bigger rectangle. // Tries to make the single bigger rectangle
splitHorizontal = (placedRect.width * h > w * placedRect.height); splitHorizontal = (placedRect.width * h > w * placedRect.height);
break; break;
case SplitShorterAxis: case SplitShorterAxis:
// Split along the shorter total axis. // Split along the shorter total axis
splitHorizontal = (freeRect.width <= freeRect.height); splitHorizontal = (freeRect.width <= freeRect.height);
break; break;
case SplitShorterLeftoverAxis: case SplitShorterLeftoverAxis:
// Split along the shorter leftover axis. // Split along the shorter leftover axis
splitHorizontal = (w <= h); splitHorizontal = (w <= h);
break; break;
@ -417,10 +616,22 @@ namespace Nz
splitHorizontal = true; splitHorizontal = true;
} }
// Perform the actual split. // Perform the actual split
SplitFreeRectAlongAxis(freeRect, placedRect, splitHorizontal); SplitFreeRectAlongAxis(freeRect, placedRect, splitHorizontal);
} }
/*!
* \brief Gets the score using heuristic
* \return Score of the heuristic
*
* \param width Width
* \param height Height
* \param freeRect Free area
* \param rectChoice Heuristic to get score
*
* \remark Produces a NazaraError if enumeration FreeRectChoiceHeuristic is invalid
*/
int GuillotineBinPack::ScoreByHeuristic(int width, int height, const Rectui& freeRect, FreeRectChoiceHeuristic rectChoice) int GuillotineBinPack::ScoreByHeuristic(int width, int height, const Rectui& freeRect, FreeRectChoiceHeuristic rectChoice)
{ {
switch (rectChoice) switch (rectChoice)

View File

@ -82,11 +82,31 @@ namespace Nz
char s_brandString[48] = "Not initialized"; char s_brandString[48] = "Not initialized";
} }
/*!
* \class Nz::HardwareInfo
* \brief Core class that represents the info we can get from hardware
*/
/*!
* \brief Generates the cpuid instruction (available on x86 & x64)
*
* \param functionId Information to retrieve
* \param subFunctionId Additional code for information retrieval
* \param result Supported features of the CPU
*/
void HardwareInfo::Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 result[4]) void HardwareInfo::Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 result[4])
{ {
return HardwareInfoImpl::Cpuid(functionId, subFunctionId, result); return HardwareInfoImpl::Cpuid(functionId, subFunctionId, result);
} }
/*!
* \brief Gets the brand of the processor
* \return String of the brand
*
* \remark Produces a NazaraError if not Initialize
*/
String HardwareInfo::GetProcessorBrandString() String HardwareInfo::GetProcessorBrandString()
{ {
if (!Initialize()) if (!Initialize())
@ -95,13 +115,26 @@ namespace Nz
return s_brandString; return s_brandString;
} }
/*!
* \brief Gets the number of threads
* \return Number of threads available on the CPU
*
* \remark Doesn't need the initialization of HardwareInfo
*/
unsigned int HardwareInfo::GetProcessorCount() unsigned int HardwareInfo::GetProcessorCount()
{ {
///DOC: Ne nécessite pas l'initialisation de HardwareInfo pour fonctionner
static unsigned int processorCount = std::max(HardwareInfoImpl::GetProcessorCount(), 1U); static unsigned int processorCount = std::max(HardwareInfoImpl::GetProcessorCount(), 1U);
return processorCount; return processorCount;
} }
/*!
* \brief Gets the processor vendor
* \return ProcessorVendor containing information the vendor
*
* \remark Produces a NazaraError if not Initialize
*/
ProcessorVendor HardwareInfo::GetProcessorVendor() ProcessorVendor HardwareInfo::GetProcessorVendor()
{ {
if (!Initialize()) if (!Initialize())
@ -110,6 +143,13 @@ namespace Nz
return s_vendorEnum; return s_vendorEnum;
} }
/*!
* \brief Gets the vendor of the processor
* \return String of the vendor
*
* \remark Produces a NazaraError if not Initialize
*/
String HardwareInfo::GetProcessorVendorName() String HardwareInfo::GetProcessorVendorName()
{ {
if (!Initialize()) if (!Initialize())
@ -118,13 +158,26 @@ namespace Nz
return vendorNames[s_vendorEnum+1]; return vendorNames[s_vendorEnum+1];
} }
/*!
* \brief Gets the amount of total memory
* \return Number of total memory available
*
* \remark Doesn't need the initialization of HardwareInfo
*/
UInt64 HardwareInfo::GetTotalMemory() UInt64 HardwareInfo::GetTotalMemory()
{ {
///DOC: Ne nécessite pas l'initialisation de HardwareInfo pour fonctionner
static UInt64 totalMemory = HardwareInfoImpl::GetTotalMemory(); static UInt64 totalMemory = HardwareInfoImpl::GetTotalMemory();
return totalMemory; return totalMemory;
} }
/*!
* \brief Checks whether the processor owns the capacity to handle certain instructions
* \return true If instructions supported
*
* \remark Produces a NazaraError if capability is a wrong enum with NAZARA_DEBUG defined
*/
bool HardwareInfo::HasCapability(ProcessorCap capability) bool HardwareInfo::HasCapability(ProcessorCap capability)
{ {
#ifdef NAZARA_DEBUG #ifdef NAZARA_DEBUG
@ -138,9 +191,16 @@ namespace Nz
return s_capabilities[capability]; return s_capabilities[capability];
} }
/*!
* \brief Initializes the HardwareInfo class
* \return true if successful
*
* \remark Produces a NazaraError if cpuid is not supported
*/
bool HardwareInfo::Initialize() bool HardwareInfo::Initialize()
{ {
if (s_initialized) if (IsInitialized())
return true; return true;
if (!HardwareInfoImpl::IsCpuidSupported()) if (!HardwareInfoImpl::IsCpuidSupported())
@ -151,21 +211,21 @@ namespace Nz
s_initialized = true; s_initialized = true;
UInt32 registers[4]; // Récupère les quatre registres (EAX, EBX, ECX et EDX) UInt32 registers[4]; // Get the four registers (EAX, EBX, ECX et EDX)
// Pour plus de clarté // To make it more clear
UInt32& eax = registers[0]; UInt32& eax = registers[0];
UInt32& ebx = registers[1]; UInt32& ebx = registers[1];
UInt32& ecx = registers[2]; UInt32& ecx = registers[2];
UInt32& edx = registers[3]; UInt32& edx = registers[3];
// Pour commencer, on va récupérer l'identifiant du constructeur ainsi que l'id de fonction maximal supporté par le CPUID // To begin, we get the id of the constructor and the id of maximal functions supported by the CPUID
HardwareInfoImpl::Cpuid(0, 0, registers); HardwareInfoImpl::Cpuid(0, 0, registers);
// Attention à l'ordre : EBX, EDX, ECX // Watchout to the order : EBX, EDX, ECX
UInt32 manufacturerId[3] = {ebx, edx, ecx}; UInt32 manufacturerId[3] = {ebx, edx, ecx};
// Identification du concepteur // Identification of conceptor
s_vendorEnum = ProcessorVendor_Unknown; s_vendorEnum = ProcessorVendor_Unknown;
for (const VendorString& vendorString : vendorStrings) for (const VendorString& vendorString : vendorStrings)
{ {
@ -178,7 +238,7 @@ namespace Nz
if (eax >= 1) if (eax >= 1)
{ {
// Récupération de certaines capacités du processeur (ECX et EDX, fonction 1) // Recuperation of certain capacities of the processor (ECX et EDX, function 1)
HardwareInfoImpl::Cpuid(1, 0, registers); HardwareInfoImpl::Cpuid(1, 0, registers);
s_capabilities[ProcessorCap_AVX] = (ecx & (1U << 28)) != 0; s_capabilities[ProcessorCap_AVX] = (ecx & (1U << 28)) != 0;
@ -192,53 +252,67 @@ namespace Nz
s_capabilities[ProcessorCap_SSE42] = (ecx & (1U << 20)) != 0; s_capabilities[ProcessorCap_SSE42] = (ecx & (1U << 20)) != 0;
} }
// Récupération de la plus grande fonction étendue supportée (EAX, fonction 0x80000000) // Recuperation of biggest extended function handled (EAX, fonction 0x80000000)
HardwareInfoImpl::Cpuid(0x80000000, 0, registers); HardwareInfoImpl::Cpuid(0x80000000, 0, registers);
UInt32 maxSupportedExtendedFunction = eax; UInt32 maxSupportedExtendedFunction = eax;
if (maxSupportedExtendedFunction >= 0x80000001) if (maxSupportedExtendedFunction >= 0x80000001)
{ {
// Récupération des capacités étendues du processeur (ECX et EDX, fonction 0x80000001) // Recuperation of extended capabilities of the processor (ECX et EDX, fonction 0x80000001)
HardwareInfoImpl::Cpuid(0x80000001, 0, registers); HardwareInfoImpl::Cpuid(0x80000001, 0, registers);
s_capabilities[ProcessorCap_x64] = (edx & (1U << 29)) != 0; // Support du 64bits, indépendant de l'OS s_capabilities[ProcessorCap_x64] = (edx & (1U << 29)) != 0; // Support of 64bits, independant of the OS
s_capabilities[ProcessorCap_FMA4] = (ecx & (1U << 16)) != 0; s_capabilities[ProcessorCap_FMA4] = (ecx & (1U << 16)) != 0;
s_capabilities[ProcessorCap_SSE4a] = (ecx & (1U << 6)) != 0; s_capabilities[ProcessorCap_SSE4a] = (ecx & (1U << 6)) != 0;
s_capabilities[ProcessorCap_XOP] = (ecx & (1U << 11)) != 0; s_capabilities[ProcessorCap_XOP] = (ecx & (1U << 11)) != 0;
if (maxSupportedExtendedFunction >= 0x80000004) if (maxSupportedExtendedFunction >= 0x80000004)
{ {
// Récupération d'une chaîne de caractère décrivant le processeur (EAX, EBX, ECX et EDX, // Recuperation of the string describing the processor (EAX, EBX, ECX et EDX,
// fonctions de 0x80000002 à 0x80000004 compris) // functions from 0x80000002 to 0x80000004 inclusive)
char* ptr = &s_brandString[0]; char* ptr = &s_brandString[0];
for (UInt32 code = 0x80000002; code <= 0x80000004; ++code) for (UInt32 code = 0x80000002; code <= 0x80000004; ++code)
{ {
HardwareInfoImpl::Cpuid(code, 0, registers); HardwareInfoImpl::Cpuid(code, 0, registers);
std::memcpy(ptr, &registers[0], 4*sizeof(UInt32)); // On rajoute les 16 octets à la chaîne std::memcpy(ptr, &registers[0], 4*sizeof(UInt32)); // We add the 16 bytes to the string
ptr += 4*sizeof(UInt32); ptr += 4*sizeof(UInt32);
} }
// Le caractère nul faisant partie de la chaîne retournée par le CPUID, pas besoin de le rajouter // The character '\0' is already returned
} }
} }
return true; return true;
} }
/*!
* \brief Checks whether the instruction of cpuid is supported
* \return true if it the case
*/
bool HardwareInfo::IsCpuidSupported() bool HardwareInfo::IsCpuidSupported()
{ {
return HardwareInfoImpl::IsCpuidSupported(); return HardwareInfoImpl::IsCpuidSupported();
} }
/*!
* \brief Checks whether the class HardwareInfo is initialized
* \return true if it is initialized
*/
bool HardwareInfo::IsInitialized() bool HardwareInfo::IsInitialized()
{ {
return s_initialized; return s_initialized;
} }
/*!
* \brief Unitializes the class HardwareInfo
*/
void HardwareInfo::Uninitialize() void HardwareInfo::Uninitialize()
{ {
// Rien à faire // Nothing to do
s_initialized = false; s_initialized = false;
} }
} }

View File

@ -0,0 +1,256 @@
#include <Nazara/Math/Algorithm.hpp>
#include <Catch/catch.hpp>
TEST_CASE("Approach", "[MATH][ALGORITHM]")
{
SECTION("Approach 8 with 5 by 2")
{
REQUIRE(Nz::Approach(5, 8, 2) == 7);
}
SECTION("Approach 5 with 8 by 2")
{
REQUIRE(Nz::Approach(8, 5, 2) == 6);
}
SECTION("Approach 8 with 8 by 2")
{
REQUIRE(Nz::Approach(8, 8, 2) == 8);
}
}
TEST_CASE("Clamp", "[MATH][ALGORITHM]")
{
SECTION("Clamp 8 between 5 and 10")
{
REQUIRE(Nz::Clamp(8, 5, 10) == 8);
}
SECTION("Clamp 4 between 5 and 10")
{
REQUIRE(Nz::Clamp(4, 5, 10) == 5);
}
SECTION("Clamp 12 between 5 and 10")
{
REQUIRE(Nz::Clamp(12, 5, 10) == 10);
}
}
TEST_CASE("CountBits", "[MATH][ALGORITHM]")
{
SECTION("Number 10 has 2 bits set to 1")
{
REQUIRE(Nz::CountBits(10) == 2);
}
SECTION("Number 0 has 0 bit set to 1")
{
REQUIRE(Nz::CountBits(0) == 0);
}
}
TEST_CASE("DegreeToRadian", "[MATH][ALGORITHM]")
{
SECTION("Convert 45.f degree to radian")
{
REQUIRE(Nz::DegreeToRadian(45.f) == Approx(M_PI / 4));
}
}
TEST_CASE("GetNearestPowerOfTwo", "[MATH][ALGORITHM]")
{
SECTION("Nearest power of two of 0 = 1")
{
REQUIRE(Nz::GetNearestPowerOfTwo(0) == 1);
}
SECTION("Nearest power of two of 16 = 16")
{
REQUIRE(Nz::GetNearestPowerOfTwo(16) == 16);
}
SECTION("Nearest power of two of 17 = 32")
{
REQUIRE(Nz::GetNearestPowerOfTwo(17) == 32);
}
}
TEST_CASE("GetNumberLength", "[MATH][ALGORITHM]")
{
SECTION("GetNumberLength of -127 signed char")
{
signed char minus127 = -127;
REQUIRE(Nz::GetNumberLength(minus127) == 4);
}
SECTION("GetNumberLength of 255 unsigned char")
{
unsigned char plus255 = 255;
REQUIRE(Nz::GetNumberLength(plus255) == 3);
}
SECTION("GetNumberLength of -1270 signed int")
{
signed int minus1270 = -1270;
REQUIRE(Nz::GetNumberLength(minus1270) == 5);
}
SECTION("GetNumberLength of 2550 unsigned int")
{
unsigned int plus2550 = 2550;
REQUIRE(Nz::GetNumberLength(plus2550) == 4);
}
SECTION("GetNumberLength of -1270 signed long long")
{
signed long long minus12700 = -12700;
REQUIRE(Nz::GetNumberLength(minus12700) == 6);
}
SECTION("GetNumberLength of 2550 unsigned long long")
{
unsigned long long plus25500 = 25500;
REQUIRE(Nz::GetNumberLength(plus25500) == 5);
}
SECTION("GetNumberLength of -2.456f float")
{
float minus2P456 = -2.456f;
REQUIRE(Nz::GetNumberLength(minus2P456, 3) == 6);
}
SECTION("GetNumberLength of -2.456 double")
{
double minus2P456 = -2.456;
REQUIRE(Nz::GetNumberLength(minus2P456, 3) == 6);
}
SECTION("GetNumberLength of -2.456 long double")
{
long double minus2P456 = -2.456L;
REQUIRE(Nz::GetNumberLength(minus2P456, 3) == 6);
}
}
TEST_CASE("IntegralLog2", "[MATH][ALGORITHM]")
{
SECTION("According to implementation, log in base 2 of 0 = 0")
{
REQUIRE(Nz::IntegralLog2(0) == 0);
}
SECTION("Log in base 2 of 1 = 0")
{
REQUIRE(Nz::IntegralLog2(1) == 0);
}
SECTION("Log in base 2 of 4 = 2")
{
REQUIRE(Nz::IntegralLog2(4) == 2);
}
SECTION("Log in base 2 of 5 = 2")
{
REQUIRE(Nz::IntegralLog2(5) == 2);
}
}
TEST_CASE("IntegralLog2Pot", "[MATH][ALGORITHM]")
{
SECTION("According to implementation, log in base 2 of 0 = 0")
{
REQUIRE(Nz::IntegralLog2Pot(0) == 0);
}
SECTION("Log in base 2 of 1 = 0")
{
REQUIRE(Nz::IntegralLog2Pot(1) == 0);
}
SECTION("Log in base 2 of 4 = 2")
{
REQUIRE(Nz::IntegralLog2Pot(4) == 2);
}
}
TEST_CASE("IntegralPow", "[MATH][ALGORITHM]")
{
SECTION("2 to power 4")
{
REQUIRE(Nz::IntegralPow(2, 4) == 16);
}
}
TEST_CASE("Lerp", "[MATH][ALGORITHM]")
{
SECTION("Lerp 2 to 6 with 0.5")
{
REQUIRE(Nz::Lerp(2, 6, 0.5) == 4);
}
}
TEST_CASE("MultiplyAdd", "[MATH][ALGORITHM]")
{
SECTION("2 * 3 + 1")
{
REQUIRE(Nz::MultiplyAdd(2, 3, 1) == 7);
}
}
TEST_CASE("NumberEquals", "[MATH][ALGORITHM]")
{
SECTION("2.35 and 2.351 should be the same at 0.01")
{
CHECK(Nz::NumberEquals(2.35, 2.35, 0.01));
}
SECTION("3 and 4 unsigned should be the same at 1")
{
CHECK(Nz::NumberEquals(3U, 4U, 1U));
}
}
TEST_CASE("NumberToString", "[MATH][ALGORITHM]")
{
SECTION("235 to string")
{
REQUIRE(Nz::NumberToString(235) == "235");
}
SECTION("-235 to string")
{
REQUIRE(Nz::NumberToString(-235) == "-235");
}
SECTION("16 in base 16 to string")
{
REQUIRE(Nz::NumberToString(16, 16) == "10");
}
}
TEST_CASE("RadianToDegree", "[MATH][ALGORITHM]")
{
SECTION("PI / 4 to degree")
{
REQUIRE(Nz::RadianToDegree(M_PI / 4) == Approx(45.f));
}
}
TEST_CASE("StringToNumber", "[MATH][ALGORITHM]")
{
SECTION("235 in string")
{
REQUIRE(Nz::StringToNumber("235") == 235);
}
SECTION("-235 in string")
{
REQUIRE(Nz::StringToNumber("-235") == -235);
}
SECTION("16 in base 16 in string")
{
REQUIRE(Nz::StringToNumber("10", 16) == 16);
}
}