MandelVideoGenerator.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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. VideoStream vs(evi.width, evi.height, evi.path, evi.bitrate, evi.fps, evi.preset.c_str());
  19. mnd::Real x = evi.end.x + evi.end.width / 2;
  20. mnd::Real y = evi.end.y + evi.end.height / 2;
  21. mnd::Real w = evi.start.width;
  22. mnd::Real h = evi.start.height;
  23. mnd::Real bigW = mnd::Real("1e+300");
  24. double bigFac = 1.0;
  25. Bitmap<RGBColor> big;
  26. Bitmap<RGBColor> small;
  27. int64_t frameCounter = 0;
  28. const float oversizeFactor = 2;
  29. const float sqrFactor = sqrt(oversizeFactor);
  30. //const mnd::Real invsqrt2 = mnd::Real(1.0) / mnd::sqrt(mnd::Real(2));
  31. mnd::MandelInfo mi;
  32. mi.bWidth = evi.width * oversizeFactor;
  33. mi.bHeight = evi.height * oversizeFactor;
  34. mi.maxIter = evi.maxIterations;
  35. bool first = true;
  36. while(w > evi.end.width || h > evi.end.height) {
  37. if (bigW > sqrt(oversizeFactor) * w) {
  38. mi.view = mnd::MandelViewport{ x - w/2, y - h/2, w, h };
  39. Bitmap<float> raw{ evi.width * oversizeFactor, evi.height * oversizeFactor };
  40. Bitmap<float> rawSmall{ evi.width * oversizeFactor, evi.height * oversizeFactor };
  41. mi.view.zoomCenter(oversizeFactor);
  42. gen.generate(mi, rawSmall.pixels.get());
  43. //mi.view.zoomCenter(sqrt(oversizeFactor));
  44. //gen.generate(mi, raw.pixels.get());
  45. //auto before = std::chrono::high_resolution_clock::now();
  46. if (first) {
  47. mi.view.zoomCenter(sqrt(oversizeFactor));
  48. gen.generate(mi, raw.pixels.get());
  49. small = raw.map<RGBColor>([&mi, this] (float i) {
  50. return i >= mi.maxIter ? RGBColor{ 0, 0, 0 } : evi.gradient.get(i);
  51. });
  52. }
  53. big = std::move(small);
  54. small = rawSmall.map<RGBColor>([&mi, this] (float i) {
  55. return i >= mi.maxIter ? RGBColor{ 0, 0, 0 } : evi.gradient.get(i);
  56. });
  57. printf("recalced\n");
  58. /*mi.view.zoomCenter(0.5);
  59. gen.generate(mi, raw.pixels.get());
  60. small = raw.map<RGBColor>([] (float x) { return
  61. RGBColor{ uint8_t(::sin(x / 100) * 127 + 127), uint8_t(::sin(x / 213) * 127 + 127), uint8_t(::cos(x / 173) * 127 + 127) };
  62. });*/
  63. bigW = w;
  64. bigFac = 1.0;
  65. first = false;
  66. }
  67. vs.addFrame(overlay(big, small, evi.width, evi.height, bigFac, sqrt(oversizeFactor)));
  68. frameCounter++;
  69. MandelVideoProgressInfo mvpi{ frameCounter };
  70. callCallbacks(mvpi);
  71. w *= ::pow(0.99, evi.zoomSpeed);
  72. h *= ::pow(0.99, evi.zoomSpeed);
  73. bigFac *= ::pow(0.99, evi.zoomSpeed);
  74. }
  75. }
  76. void MandelVideoGenerator::callCallbacks(const MandelVideoProgressInfo& evi)
  77. {
  78. for (auto& pc : progressCallbacks) {
  79. pc(evi);
  80. }
  81. }
  82. inline RGBColor lerpColors(const RGBColor& a, const RGBColor& b, double lerp)
  83. {
  84. auto mklin = [] (double x) {
  85. return x;
  86. };
  87. auto unlin = [] (double x) {
  88. return x;
  89. };
  90. return RGBColor{
  91. a.r * lerp + b.r * (1 - lerp),
  92. a.g * lerp + b.g * (1 - lerp),
  93. a.b * lerp + b.b * (1 - lerp)
  94. };
  95. }
  96. inline RGBColor biliniear(const Bitmap<RGBColor>& img, double x, double y)
  97. {
  98. int xfloor = int(::floor(x));
  99. int yfloor = int(::floor(y));
  100. int xceil = int(::ceil(x));
  101. int yceil = int(::ceil(y));
  102. double xLerp = x - xfloor;
  103. double yLerp = y - yfloor;
  104. RGBColor samples[2][2] = {
  105. {
  106. img.get(xfloor, yfloor),
  107. img.get(xfloor, yceil),
  108. },
  109. {
  110. img.get(xceil, yfloor),
  111. img.get(xceil, yceil),
  112. }
  113. };
  114. double r = 0, g = 0, b = 0;
  115. auto mklin = [] (double x) {
  116. return x;
  117. };
  118. auto unlin = [] (double x) {
  119. return x;
  120. };
  121. r += (1 - xLerp) * (1 - yLerp) * mklin(samples[0][0].r);
  122. r += (1 - xLerp) * yLerp * mklin(samples[0][1].r);
  123. r += xLerp * (1 - yLerp) * mklin(samples[1][0].r);
  124. r += xLerp * yLerp * mklin(samples[1][1].r);
  125. g += (1 - xLerp) * (1 - yLerp) * mklin(samples[0][0].g);
  126. g += (1 - xLerp) * yLerp * mklin(samples[0][1].g);
  127. g += xLerp * (1 - yLerp) * mklin(samples[1][0].g);
  128. g += xLerp * yLerp * mklin(samples[1][1].g);
  129. b += (1 - xLerp) * (1 - yLerp) * mklin(samples[0][0].b);
  130. b += (1 - xLerp) * yLerp * mklin(samples[0][1].b);
  131. b += xLerp * (1 - yLerp) * mklin(samples[1][0].b);
  132. b += xLerp * yLerp * mklin(samples[1][1].b);
  133. return RGBColor{ uint8_t(unlin(r)), uint8_t(unlin(g)), uint8_t(unlin(b)) };
  134. }
  135. inline RGBColor nearest(const Bitmap<RGBColor>& img, double x, double y)
  136. {
  137. int xfloor = int(::floor(x));
  138. int yfloor = int(::floor(y));
  139. return img.get(xfloor, yfloor);
  140. }
  141. Bitmap<RGBColor> MandelVideoGenerator::overlay(const Bitmap<RGBColor>& outer,
  142. const Bitmap<RGBColor>& inner, long bw, long bh,
  143. double scale, double oversizeFactor)
  144. {
  145. printf("%lf\n", scale);
  146. Bitmap<RGBColor> ret{ bw, bh };
  147. double outerLeft = outer.width * (1 - scale / oversizeFactor / oversizeFactor) / 2;
  148. double outerTop = outer.height * (1 - scale / oversizeFactor / oversizeFactor) / 2;
  149. double outerWidth = outer.width * scale / oversizeFactor / oversizeFactor;
  150. double outerHeight = outer.height * scale / oversizeFactor / oversizeFactor;
  151. double innerLeft = outer.width * (1 - scale / oversizeFactor) / 2;
  152. double innerTop = outer.height * (1 - scale / oversizeFactor) / 2;
  153. double innerWidth = outer.width * scale / oversizeFactor;
  154. double innerHeight = outer.height * scale / oversizeFactor;
  155. double lerpVal = ::log(1.0 / scale) / ::log(oversizeFactor);
  156. printf("lerpval: %f\n", lerpVal);
  157. auto before = std::chrono::high_resolution_clock::now();
  158. #pragma omp parallel for schedule(static, 1)
  159. for (int i = 0; i < ret.height; i++) {
  160. for (int j = 0; j < ret.width; j++) {
  161. double newJ = outerLeft + outerWidth * j / ret.width;
  162. double newI = outerTop + outerHeight * i / ret.height;
  163. RGBColor a = biliniear(outer, newJ, newI);
  164. double innJ = innerLeft + innerWidth * j / ret.width;
  165. double innI = innerTop + innerHeight * i / ret.height;
  166. RGBColor b = biliniear(inner, innJ, innI);
  167. double lerpVal = -::log(scale) / ::log(oversizeFactor);
  168. RGBColor lerped = lerpColors(b, a, lerpVal);
  169. ret.get(j, i) = lerped;
  170. }
  171. }
  172. auto after = std::chrono::high_resolution_clock::now();
  173. //printf("gradient applied in: %lld microseconds\n", std::chrono::duration_cast<std::chrono::microseconds>(after - before).count());
  174. fflush(stdout);
  175. /*for (int i = 0; i < ret.height * ret.width; i++) {
  176. ret.pixels[i] = outer.pixels[i];
  177. }*/
  178. return ret;
  179. }