MathModule.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /**
  2. * Copyright (c) 2006-2016 LOVE Development Team
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. *
  8. * Permission is granted to anyone to use this software for any purpose,
  9. * including commercial applications, and to alter it and redistribute it
  10. * freely, subject to the following restrictions:
  11. *
  12. * 1. The origin of this software must not be misrepresented; you must not
  13. * claim that you wrote the original software. If you use this software
  14. * in a product, an acknowledgment in the product documentation would be
  15. * appreciated but is not required.
  16. * 2. Altered source versions must be plainly marked as such, and must not be
  17. * misrepresented as being the original software.
  18. * 3. This notice may not be removed or altered from any source distribution.
  19. **/
  20. // LOVE
  21. #include "MathModule.h"
  22. #include "common/Vector.h"
  23. #include "common/b64.h"
  24. #include "common/int.h"
  25. #include "BezierCurve.h"
  26. // STL
  27. #include <cmath>
  28. #include <list>
  29. #include <iostream>
  30. using std::list;
  31. using std::vector;
  32. using love::Vertex;
  33. namespace
  34. {
  35. static const char hexchars[] = "0123456789abcdef";
  36. char *bytesToHex(const love::uint8 *src, size_t srclen, size_t &dstlen)
  37. {
  38. dstlen = srclen * 2;
  39. if (dstlen == 0)
  40. return nullptr;
  41. char *dst = nullptr;
  42. try
  43. {
  44. dst = new char[dstlen + 1];
  45. }
  46. catch (std::exception &)
  47. {
  48. throw love::Exception("Out of memory.");
  49. }
  50. for (size_t i = 0; i < srclen; i++)
  51. {
  52. love::uint8 b = src[i];
  53. dst[i * 2 + 0] = hexchars[b >> 4];
  54. dst[i * 2 + 1] = hexchars[b & 0xF];
  55. }
  56. dst[dstlen] = '\0';
  57. return dst;
  58. }
  59. love::uint8 nibble(char c)
  60. {
  61. if (c >= '0' && c <= '9')
  62. return (love::uint8) (c - '0');
  63. if (c >= 'A' && c <= 'F')
  64. return (love::uint8) (c - 'A' + 0x0a);
  65. if (c >= 'a' && c <= 'f')
  66. return (love::uint8) (c - 'a' + 0x0a);
  67. return 0;
  68. }
  69. love::uint8 *hexToBytes(const char *src, size_t srclen, size_t &dstlen)
  70. {
  71. if (srclen >= 2 && src[0] == '0' && (src[1] == 'x' || src[1] == 'X'))
  72. {
  73. src += 2;
  74. srclen -= 2;
  75. }
  76. dstlen = (srclen + 1) / 2;
  77. if (dstlen == 0)
  78. return nullptr;
  79. love::uint8 *dst = nullptr;
  80. try
  81. {
  82. dst = new love::uint8[dstlen];
  83. }
  84. catch (std::exception &)
  85. {
  86. throw love::Exception("Out of memory.");
  87. }
  88. for (size_t i = 0; i < dstlen; i++)
  89. {
  90. dst[i] = nibble(src[i * 2]) << 4;
  91. if (i * 2 + 1 < srclen)
  92. dst[i] |= nibble(src[i * 2 + 1]);
  93. }
  94. return dst;
  95. }
  96. // check if an angle is oriented counter clockwise
  97. inline bool is_oriented_ccw(const Vertex &a, const Vertex &b, const Vertex &c)
  98. {
  99. // return det(b-a, c-a) >= 0
  100. return ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)) >= 0;
  101. }
  102. // check if a and b are on the same side of the line c->d
  103. bool on_same_side(const Vertex &a, const Vertex &b, const Vertex &c, const Vertex &d)
  104. {
  105. float px = d.x - c.x, py = d.y - c.y;
  106. // return det(p, a-c) * det(p, b-c) >= 0
  107. float l = px * (a.y - c.y) - py * (a.x - c.x);
  108. float m = px * (b.y - c.y) - py * (b.x - c.x);
  109. return l * m >= 0;
  110. }
  111. // checks is p is contained in the triangle abc
  112. inline bool point_in_triangle(const Vertex &p, const Vertex &a, const Vertex &b, const Vertex &c)
  113. {
  114. return on_same_side(p,a, b,c) && on_same_side(p,b, a,c) && on_same_side(p,c, a,b);
  115. }
  116. // checks if any vertex in `vertices' is in the triangle abc.
  117. bool any_point_in_triangle(const list<const Vertex *> &vertices, const Vertex &a, const Vertex &b, const Vertex &c)
  118. {
  119. list<const Vertex *>::const_iterator it, end = vertices.end();
  120. for (it = vertices.begin(); it != end; ++it)
  121. {
  122. const Vertex *p = *it;
  123. if ((p != &a) && (p != &b) && (p != &c) && point_in_triangle(*p, a,b,c)) // oh god...
  124. return true;
  125. }
  126. return false;
  127. }
  128. inline bool is_ear(const Vertex &a, const Vertex &b, const Vertex &c, const list<const Vertex *> &vertices)
  129. {
  130. return is_oriented_ccw(a,b,c) && !any_point_in_triangle(vertices, a,b,c);
  131. }
  132. } // anonymous namespace
  133. namespace love
  134. {
  135. namespace math
  136. {
  137. Math Math::instance;
  138. Math::Math()
  139. : rng()
  140. {
  141. // prevent the runtime from free()-ing this
  142. retain();
  143. }
  144. Math::~Math()
  145. {
  146. }
  147. RandomGenerator *Math::newRandomGenerator()
  148. {
  149. return new RandomGenerator();
  150. }
  151. BezierCurve *Math::newBezierCurve(const vector<Vector> &points)
  152. {
  153. return new BezierCurve(points);
  154. }
  155. vector<Triangle> Math::triangulate(const vector<Vertex> &polygon)
  156. {
  157. if (polygon.size() < 3)
  158. throw love::Exception("Not a polygon");
  159. else if (polygon.size() == 3)
  160. return vector<Triangle>(1, Triangle(polygon[0], polygon[1], polygon[2]));
  161. // collect list of connections and record leftmost item to check if the polygon
  162. // has the expected winding
  163. vector<size_t> next_idx(polygon.size()), prev_idx(polygon.size());
  164. size_t idx_lm = 0;
  165. for (size_t i = 0; i < polygon.size(); ++i)
  166. {
  167. const Vertex &lm = polygon[idx_lm], &p = polygon[i];
  168. if (p.x < lm.x || (p.x == lm.x && p.y < lm.y))
  169. idx_lm = i;
  170. next_idx[i] = i+1;
  171. prev_idx[i] = i-1;
  172. }
  173. next_idx[next_idx.size()-1] = 0;
  174. prev_idx[0] = prev_idx.size()-1;
  175. // check if the polygon has the expected winding and reverse polygon if needed
  176. if (!is_oriented_ccw(polygon[prev_idx[idx_lm]], polygon[idx_lm], polygon[next_idx[idx_lm]]))
  177. next_idx.swap(prev_idx);
  178. // collect list of concave polygons
  179. list<const Vertex *> concave_vertices;
  180. for (size_t i = 0; i < polygon.size(); ++i)
  181. {
  182. if (!is_oriented_ccw(polygon[prev_idx[i]], polygon[i], polygon[next_idx[i]]))
  183. concave_vertices.push_back(&polygon[i]);
  184. }
  185. // triangulation according to kong
  186. vector<Triangle> triangles;
  187. size_t n_vertices = polygon.size();
  188. size_t current = 1, skipped = 0, next, prev;
  189. while (n_vertices > 3)
  190. {
  191. next = next_idx[current];
  192. prev = prev_idx[current];
  193. const Vertex &a = polygon[prev], &b = polygon[current], &c = polygon[next];
  194. if (is_ear(a,b,c, concave_vertices))
  195. {
  196. triangles.push_back(Triangle(a,b,c));
  197. next_idx[prev] = next;
  198. prev_idx[next] = prev;
  199. concave_vertices.remove(&b);
  200. --n_vertices;
  201. skipped = 0;
  202. }
  203. else if (++skipped > n_vertices)
  204. {
  205. throw love::Exception("Cannot triangulate polygon.");
  206. }
  207. current = next;
  208. }
  209. next = next_idx[current];
  210. prev = prev_idx[current];
  211. triangles.push_back(Triangle(polygon[prev], polygon[current], polygon[next]));
  212. return triangles;
  213. }
  214. bool Math::isConvex(const std::vector<Vertex> &polygon)
  215. {
  216. if (polygon.size() < 3)
  217. return false;
  218. // a polygon is convex if all corners turn in the same direction
  219. // turning direction can be determined using the cross-product of
  220. // the forward difference vectors
  221. size_t i = polygon.size() - 2, j = polygon.size() - 1, k = 0;
  222. Vector p(polygon[j].x - polygon[i].x, polygon[j].y - polygon[i].y);
  223. Vector q(polygon[k].x - polygon[j].x, polygon[k].y - polygon[j].y);
  224. float winding = p ^ q;
  225. while (k+1 < polygon.size())
  226. {
  227. i = j; j = k; k++;
  228. p.x = polygon[j].x - polygon[i].x;
  229. p.y = polygon[j].y - polygon[i].y;
  230. q.x = polygon[k].x - polygon[j].x;
  231. q.y = polygon[k].y - polygon[j].y;
  232. if ((p^q) * winding < 0)
  233. return false;
  234. }
  235. return true;
  236. }
  237. /**
  238. * http://en.wikipedia.org/wiki/SRGB#The_reverse_transformation
  239. **/
  240. float Math::gammaToLinear(float c) const
  241. {
  242. if (c <= 0.04045f)
  243. return c / 12.92f;
  244. else
  245. return powf((c + 0.055f) / 1.055f, 2.4f);
  246. }
  247. /**
  248. * http://en.wikipedia.org/wiki/SRGB#The_forward_transformation_.28CIE_xyY_or_CIE_XYZ_to_sRGB.29
  249. **/
  250. float Math::linearToGamma(float c) const
  251. {
  252. if (c <= 0.0031308f)
  253. return c * 12.92f;
  254. else
  255. return 1.055f * powf(c, 1.0f / 2.4f) - 0.055f;
  256. }
  257. CompressedData *Math::compress(Compressor::Format format, love::Data *rawdata, int level)
  258. {
  259. return compress(format, (const char *) rawdata->getData(), rawdata->getSize(), level);
  260. }
  261. CompressedData *Math::compress(Compressor::Format format, const char *rawbytes, size_t rawsize, int level)
  262. {
  263. Compressor *compressor = Compressor::getCompressor(format);
  264. if (compressor == nullptr)
  265. throw love::Exception("Invalid compression format.");
  266. size_t compressedsize = 0;
  267. char *cbytes = compressor->compress(format, rawbytes, rawsize, level, compressedsize);
  268. CompressedData *data = nullptr;
  269. try
  270. {
  271. data = new CompressedData(format, cbytes, compressedsize, rawsize, true);
  272. }
  273. catch (love::Exception &)
  274. {
  275. delete[] cbytes;
  276. throw;
  277. }
  278. return data;
  279. }
  280. char *Math::decompress(CompressedData *data, size_t &decompressedsize)
  281. {
  282. size_t rawsize = data->getDecompressedSize();
  283. char *rawbytes = decompress(data->getFormat(), (const char *) data->getData(),
  284. data->getSize(), rawsize);
  285. decompressedsize = rawsize;
  286. return rawbytes;
  287. }
  288. char *Math::decompress(Compressor::Format format, const char *cbytes, size_t compressedsize, size_t &rawsize)
  289. {
  290. Compressor *compressor = Compressor::getCompressor(format);
  291. if (compressor == nullptr)
  292. throw love::Exception("Invalid compression format.");
  293. return compressor->decompress(format, cbytes, compressedsize, rawsize);
  294. }
  295. char *Math::encode(EncodeFormat format, const char *src, size_t srclen, size_t &dstlen, size_t linelen)
  296. {
  297. switch (format)
  298. {
  299. case ENCODE_BASE64:
  300. default:
  301. return b64_encode(src, srclen, linelen, dstlen);
  302. case ENCODE_HEX:
  303. return bytesToHex((const uint8 *) src, srclen, dstlen);
  304. }
  305. }
  306. char *Math::decode(EncodeFormat format, const char *src, size_t srclen, size_t &dstlen)
  307. {
  308. switch (format)
  309. {
  310. case ENCODE_BASE64:
  311. default:
  312. return b64_decode(src, srclen, dstlen);
  313. case ENCODE_HEX:
  314. return (char *) hexToBytes(src, srclen, dstlen);
  315. }
  316. }
  317. bool Math::getConstant(const char *in, EncodeFormat &out)
  318. {
  319. return encoders.find(in, out);
  320. }
  321. bool Math::getConstant(EncodeFormat in, const char *&out)
  322. {
  323. return encoders.find(in, out);
  324. }
  325. StringMap<Math::EncodeFormat, Math::ENCODE_MAX_ENUM>::Entry Math::encoderEntries[] =
  326. {
  327. { "base64", ENCODE_BASE64 },
  328. { "hex", ENCODE_HEX },
  329. };
  330. StringMap<Math::EncodeFormat, Math::ENCODE_MAX_ENUM> Math::encoders(Math::encoderEntries, sizeof(Math::encoderEntries));
  331. } // math
  332. } // love