Update: I realized that by trying to show off too many features of LTemplate, I made an overengineered mess that will sooner deter people from LTemplate then attract them. Here's a single function solution, which is 95% as good as the complicated one below, but much shorter.
template =
LClass["CliffordAttractor2",
{LFun["compute", {{Real, 1}, Integer (* iterations *), Integer (*
image width *)}, Image]}
];
code = "
#include <cmath>
using namespace std;
using namespace mma;
struct CliffordAttractor2 {
GenericImageRef compute(RealTensorRef param, mint n, mint size) {
massert(param.size() == 4 && size > 0);
double a, b, c, d, h, w;
a = param[0]; b = param[1]; c = param[2]; d = param[3];
w = 1 + abs(c);
h = 1 + abs(d);
auto image = makeImage<float>(size, size * (h/w));
std::fill(image.begin(), image.end(), 0.0f);
double x = 0, y = 0;
for (mint i=0; i < n; ++i) {
double newx, newy;
newx = sin(a*y) + c*cos(a*x);
newy = sin(b*x) + d*cos(b*y);
x = newx; y = newy;
image( (image.rows()-1) * (y+h)/(2*h), (image.cols()-1) * (x+w)/(2*w) ) += 1;
}
return image;
}
};
";
Export["CliffordAttractor2.h", code, "String"];
CompileTemplate[template, "CompileOptions" -> {"-ffast-math"}]
LoadTemplate[template]
cliff = Make[CliffordAttractor2];
im = cliff@"compute"[{-1.7, 1.3, -0.1, -1.2}, 100000000, 400];
Colorize[ImageAdjust[im]^0.15,
ColorFunction -> (Blend[{White, RGBColor[
0.97, 0.9500000000000001, 0.79], RGBColor[
0.97, 0.25, 0.04]}, #] &)]