MandelVideoGenerator.cpp 4.4 KB

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