chore: CRLF to LF
This commit is contained in:
+643
-643
File diff suppressed because it is too large
Load Diff
+134
-134
@@ -1,134 +1,134 @@
|
||||
/** @file GuillotineBinPack.h
|
||||
@author Jukka Jylänki
|
||||
|
||||
@brief Implements different bin packer algorithms that use the GUILLOTINE data structure.
|
||||
|
||||
This work is released to Public Domain, do whatever you want with it.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Rect.h"
|
||||
|
||||
namespace rbp {
|
||||
|
||||
/** GuillotineBinPack implements different variants of bin packer algorithms that use the GUILLOTINE data structure
|
||||
to keep track of the free space of the bin where rectangles may be placed. */
|
||||
class GuillotineBinPack
|
||||
{
|
||||
public:
|
||||
/// The initial bin size will be (0,0). Call Init to set the bin size.
|
||||
GuillotineBinPack();
|
||||
|
||||
/// Initializes a new bin of the given size.
|
||||
GuillotineBinPack(int width, int height);
|
||||
|
||||
/// (Re)initializes the packer to an empty bin of width x height units. Call whenever
|
||||
/// you need to restart with a new bin.
|
||||
void Init(int width, int height);
|
||||
|
||||
/// Specifies the different choice heuristics that can be used when deciding which of the free subrectangles
|
||||
/// to place the to-be-packed rectangle into.
|
||||
enum FreeRectChoiceHeuristic
|
||||
{
|
||||
RectBestAreaFit, ///< -BAF
|
||||
RectBestShortSideFit, ///< -BSSF
|
||||
RectBestLongSideFit, ///< -BLSF
|
||||
RectWorstAreaFit, ///< -WAF
|
||||
RectWorstShortSideFit, ///< -WSSF
|
||||
RectWorstLongSideFit ///< -WLSF
|
||||
};
|
||||
|
||||
/// Specifies the different choice heuristics that can be used when the packer needs to decide whether to
|
||||
/// subdivide the remaining free space in horizontal or vertical direction.
|
||||
enum GuillotineSplitHeuristic
|
||||
{
|
||||
SplitShorterLeftoverAxis, ///< -SLAS
|
||||
SplitLongerLeftoverAxis, ///< -LLAS
|
||||
SplitMinimizeArea, ///< -MINAS, Try to make a single big rectangle at the expense of making the other small.
|
||||
SplitMaximizeArea, ///< -MAXAS, Try to make both remaining rectangles as even-sized as possible.
|
||||
SplitShorterAxis, ///< -SAS
|
||||
SplitLongerAxis ///< -LAS
|
||||
};
|
||||
|
||||
/// Inserts a single rectangle into the bin. The packer might rotate the rectangle, in which case the returned
|
||||
/// struct will have the width and height values swapped.
|
||||
/// @param merge If true, performs free Rectangle Merge procedure after packing the new rectangle. This procedure
|
||||
/// tries to defragment the list of disjoint free rectangles to improve packing performance, but also takes up
|
||||
/// some extra time.
|
||||
/// @param rectChoice The free rectangle choice heuristic rule to use.
|
||||
/// @param splitMethod The free rectangle split heuristic rule to use.
|
||||
Rect Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
|
||||
|
||||
/// Inserts a list of rectangles into the bin.
|
||||
/// @param rects The list of rectangles to add. This list will be destroyed in the packing process.
|
||||
/// @param merge If true, performs Rectangle Merge operations during the packing process.
|
||||
/// @param rectChoice The free rectangle choice heuristic rule to use.
|
||||
/// @param splitMethod The free rectangle split heuristic rule to use.
|
||||
void Insert(std::vector<RectSize> &rects, bool merge,
|
||||
FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
|
||||
|
||||
// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice.
|
||||
// void InsertMaxFitting(std::vector<RectSize> &rects, std::vector<Rect> &dst, bool merge,
|
||||
// FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
|
||||
|
||||
/// Computes the ratio of used/total surface area. 0.00 means no space is yet used, 1.00 means the whole bin is used.
|
||||
float Occupancy() const;
|
||||
|
||||
/// Returns the internal list of disjoint rectangles that track the free area of the bin. You may alter this vector
|
||||
/// any way desired, as long as the end result still is a list of disjoint rectangles.
|
||||
std::vector<Rect> &GetFreeRectangles() { return freeRectangles; }
|
||||
|
||||
/// Returns the list of packed rectangles. You may alter this vector at will, for example, you can move a Rect from
|
||||
/// this list to the Free Rectangles list to free up space on-the-fly, but notice that this causes fragmentation.
|
||||
std::vector<Rect> &GetUsedRectangles() { return usedRectangles; }
|
||||
|
||||
/// Performs a Rectangle Merge operation. This procedure looks for adjacent free rectangles and merges them if they
|
||||
/// can be represented with a single rectangle. Takes up Theta(|freeRectangles|^2) time.
|
||||
void MergeFreeList();
|
||||
|
||||
private:
|
||||
int binWidth;
|
||||
int binHeight;
|
||||
|
||||
/// Stores a list of all the rectangles that we have packed so far. This is used only to compute the Occupancy ratio,
|
||||
/// so if you want to have the packer consume less memory, this can be removed.
|
||||
std::vector<Rect> usedRectangles;
|
||||
|
||||
/// Stores a list of rectangles that represents the free area of the bin. This rectangles in this list are disjoint.
|
||||
std::vector<Rect> freeRectangles;
|
||||
|
||||
#ifdef _DEBUG
|
||||
/// Used to track that the packer produces proper packings.
|
||||
DisjointRectCollection disjointRects;
|
||||
#endif
|
||||
|
||||
/// Goes through the list of free rectangles and finds the best one to place a rectangle of given size into.
|
||||
/// Running time is Theta(|freeRectangles|).
|
||||
/// @param nodeIndex [out] The index of the free rectangle in the freeRectangles array into which the new
|
||||
/// rect was placed.
|
||||
/// @return A Rect structure that represents the placement of the new rect into the best free rectangle.
|
||||
Rect FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex);
|
||||
|
||||
static int ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice);
|
||||
// The following functions compute (penalty) score values if a rect of the given size was placed into the
|
||||
// given free rectangle. In these score values, smaller is better.
|
||||
|
||||
static int ScoreBestAreaFit(int width, int height, const Rect &freeRect);
|
||||
static int ScoreBestShortSideFit(int width, int height, const Rect &freeRect);
|
||||
static int ScoreBestLongSideFit(int width, int height, const Rect &freeRect);
|
||||
|
||||
static int ScoreWorstAreaFit(int width, int height, const Rect &freeRect);
|
||||
static int ScoreWorstShortSideFit(int width, int height, const Rect &freeRect);
|
||||
static int ScoreWorstLongSideFit(int width, int height, const Rect &freeRect);
|
||||
|
||||
/// Splits the given L-shaped free rectangle into two new free rectangles after placedRect has been placed into it.
|
||||
/// Determines the split axis by using the given heuristic.
|
||||
void SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method);
|
||||
|
||||
/// Splits the given L-shaped free rectangle into two new free rectangles along the given fixed split axis.
|
||||
void SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal);
|
||||
};
|
||||
|
||||
}
|
||||
/** @file GuillotineBinPack.h
|
||||
@author Jukka Jylänki
|
||||
|
||||
@brief Implements different bin packer algorithms that use the GUILLOTINE data structure.
|
||||
|
||||
This work is released to Public Domain, do whatever you want with it.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Rect.h"
|
||||
|
||||
namespace rbp {
|
||||
|
||||
/** GuillotineBinPack implements different variants of bin packer algorithms that use the GUILLOTINE data structure
|
||||
to keep track of the free space of the bin where rectangles may be placed. */
|
||||
class GuillotineBinPack
|
||||
{
|
||||
public:
|
||||
/// The initial bin size will be (0,0). Call Init to set the bin size.
|
||||
GuillotineBinPack();
|
||||
|
||||
/// Initializes a new bin of the given size.
|
||||
GuillotineBinPack(int width, int height);
|
||||
|
||||
/// (Re)initializes the packer to an empty bin of width x height units. Call whenever
|
||||
/// you need to restart with a new bin.
|
||||
void Init(int width, int height);
|
||||
|
||||
/// Specifies the different choice heuristics that can be used when deciding which of the free subrectangles
|
||||
/// to place the to-be-packed rectangle into.
|
||||
enum FreeRectChoiceHeuristic
|
||||
{
|
||||
RectBestAreaFit, ///< -BAF
|
||||
RectBestShortSideFit, ///< -BSSF
|
||||
RectBestLongSideFit, ///< -BLSF
|
||||
RectWorstAreaFit, ///< -WAF
|
||||
RectWorstShortSideFit, ///< -WSSF
|
||||
RectWorstLongSideFit ///< -WLSF
|
||||
};
|
||||
|
||||
/// Specifies the different choice heuristics that can be used when the packer needs to decide whether to
|
||||
/// subdivide the remaining free space in horizontal or vertical direction.
|
||||
enum GuillotineSplitHeuristic
|
||||
{
|
||||
SplitShorterLeftoverAxis, ///< -SLAS
|
||||
SplitLongerLeftoverAxis, ///< -LLAS
|
||||
SplitMinimizeArea, ///< -MINAS, Try to make a single big rectangle at the expense of making the other small.
|
||||
SplitMaximizeArea, ///< -MAXAS, Try to make both remaining rectangles as even-sized as possible.
|
||||
SplitShorterAxis, ///< -SAS
|
||||
SplitLongerAxis ///< -LAS
|
||||
};
|
||||
|
||||
/// Inserts a single rectangle into the bin. The packer might rotate the rectangle, in which case the returned
|
||||
/// struct will have the width and height values swapped.
|
||||
/// @param merge If true, performs free Rectangle Merge procedure after packing the new rectangle. This procedure
|
||||
/// tries to defragment the list of disjoint free rectangles to improve packing performance, but also takes up
|
||||
/// some extra time.
|
||||
/// @param rectChoice The free rectangle choice heuristic rule to use.
|
||||
/// @param splitMethod The free rectangle split heuristic rule to use.
|
||||
Rect Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
|
||||
|
||||
/// Inserts a list of rectangles into the bin.
|
||||
/// @param rects The list of rectangles to add. This list will be destroyed in the packing process.
|
||||
/// @param merge If true, performs Rectangle Merge operations during the packing process.
|
||||
/// @param rectChoice The free rectangle choice heuristic rule to use.
|
||||
/// @param splitMethod The free rectangle split heuristic rule to use.
|
||||
void Insert(std::vector<RectSize> &rects, bool merge,
|
||||
FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
|
||||
|
||||
// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice.
|
||||
// void InsertMaxFitting(std::vector<RectSize> &rects, std::vector<Rect> &dst, bool merge,
|
||||
// FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
|
||||
|
||||
/// Computes the ratio of used/total surface area. 0.00 means no space is yet used, 1.00 means the whole bin is used.
|
||||
float Occupancy() const;
|
||||
|
||||
/// Returns the internal list of disjoint rectangles that track the free area of the bin. You may alter this vector
|
||||
/// any way desired, as long as the end result still is a list of disjoint rectangles.
|
||||
std::vector<Rect> &GetFreeRectangles() { return freeRectangles; }
|
||||
|
||||
/// Returns the list of packed rectangles. You may alter this vector at will, for example, you can move a Rect from
|
||||
/// this list to the Free Rectangles list to free up space on-the-fly, but notice that this causes fragmentation.
|
||||
std::vector<Rect> &GetUsedRectangles() { return usedRectangles; }
|
||||
|
||||
/// Performs a Rectangle Merge operation. This procedure looks for adjacent free rectangles and merges them if they
|
||||
/// can be represented with a single rectangle. Takes up Theta(|freeRectangles|^2) time.
|
||||
void MergeFreeList();
|
||||
|
||||
private:
|
||||
int binWidth;
|
||||
int binHeight;
|
||||
|
||||
/// Stores a list of all the rectangles that we have packed so far. This is used only to compute the Occupancy ratio,
|
||||
/// so if you want to have the packer consume less memory, this can be removed.
|
||||
std::vector<Rect> usedRectangles;
|
||||
|
||||
/// Stores a list of rectangles that represents the free area of the bin. This rectangles in this list are disjoint.
|
||||
std::vector<Rect> freeRectangles;
|
||||
|
||||
#ifdef _DEBUG
|
||||
/// Used to track that the packer produces proper packings.
|
||||
DisjointRectCollection disjointRects;
|
||||
#endif
|
||||
|
||||
/// Goes through the list of free rectangles and finds the best one to place a rectangle of given size into.
|
||||
/// Running time is Theta(|freeRectangles|).
|
||||
/// @param nodeIndex [out] The index of the free rectangle in the freeRectangles array into which the new
|
||||
/// rect was placed.
|
||||
/// @return A Rect structure that represents the placement of the new rect into the best free rectangle.
|
||||
Rect FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex);
|
||||
|
||||
static int ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice);
|
||||
// The following functions compute (penalty) score values if a rect of the given size was placed into the
|
||||
// given free rectangle. In these score values, smaller is better.
|
||||
|
||||
static int ScoreBestAreaFit(int width, int height, const Rect &freeRect);
|
||||
static int ScoreBestShortSideFit(int width, int height, const Rect &freeRect);
|
||||
static int ScoreBestLongSideFit(int width, int height, const Rect &freeRect);
|
||||
|
||||
static int ScoreWorstAreaFit(int width, int height, const Rect &freeRect);
|
||||
static int ScoreWorstShortSideFit(int width, int height, const Rect &freeRect);
|
||||
static int ScoreWorstLongSideFit(int width, int height, const Rect &freeRect);
|
||||
|
||||
/// Splits the given L-shaped free rectangle into two new free rectangles after placedRect has been placed into it.
|
||||
/// Determines the split axis by using the given heuristic.
|
||||
void SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method);
|
||||
|
||||
/// Splits the given L-shaped free rectangle into two new free rectangles along the given fixed split axis.
|
||||
void SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+50
-50
@@ -1,51 +1,51 @@
|
||||
/** @file Rect.cpp
|
||||
@author Jukka Jylänki
|
||||
|
||||
This work is released to Public Domain, do whatever you want with it.
|
||||
*/
|
||||
#include <utility>
|
||||
|
||||
#include "Rect.h"
|
||||
|
||||
namespace rbp {
|
||||
|
||||
/*
|
||||
#include "clb/Algorithm/Sort.h"
|
||||
|
||||
int CompareRectShortSide(const Rect &a, const Rect &b)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
int smallerSideA = min(a.width, a.height);
|
||||
int smallerSideB = min(b.width, b.height);
|
||||
|
||||
if (smallerSideA != smallerSideB)
|
||||
return clb::sort::TriCmp(smallerSideA, smallerSideB);
|
||||
|
||||
// Tie-break on the larger side.
|
||||
int largerSideA = max(a.width, a.height);
|
||||
int largerSideB = max(b.width, b.height);
|
||||
|
||||
return clb::sort::TriCmp(largerSideA, largerSideB);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
int NodeSortCmp(const Rect &a, const Rect &b)
|
||||
{
|
||||
if (a.x != b.x)
|
||||
return clb::sort::TriCmp(a.x, b.x);
|
||||
if (a.y != b.y)
|
||||
return clb::sort::TriCmp(a.y, b.y);
|
||||
if (a.width != b.width)
|
||||
return clb::sort::TriCmp(a.width, b.width);
|
||||
return clb::sort::TriCmp(a.height, b.height);
|
||||
}
|
||||
*/
|
||||
bool IsContainedIn(const Rect &a, const Rect &b)
|
||||
{
|
||||
return a.x >= b.x && a.y >= b.y
|
||||
&& a.x+a.width <= b.x+b.width
|
||||
&& a.y+a.height <= b.y+b.height;
|
||||
}
|
||||
|
||||
/** @file Rect.cpp
|
||||
@author Jukka Jylänki
|
||||
|
||||
This work is released to Public Domain, do whatever you want with it.
|
||||
*/
|
||||
#include <utility>
|
||||
|
||||
#include "Rect.h"
|
||||
|
||||
namespace rbp {
|
||||
|
||||
/*
|
||||
#include "clb/Algorithm/Sort.h"
|
||||
|
||||
int CompareRectShortSide(const Rect &a, const Rect &b)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
int smallerSideA = min(a.width, a.height);
|
||||
int smallerSideB = min(b.width, b.height);
|
||||
|
||||
if (smallerSideA != smallerSideB)
|
||||
return clb::sort::TriCmp(smallerSideA, smallerSideB);
|
||||
|
||||
// Tie-break on the larger side.
|
||||
int largerSideA = max(a.width, a.height);
|
||||
int largerSideB = max(b.width, b.height);
|
||||
|
||||
return clb::sort::TriCmp(largerSideA, largerSideB);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
int NodeSortCmp(const Rect &a, const Rect &b)
|
||||
{
|
||||
if (a.x != b.x)
|
||||
return clb::sort::TriCmp(a.x, b.x);
|
||||
if (a.y != b.y)
|
||||
return clb::sort::TriCmp(a.y, b.y);
|
||||
if (a.width != b.width)
|
||||
return clb::sort::TriCmp(a.width, b.width);
|
||||
return clb::sort::TriCmp(a.height, b.height);
|
||||
}
|
||||
*/
|
||||
bool IsContainedIn(const Rect &a, const Rect &b)
|
||||
{
|
||||
return a.x >= b.x && a.y >= b.y
|
||||
&& a.x+a.width <= b.x+b.width
|
||||
&& a.y+a.height <= b.y+b.height;
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
+94
-94
@@ -1,94 +1,94 @@
|
||||
/** @file Rect.h
|
||||
@author Jukka Jylänki
|
||||
|
||||
This work is released to Public Domain, do whatever you want with it.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef _DEBUG
|
||||
/// debug_assert is an assert that also requires debug mode to be defined.
|
||||
#define debug_assert(x) assert(x)
|
||||
#else
|
||||
#define debug_assert(x)
|
||||
#endif
|
||||
|
||||
//using namespace std;
|
||||
|
||||
namespace rbp {
|
||||
|
||||
struct RectSize
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
struct Rect
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
/// Performs a lexicographic compare on (rect short side, rect long side).
|
||||
/// @return -1 if the smaller side of a is shorter than the smaller side of b, 1 if the other way around.
|
||||
/// If they are equal, the larger side length is used as a tie-breaker.
|
||||
/// If the rectangles are of same size, returns 0.
|
||||
int CompareRectShortSide(const Rect &a, const Rect &b);
|
||||
|
||||
/// Performs a lexicographic compare on (x, y, width, height).
|
||||
int NodeSortCmp(const Rect &a, const Rect &b);
|
||||
|
||||
/// Returns true if a is contained in b.
|
||||
bool IsContainedIn(const Rect &a, const Rect &b);
|
||||
|
||||
class DisjointRectCollection
|
||||
{
|
||||
public:
|
||||
std::vector<Rect> rects;
|
||||
|
||||
bool Add(const Rect &r)
|
||||
{
|
||||
// Degenerate rectangles are ignored.
|
||||
if (r.width == 0 || r.height == 0)
|
||||
return true;
|
||||
|
||||
if (!Disjoint(r))
|
||||
return false;
|
||||
rects.push_back(r);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
rects.clear();
|
||||
}
|
||||
|
||||
bool Disjoint(const Rect &r) const
|
||||
{
|
||||
// Degenerate rectangles are ignored.
|
||||
if (r.width == 0 || r.height == 0)
|
||||
return true;
|
||||
|
||||
for(size_t i = 0; i < rects.size(); ++i)
|
||||
if (!Disjoint(rects[i], r))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Disjoint(const Rect &a, const Rect &b)
|
||||
{
|
||||
if (a.x + a.width <= b.x ||
|
||||
b.x + b.width <= a.x ||
|
||||
a.y + a.height <= b.y ||
|
||||
b.y + b.height <= a.y)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
/** @file Rect.h
|
||||
@author Jukka Jylänki
|
||||
|
||||
This work is released to Public Domain, do whatever you want with it.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef _DEBUG
|
||||
/// debug_assert is an assert that also requires debug mode to be defined.
|
||||
#define debug_assert(x) assert(x)
|
||||
#else
|
||||
#define debug_assert(x)
|
||||
#endif
|
||||
|
||||
//using namespace std;
|
||||
|
||||
namespace rbp {
|
||||
|
||||
struct RectSize
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
struct Rect
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
/// Performs a lexicographic compare on (rect short side, rect long side).
|
||||
/// @return -1 if the smaller side of a is shorter than the smaller side of b, 1 if the other way around.
|
||||
/// If they are equal, the larger side length is used as a tie-breaker.
|
||||
/// If the rectangles are of same size, returns 0.
|
||||
int CompareRectShortSide(const Rect &a, const Rect &b);
|
||||
|
||||
/// Performs a lexicographic compare on (x, y, width, height).
|
||||
int NodeSortCmp(const Rect &a, const Rect &b);
|
||||
|
||||
/// Returns true if a is contained in b.
|
||||
bool IsContainedIn(const Rect &a, const Rect &b);
|
||||
|
||||
class DisjointRectCollection
|
||||
{
|
||||
public:
|
||||
std::vector<Rect> rects;
|
||||
|
||||
bool Add(const Rect &r)
|
||||
{
|
||||
// Degenerate rectangles are ignored.
|
||||
if (r.width == 0 || r.height == 0)
|
||||
return true;
|
||||
|
||||
if (!Disjoint(r))
|
||||
return false;
|
||||
rects.push_back(r);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
rects.clear();
|
||||
}
|
||||
|
||||
bool Disjoint(const Rect &r) const
|
||||
{
|
||||
// Degenerate rectangles are ignored.
|
||||
if (r.width == 0 || r.height == 0)
|
||||
return true;
|
||||
|
||||
for(size_t i = 0; i < rects.size(); ++i)
|
||||
if (!Disjoint(rects[i], r))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Disjoint(const Rect &a, const Rect &b)
|
||||
{
|
||||
if (a.x + a.width <= b.x ||
|
||||
b.x + b.width <= a.x ||
|
||||
a.y + a.height <= b.y ||
|
||||
b.y + b.height <= a.y)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+2596
-2596
File diff suppressed because it is too large
Load Diff
+446
-446
@@ -1,446 +1,446 @@
|
||||
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
|
||||
#define RAPIDXML_PRINT_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
// Only include streams if not disabled
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
#endif
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Printing flags
|
||||
|
||||
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Internal
|
||||
|
||||
//! \cond internal
|
||||
namespace internal
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal character operations
|
||||
|
||||
// Copy characters from given range to given output iterator
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
*out++ = *begin++;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Copy characters from given range to given output iterator and expand
|
||||
// characters into references (< > ' " &)
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
if (*begin == noexpand)
|
||||
{
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (*begin)
|
||||
{
|
||||
case Ch('<'):
|
||||
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('>'):
|
||||
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('\''):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('"'):
|
||||
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('&'):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
|
||||
break;
|
||||
default:
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
}
|
||||
++begin; // Step to next character
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Fill given output iterator with repetitions of the same character
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt fill_chars(OutIt out, int n, Ch ch)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
*out++ = ch;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Find character
|
||||
template<class Ch, Ch ch>
|
||||
inline bool find_char(const Ch *begin, const Ch *end)
|
||||
{
|
||||
while (begin != end)
|
||||
if (*begin++ == ch)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal printing operations
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
// Print node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print proper node type
|
||||
switch (node->type())
|
||||
{
|
||||
|
||||
// Document
|
||||
case node_document:
|
||||
out = print_children(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Element
|
||||
case node_element:
|
||||
out = print_element_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Data
|
||||
case node_data:
|
||||
out = print_data_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// CDATA
|
||||
case node_cdata:
|
||||
out = print_cdata_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Declaration
|
||||
case node_declaration:
|
||||
out = print_declaration_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Comment
|
||||
case node_comment:
|
||||
out = print_comment_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Doctype
|
||||
case node_doctype:
|
||||
out = print_doctype_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Pi
|
||||
case node_pi:
|
||||
out = print_pi_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Unknown
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
// If indenting not disabled, add line break after node
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
|
||||
// Return modified iterator
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print children of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
|
||||
out = print_node(out, child, flags, indent);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print attributes of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
|
||||
{
|
||||
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
|
||||
{
|
||||
if (attribute->name() && attribute->value())
|
||||
{
|
||||
// Print attribute name
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
|
||||
*out = Ch('='), ++out;
|
||||
// Print attribute value using appropriate quote type
|
||||
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
|
||||
{
|
||||
*out = Ch('\''), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
|
||||
*out = Ch('\''), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = Ch('"'), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
|
||||
*out = Ch('"'), ++out;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_data);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_cdata);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'); ++out;
|
||||
*out = Ch('!'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
*out = Ch('C'); ++out;
|
||||
*out = Ch('D'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('T'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch('>'); ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print element node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_element);
|
||||
|
||||
// Print element name and attributes, if any
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// If node is childless
|
||||
if (node->value_size() == 0 && !node->first_node())
|
||||
{
|
||||
// Print childless node tag ending
|
||||
*out = Ch('/'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print normal node tag ending
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
// Test if node contains a single data node only (and no other nodes)
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
if (!child)
|
||||
{
|
||||
// If node has no children, only print its value without indenting
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
}
|
||||
else if (child->next_sibling() == 0 && child->type() == node_data)
|
||||
{
|
||||
// If node has a sole data child, only print its value without indenting
|
||||
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print all children with full indenting
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
out = print_children(out, node, flags, indent + 1);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
}
|
||||
|
||||
// Print node end
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('/'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print declaration node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print declaration start
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('x'), ++out;
|
||||
*out = Ch('m'), ++out;
|
||||
*out = Ch('l'), ++out;
|
||||
|
||||
// Print attributes
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// Print declaration end
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print comment node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_comment);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print doctype node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_doctype);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('D'), ++out;
|
||||
*out = Ch('O'), ++out;
|
||||
*out = Ch('C'), ++out;
|
||||
*out = Ch('T'), ++out;
|
||||
*out = Ch('Y'), ++out;
|
||||
*out = Ch('P'), ++out;
|
||||
*out = Ch('E'), ++out;
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print pi node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_pi);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
//! \endcond
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Printing
|
||||
|
||||
//! Prints XML to given output iterator.
|
||||
//! \param out Output iterator to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output iterator pointing to position immediately after last character of printed text.
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
return internal::print_node(out, &node, flags, 0);
|
||||
}
|
||||
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
|
||||
//! Prints XML to given output stream.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
print(std::ostream_iterator<Ch>(out), node, flags);
|
||||
return out;
|
||||
}
|
||||
|
||||
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
|
||||
{
|
||||
return print(out, node);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
|
||||
#define RAPIDXML_PRINT_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
// Only include streams if not disabled
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
#endif
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Printing flags
|
||||
|
||||
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Internal
|
||||
|
||||
//! \cond internal
|
||||
namespace internal
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal character operations
|
||||
|
||||
// Copy characters from given range to given output iterator
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
*out++ = *begin++;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Copy characters from given range to given output iterator and expand
|
||||
// characters into references (< > ' " &)
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
if (*begin == noexpand)
|
||||
{
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (*begin)
|
||||
{
|
||||
case Ch('<'):
|
||||
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('>'):
|
||||
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('\''):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('"'):
|
||||
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('&'):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
|
||||
break;
|
||||
default:
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
}
|
||||
++begin; // Step to next character
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Fill given output iterator with repetitions of the same character
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt fill_chars(OutIt out, int n, Ch ch)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
*out++ = ch;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Find character
|
||||
template<class Ch, Ch ch>
|
||||
inline bool find_char(const Ch *begin, const Ch *end)
|
||||
{
|
||||
while (begin != end)
|
||||
if (*begin++ == ch)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal printing operations
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
// Print node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print proper node type
|
||||
switch (node->type())
|
||||
{
|
||||
|
||||
// Document
|
||||
case node_document:
|
||||
out = print_children(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Element
|
||||
case node_element:
|
||||
out = print_element_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Data
|
||||
case node_data:
|
||||
out = print_data_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// CDATA
|
||||
case node_cdata:
|
||||
out = print_cdata_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Declaration
|
||||
case node_declaration:
|
||||
out = print_declaration_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Comment
|
||||
case node_comment:
|
||||
out = print_comment_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Doctype
|
||||
case node_doctype:
|
||||
out = print_doctype_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Pi
|
||||
case node_pi:
|
||||
out = print_pi_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Unknown
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
// If indenting not disabled, add line break after node
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
|
||||
// Return modified iterator
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print children of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
|
||||
out = print_node(out, child, flags, indent);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print attributes of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
|
||||
{
|
||||
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
|
||||
{
|
||||
if (attribute->name() && attribute->value())
|
||||
{
|
||||
// Print attribute name
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
|
||||
*out = Ch('='), ++out;
|
||||
// Print attribute value using appropriate quote type
|
||||
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
|
||||
{
|
||||
*out = Ch('\''), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
|
||||
*out = Ch('\''), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = Ch('"'), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
|
||||
*out = Ch('"'), ++out;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_data);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_cdata);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'); ++out;
|
||||
*out = Ch('!'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
*out = Ch('C'); ++out;
|
||||
*out = Ch('D'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('T'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch('>'); ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print element node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_element);
|
||||
|
||||
// Print element name and attributes, if any
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// If node is childless
|
||||
if (node->value_size() == 0 && !node->first_node())
|
||||
{
|
||||
// Print childless node tag ending
|
||||
*out = Ch('/'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print normal node tag ending
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
// Test if node contains a single data node only (and no other nodes)
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
if (!child)
|
||||
{
|
||||
// If node has no children, only print its value without indenting
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
}
|
||||
else if (child->next_sibling() == 0 && child->type() == node_data)
|
||||
{
|
||||
// If node has a sole data child, only print its value without indenting
|
||||
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print all children with full indenting
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
out = print_children(out, node, flags, indent + 1);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
}
|
||||
|
||||
// Print node end
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('/'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print declaration node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print declaration start
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('x'), ++out;
|
||||
*out = Ch('m'), ++out;
|
||||
*out = Ch('l'), ++out;
|
||||
|
||||
// Print attributes
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// Print declaration end
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print comment node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_comment);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print doctype node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_doctype);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('D'), ++out;
|
||||
*out = Ch('O'), ++out;
|
||||
*out = Ch('C'), ++out;
|
||||
*out = Ch('T'), ++out;
|
||||
*out = Ch('Y'), ++out;
|
||||
*out = Ch('P'), ++out;
|
||||
*out = Ch('E'), ++out;
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print pi node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_pi);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
//! \endcond
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Printing
|
||||
|
||||
//! Prints XML to given output iterator.
|
||||
//! \param out Output iterator to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output iterator pointing to position immediately after last character of printed text.
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
return internal::print_node(out, &node, flags, 0);
|
||||
}
|
||||
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
|
||||
//! Prints XML to given output stream.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
print(std::ostream_iterator<Ch>(out), node, flags);
|
||||
return out;
|
||||
}
|
||||
|
||||
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
|
||||
{
|
||||
return print(out, node);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+37
-37
@@ -1,37 +1,37 @@
|
||||
// stb_dxt.cpp - Real-Time DXT1/DXT5 compressor
|
||||
// Based on original by fabian "ryg" giesen v1.04
|
||||
// Custom version, modified by Yann Collet
|
||||
//
|
||||
/*
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- RygsDXTc source repository : http://code.google.com/p/rygsdxtc/
|
||||
*/
|
||||
|
||||
|
||||
#define STB_DXT_IMPLEMENTATION
|
||||
#include "stb_dxt.h"
|
||||
// stb_dxt.cpp - Real-Time DXT1/DXT5 compressor
|
||||
// Based on original by fabian "ryg" giesen v1.04
|
||||
// Custom version, modified by Yann Collet
|
||||
//
|
||||
/*
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- RygsDXTc source repository : http://code.google.com/p/rygsdxtc/
|
||||
*/
|
||||
|
||||
|
||||
#define STB_DXT_IMPLEMENTATION
|
||||
#include "stb_dxt.h"
|
||||
|
||||
+1043
-1043
File diff suppressed because it is too large
Load Diff
Vendored
+9
-9
@@ -1,9 +1,9 @@
|
||||
Treat the license for this code as though it were the Apache-2.0 license,
|
||||
WITH THE FOLLOWING MODIFICATIONS:
|
||||
|
||||
If you integrate LayeredFS into your launcher of choice, you MUST NOT modify the
|
||||
existing commandline argument names.
|
||||
|
||||
If you add any commandline arguments, they MUST begin with `--layered-`.
|
||||
|
||||
I'm sure this lax wording is not legally binding, but please don't be an asshole.
|
||||
Treat the license for this code as though it were the Apache-2.0 license,
|
||||
WITH THE FOLLOWING MODIFICATIONS:
|
||||
|
||||
If you integrate LayeredFS into your launcher of choice, you MUST NOT modify the
|
||||
existing commandline argument names.
|
||||
|
||||
If you add any commandline arguments, they MUST begin with `--layered-`.
|
||||
|
||||
I'm sure this lax wording is not legally binding, but please don't be an asshole.
|
||||
|
||||
Vendored
+38
-38
@@ -1,38 +1,38 @@
|
||||
#include <string.h>
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define VERBOSE_FLAG L"--layered-verbose"
|
||||
#define DEVMODE_FLAG L"--layered-devmode"
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
config_t config{};
|
||||
|
||||
void load_config(void) {
|
||||
LPWSTR *szArglist;
|
||||
int nArgs;
|
||||
int i;
|
||||
|
||||
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
|
||||
if (NULL == szArglist) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < nArgs; i++) {
|
||||
if (lstrcmpW(szArglist[i], VERBOSE_FLAG) == 0) {
|
||||
config.verbose_logs = true;
|
||||
} else if (lstrcmpW(szArglist[i], DEVMODE_FLAG) == 0) {
|
||||
config.developer_mode = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Free memory allocated for CommandLineToArgvW arguments.
|
||||
LocalFree(szArglist);
|
||||
|
||||
logf("Options: %ls=%d %ls=%d", VERBOSE_FLAG, config.verbose_logs, DEVMODE_FLAG, config.developer_mode);
|
||||
}
|
||||
}
|
||||
#include <string.h>
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define VERBOSE_FLAG L"--layered-verbose"
|
||||
#define DEVMODE_FLAG L"--layered-devmode"
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
config_t config{};
|
||||
|
||||
void load_config(void) {
|
||||
LPWSTR *szArglist;
|
||||
int nArgs;
|
||||
int i;
|
||||
|
||||
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
|
||||
if (NULL == szArglist) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < nArgs; i++) {
|
||||
if (lstrcmpW(szArglist[i], VERBOSE_FLAG) == 0) {
|
||||
config.verbose_logs = true;
|
||||
} else if (lstrcmpW(szArglist[i], DEVMODE_FLAG) == 0) {
|
||||
config.developer_mode = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Free memory allocated for CommandLineToArgvW arguments.
|
||||
LocalFree(szArglist);
|
||||
|
||||
logf("Options: %ls=%d %ls=%d", VERBOSE_FLAG, config.verbose_logs, DEVMODE_FLAG, config.developer_mode);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+13
-13
@@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
typedef struct config {
|
||||
bool verbose_logs = false;
|
||||
bool developer_mode = false;
|
||||
} config_t;
|
||||
|
||||
extern config_t config;
|
||||
|
||||
void load_config(void);
|
||||
}
|
||||
#pragma once
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
typedef struct config {
|
||||
bool verbose_logs = false;
|
||||
bool developer_mode = false;
|
||||
} config_t;
|
||||
|
||||
extern config_t config;
|
||||
|
||||
void load_config(void);
|
||||
}
|
||||
|
||||
Vendored
+847
-847
File diff suppressed because it is too large
Load Diff
Vendored
+14
-14
@@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include "avs/core.h"
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
extern time_t dll_time;
|
||||
extern bool initialized;
|
||||
|
||||
int hook_avs_fs_lstat(const char *name, struct avs::core::avs_stat *st);
|
||||
avs::core::avs_file_t hook_avs_fs_open(const char *name, uint16_t mode, int flags);
|
||||
int init(void);
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include "avs/core.h"
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
extern time_t dll_time;
|
||||
extern bool initialized;
|
||||
|
||||
int hook_avs_fs_lstat(const char *name, struct avs::core::avs_stat *st);
|
||||
avs::core::avs_file_t hook_avs_fs_open(const char *name, uint16_t mode, int flags);
|
||||
int init(void);
|
||||
}
|
||||
|
||||
+227
-227
@@ -1,227 +1,227 @@
|
||||
#include <windows.h>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "modpath_handler.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
|
||||
using std::nullopt;
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
typedef struct {
|
||||
std::string name;
|
||||
std::unordered_set<string> contents;
|
||||
} mod_contents_t;
|
||||
|
||||
std::vector<mod_contents_t> cached_mods;
|
||||
|
||||
std::unordered_set<string> walk_dir(const string &path, const string &root) {
|
||||
std::unordered_set<string> result;
|
||||
|
||||
WIN32_FIND_DATAA ffd;
|
||||
auto contents = FindFirstFileA((path + "/*").c_str(), &ffd);
|
||||
|
||||
if (contents != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (!strcmp(ffd.cFileName, ".") ||
|
||||
!strcmp(ffd.cFileName, "..")) {
|
||||
continue;
|
||||
}
|
||||
string result_path;
|
||||
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
result_path = root + ffd.cFileName + "/";
|
||||
logf_verbose(" %s", result_path.c_str());
|
||||
auto subdir_walk = walk_dir(path + "/" + ffd.cFileName, result_path);
|
||||
result.insert(subdir_walk.begin(), subdir_walk.end());
|
||||
} else {
|
||||
result_path = root + ffd.cFileName;
|
||||
logf_verbose(" %s", result_path.c_str());
|
||||
}
|
||||
result.insert(result_path);
|
||||
} while (FindNextFileA(contents, &ffd) != 0);
|
||||
|
||||
FindClose(contents);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void cache_mods(void) {
|
||||
if (config.developer_mode)
|
||||
return;
|
||||
|
||||
// this is a bit hacky
|
||||
config.developer_mode = true;
|
||||
auto avail_mods = available_mods();
|
||||
config.developer_mode = false;
|
||||
|
||||
for (auto &dir : avail_mods) {
|
||||
logf_verbose("Walking %s", dir.c_str());
|
||||
mod_contents_t mod;
|
||||
mod.name = dir;
|
||||
mod.contents = walk_dir(dir, "");
|
||||
cached_mods.push_back(mod);
|
||||
}
|
||||
}
|
||||
|
||||
optional<string> normalise_path(const string &path) {
|
||||
auto data_pos = path.find("data/");
|
||||
auto data2_pos = string::npos;
|
||||
|
||||
if (data_pos == string::npos) {
|
||||
data2_pos = path.find("data2/");
|
||||
|
||||
if (data2_pos == string::npos)
|
||||
return nullopt;
|
||||
}
|
||||
auto actual_pos = (data_pos != string::npos) ? data_pos : data2_pos;
|
||||
// if data2 was found, use root data2/.../... instead of just .../...
|
||||
auto offset = (data2_pos != string::npos) ? 0 : strlen("data/");
|
||||
auto data_str = path.substr(actual_pos + offset);
|
||||
// nuke backslash
|
||||
string_replace(data_str, "\\", "/");
|
||||
// nuke double slash
|
||||
string_replace(data_str, "//", "/");
|
||||
|
||||
return data_str;
|
||||
}
|
||||
|
||||
vector<string> available_mods() {
|
||||
vector<string> ret;
|
||||
string mod_root = MOD_FOLDER "/";
|
||||
|
||||
if (config.developer_mode) {
|
||||
WIN32_FIND_DATAA ffd;
|
||||
auto mods = FindFirstFileA(MOD_FOLDER "/*", &ffd);
|
||||
|
||||
if (mods != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
|
||||
!strcmp(ffd.cFileName, ".") ||
|
||||
!strcmp(ffd.cFileName, "..") ||
|
||||
!strcmp(ffd.cFileName, "_cache")) {
|
||||
continue;
|
||||
}
|
||||
ret.push_back(mod_root + ffd.cFileName);
|
||||
} while (FindNextFileA(mods, &ffd) != 0);
|
||||
|
||||
FindClose(mods);
|
||||
}
|
||||
} else {
|
||||
for (auto &dir : cached_mods) {
|
||||
ret.push_back(dir.name);
|
||||
}
|
||||
}
|
||||
std::sort(ret.begin(), ret.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool mkdir_p(string &path) {
|
||||
/* Adapted from http://stackoverflow.com/a/2336245/119527 */
|
||||
const size_t len = strlen(path.c_str());
|
||||
char _path[MAX_PATH + 1];
|
||||
char *p;
|
||||
|
||||
errno = 0;
|
||||
|
||||
/* Copy string so its mutable */
|
||||
if (len > sizeof(_path) - 1) {
|
||||
return false;
|
||||
}
|
||||
strncpy(_path, path.c_str(), MAX_PATH);
|
||||
_path[MAX_PATH] = '\0';
|
||||
|
||||
/* Iterate the string */
|
||||
for (p = _path + 1; *p; p++) {
|
||||
if (*p == '/') {
|
||||
/* Temporarily truncate */
|
||||
*p = '\0';
|
||||
|
||||
if (!CreateDirectoryA(_path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
|
||||
if (!CreateDirectoryA(_path, NULL)) {
|
||||
if (GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// same for files and folders when cached
|
||||
optional<string> find_first_cached_item(const string &norm_path) {
|
||||
for (auto &dir : cached_mods) {
|
||||
auto file_search = dir.contents.find(norm_path);
|
||||
if (file_search == dir.contents.end()) {
|
||||
continue;
|
||||
}
|
||||
return dir.name + "/" + *file_search;
|
||||
}
|
||||
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
optional<string> find_first_modfile(const string &norm_path) {
|
||||
if (config.developer_mode) {
|
||||
for (auto &dir : available_mods()) {
|
||||
auto mod_path = dir + "/" + norm_path;
|
||||
if (file_exists(mod_path.c_str())) {
|
||||
return mod_path;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return find_first_cached_item(norm_path);
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
optional<string> find_first_modfolder(const string &norm_path) {
|
||||
if (config.developer_mode) {
|
||||
for (auto &dir : available_mods()) {
|
||||
auto mod_path = dir + "/" + norm_path;
|
||||
if (folder_exists(mod_path.c_str())) {
|
||||
return mod_path;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return find_first_cached_item(norm_path + "/");
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
vector<string> find_all_modfile(const string &norm_path) {
|
||||
vector<string> ret;
|
||||
|
||||
if (config.developer_mode) {
|
||||
for (auto &dir : available_mods()) {
|
||||
auto mod_path = dir + "/" + norm_path;
|
||||
if (file_exists(mod_path.c_str())) {
|
||||
ret.push_back(mod_path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto &dir : cached_mods) {
|
||||
auto file_search = dir.contents.find(norm_path);
|
||||
if (file_search == dir.contents.end()) {
|
||||
continue;
|
||||
}
|
||||
ret.push_back(dir.name + "/" + *file_search);
|
||||
}
|
||||
}
|
||||
|
||||
// needed for consistency when hashing names
|
||||
std::sort(ret.begin(), ret.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
#include <windows.h>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "modpath_handler.h"
|
||||
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
|
||||
using std::nullopt;
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
typedef struct {
|
||||
std::string name;
|
||||
std::unordered_set<string> contents;
|
||||
} mod_contents_t;
|
||||
|
||||
std::vector<mod_contents_t> cached_mods;
|
||||
|
||||
std::unordered_set<string> walk_dir(const string &path, const string &root) {
|
||||
std::unordered_set<string> result;
|
||||
|
||||
WIN32_FIND_DATAA ffd;
|
||||
auto contents = FindFirstFileA((path + "/*").c_str(), &ffd);
|
||||
|
||||
if (contents != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (!strcmp(ffd.cFileName, ".") ||
|
||||
!strcmp(ffd.cFileName, "..")) {
|
||||
continue;
|
||||
}
|
||||
string result_path;
|
||||
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
result_path = root + ffd.cFileName + "/";
|
||||
logf_verbose(" %s", result_path.c_str());
|
||||
auto subdir_walk = walk_dir(path + "/" + ffd.cFileName, result_path);
|
||||
result.insert(subdir_walk.begin(), subdir_walk.end());
|
||||
} else {
|
||||
result_path = root + ffd.cFileName;
|
||||
logf_verbose(" %s", result_path.c_str());
|
||||
}
|
||||
result.insert(result_path);
|
||||
} while (FindNextFileA(contents, &ffd) != 0);
|
||||
|
||||
FindClose(contents);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void cache_mods(void) {
|
||||
if (config.developer_mode)
|
||||
return;
|
||||
|
||||
// this is a bit hacky
|
||||
config.developer_mode = true;
|
||||
auto avail_mods = available_mods();
|
||||
config.developer_mode = false;
|
||||
|
||||
for (auto &dir : avail_mods) {
|
||||
logf_verbose("Walking %s", dir.c_str());
|
||||
mod_contents_t mod;
|
||||
mod.name = dir;
|
||||
mod.contents = walk_dir(dir, "");
|
||||
cached_mods.push_back(mod);
|
||||
}
|
||||
}
|
||||
|
||||
optional<string> normalise_path(const string &path) {
|
||||
auto data_pos = path.find("data/");
|
||||
auto data2_pos = string::npos;
|
||||
|
||||
if (data_pos == string::npos) {
|
||||
data2_pos = path.find("data2/");
|
||||
|
||||
if (data2_pos == string::npos)
|
||||
return nullopt;
|
||||
}
|
||||
auto actual_pos = (data_pos != string::npos) ? data_pos : data2_pos;
|
||||
// if data2 was found, use root data2/.../... instead of just .../...
|
||||
auto offset = (data2_pos != string::npos) ? 0 : strlen("data/");
|
||||
auto data_str = path.substr(actual_pos + offset);
|
||||
// nuke backslash
|
||||
string_replace(data_str, "\\", "/");
|
||||
// nuke double slash
|
||||
string_replace(data_str, "//", "/");
|
||||
|
||||
return data_str;
|
||||
}
|
||||
|
||||
vector<string> available_mods() {
|
||||
vector<string> ret;
|
||||
string mod_root = MOD_FOLDER "/";
|
||||
|
||||
if (config.developer_mode) {
|
||||
WIN32_FIND_DATAA ffd;
|
||||
auto mods = FindFirstFileA(MOD_FOLDER "/*", &ffd);
|
||||
|
||||
if (mods != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
|
||||
!strcmp(ffd.cFileName, ".") ||
|
||||
!strcmp(ffd.cFileName, "..") ||
|
||||
!strcmp(ffd.cFileName, "_cache")) {
|
||||
continue;
|
||||
}
|
||||
ret.push_back(mod_root + ffd.cFileName);
|
||||
} while (FindNextFileA(mods, &ffd) != 0);
|
||||
|
||||
FindClose(mods);
|
||||
}
|
||||
} else {
|
||||
for (auto &dir : cached_mods) {
|
||||
ret.push_back(dir.name);
|
||||
}
|
||||
}
|
||||
std::sort(ret.begin(), ret.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool mkdir_p(string &path) {
|
||||
/* Adapted from http://stackoverflow.com/a/2336245/119527 */
|
||||
const size_t len = strlen(path.c_str());
|
||||
char _path[MAX_PATH + 1];
|
||||
char *p;
|
||||
|
||||
errno = 0;
|
||||
|
||||
/* Copy string so its mutable */
|
||||
if (len > sizeof(_path) - 1) {
|
||||
return false;
|
||||
}
|
||||
strncpy(_path, path.c_str(), MAX_PATH);
|
||||
_path[MAX_PATH] = '\0';
|
||||
|
||||
/* Iterate the string */
|
||||
for (p = _path + 1; *p; p++) {
|
||||
if (*p == '/') {
|
||||
/* Temporarily truncate */
|
||||
*p = '\0';
|
||||
|
||||
if (!CreateDirectoryA(_path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*p = '/';
|
||||
}
|
||||
}
|
||||
|
||||
if (!CreateDirectoryA(_path, NULL)) {
|
||||
if (GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// same for files and folders when cached
|
||||
optional<string> find_first_cached_item(const string &norm_path) {
|
||||
for (auto &dir : cached_mods) {
|
||||
auto file_search = dir.contents.find(norm_path);
|
||||
if (file_search == dir.contents.end()) {
|
||||
continue;
|
||||
}
|
||||
return dir.name + "/" + *file_search;
|
||||
}
|
||||
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
optional<string> find_first_modfile(const string &norm_path) {
|
||||
if (config.developer_mode) {
|
||||
for (auto &dir : available_mods()) {
|
||||
auto mod_path = dir + "/" + norm_path;
|
||||
if (file_exists(mod_path.c_str())) {
|
||||
return mod_path;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return find_first_cached_item(norm_path);
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
optional<string> find_first_modfolder(const string &norm_path) {
|
||||
if (config.developer_mode) {
|
||||
for (auto &dir : available_mods()) {
|
||||
auto mod_path = dir + "/" + norm_path;
|
||||
if (folder_exists(mod_path.c_str())) {
|
||||
return mod_path;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return find_first_cached_item(norm_path + "/");
|
||||
}
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
vector<string> find_all_modfile(const string &norm_path) {
|
||||
vector<string> ret;
|
||||
|
||||
if (config.developer_mode) {
|
||||
for (auto &dir : available_mods()) {
|
||||
auto mod_path = dir + "/" + norm_path;
|
||||
if (file_exists(mod_path.c_str())) {
|
||||
ret.push_back(mod_path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto &dir : cached_mods) {
|
||||
auto file_search = dir.contents.find(norm_path);
|
||||
if (file_search == dir.contents.end()) {
|
||||
continue;
|
||||
}
|
||||
ret.push_back(dir.name + "/" + *file_search);
|
||||
}
|
||||
}
|
||||
|
||||
// needed for consistency when hashing names
|
||||
std::sort(ret.begin(), ret.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Vendored
+29
-29
@@ -1,29 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if 0
|
||||
#include <experimental/optional>
|
||||
using std::experimental::optional;
|
||||
#else
|
||||
#include <optional>
|
||||
using std::optional;
|
||||
#endif
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
#define MOD_FOLDER "./data_mods"
|
||||
#define CACHE_FOLDER MOD_FOLDER "/_cache"
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
void cache_mods(void);
|
||||
vector<string> available_mods();
|
||||
optional<string> normalise_path(const string &path);
|
||||
optional<string> find_first_modfile(const string &norm_path);
|
||||
optional<string> find_first_modfolder(const string &norm_path);
|
||||
vector<string> find_all_modfile(const string &norm_path);
|
||||
bool mkdir_p(string &path);
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if 0
|
||||
#include <experimental/optional>
|
||||
using std::experimental::optional;
|
||||
#else
|
||||
#include <optional>
|
||||
using std::optional;
|
||||
#endif
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
#define MOD_FOLDER "./data_mods"
|
||||
#define CACHE_FOLDER MOD_FOLDER "/_cache"
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
void cache_mods(void);
|
||||
vector<string> available_mods();
|
||||
optional<string> normalise_path(const string &path);
|
||||
optional<string> find_first_modfile(const string &norm_path);
|
||||
optional<string> find_first_modfolder(const string &norm_path);
|
||||
vector<string> find_all_modfile(const string &norm_path);
|
||||
bool mkdir_p(string &path);
|
||||
}
|
||||
|
||||
+69
-69
@@ -1,69 +1,69 @@
|
||||
#include "texture_packer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "3rd_party/GuillotineBinPack.h"
|
||||
|
||||
using namespace rbp;
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
Bitmap::Bitmap(const string &name, int width, int height)
|
||||
: name(name), width(width), height(height) {
|
||||
|
||||
}
|
||||
|
||||
bool pack_textures(vector<Bitmap *> &textures, vector<Packer *> &packed_textures) {
|
||||
std::sort(textures.begin(), textures.end(), [](const Bitmap *a, const Bitmap *b) {
|
||||
return (a->width * a->height) < (b->width * b->height);
|
||||
});
|
||||
|
||||
// pack the bitmaps
|
||||
while (!textures.empty()) {
|
||||
auto packer = new Packer(MAX_TEXTURE);
|
||||
packer->Pack(textures);
|
||||
packed_textures.push_back(packer);
|
||||
|
||||
// failed
|
||||
if (packer->bitmaps.empty())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Packer::Packer(int max_size)
|
||||
: width(max_size), height(max_size) {
|
||||
|
||||
}
|
||||
|
||||
void Packer::Pack(vector<Bitmap *> &bitmaps) {
|
||||
GuillotineBinPack packer(width, height);
|
||||
|
||||
int ww = 0;
|
||||
int hh = 0;
|
||||
while (!bitmaps.empty()) {
|
||||
auto bitmap = bitmaps.back();
|
||||
|
||||
Rect rect = packer.Insert(bitmap->width, bitmap->height, false,
|
||||
GuillotineBinPack::FreeRectChoiceHeuristic::RectBestAreaFit,
|
||||
GuillotineBinPack::GuillotineSplitHeuristic::SplitLongerAxis);
|
||||
|
||||
if (rect.width == 0 || rect.height == 0)
|
||||
break;
|
||||
|
||||
bitmap->packX = rect.x;
|
||||
bitmap->packY = rect.y;
|
||||
this->bitmaps.push_back(bitmap);
|
||||
bitmaps.pop_back();
|
||||
|
||||
ww = std::max(rect.x + rect.width, ww);
|
||||
hh = std::max(rect.y + rect.height, hh);
|
||||
}
|
||||
|
||||
while (width / 2 >= ww)
|
||||
width /= 2;
|
||||
while (height / 2 >= hh)
|
||||
height /= 2;
|
||||
}
|
||||
}
|
||||
#include "texture_packer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "3rd_party/GuillotineBinPack.h"
|
||||
|
||||
using namespace rbp;
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
Bitmap::Bitmap(const string &name, int width, int height)
|
||||
: name(name), width(width), height(height) {
|
||||
|
||||
}
|
||||
|
||||
bool pack_textures(vector<Bitmap *> &textures, vector<Packer *> &packed_textures) {
|
||||
std::sort(textures.begin(), textures.end(), [](const Bitmap *a, const Bitmap *b) {
|
||||
return (a->width * a->height) < (b->width * b->height);
|
||||
});
|
||||
|
||||
// pack the bitmaps
|
||||
while (!textures.empty()) {
|
||||
auto packer = new Packer(MAX_TEXTURE);
|
||||
packer->Pack(textures);
|
||||
packed_textures.push_back(packer);
|
||||
|
||||
// failed
|
||||
if (packer->bitmaps.empty())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Packer::Packer(int max_size)
|
||||
: width(max_size), height(max_size) {
|
||||
|
||||
}
|
||||
|
||||
void Packer::Pack(vector<Bitmap *> &bitmaps) {
|
||||
GuillotineBinPack packer(width, height);
|
||||
|
||||
int ww = 0;
|
||||
int hh = 0;
|
||||
while (!bitmaps.empty()) {
|
||||
auto bitmap = bitmaps.back();
|
||||
|
||||
Rect rect = packer.Insert(bitmap->width, bitmap->height, false,
|
||||
GuillotineBinPack::FreeRectChoiceHeuristic::RectBestAreaFit,
|
||||
GuillotineBinPack::GuillotineSplitHeuristic::SplitLongerAxis);
|
||||
|
||||
if (rect.width == 0 || rect.height == 0)
|
||||
break;
|
||||
|
||||
bitmap->packX = rect.x;
|
||||
bitmap->packY = rect.y;
|
||||
this->bitmaps.push_back(bitmap);
|
||||
bitmaps.pop_back();
|
||||
|
||||
ww = std::max(rect.x + rect.width, ww);
|
||||
hh = std::max(rect.y + rect.height, hh);
|
||||
}
|
||||
|
||||
while (width / 2 >= ww)
|
||||
width /= 2;
|
||||
while (height / 2 >= hh)
|
||||
height /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+35
-35
@@ -1,35 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#define MAX_TEXTURE 4096
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
struct Bitmap {
|
||||
string name;
|
||||
int width;
|
||||
int height;
|
||||
int packX;
|
||||
int packY;
|
||||
|
||||
Bitmap(const string &name, int width, int height);
|
||||
};
|
||||
|
||||
struct Packer {
|
||||
int width;
|
||||
int height;
|
||||
|
||||
vector<Bitmap *> bitmaps;
|
||||
|
||||
Packer(int max_size);
|
||||
|
||||
void Pack(vector<Bitmap *> &bitmaps);
|
||||
};
|
||||
|
||||
bool pack_textures(vector<Bitmap *> &textures, vector<Packer *> &packed_textures);
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#define MAX_TEXTURE 4096
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
struct Bitmap {
|
||||
string name;
|
||||
int width;
|
||||
int height;
|
||||
int packX;
|
||||
int packY;
|
||||
|
||||
Bitmap(const string &name, int width, int height);
|
||||
};
|
||||
|
||||
struct Packer {
|
||||
int width;
|
||||
int height;
|
||||
|
||||
vector<Bitmap *> bitmaps;
|
||||
|
||||
Packer(int max_size);
|
||||
|
||||
void Pack(vector<Bitmap *> &bitmaps);
|
||||
};
|
||||
|
||||
bool pack_textures(vector<Bitmap *> &textures, vector<Packer *> &packed_textures);
|
||||
}
|
||||
|
||||
Vendored
+185
-185
@@ -1,185 +1,185 @@
|
||||
#include "utils.h"
|
||||
#include "avs/core.h"
|
||||
#include "util/utils.h"
|
||||
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
char *snprintf_auto(const char *fmt, ...) {
|
||||
va_list argList;
|
||||
|
||||
va_start(argList, fmt);
|
||||
size_t len = vsnprintf(NULL, 0, fmt, argList);
|
||||
auto s = (char *) malloc(len + 1);
|
||||
vsnprintf(s, len + 1, fmt, argList);
|
||||
va_end(argList);
|
||||
return s;
|
||||
}
|
||||
|
||||
int string_ends_with(const char *str, const char *suffix) {
|
||||
size_t str_len = strlen(str);
|
||||
size_t suffix_len = strlen(suffix);
|
||||
|
||||
return
|
||||
(str_len >= suffix_len) &&
|
||||
(0 == strcmp(str + (str_len - suffix_len), suffix));
|
||||
}
|
||||
|
||||
void string_replace(std::string &str, const char *from, const char *to) {
|
||||
auto to_len = strlen(to);
|
||||
auto from_len = strlen(from);
|
||||
size_t offset = 0;
|
||||
for (auto pos = str.find(from); pos != std::string::npos; pos = str.find(from, offset)) {
|
||||
str.replace(pos, from_len, to);
|
||||
// avoid recursion if to contains from
|
||||
offset = pos + to_len;
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t *str_widen(const char *src) {
|
||||
int nchars;
|
||||
wchar_t *result;
|
||||
|
||||
nchars = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
|
||||
|
||||
if (!nchars) {
|
||||
abort();
|
||||
}
|
||||
|
||||
result = (wchar_t *) malloc(nchars * sizeof(wchar_t));
|
||||
|
||||
if (!MultiByteToWideChar(CP_ACP, 0, src, -1, result, nchars)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool file_exists(const char *name) {
|
||||
auto res = avs::core::avs_fs_open(name, 1, 420);
|
||||
if (res > 0)
|
||||
avs::core::avs_fs_close(res);
|
||||
return res > 0;
|
||||
}
|
||||
|
||||
bool folder_exists(const char *name) {
|
||||
WIN32_FIND_DATAA ffd;
|
||||
HANDLE hFind = FindFirstFileA(name, &ffd);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE || !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
return false;
|
||||
}
|
||||
FindClose(hFind);
|
||||
return true;
|
||||
}
|
||||
|
||||
time_t file_time(const char *path) {
|
||||
auto wide = str_widen(path);
|
||||
auto hFile = CreateFileW(wide, // file to open
|
||||
GENERIC_READ, // open for reading
|
||||
FILE_SHARE_READ, // share for reading
|
||||
NULL, // default security
|
||||
OPEN_EXISTING, // existing file only
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // normal file
|
||||
NULL); // no attr. template
|
||||
free(wide);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME mtime;
|
||||
GetFileTime(hFile, NULL, NULL, &mtime);
|
||||
CloseHandle(hFile);
|
||||
|
||||
ULARGE_INTEGER result;
|
||||
result.LowPart = mtime.dwLowDateTime;
|
||||
result.HighPart = mtime.dwHighDateTime;
|
||||
return result.QuadPart;
|
||||
}
|
||||
|
||||
LONG time(void) {
|
||||
SYSTEMTIME time;
|
||||
GetSystemTime(&time);
|
||||
return (time.wSecond * 1000) + time.wMilliseconds;
|
||||
}
|
||||
|
||||
uint8_t *lz_compress(uint8_t *input, size_t input_length, size_t *compressed_length) {
|
||||
|
||||
// check if cstream is unavailable
|
||||
if (avs::core::cstream_create == nullptr) {
|
||||
return lz_compress_dummy(input, input_length, compressed_length);
|
||||
} else {
|
||||
|
||||
/*
|
||||
* Compression using cstream
|
||||
*/
|
||||
|
||||
auto compressor = avs::core::cstream_create(avs::core::CSTREAM_AVSLZ_COMPRESS);
|
||||
if (!compressor) {
|
||||
logf("Couldn't create");
|
||||
return NULL;
|
||||
}
|
||||
compressor->in_buf = input;
|
||||
compressor->in_size = (uint32_t) input_length;
|
||||
// worst case, for every 8 bytes there will be an extra flag byte
|
||||
auto to_add = MAX(input_length / 8, 1);
|
||||
auto compress_size = input_length + to_add;
|
||||
auto compress_buffer = (unsigned char*)malloc(compress_size);
|
||||
compressor->out_buf = compress_buffer;
|
||||
compressor->out_size = (uint32_t) compress_size;
|
||||
|
||||
bool ret;
|
||||
ret = avs::core::cstream_operate(compressor);
|
||||
if (!ret && !compressor->in_size) {
|
||||
compressor->in_buf = NULL;
|
||||
compressor->in_size = -1;
|
||||
ret = avs::core::cstream_operate(compressor);
|
||||
}
|
||||
if (!ret) {
|
||||
logf("Couldn't operate");
|
||||
return NULL;
|
||||
}
|
||||
if (avs::core::cstream_finish(compressor)) {
|
||||
logf("Couldn't finish");
|
||||
return NULL;
|
||||
}
|
||||
*compressed_length = compress_size - compressor->out_size;
|
||||
avs::core::cstream_destroy(compressor);
|
||||
return compress_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *lz_compress_dummy(uint8_t *input, size_t input_length, size_t *compressed_length) {
|
||||
uint8_t *output = (uint8_t *) malloc(input_length + input_length / 8 + 9);
|
||||
uint8_t *cur_byte = &output[0];
|
||||
|
||||
// copy data blocks
|
||||
for (size_t n = 0; n < input_length / 8; n++) {
|
||||
|
||||
// fake flag
|
||||
*cur_byte++ = 0xFF;
|
||||
|
||||
// uncompressed data
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
*cur_byte++ = input[n * 8 + i];
|
||||
}
|
||||
}
|
||||
|
||||
// remaining bytes
|
||||
int extra_bytes = input_length % 8;
|
||||
if (extra_bytes == 0) {
|
||||
*cur_byte++ = 0x00;
|
||||
} else {
|
||||
*cur_byte++ = 0xFF >> (8 - extra_bytes);
|
||||
for (size_t i = input_length - extra_bytes; i < input_length; i++) {
|
||||
*cur_byte++ = input[i];
|
||||
}
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
*cur_byte++ = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate size
|
||||
*compressed_length = (size_t) (cur_byte - &output[0]);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
#include "utils.h"
|
||||
#include "avs/core.h"
|
||||
#include "util/utils.h"
|
||||
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
char *snprintf_auto(const char *fmt, ...) {
|
||||
va_list argList;
|
||||
|
||||
va_start(argList, fmt);
|
||||
size_t len = vsnprintf(NULL, 0, fmt, argList);
|
||||
auto s = (char *) malloc(len + 1);
|
||||
vsnprintf(s, len + 1, fmt, argList);
|
||||
va_end(argList);
|
||||
return s;
|
||||
}
|
||||
|
||||
int string_ends_with(const char *str, const char *suffix) {
|
||||
size_t str_len = strlen(str);
|
||||
size_t suffix_len = strlen(suffix);
|
||||
|
||||
return
|
||||
(str_len >= suffix_len) &&
|
||||
(0 == strcmp(str + (str_len - suffix_len), suffix));
|
||||
}
|
||||
|
||||
void string_replace(std::string &str, const char *from, const char *to) {
|
||||
auto to_len = strlen(to);
|
||||
auto from_len = strlen(from);
|
||||
size_t offset = 0;
|
||||
for (auto pos = str.find(from); pos != std::string::npos; pos = str.find(from, offset)) {
|
||||
str.replace(pos, from_len, to);
|
||||
// avoid recursion if to contains from
|
||||
offset = pos + to_len;
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t *str_widen(const char *src) {
|
||||
int nchars;
|
||||
wchar_t *result;
|
||||
|
||||
nchars = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
|
||||
|
||||
if (!nchars) {
|
||||
abort();
|
||||
}
|
||||
|
||||
result = (wchar_t *) malloc(nchars * sizeof(wchar_t));
|
||||
|
||||
if (!MultiByteToWideChar(CP_ACP, 0, src, -1, result, nchars)) {
|
||||
abort();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool file_exists(const char *name) {
|
||||
auto res = avs::core::avs_fs_open(name, 1, 420);
|
||||
if (res > 0)
|
||||
avs::core::avs_fs_close(res);
|
||||
return res > 0;
|
||||
}
|
||||
|
||||
bool folder_exists(const char *name) {
|
||||
WIN32_FIND_DATAA ffd;
|
||||
HANDLE hFind = FindFirstFileA(name, &ffd);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE || !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
||||
return false;
|
||||
}
|
||||
FindClose(hFind);
|
||||
return true;
|
||||
}
|
||||
|
||||
time_t file_time(const char *path) {
|
||||
auto wide = str_widen(path);
|
||||
auto hFile = CreateFileW(wide, // file to open
|
||||
GENERIC_READ, // open for reading
|
||||
FILE_SHARE_READ, // share for reading
|
||||
NULL, // default security
|
||||
OPEN_EXISTING, // existing file only
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // normal file
|
||||
NULL); // no attr. template
|
||||
free(wide);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME mtime;
|
||||
GetFileTime(hFile, NULL, NULL, &mtime);
|
||||
CloseHandle(hFile);
|
||||
|
||||
ULARGE_INTEGER result;
|
||||
result.LowPart = mtime.dwLowDateTime;
|
||||
result.HighPart = mtime.dwHighDateTime;
|
||||
return result.QuadPart;
|
||||
}
|
||||
|
||||
LONG time(void) {
|
||||
SYSTEMTIME time;
|
||||
GetSystemTime(&time);
|
||||
return (time.wSecond * 1000) + time.wMilliseconds;
|
||||
}
|
||||
|
||||
uint8_t *lz_compress(uint8_t *input, size_t input_length, size_t *compressed_length) {
|
||||
|
||||
// check if cstream is unavailable
|
||||
if (avs::core::cstream_create == nullptr) {
|
||||
return lz_compress_dummy(input, input_length, compressed_length);
|
||||
} else {
|
||||
|
||||
/*
|
||||
* Compression using cstream
|
||||
*/
|
||||
|
||||
auto compressor = avs::core::cstream_create(avs::core::CSTREAM_AVSLZ_COMPRESS);
|
||||
if (!compressor) {
|
||||
logf("Couldn't create");
|
||||
return NULL;
|
||||
}
|
||||
compressor->in_buf = input;
|
||||
compressor->in_size = (uint32_t) input_length;
|
||||
// worst case, for every 8 bytes there will be an extra flag byte
|
||||
auto to_add = MAX(input_length / 8, 1);
|
||||
auto compress_size = input_length + to_add;
|
||||
auto compress_buffer = (unsigned char*)malloc(compress_size);
|
||||
compressor->out_buf = compress_buffer;
|
||||
compressor->out_size = (uint32_t) compress_size;
|
||||
|
||||
bool ret;
|
||||
ret = avs::core::cstream_operate(compressor);
|
||||
if (!ret && !compressor->in_size) {
|
||||
compressor->in_buf = NULL;
|
||||
compressor->in_size = -1;
|
||||
ret = avs::core::cstream_operate(compressor);
|
||||
}
|
||||
if (!ret) {
|
||||
logf("Couldn't operate");
|
||||
return NULL;
|
||||
}
|
||||
if (avs::core::cstream_finish(compressor)) {
|
||||
logf("Couldn't finish");
|
||||
return NULL;
|
||||
}
|
||||
*compressed_length = compress_size - compressor->out_size;
|
||||
avs::core::cstream_destroy(compressor);
|
||||
return compress_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *lz_compress_dummy(uint8_t *input, size_t input_length, size_t *compressed_length) {
|
||||
uint8_t *output = (uint8_t *) malloc(input_length + input_length / 8 + 9);
|
||||
uint8_t *cur_byte = &output[0];
|
||||
|
||||
// copy data blocks
|
||||
for (size_t n = 0; n < input_length / 8; n++) {
|
||||
|
||||
// fake flag
|
||||
*cur_byte++ = 0xFF;
|
||||
|
||||
// uncompressed data
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
*cur_byte++ = input[n * 8 + i];
|
||||
}
|
||||
}
|
||||
|
||||
// remaining bytes
|
||||
int extra_bytes = input_length % 8;
|
||||
if (extra_bytes == 0) {
|
||||
*cur_byte++ = 0x00;
|
||||
} else {
|
||||
*cur_byte++ = 0xFF >> (8 - extra_bytes);
|
||||
for (size_t i = input_length - extra_bytes; i < input_length; i++) {
|
||||
*cur_byte++ = input[i];
|
||||
}
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
*cur_byte++ = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate size
|
||||
*compressed_length = (size_t) (cur_byte - &output[0]);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+28
-28
@@ -1,28 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "util/logging.h"
|
||||
#include "config.h"
|
||||
|
||||
#define logf(fmt,...) {char*b=snprintf_auto(fmt,##__VA_ARGS__);log_misc("layeredfs","{}",b?b:":(");if(b)free(b);} void()
|
||||
#define logf_verbose(...) if (config.verbose_logs) {logf(__VA_ARGS__);} void()
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
char *snprintf_auto(const char *fmt, ...);
|
||||
int string_ends_with(const char *str, const char *suffix);
|
||||
void string_replace(std::string &str, const char *from, const char *to);
|
||||
wchar_t *str_widen(const char *src);
|
||||
bool file_exists(const char *name);
|
||||
bool folder_exists(const char *name);
|
||||
time_t file_time(const char *path);
|
||||
LONG time(void);
|
||||
uint8_t *lz_compress(uint8_t *input, size_t input_length, size_t *compressed_length);
|
||||
uint8_t *lz_compress_dummy(uint8_t *input, size_t input_length, size_t *compressed_length);
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "util/logging.h"
|
||||
#include "config.h"
|
||||
|
||||
#define logf(fmt,...) {char*b=snprintf_auto(fmt,##__VA_ARGS__);log_misc("layeredfs","{}",b?b:":(");if(b)free(b);} void()
|
||||
#define logf_verbose(...) if (config.verbose_logs) {logf(__VA_ARGS__);} void()
|
||||
|
||||
namespace layeredfs {
|
||||
|
||||
char *snprintf_auto(const char *fmt, ...);
|
||||
int string_ends_with(const char *str, const char *suffix);
|
||||
void string_replace(std::string &str, const char *from, const char *to);
|
||||
wchar_t *str_widen(const char *src);
|
||||
bool file_exists(const char *name);
|
||||
bool folder_exists(const char *name);
|
||||
time_t file_time(const char *path);
|
||||
LONG time(void);
|
||||
uint8_t *lz_compress(uint8_t *input, size_t input_length, size_t *compressed_length);
|
||||
uint8_t *lz_compress_dummy(uint8_t *input, size_t input_length, size_t *compressed_length);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user