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

@@ -46,7 +46,7 @@ namespace Nz
* \brief Utility class that measure the elapsed time
*/
/*!
/*!
* \brief Constructs a Clock object
*
* \param startingValue The starting time value, in microseconds

View File

@@ -16,13 +16,36 @@
namespace Nz
{
/*!
* \class Nz::GuillotineBinPack
* \brief Core class that represents the "Guillotine problem", combination of the "Bin packing problem" and the "cutting stock"
*/
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)
{
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 leftoverHoriz = std::abs(static_cast<int>(freeRectSize.width - width));
@@ -32,6 +55,15 @@ namespace Nz
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 leftoverHoriz = std::abs(static_cast<int>(freeRectSize.width - width));
@@ -41,37 +73,85 @@ namespace Nz
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)
{
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)
{
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)
{
return -ScoreBestShortSideFit(width, height, freeRectSize);
}
}
/*!
* \brief Constructs a GuillotineBinPack object by default
*/
GuillotineBinPack::GuillotineBinPack()
{
Reset();
}
/*!
* \brief Constructs a GuillotineBinPack object with width and height
*
* \param width Width
* \param height Height
*/
GuillotineBinPack::GuillotineBinPack(unsigned int width, unsigned int height)
{
Reset(width, height);
}
/*!
* \brief Constructs a GuillotineBinPack object with area
*
* \param size Vector2 representing the area (width, height)
*/
GuillotineBinPack::GuillotineBinPack(const Vector2ui& size)
{
Reset(size);
}
/*!
* \brief Clears the content
*/
void GuillotineBinPack::Clear()
{
m_freeRectangles.clear();
@@ -80,6 +160,15 @@ namespace Nz
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)
{
unsigned int oldWidth = m_width;
@@ -98,52 +187,123 @@ namespace Nz
while (MergeFreeRectangles());
}
/*!
* \brief Expands the content
*
* \param newSize New area for the expansion
*
* \see Expand
*/
void GuillotineBinPack::Expand(const Vector2ui& newSize)
{
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)
{
///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_usedArea -= rect.width * rect.height;
}
/*!
* \brief Gets the height
* \return Height of the area
*/
unsigned int GuillotineBinPack::GetHeight() const
{
return m_height;
}
/*!
* \brief Gets percentage of occupation
* \return Percentage of the already occupied area
*/
float GuillotineBinPack::GetOccupancy() const
{
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
{
return Vector2ui(m_width, m_height);
}
/*!
* \brief Gets the width
* \return Width of the area
*/
unsigned int GuillotineBinPack::GetWidth() const
{
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)
{
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)
{
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)
{
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)
remainingRects[i] = &rects[i];
@@ -214,7 +374,7 @@ namespace Nz
// If we didn't manage to find any rectangle to pack, abort.
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)
{
for (Rectui* rect : remainingRects)
@@ -259,9 +419,13 @@ namespace Nz
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()
{
///DOC: Renvoie true s'il y a eu fusion (et donc si une fusion est encore possible)
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.
@@ -312,6 +476,10 @@ namespace Nz
return m_freeRectangles.size() < oriSize;
}
/*!
* \brief Resets the area
*/
void GuillotineBinPack::Reset()
{
m_height = 0;
@@ -320,6 +488,13 @@ namespace Nz
Clear();
}
/*!
* \brief Resets the area
*
* \param width Width
* \param height Height
*/
void GuillotineBinPack::Reset(unsigned int width, unsigned int height)
{
m_height = height;
@@ -328,11 +503,25 @@ namespace Nz
Clear();
}
/*!
* \brief Resets the area
*
* \param size Size of the area
*/
void GuillotineBinPack::Reset(const Vector2ui& size)
{
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)
{
// Form the two new rectangles.
@@ -365,50 +554,60 @@ namespace Nz
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)
{
// Compute the lengths of the leftover area.
// Compute the lengths of the leftover area
const int w = freeRect.width - placedRect.width;
const int h = freeRect.height - placedRect.height;
// 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.
// We have two choices: horizontal or vertical.
// two disjoint rectangles. This can be achieved with by splitting the L-shape using a single line
// 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;
switch (method)
{
case SplitLongerAxis:
// Split along the longer total axis.
// Split along the longer total axis
splitHorizontal = (freeRect.width > freeRect.height);
break;
case SplitLongerLeftoverAxis:
// Split along the longer leftover axis.
// Split along the longer leftover axis
splitHorizontal = (w > h);
break;
case SplitMaximizeArea:
// Maximize the smaller area == minimize the larger area.
// Tries to make the rectangles more even-sized.
// Maximize the smaller area == minimize the larger area
// Tries to make the rectangles more even-sized
splitHorizontal = (placedRect.width * h <= w * placedRect.height);
break;
case SplitMinimizeArea:
// Maximize the larger area == minimize the smaller area.
// Tries to make the single bigger rectangle.
// Maximize the larger area == minimize the smaller area
// Tries to make the single bigger rectangle
splitHorizontal = (placedRect.width * h > w * placedRect.height);
break;
case SplitShorterAxis:
// Split along the shorter total axis.
// Split along the shorter total axis
splitHorizontal = (freeRect.width <= freeRect.height);
break;
case SplitShorterLeftoverAxis:
// Split along the shorter leftover axis.
// Split along the shorter leftover axis
splitHorizontal = (w <= h);
break;
@@ -417,10 +616,22 @@ namespace Nz
splitHorizontal = true;
}
// Perform the actual split.
// Perform the actual split
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)
{
switch (rectChoice)

View File

@@ -82,11 +82,31 @@ namespace Nz
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])
{
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()
{
if (!Initialize())
@@ -95,13 +115,26 @@ namespace Nz
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()
{
///DOC: Ne nécessite pas l'initialisation de HardwareInfo pour fonctionner
static unsigned int processorCount = std::max(HardwareInfoImpl::GetProcessorCount(), 1U);
return processorCount;
}
/*!
* \brief Gets the processor vendor
* \return ProcessorVendor containing information the vendor
*
* \remark Produces a NazaraError if not Initialize
*/
ProcessorVendor HardwareInfo::GetProcessorVendor()
{
if (!Initialize())
@@ -110,6 +143,13 @@ namespace Nz
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()
{
if (!Initialize())
@@ -118,13 +158,26 @@ namespace Nz
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()
{
///DOC: Ne nécessite pas l'initialisation de HardwareInfo pour fonctionner
static UInt64 totalMemory = HardwareInfoImpl::GetTotalMemory();
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)
{
#ifdef NAZARA_DEBUG
@@ -138,9 +191,16 @@ namespace Nz
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()
{
if (s_initialized)
if (IsInitialized())
return true;
if (!HardwareInfoImpl::IsCpuidSupported())
@@ -151,21 +211,21 @@ namespace Nz
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 clar
// To make it more clear
UInt32& eax = registers[0];
UInt32& ebx = registers[1];
UInt32& ecx = registers[2];
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);
// Attention à l'ordre : EBX, EDX, ECX
// Watchout to the order : EBX, EDX, ECX
UInt32 manufacturerId[3] = {ebx, edx, ecx};
// Identification du concepteur
// Identification of conceptor
s_vendorEnum = ProcessorVendor_Unknown;
for (const VendorString& vendorString : vendorStrings)
{
@@ -178,7 +238,7 @@ namespace Nz
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);
s_capabilities[ProcessorCap_AVX] = (ecx & (1U << 28)) != 0;
@@ -192,53 +252,67 @@ namespace Nz
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);
UInt32 maxSupportedExtendedFunction = eax;
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);
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_SSE4a] = (ecx & (1U << 6)) != 0;
s_capabilities[ProcessorCap_XOP] = (ecx & (1U << 11)) != 0;
if (maxSupportedExtendedFunction >= 0x80000004)
{
// Récupération d'une chaîne de caractère décrivant le processeur (EAX, EBX, ECX et EDX,
// fonctions de 0x80000002 à 0x80000004 compris)
// Recuperation of the string describing the processor (EAX, EBX, ECX et EDX,
// functions from 0x80000002 to 0x80000004 inclusive)
char* ptr = &s_brandString[0];
for (UInt32 code = 0x80000002; code <= 0x80000004; ++code)
{
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);
}
// 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;
}
/*!
* \brief Checks whether the instruction of cpuid is supported
* \return true if it the case
*/
bool HardwareInfo::IsCpuidSupported()
{
return HardwareInfoImpl::IsCpuidSupported();
}
/*!
* \brief Checks whether the class HardwareInfo is initialized
* \return true if it is initialized
*/
bool HardwareInfo::IsInitialized()
{
return s_initialized;
}
/*!
* \brief Unitializes the class HardwareInfo
*/
void HardwareInfo::Uninitialize()
{
// Rien à faire
// Nothing to do
s_initialized = false;
}
}