MandelVideoGenerator.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #include "MandelVideoGenerator.h"
  2. #include "VideoStream.h"
  3. #include "Mandel.h"
  4. #include <thread>
  5. #include <cmath>
  6. MandelVideoGenerator::MandelVideoGenerator(const ExportVideoInfo& evi) :
  7. evi{ evi }
  8. {
  9. }
  10. void MandelVideoGenerator::addProgressCallback(ProgressCallback pc)
  11. {
  12. progressCallbacks.push_back(std::move(pc));
  13. }
  14. void MandelVideoGenerator::generate(void)
  15. {
  16. mnd::MandelContext ctxt = mnd::initializeContext();
  17. mnd::MandelGenerator& gen = ctxt.getDefaultGenerator();
  18. mnd::MandelInfo mi;
  19. mi.bWidth = evi.width * 2;
  20. mi.bHeight = evi.height * 2;
  21. mi.maxIter = evi.maxIterations;
  22. VideoStream vs(evi.width, evi.height, evi.path, evi.bitrate, evi.fps, evi.preset.c_str());
  23. mnd::Real x = evi.end.x + evi.end.width / 2;
  24. mnd::Real y = evi.end.y + evi.end.height / 2;
  25. mnd::Real w = evi.start.width;
  26. mnd::Real h = evi.start.height;
  27. mnd::Real bigW = 10000000000000000.0;
  28. double bigFac = 1.0;
  29. Bitmap<RGBColor> big;
  30. Bitmap<RGBColor> small;
  31. int64_t frameCounter = 0;
  32. while(w > evi.end.width || h > evi.end.height) {
  33. mi.view = mnd::MandelViewport{ x - w/2, y - h/2, w, h };
  34. if (bigW > 2 * w) {
  35. Bitmap<float> raw{ evi.width * 2, evi.height * 2 };
  36. gen.generate(mi, raw.pixels.get());
  37. //auto before = std::chrono::high_resolution_clock::now();
  38. big = raw.map<RGBColor>([&mi, this] (float i) {
  39. return i >= mi.maxIter ? RGBColor{ 0, 0, 0 } : evi.gradient.get(i);
  40. });
  41. /*mi.view.zoomCenter(0.5);
  42. gen.generate(mi, raw.pixels.get());
  43. small = raw.map<RGBColor>([] (float x) { return
  44. RGBColor{ uint8_t(::sin(x / 100) * 127 + 127), uint8_t(::sin(x / 213) * 127 + 127), uint8_t(::cos(x / 173) * 127 + 127) };
  45. });*/
  46. bigW = w;
  47. bigFac = 1.0;
  48. }
  49. vs.addFrame(overlay(big, small, bigFac));
  50. frameCounter++;
  51. MandelVideoProgressInfo mvpi{ frameCounter };
  52. callCallbacks(mvpi);
  53. w *= ::pow(0.99, evi.zoomSpeed);
  54. h *= ::pow(0.99, evi.zoomSpeed);
  55. bigFac *= ::pow(0.99, evi.zoomSpeed);
  56. }
  57. }
  58. void MandelVideoGenerator::callCallbacks(const MandelVideoProgressInfo& evi)
  59. {
  60. for (auto& pc : progressCallbacks) {
  61. pc(evi);
  62. }
  63. }
  64. inline RGBColor biliniear(const Bitmap<RGBColor>& img, double x, double y)
  65. {
  66. int xfloor = int(::floor(x));
  67. int yfloor = int(::floor(y));
  68. int xceil = int(::ceil(x));
  69. int yceil = int(::ceil(y));
  70. double xLerp = x - xfloor;
  71. double yLerp = y - yfloor;
  72. RGBColor samples[2][2] = {
  73. {
  74. img.get(xfloor, yfloor),
  75. img.get(xfloor, yceil),
  76. },
  77. {
  78. img.get(xceil, yfloor),
  79. img.get(xceil, yceil),
  80. }
  81. };
  82. double r = 0, g = 0, b = 0;
  83. auto mklin = [] (double x) {
  84. return x;
  85. };
  86. auto unlin = [] (double x) {
  87. return x;
  88. };
  89. r += (1 - xLerp) * (1 - yLerp) * mklin(samples[0][0].r);
  90. r += (1 - xLerp) * yLerp * mklin(samples[0][1].r);
  91. r += xLerp * (1 - yLerp) * mklin(samples[1][0].r);
  92. r += xLerp * yLerp * mklin(samples[1][1].r);
  93. g += (1 - xLerp) * (1 - yLerp) * mklin(samples[0][0].g);
  94. g += (1 - xLerp) * yLerp * mklin(samples[0][1].g);
  95. g += xLerp * (1 - yLerp) * mklin(samples[1][0].g);
  96. g += xLerp * yLerp * mklin(samples[1][1].g);
  97. b += (1 - xLerp) * (1 - yLerp) * mklin(samples[0][0].b);
  98. b += (1 - xLerp) * yLerp * mklin(samples[0][1].b);
  99. b += xLerp * (1 - yLerp) * mklin(samples[1][0].b);
  100. b += xLerp * yLerp * mklin(samples[1][1].b);
  101. return RGBColor{ uint8_t(unlin(r)), uint8_t(unlin(g)), uint8_t(unlin(b)) };
  102. }
  103. inline RGBColor nearest(const Bitmap<RGBColor>& img, double x, double y)
  104. {
  105. int xfloor = int(::floor(x));
  106. int yfloor = int(::floor(y));
  107. return img.get(xfloor, yfloor);
  108. }
  109. Bitmap<RGBColor> MandelVideoGenerator::overlay(const Bitmap<RGBColor>& outer,
  110. const Bitmap<RGBColor>& inner, double scale)
  111. {
  112. printf("%lf\n", scale);
  113. Bitmap<RGBColor> ret{ outer.width / 2, outer.height / 2 };
  114. double newW = outer.width * scale * 2;
  115. double newH = outer.height * scale * 2;
  116. double newX = outer.width * (1 - scale) / 2;
  117. double newY = outer.height * (1 - scale) / 2;
  118. auto before = std::chrono::high_resolution_clock::now();
  119. #pragma omp parallel for schedule(static, 1)
  120. for (int i = 0; i < ret.height; i++) {
  121. for (int j = 0; j < ret.width; j++) {
  122. double newJ = newX + j * newW / outer.width;
  123. double newI = newY + i * newH / outer.height;
  124. RGBColor a = biliniear(outer, newJ, newI);
  125. ret.get(j, i) = a;
  126. }
  127. }
  128. auto after = std::chrono::high_resolution_clock::now();
  129. printf("gradient applied in: %lld microseconds\n", std::chrono::duration_cast<std::chrono::microseconds>(after - before).count());
  130. fflush(stdout);
  131. /*for (int i = 0; i < ret.height * ret.width; i++) {
  132. ret.pixels[i] = outer.pixels[i];
  133. }*/
  134. return ret;
  135. }