main.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. /*
  2. Copyright (C) 2010-2015 Matthias Kretz <kretz@kde.org>
  3. Permission to use, copy, modify, and distribute this software
  4. and its documentation for any purpose and without fee is hereby
  5. granted, provided that the above copyright notice appear in all
  6. copies and that both that the copyright notice and this
  7. permission notice and warranty disclaimer appear in supporting
  8. documentation, and that the name of the author not be used in
  9. advertising or publicity pertaining to distribution of the
  10. software without specific, written prior permission.
  11. The author disclaim all warranties with regard to this
  12. software, including all implied warranties of merchantability
  13. and fitness. In no event shall the author be liable for any
  14. special, indirect or consequential damages or any damages
  15. whatsoever resulting from loss of use, data or profits, whether
  16. in an action of contract, negligence or other tortious action,
  17. arising out of or in connection with the use or performance of
  18. this software.
  19. */
  20. #include "main.h"
  21. #include "../tsc.h"
  22. #include <complex>
  23. #include <cmath>
  24. #include <QApplication>
  25. #include <QTextStream>
  26. #include <QTimer>
  27. #include <QtCore/QtDebug>
  28. #include <QPainter>
  29. #include <QProgressBar>
  30. #ifdef Scalar
  31. typedef float float_v;
  32. typedef int int_v;
  33. typedef bool int_m;
  34. #ifdef _MSC_VER
  35. #define Vc_CDECL __cdecl
  36. #else
  37. #define Vc_CDECL
  38. #endif
  39. #else
  40. #include <Vc/Vc>
  41. using Vc::float_v;
  42. using Vc::float_m;
  43. using int_v = Vc::SimdArray<int, float_v::size()>;
  44. using int_m = int_v::mask_type;
  45. #endif
  46. ProgressWriter::ProgressWriter()
  47. : m_out(stdout)
  48. {
  49. }
  50. void ProgressWriter::setValue(float vf)
  51. {
  52. static int lastPercent = -1;
  53. static int lastHash = 0;
  54. int p = static_cast<int>(vf + 0.5f);
  55. int h = static_cast<int>(vf * 0.78f + 0.5f);
  56. bool flush = false;
  57. if (p != lastPercent) {
  58. flush = true;
  59. if (lastPercent == -1) {
  60. m_out << "\033[80D\033[K"
  61. << "[ ";
  62. m_out.setFieldWidth(3);
  63. m_out << p;
  64. m_out.setFieldWidth(0);
  65. m_out << "% ]"
  66. << "\033[79D";
  67. } else {
  68. m_out << "\033[s\033[80D\033[37C";
  69. m_out.setFieldWidth(3);
  70. m_out << p;
  71. m_out.setFieldWidth(0);
  72. m_out << "\033[u";
  73. }
  74. lastPercent = p;
  75. }
  76. for (; lastHash < h; ++lastHash) {
  77. flush = true;
  78. if (lastHash < 36 || lastHash > 39) {
  79. m_out << '#';
  80. } else {
  81. m_out << "\033[1C";
  82. }
  83. }
  84. if (flush) {
  85. m_out.flush();
  86. }
  87. }
  88. void ProgressWriter::done()
  89. {
  90. setValue(100.f);
  91. m_out << "\033[2C";
  92. m_out.flush();
  93. }
  94. Baker::Baker()
  95. {
  96. }
  97. void Baker::setSize(int w, int h)
  98. {
  99. m_y = -1.f;
  100. m_height = 2.f;
  101. m_width = w * m_height / h;
  102. m_x = m_width * -0.667f;
  103. m_image = QImage(w, h, QImage::Format_RGB32);
  104. }
  105. void Baker::setFilename(const QString &filename)
  106. {
  107. m_filename = filename;
  108. }
  109. struct Z
  110. {
  111. using value_type = float_v;
  112. value_type real, imag;
  113. };
  114. inline Z operator*(Z a, Z b)
  115. {
  116. return {a.real * b.real - a.imag * b.imag, a.real * b.imag + a.imag * b.real};
  117. }
  118. inline Z operator+(Z a, Z b)
  119. {
  120. return {a.real + b.real, a.imag + b.imag};
  121. }
  122. static inline Z P(Z z, Z c)
  123. {
  124. return z * z + c;
  125. }
  126. static inline Z::value_type fastNorm(const Z &z)
  127. {
  128. return z.real * z.real + z.imag * z.imag;
  129. }
  130. template<typename T> static inline T square(T a) { return a * a; }
  131. template<typename T> static inline T minOf(T a, T b) { return a < b ? a : b; }
  132. template<typename T> static inline T maxOf(T a, T b) { return a < b ? b : a; }
  133. template<typename T> static inline T clamp(T min, T value, T max)
  134. {
  135. if (value > max) {
  136. return max;
  137. }
  138. return value < min ? min : value;
  139. }
  140. struct Pixel
  141. {
  142. float blue;
  143. float green;
  144. float red;
  145. };
  146. static const Pixel NULL_PIXEL = { 0, 0, 0 };
  147. class Canvas
  148. {
  149. public:
  150. Canvas(int h, int w);
  151. void addDot(float x, float y, int red, int green, int blue);
  152. void toQImage(QImage *);
  153. private:
  154. void addDot(int x, int y, float red, float green, float blue) {
  155. Pixel &p = m_pixels[x + y * m_width];
  156. p.blue += blue;
  157. p.green += green;
  158. p.red += red;
  159. }
  160. const int m_width;
  161. std::vector<Pixel> m_pixels;
  162. };
  163. Canvas::Canvas(int h, int w)
  164. : m_width(w), m_pixels(h * w, NULL_PIXEL)
  165. {
  166. }
  167. void Canvas::addDot(float x, float y, int red, int green, int blue)
  168. {
  169. const int x1 = static_cast<int>(std::floor(x));
  170. const int x2 = static_cast<int>(std::ceil (x));
  171. const int y1 = static_cast<int>(std::floor(y));
  172. const int y2 = static_cast<int>(std::ceil (y));
  173. const float xfrac = x - std::floor(x);
  174. const float yfrac = y - std::floor(y);
  175. const float r = red;
  176. const float g = green;
  177. const float b = blue;
  178. const float frac11 = (1.f - xfrac) * (1.f - yfrac);
  179. const float frac12 = (1.f - xfrac) * yfrac;
  180. const float frac21 = xfrac * (1.f - yfrac);
  181. const float frac22 = xfrac * yfrac;
  182. addDot(x1, y1, r * frac11, g * frac11, b * frac11);
  183. addDot(x2, y1, r * frac21, g * frac21, b * frac21);
  184. addDot(x1, y2, r * frac12, g * frac12, b * frac12);
  185. addDot(x2, y2, r * frac22, g * frac22, b * frac22);
  186. }
  187. #define BUDDHABROT_USE_FUNCTION1
  188. #ifdef BUDDHABROT_USE_FUNCTION2
  189. static inline uchar reduceRange(float x, float m, float h)
  190. {
  191. /* m: max, h: median
  192. * +- -+
  193. * | 3 3 2 |
  194. * | 510 h + 127 m - 765 h m |
  195. * | -------------------------- |
  196. * | 3 3 2 2 |
  197. * | h m + h m - 2 h m |
  198. * | |
  199. * | 3 3 2 |
  200. * | - 255 h - 254 m + 765 h m |
  201. * | ---------------------------- |
  202. * | 4 2 3 3 2 |
  203. * | h m - 2 h m + h m |
  204. * | |
  205. * | 2 2 |
  206. * | - 510 h m + 255 h + 127 m |
  207. * | --------------------------- |
  208. * | 4 2 3 3 2 |
  209. * | h m - 2 h m + h m |
  210. * +- -+
  211. */
  212. const float h2 = h * h;
  213. const float h3 = h2 * h;
  214. const float m2 = m * m;
  215. const float m3 = m2 * m;
  216. const float denom = h * m * square(m - h);
  217. return minOf(255.f, 0.5f //rounding
  218. + x / denom * (
  219. 510.f * h3 + 127.f * m3 - 765.f * h2 * m
  220. + x / m * (
  221. 765.f * h * m2 - 255.f * h3 - 254.f * m3
  222. + x * (
  223. 255.f * h2 + 127.f * m2 - 510.f * h * m)
  224. )));
  225. }
  226. #elif defined(BUDDHABROT_USE_FUNCTION1)
  227. static inline unsigned int reduceRange(float x, float m, float h)
  228. {
  229. if (x <= m) {
  230. return 0.5f // rounding
  231. + 4.f / 255.f * h * h / m * x
  232. + square(x) * (h / square(m)) * (4.f - 8.f / 255.f * h);
  233. } else {
  234. return 0.5f // rounding
  235. + 255.f - 4.f * h + 4.f / 255.f * square(h)
  236. + x / m * (16.f * h - 1020.f - 12.f / 255.f * square(h))
  237. + square(x / m) * (1020.f - 12.f * h + 8.f / 255.f * square(h));
  238. }
  239. }
  240. #endif
  241. void Canvas::toQImage(QImage *img)
  242. {
  243. uchar *line = img->scanLine(0);
  244. const Pixel *p = &m_pixels[0];
  245. #ifdef BUDDHABROT_USE_FUNCTION2
  246. float max [3] = { 0.f, 0.f, 0.f };
  247. std::vector<float> sorted[3];
  248. for (int i = 0; i < 3; ++i) {
  249. sorted[i].reserve(m_pixels.size());
  250. }
  251. for (unsigned int i = 0; i < m_pixels.size(); ++i) {
  252. max[0] = maxOf(max[0], m_pixels[i].red);
  253. max[1] = maxOf(max[1], m_pixels[i].green);
  254. max[2] = maxOf(max[2], m_pixels[i].blue);
  255. if (m_pixels[i].red > 1.f) {
  256. sorted[0].push_back(m_pixels[i].red);
  257. }
  258. if (m_pixels[i].green > 1.f) {
  259. sorted[1].push_back(m_pixels[i].green);
  260. }
  261. if (m_pixels[i].blue > 1.f) {
  262. sorted[2].push_back(m_pixels[i].blue);
  263. }
  264. }
  265. for (int i = 0; i < 3; ++i) {
  266. std::sort(sorted[i].begin(), sorted[i].end());
  267. }
  268. const float median[3] = {
  269. sorted[0][sorted[0].size() / 2],
  270. sorted[1][sorted[1].size() / 2],
  271. sorted[2][sorted[2].size() / 2]
  272. };
  273. /*
  274. int hist[3][2];
  275. for (int i = 0; i < 3; ++i) {
  276. hist[i][0] = hist[i][1] = 0;
  277. }
  278. for (unsigned int i = 0; i < m_pixels.size(); ++i) {
  279. ++hist[0][reduceRange(m_pixels[i].red , max[0], median[0]) / 128];
  280. ++hist[1][reduceRange(m_pixels[i].green, max[1], median[1]) / 128];
  281. ++hist[2][reduceRange(m_pixels[i].blue , max[2], median[2]) / 128];
  282. }
  283. qDebug() << "Histogram:\n red:"
  284. << median[0] << hist[0][0] << hist[0][1] << "\ngreen:"
  285. << median[1] << hist[1][0] << hist[1][1] << "\n blue:"
  286. << median[2] << hist[2][0] << hist[2][1];
  287. */
  288. for (int yy = 0; yy < img->height(); ++yy) {
  289. for (int xx = 0; xx < img->width(); ++xx) {
  290. line[0] = reduceRange(p->blue , max[2], median[2]);
  291. line[1] = reduceRange(p->green, max[1], median[1]);
  292. line[2] = reduceRange(p->red , max[0], median[0]);
  293. line += 4;
  294. ++p;
  295. }
  296. }
  297. #elif defined(BUDDHABROT_USE_FUNCTION1)
  298. float max[3] = { 0.f, 0.f, 0.f };
  299. for (unsigned int i = 0; i < m_pixels.size(); ++i) {
  300. max[0] = maxOf(max[0], m_pixels[i].red);
  301. max[1] = maxOf(max[1], m_pixels[i].green);
  302. max[2] = maxOf(max[2], m_pixels[i].blue);
  303. }
  304. float h[3] = { 220.f, 220.f, 220.f };
  305. /*
  306. int hist[3][2];
  307. for (int i = 0; i < 3; ++i) {
  308. hist[i][0] = hist[i][1] = 0;
  309. }
  310. for (unsigned int i = 0; i < m_pixels.size(); ++i) {
  311. ++hist[0][reduceRange(m_pixels[i].red , max[0], h[0]) / 128];
  312. ++hist[1][reduceRange(m_pixels[i].green, max[1], h[1]) / 128];
  313. ++hist[2][reduceRange(m_pixels[i].blue , max[2], h[2]) / 128];
  314. }
  315. qDebug() << "Histogram:\n red:"
  316. << hist[0][0] << hist[0][1] << "\ngreen:"
  317. << hist[1][0] << hist[1][1] << "\n blue:"
  318. << hist[2][0] << hist[2][1];
  319. */
  320. for (int yy = 0; yy < img->height(); ++yy) {
  321. for (int xx = 0; xx < img->width(); ++xx) {
  322. line[0] = reduceRange(p->blue , max[2], h[2]);
  323. line[1] = reduceRange(p->green, max[1], h[1]);
  324. line[2] = reduceRange(p->red , max[0], h[0]);
  325. line += 4;
  326. ++p;
  327. }
  328. }
  329. #else
  330. float max [3] = { 0.f, 0.f, 0.f };
  331. float mean [3] = { 0.f, 0.f, 0.f };
  332. float stddev[3] = { 0.f, 0.f, 0.f };
  333. for (unsigned int i = 0; i < m_pixels.size(); ++i) {
  334. max[0] = maxOf(max[0], m_pixels[i].red);
  335. max[1] = maxOf(max[1], m_pixels[i].green);
  336. max[2] = maxOf(max[2], m_pixels[i].blue);
  337. mean[0] += m_pixels[i].red;
  338. mean[1] += m_pixels[i].green;
  339. mean[2] += m_pixels[i].blue;
  340. stddev[0] += square(m_pixels[i].red);
  341. stddev[1] += square(m_pixels[i].green);
  342. stddev[2] += square(m_pixels[i].blue);
  343. }
  344. const float normalization = 1.f / m_pixels.size();
  345. mean[0] *= normalization;
  346. mean[1] *= normalization;
  347. mean[2] *= normalization;
  348. stddev[0] = std::sqrt(stddev[0] * normalization - square(mean[0]));
  349. stddev[1] = std::sqrt(stddev[1] * normalization - square(mean[1]));
  350. stddev[2] = std::sqrt(stddev[2] * normalization - square(mean[2]));
  351. qDebug() << " max:" << max[0] << max[1] << max[2];
  352. qDebug() << " mean:" << mean[0] << mean[1] << mean[2];
  353. qDebug() << "stddev:" << stddev[0] << stddev[1] << stddev[2];
  354. // colors have the range 0..max at this point
  355. // they should be transformed such that for the resulting mean and stddev:
  356. // mean - stddev = 0
  357. // mean + stddev = min(min(2 * mean, max), 255)
  358. //
  359. // newColor = (c - mean) * min(min(2 * mean, max), 255) * 0.5 / stddev + 127.5
  360. const float center[3] = {
  361. minOf(minOf(2.f * mean[0], max[0]), 255.f) * 0.5f,
  362. minOf(minOf(2.f * mean[1], max[1]), 255.f) * 0.5f,
  363. minOf(minOf(2.f * mean[2], max[2]), 255.f) * 0.5f
  364. };
  365. const float sdFactor[3] = { 2.f, 2.f, 2.f };
  366. const float redFactor = center[0] / (sdFactor[0] * stddev[0]);
  367. const float greenFactor = center[1] / (sdFactor[1] * stddev[1]);
  368. const float blueFactor = center[2] / (sdFactor[2] * stddev[2]);
  369. for (int yy = 0; yy < img->height(); ++yy) {
  370. for (int xx = 0; xx < img->width(); ++xx) {
  371. line[0] = clamp(0, static_cast<int>(center[2] + (p->blue - mean[2]) * blueFactor ), 255);
  372. line[1] = clamp(0, static_cast<int>(center[1] + (p->green - mean[1]) * greenFactor), 255);
  373. line[2] = clamp(0, static_cast<int>(center[0] + (p->red - mean[0]) * redFactor ), 255);
  374. line += 4;
  375. ++p;
  376. }
  377. }
  378. #endif
  379. }
  380. Baker::Options::Options()
  381. {
  382. red[0] = 2;
  383. red[1] = 10;
  384. green[0] = 0;
  385. green[1] = 1;
  386. blue[0] = 11;
  387. blue[1] = 20;
  388. it[0] = 10000;
  389. it[1] = 50000;
  390. steps[0] = steps[1] = -1;
  391. }
  392. void Baker::createImage()
  393. {
  394. const int iHeight = m_image.height();
  395. const int iWidth = m_image.width();
  396. // Parameters Begin
  397. const float S = 4.f;
  398. const float nSteps[2] = {
  399. static_cast<float>(m_opt.steps[0] == -1 ? std::sqrt(iWidth) * iWidth : m_opt.steps[0]),
  400. static_cast<float>(m_opt.steps[1] == -1 ? std::sqrt(iHeight) * iHeight : m_opt.steps[1])
  401. };
  402. const int upperBound[3] = { m_opt.red[1], m_opt.green[1], m_opt.blue[1] };
  403. const int lowerBound[3] = { m_opt.red[0], m_opt.green[0], m_opt.blue[0] };
  404. int overallLowerBound = m_opt.it[0];
  405. int maxIterations = m_opt.it[1];// maxOf(maxOf(overallLowerBound, upperBound[0]), maxOf(upperBound[1], upperBound[2]));
  406. float realMin = -2.102613f;
  407. float realMax = 1.200613f;
  408. float imagMin = 0.f;
  409. float imagMax = 1.23971f;
  410. // Parameters End
  411. TimeStampCounter timer;
  412. timer.start();
  413. // helper constants
  414. const int overallUpperBound = maxOf(upperBound[0], maxOf(upperBound[1], upperBound[2]));
  415. const float maxX = static_cast<float>(iWidth ) - 1.f;
  416. const float maxY = static_cast<float>(iHeight) - 1.f;
  417. const float xFact = iWidth / m_width;
  418. const float yFact = iHeight / m_height;
  419. const float realStep = (realMax - realMin) / nSteps[0];
  420. const float imagStep = (imagMax - imagMin) / nSteps[1];
  421. Canvas canvas(iHeight, iWidth);
  422. #ifdef Scalar
  423. for (float real = realMin; real <= realMax; real += realStep) {
  424. m_progress.setValue(99.f * (real - realMin) / (realMax - realMin));
  425. for (float imag = imagMin; imag <= imagMax; imag += imagStep) {
  426. Z c{real, imag};
  427. Z c2{1.08f * real + 0.15f, imag};
  428. if (fastNorm(Z{real + 1.f, imag}) < 0.06f ||
  429. (c2.real < 0.42f && fastNorm(c2) < 0.417f)) {
  430. continue;
  431. }
  432. Z z = c;
  433. int n;
  434. for (n = 0; n <= maxIterations && fastNorm(z) < S; ++n) {
  435. z = P(z, c);
  436. }
  437. if (n <= maxIterations && n >= overallLowerBound) {
  438. // point is outside of the Mandelbrot set and required enough (overallLowerBound)
  439. // iterations to reach the cut-off value S
  440. Z cn{real, -imag};
  441. Z zn = cn;
  442. z = c;
  443. for (int i = 0; i <= overallUpperBound; ++i) {
  444. const float y2 = (z.imag - m_y) * yFact;
  445. const float yn2 = (zn.imag - m_y) * yFact;
  446. if (y2 >= 0.f && y2 < maxY && yn2 >= 0.f && yn2 < maxY) {
  447. const float x2 = (z.real - m_x) * xFact;
  448. if (x2 >= 0.f && x2 < maxX) {
  449. const int red = (i >= lowerBound[0] && i <= upperBound[0]) ? 1 : 0;
  450. const int green = (i >= lowerBound[1] && i <= upperBound[1]) ? 1 : 0;
  451. const int blue = (i >= lowerBound[2] && i <= upperBound[2]) ? 1 : 0;
  452. canvas.addDot(x2, y2 , red, green, blue);
  453. canvas.addDot(x2, yn2, red, green, blue);
  454. }
  455. }
  456. z = P(z, c);
  457. zn = P(zn, cn);
  458. if (fastNorm(z) >= S) { // optimization: skip some useless looping
  459. break;
  460. }
  461. }
  462. }
  463. }
  464. }
  465. #else
  466. const float imagStep2 = imagStep * float_v::Size;
  467. const float_v imagMin2 = imagMin + imagStep * float_v::IndexesFromZero();
  468. for (float real = realMin; real <= realMax; real += realStep) {
  469. m_progress.setValue(99.f * (real - realMin) / (realMax - realMin));
  470. for (float_v imag = imagMin2; all_of(imag <= imagMax); imag += imagStep2) {
  471. // FIXME: extra "tracks" if nSteps[1] is not a multiple of float_v::Size
  472. Z c{real, imag};
  473. Z c2 = Z{1.08f * real + 0.15f, imag};
  474. if (all_of(fastNorm(Z{real + 1.f, imag}) < 0.06f ||
  475. (c2.real < 0.42f && fastNorm(c2) < 0.417f))) {
  476. continue;
  477. }
  478. Z z = c;
  479. int_v n(Vc::Zero);
  480. int_m inside = fastNorm(z) < S;
  481. while (!(inside && n <= maxIterations).isEmpty()) {
  482. z = P(z, c);
  483. ++n(inside);
  484. inside &= fastNorm(z) < S;
  485. }
  486. inside |= n < overallLowerBound;
  487. if (inside.isFull()) {
  488. continue;
  489. }
  490. Z cn{real, -imag};
  491. Z zn = cn;
  492. z = c;
  493. for (int i = 0; i <= overallUpperBound; ++i) {
  494. const float_v y2 = (z.imag - m_y) * yFact;
  495. const float_v yn2 = (zn.imag - m_y) * yFact;
  496. const float_v x2 = (z.real - m_x) * xFact;
  497. z = P(z, c);
  498. zn = P(zn, cn);
  499. const float_m drawMask = !inside && y2 >= 0.f && x2 >= 0.f && y2 < maxY && x2 < maxX && yn2 >= 0.f && yn2 < maxY;
  500. const int red = (i >= lowerBound[0] && i <= upperBound[0]) ? 1 : 0;
  501. const int green = (i >= lowerBound[1] && i <= upperBound[1]) ? 1 : 0;
  502. const int blue = (i >= lowerBound[2] && i <= upperBound[2]) ? 1 : 0;
  503. for(int j : where(drawMask)) {
  504. canvas.addDot(x2[j], y2 [j], red, green, blue);
  505. canvas.addDot(x2[j], yn2[j], red, green, blue);
  506. }
  507. if (all_of(fastNorm(z) >= S)) { // optimization: skip some useless looping
  508. break;
  509. }
  510. }
  511. }
  512. }
  513. #endif
  514. canvas.toQImage(&m_image);
  515. timer.stop();
  516. m_progress.done();
  517. qDebug() << timer.cycles() << "cycles";
  518. if (m_filename.isEmpty()) {
  519. m_filename = QString("r%1-%2_g%3-%4_b%5-%6_s%7-%8_i%9-%10_%11x%12.png")
  520. .arg(lowerBound[0]).arg(upperBound[0])
  521. .arg(lowerBound[1]).arg(upperBound[1])
  522. .arg(lowerBound[2]).arg(upperBound[2])
  523. .arg(nSteps[0]).arg(nSteps[1])
  524. .arg(overallLowerBound).arg(maxIterations)
  525. .arg(m_image.width()).arg(m_image.height());
  526. }
  527. m_image.save(m_filename);
  528. }
  529. static void usage(const char *argv0)
  530. {
  531. Baker::Options o;
  532. QTextStream out(stdout);
  533. out << "Usage: " << argv0 << " [options] [<filename>]\n\n"
  534. << "Options:\n"
  535. << " -h|--help This message.\n"
  536. << " -s|--size <w> <h> Specify the width and height of the resulting image file. [1024 768]\n"
  537. << " -r|--red <int> <int> Specify lower and upper iteration bounds for a red trace. ["
  538. << o.red[0] << ' ' << o.red[1] << "]\n"
  539. << " -g|--green <int> <int> Specify lower and upper iteration bounds for a green trace. ["
  540. << o.green[0] << ' ' << o.green[1] << "]\n"
  541. << " -b|--blue <int> <int> Specify lower and upper iteration bounds for a blue trace. ["
  542. << o.blue[0] << ' ' << o.blue[1] << "]\n"
  543. << " --steps <int> <int> Specify the steps in real and imaginary direction. [width^1.5 height^1.5]\n"
  544. << " --minIt <int> Overall lower iteration bound. [" << o.it[0] << "]\n"
  545. << " --maxIt <int> Overall upper iteration bound. [" << o.it[1] << "]\n"
  546. ;
  547. }
  548. int Vc_CDECL main(int argc, char **argv)
  549. {
  550. QCoreApplication app(argc, argv);
  551. const QStringList &args = QCoreApplication::arguments();
  552. if (args.contains("--help") || args.contains("-h")) {
  553. usage(argv[0]);
  554. return 0;
  555. }
  556. Baker b;
  557. Baker::Options opt;
  558. int width = 1024;
  559. int height = 768;
  560. // parse args
  561. for (int i = 1; i < args.size(); ++i) {
  562. const QString &arg = args[i];
  563. bool ok = true;
  564. if (arg == QLatin1String("--red") || arg == QLatin1String("-r")) {
  565. opt.red[0] = args[++i].toInt(&ok);
  566. if (ok) {
  567. opt.red[1] = args[++i].toInt(&ok);
  568. }
  569. } else if (arg == QLatin1String("--green") || arg == QLatin1String("-g")) {
  570. opt.green[0] = args[++i].toInt(&ok);
  571. if (ok) {
  572. opt.green[1] = args[++i].toInt(&ok);
  573. }
  574. } else if (arg == QLatin1String("--blue") || arg == QLatin1String("-b")) {
  575. opt.blue[0] = args[++i].toInt(&ok);
  576. if (ok) {
  577. opt.blue[1] = args[++i].toInt(&ok);
  578. }
  579. } else if (arg == QLatin1String("--steps")) {
  580. opt.steps[0] = args[++i].toInt(&ok);
  581. if (ok) {
  582. opt.steps[1] = args[++i].toInt(&ok);
  583. }
  584. } else if (arg == QLatin1String("--minIt")) {
  585. opt.it[0] = args[++i].toInt(&ok);
  586. } else if (arg == QLatin1String("--maxIt")) {
  587. opt.it[1] = args[++i].toInt(&ok);
  588. } else if (arg == QLatin1String("--size") || arg == QLatin1String("-s")) {
  589. width = args[++i].toInt(&ok);
  590. if (ok) {
  591. height = args[++i].toInt(&ok);
  592. }
  593. } else {
  594. static bool filenameSet = false;
  595. ok = !filenameSet;
  596. filenameSet = true;
  597. b.setFilename(arg);
  598. }
  599. if (!ok) {
  600. usage(argv[0]);
  601. return 1;
  602. }
  603. }
  604. b.setOptions(opt);
  605. b.setSize(width, height);
  606. b.createImage();
  607. return 0;
  608. }