|  | @@ -0,0 +1,132 @@
 | 
	
		
			
				|  |  | +#include "MandelVideoGenerator.h"
 | 
	
		
			
				|  |  | +#include "VideoStream.h"
 | 
	
		
			
				|  |  | +#include <thread>
 | 
	
		
			
				|  |  | +#include <cmath>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +MandelVideoGenerator::MandelVideoGenerator(const ExportVideoInfo& evi) :
 | 
	
		
			
				|  |  | +    evi{ evi }
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void MandelVideoGenerator::generate(void)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    mnd::MandelContext ctxt = mnd::initializeContext();
 | 
	
		
			
				|  |  | +    mnd::Generator& gen = *ctxt.getDevices()[0].getGeneratorDouble();
 | 
	
		
			
				|  |  | +    mnd::MandelInfo mi;
 | 
	
		
			
				|  |  | +    mi.bWidth = evi.width * 2;
 | 
	
		
			
				|  |  | +    mi.bHeight = evi.height * 2;
 | 
	
		
			
				|  |  | +    mi.maxIter = evi.maxIterations;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    VideoStream vs(evi.width, evi.height, evi.path);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    double x = evi.end.x + evi.end.width / 2;
 | 
	
		
			
				|  |  | +    double y = evi.end.y + evi.end.height / 2;
 | 
	
		
			
				|  |  | +    double w = evi.start.width;
 | 
	
		
			
				|  |  | +    double h = evi.start.height;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    double bigW = 10000000000000000.0;
 | 
	
		
			
				|  |  | +    double bigFac = 1.0;
 | 
	
		
			
				|  |  | +    Bitmap<RGBColor> big;
 | 
	
		
			
				|  |  | +    Bitmap<RGBColor> small;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    while(w > evi.end.width || h > evi.end.height) {
 | 
	
		
			
				|  |  | +        mi.view = mnd::MandelViewport{ x - w/2, y - h/2, w, h };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if (bigW > 2 * w) {
 | 
	
		
			
				|  |  | +            Bitmap<float> raw{ evi.width * 2, evi.height * 2 };
 | 
	
		
			
				|  |  | +            gen.generate(mi, raw.pixels.get());
 | 
	
		
			
				|  |  | +            big = raw.map<RGBColor>([] (float x) { return
 | 
	
		
			
				|  |  | +                RGBColor{ uint8_t(::sin(x / 100) * 127 + 127), uint8_t(::sin(x / 213) * 127 + 127), uint8_t(::cos(x / 173) * 127 + 127) };
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +            /*mi.view.zoomCenter(0.5);
 | 
	
		
			
				|  |  | +            gen.generate(mi, raw.pixels.get());
 | 
	
		
			
				|  |  | +            small = raw.map<RGBColor>([] (float x) { return
 | 
	
		
			
				|  |  | +                RGBColor{ uint8_t(::sin(x / 100) * 127 + 127), uint8_t(::sin(x / 213) * 127 + 127), uint8_t(::cos(x / 173) * 127 + 127) };
 | 
	
		
			
				|  |  | +            });*/
 | 
	
		
			
				|  |  | +            bigW = w;
 | 
	
		
			
				|  |  | +            bigFac = 1.0;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        vs.addFrame(overlay(big, small, bigFac));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        w *= 0.99;
 | 
	
		
			
				|  |  | +        h *= 0.99;
 | 
	
		
			
				|  |  | +        bigFac *= 0.99;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +inline RGBColor biliniear(const Bitmap<RGBColor>& img, double x, double y)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    int xfloor = int(::floor(x));
 | 
	
		
			
				|  |  | +    int yfloor = int(::floor(y));
 | 
	
		
			
				|  |  | +    int xceil = int(::ceil(x));
 | 
	
		
			
				|  |  | +    int yceil = int(::ceil(y));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    double xLerp = x - xfloor;
 | 
	
		
			
				|  |  | +    double yLerp = y - yfloor;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    RGBColor samples[2][2] = {
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            img.get(xfloor, yfloor),
 | 
	
		
			
				|  |  | +            img.get(xfloor, yceil),
 | 
	
		
			
				|  |  | +        },
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            img.get(xceil, yfloor),
 | 
	
		
			
				|  |  | +            img.get(xceil, yceil),
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    double r = 0, g = 0, b = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    auto mklin = [] (double x) {
 | 
	
		
			
				|  |  | +        return ::pow(x, 2.4);
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +    auto unlin = [] (double x) {
 | 
	
		
			
				|  |  | +        return ::pow(x, 1.0 / 2.4);
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    r += (1 - xLerp) * (1 - yLerp) * mklin(samples[0][0].r);
 | 
	
		
			
				|  |  | +    r += (1 - xLerp) * yLerp * mklin(samples[0][1].r);
 | 
	
		
			
				|  |  | +    r += xLerp * (1 - yLerp) * mklin(samples[1][0].r);
 | 
	
		
			
				|  |  | +    r += xLerp * yLerp * mklin(samples[1][1].r);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    g += (1 - xLerp) * (1 - yLerp) * mklin(samples[0][0].g);
 | 
	
		
			
				|  |  | +    g += (1 - xLerp) * yLerp * mklin(samples[0][1].g);
 | 
	
		
			
				|  |  | +    g += xLerp * (1 - yLerp) * mklin(samples[1][0].g);
 | 
	
		
			
				|  |  | +    g += xLerp * yLerp * mklin(samples[1][1].g);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    b += (1 - xLerp) * (1 - yLerp) * mklin(samples[0][0].b);
 | 
	
		
			
				|  |  | +    b += (1 - xLerp) * yLerp * mklin(samples[0][1].b);
 | 
	
		
			
				|  |  | +    b += xLerp * (1 - yLerp) * mklin(samples[1][0].b);
 | 
	
		
			
				|  |  | +    b += xLerp * yLerp * mklin(samples[1][1].b);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return RGBColor{ uint8_t(unlin(r)), uint8_t(unlin(g)), uint8_t(unlin(b)) };
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +Bitmap<RGBColor> MandelVideoGenerator::overlay(const Bitmap<RGBColor>& outer,
 | 
	
		
			
				|  |  | +                         const Bitmap<RGBColor>& inner, double scale)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +    printf("%lf\n", scale);
 | 
	
		
			
				|  |  | +    Bitmap<RGBColor> ret{ outer.width / 2, outer.height / 2 };
 | 
	
		
			
				|  |  | +    double newW = outer.width * scale * 2;
 | 
	
		
			
				|  |  | +    double newH = outer.height * scale * 2;
 | 
	
		
			
				|  |  | +    double newX = outer.width * (1 - scale) / 2;
 | 
	
		
			
				|  |  | +    double newY = outer.height * (1 - scale) / 2;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    for (int i = 0; i < ret.height; i++) {
 | 
	
		
			
				|  |  | +        for (int j = 0; j < ret.width; j++) {
 | 
	
		
			
				|  |  | +            double newJ = newX + j * newW / outer.width;
 | 
	
		
			
				|  |  | +            double newI = newY + i * newH / outer.height;
 | 
	
		
			
				|  |  | +            RGBColor a = biliniear(outer, newJ, newI);
 | 
	
		
			
				|  |  | +            ret.get(j, i) = a;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    /*for (int i = 0; i < ret.height * ret.width; i++) {
 | 
	
		
			
				|  |  | +        ret.pixels[i] = outer.pixels[i];
 | 
	
		
			
				|  |  | +    }*/
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return ret;
 | 
	
		
			
				|  |  | +}
 |