|
@@ -21,6 +21,8 @@
|
|
|
// LOVE
|
|
|
#include "MathModule.h"
|
|
|
#include "common/Vector.h"
|
|
|
+#include "common/b64.h"
|
|
|
+#include "common/int.h"
|
|
|
#include "BezierCurve.h"
|
|
|
|
|
|
// STL
|
|
@@ -34,49 +36,129 @@ using love::Vertex;
|
|
|
|
|
|
namespace
|
|
|
{
|
|
|
- // check if an angle is oriented counter clockwise
|
|
|
- inline bool is_oriented_ccw(const Vertex &a, const Vertex &b, const Vertex &c)
|
|
|
+
|
|
|
+static const char hexchars[] = "0123456789abcdef";
|
|
|
+
|
|
|
+char *bytesToHex(const love::uint8 *src, size_t srclen, size_t &dstlen)
|
|
|
+{
|
|
|
+ dstlen = srclen * 2;
|
|
|
+
|
|
|
+ if (dstlen == 0)
|
|
|
+ return nullptr;
|
|
|
+
|
|
|
+ char *dst = nullptr;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ dst = new char[dstlen + 1];
|
|
|
+ }
|
|
|
+ catch (std::exception &)
|
|
|
{
|
|
|
- // return det(b-a, c-a) >= 0
|
|
|
- return ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) >= 0;
|
|
|
+ throw love::Exception("Out of memory.");
|
|
|
}
|
|
|
|
|
|
- // check if a and b are on the same side of the line c->d
|
|
|
- bool on_same_side(const Vertex &a, const Vertex &b, const Vertex &c, const Vertex &d)
|
|
|
+ for (size_t i = 0; i < srclen; i++)
|
|
|
+ {
|
|
|
+ love::uint8 b = src[i];
|
|
|
+ dst[i * 2 + 0] = hexchars[b >> 4];
|
|
|
+ dst[i * 2 + 1] = hexchars[b & 0xF];
|
|
|
+ }
|
|
|
+
|
|
|
+ dst[dstlen] = '\0';
|
|
|
+ return dst;
|
|
|
+}
|
|
|
+
|
|
|
+love::uint8 nibble(char c)
|
|
|
+{
|
|
|
+ if (c >= '0' && c <= '9')
|
|
|
+ return (love::uint8) (c - '0');
|
|
|
+
|
|
|
+ if (c >= 'A' && c <= 'F')
|
|
|
+ return (love::uint8) (c - 'A' + 0x0a);
|
|
|
+
|
|
|
+ if (c >= 'a' && c <= 'f')
|
|
|
+ return (love::uint8) (c - 'a' + 0x0a);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+love::uint8 *hexToBytes(const char *src, size_t srclen, size_t &dstlen)
|
|
|
+{
|
|
|
+ if (srclen >= 2 && src[0] == '0' && (src[1] == 'x' || src[1] == 'X'))
|
|
|
{
|
|
|
- float px = d.x - c.x, py = d.y - c.y;
|
|
|
- // return det(p, a-c) * det(p, b-c) >= 0
|
|
|
- float l = px * (a.y - c.y) - py * (a.x - c.x);
|
|
|
- float m = px * (b.y - c.y) - py * (b.x - c.x);
|
|
|
- return l * m >= 0;
|
|
|
+ src += 2;
|
|
|
+ srclen -= 2;
|
|
|
}
|
|
|
|
|
|
- // checks is p is contained in the triangle abc
|
|
|
- inline bool point_in_triangle(const Vertex &p, const Vertex &a, const Vertex &b, const Vertex &c)
|
|
|
+ dstlen = (srclen + 1) / 2;
|
|
|
+
|
|
|
+ if (dstlen == 0)
|
|
|
+ return nullptr;
|
|
|
+
|
|
|
+ love::uint8 *dst = nullptr;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ dst = new love::uint8[dstlen];
|
|
|
+ }
|
|
|
+ catch (std::exception &)
|
|
|
{
|
|
|
- return on_same_side(p,a, b,c) && on_same_side(p,b, a,c) && on_same_side(p,c, a,b);
|
|
|
+ throw love::Exception("Out of memory.");
|
|
|
}
|
|
|
|
|
|
- // checks if any vertex in `vertices' is in the triangle abc.
|
|
|
- bool any_point_in_triangle(const list<const Vertex *> &vertices, const Vertex &a, const Vertex &b, const Vertex &c)
|
|
|
+ for (size_t i = 0; i < dstlen; i++)
|
|
|
{
|
|
|
- list<const Vertex *>::const_iterator it, end = vertices.end();
|
|
|
- for (it = vertices.begin(); it != end; ++it)
|
|
|
- {
|
|
|
- const Vertex *p = *it;
|
|
|
- if ((p != &a) && (p != &b) && (p != &c) && point_in_triangle(*p, a,b,c)) // oh god...
|
|
|
- return true;
|
|
|
- }
|
|
|
+ dst[i] = nibble(src[i * 2]) << 4;
|
|
|
|
|
|
- return false;
|
|
|
+ if (i * 2 + 1 < srclen)
|
|
|
+ dst[i] |= nibble(src[i * 2 + 1]);
|
|
|
}
|
|
|
|
|
|
- inline bool is_ear(const Vertex &a, const Vertex &b, const Vertex &c, const list<const Vertex *> &vertices)
|
|
|
+ return dst;
|
|
|
+}
|
|
|
+
|
|
|
+// check if an angle is oriented counter clockwise
|
|
|
+inline bool is_oriented_ccw(const Vertex &a, const Vertex &b, const Vertex &c)
|
|
|
+{
|
|
|
+ // return det(b-a, c-a) >= 0
|
|
|
+ return ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) >= 0;
|
|
|
+}
|
|
|
+
|
|
|
+// check if a and b are on the same side of the line c->d
|
|
|
+bool on_same_side(const Vertex &a, const Vertex &b, const Vertex &c, const Vertex &d)
|
|
|
+{
|
|
|
+ float px = d.x - c.x, py = d.y - c.y;
|
|
|
+ // return det(p, a-c) * det(p, b-c) >= 0
|
|
|
+ float l = px * (a.y - c.y) - py * (a.x - c.x);
|
|
|
+ float m = px * (b.y - c.y) - py * (b.x - c.x);
|
|
|
+ return l * m >= 0;
|
|
|
+}
|
|
|
+
|
|
|
+// checks is p is contained in the triangle abc
|
|
|
+inline bool point_in_triangle(const Vertex &p, const Vertex &a, const Vertex &b, const Vertex &c)
|
|
|
+{
|
|
|
+ return on_same_side(p,a, b,c) && on_same_side(p,b, a,c) && on_same_side(p,c, a,b);
|
|
|
+}
|
|
|
+
|
|
|
+// checks if any vertex in `vertices' is in the triangle abc.
|
|
|
+bool any_point_in_triangle(const list<const Vertex *> &vertices, const Vertex &a, const Vertex &b, const Vertex &c)
|
|
|
+{
|
|
|
+ list<const Vertex *>::const_iterator it, end = vertices.end();
|
|
|
+ for (it = vertices.begin(); it != end; ++it)
|
|
|
{
|
|
|
- return is_oriented_ccw(a,b,c) && !any_point_in_triangle(vertices, a,b,c);
|
|
|
+ const Vertex *p = *it;
|
|
|
+ if ((p != &a) && (p != &b) && (p != &c) && point_in_triangle(*p, a,b,c)) // oh god...
|
|
|
+ return true;
|
|
|
}
|
|
|
+
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+inline bool is_ear(const Vertex &a, const Vertex &b, const Vertex &c, const list<const Vertex *> &vertices)
|
|
|
+{
|
|
|
+ return is_oriented_ccw(a,b,c) && !any_point_in_triangle(vertices, a,b,c);
|
|
|
}
|
|
|
|
|
|
+} // anonymous namespace
|
|
|
+
|
|
|
namespace love
|
|
|
{
|
|
|
namespace math
|
|
@@ -270,5 +352,47 @@ char *Math::decompress(Compressor::Format format, const char *cbytes, size_t com
|
|
|
return compressor->decompress(format, cbytes, compressedsize, rawsize);
|
|
|
}
|
|
|
|
|
|
+char *Math::encode(EncodeFormat format, const char *src, size_t srclen, size_t &dstlen, size_t linelen)
|
|
|
+{
|
|
|
+ switch (format)
|
|
|
+ {
|
|
|
+ case ENCODE_BASE64:
|
|
|
+ default:
|
|
|
+ return b64_encode(src, srclen, linelen, dstlen);
|
|
|
+ case ENCODE_HEX:
|
|
|
+ return bytesToHex((const uint8 *) src, srclen, dstlen);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+char *Math::decode(EncodeFormat format, const char *src, size_t srclen, size_t &dstlen)
|
|
|
+{
|
|
|
+ switch (format)
|
|
|
+ {
|
|
|
+ case ENCODE_BASE64:
|
|
|
+ default:
|
|
|
+ return b64_decode(src, srclen, dstlen);
|
|
|
+ case ENCODE_HEX:
|
|
|
+ return (char *) hexToBytes(src, srclen, dstlen);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool Math::getConstant(const char *in, EncodeFormat &out)
|
|
|
+{
|
|
|
+ return encoders.find(in, out);
|
|
|
+}
|
|
|
+
|
|
|
+bool Math::getConstant(EncodeFormat in, const char *&out)
|
|
|
+{
|
|
|
+ return encoders.find(in, out);
|
|
|
+}
|
|
|
+
|
|
|
+StringMap<Math::EncodeFormat, Math::ENCODE_MAX_ENUM>::Entry Math::encoderEntries[] =
|
|
|
+{
|
|
|
+ { "base64", ENCODE_BASE64 },
|
|
|
+ { "hex", ENCODE_HEX },
|
|
|
+};
|
|
|
+
|
|
|
+StringMap<Math::EncodeFormat, Math::ENCODE_MAX_ENUM> Math::encoders(Math::encoderEntries, sizeof(Math::encoderEntries));
|
|
|
+
|
|
|
} // math
|
|
|
} // love
|