Created
December 31, 2016 11:50
-
-
Save Erkaman/0a9e5a6177ffd8345cdaec50a9e4b354 to your computer and use it in GitHub Desktop.
black-white-animation. Source code of this https://twitter.com/erkaman2/status/815151845068992512
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <math.h> | |
#include <stdlib.h> | |
#include <vector> | |
#include <string> | |
using std::vector; | |
using std::string; | |
using std::to_string; | |
#define PI 3.14 | |
const int WIDTH = 512; | |
const int HEIGHT = 512; | |
std::string zeroPad(int n, int len) { | |
string str = ""; | |
str = to_string(n); | |
while(str.size() < len) { | |
str = "0" + str; | |
} | |
return str; | |
} | |
class vec2 { | |
public: | |
float x; | |
float y; | |
vec2(float x, float y) { | |
this->x = x; | |
this->y = y; | |
} | |
vec2() { | |
this->x = this->y = 0; | |
} | |
}; | |
void makeSpiky(FILE* fp, float rad, string color) { | |
int N = 24; | |
// spiky center in image center. | |
float PX = WIDTH/2; | |
float PY = HEIGHT/2; | |
vector<vec2> pos(N); | |
float SMALLR = rad * 0.20f; | |
float LOL = rad * 0.05f; | |
const int NR = 8; | |
float rads[NR] = { | |
rad + SMALLR, | |
rad + SMALLR, | |
// rad + LOL, | |
rad - SMALLR, | |
rad - SMALLR, | |
// rad - LOL, | |
rad + SMALLR, | |
rad + SMALLR, | |
// rad + LOL, | |
rad - SMALLR, | |
rad - SMALLR, | |
// rad - LOL, | |
}; | |
int ir = 0; | |
// generate points on circle. But displace the points in direction of normal. | |
// so that it becomes spiky. | |
for(int i = 0; i < N; i++) { | |
float theta = (i / (float)N) * 2.0 * PI; | |
float R = rads[ir]; | |
ir = (ir + 1) % NR; | |
pos[i].x = PX + R * cos(theta); | |
pos[i].y = PY + R * sin(theta); | |
} | |
string str; | |
// now make line paths between the generated points. | |
for(int i = 0; i < (N+1); i++) { | |
vec2 v = pos[(i) % N]; | |
if(i == 0) { | |
// for first point, we just position the cursor. | |
str += "<path d=\"M" + to_string(v.x) + ", " + to_string(v.y); | |
} else { | |
str += "L " + to_string(v.x) + " " + to_string(v.y) + " "; | |
} | |
} | |
str += "Z\n"; // close loop. path is now done. | |
str += "\" />"; | |
float strokeWidth = 2.0f + 10.0f * (rad / 100.0f); | |
if(strokeWidth > 4.0f) { // clamp stroke-width to max 8.0f | |
strokeWidth = 4.0f; | |
} | |
fprintf(fp,"<g fill=\"white\" stroke=\"black\" stroke-width=\"%f\" fill-opacity=\"1.0\">", strokeWidth); | |
fprintf(fp,"%s", str.c_str() ); | |
fprintf(fp,"</g>"); | |
} | |
struct Star { | |
float rad; | |
string color; | |
Star(float rad, string color) { | |
this->rad = rad; | |
this->color = color; | |
} | |
}; | |
int main(int argc, char** argv) { | |
// create output dir. | |
system("mkdir -p temp/"); | |
float START_RAD = 3.0f; | |
float SPAWN_RAD = 40.0f; | |
float VEL = 2.0f; | |
// colors of spikys. | |
const int NC = 3; | |
string colors[NC] = { | |
/* "#990022", | |
"#888822", | |
"#9C8066", | |
*/ | |
"#FFFFFF", | |
"#FFFFFF", | |
"#FFFFFF" | |
}; | |
int frames = NC * (ceil( (SPAWN_RAD - START_RAD)/VEL )); | |
printf("frames: %d\n", frames); | |
int ic = 0; | |
string curColor = colors[ic]; | |
vector<Star> stars; | |
stars.push_back(Star(START_RAD, curColor)); | |
for(int i = 0; i < 300; i++) { // 1000 | |
FILE* fp = fopen(("temp/out" + zeroPad(i, 5) + ".svg").c_str(), "w"); | |
fprintf(fp, "<svg width=\"%f\" height=\"%f\" version=\"1.1\" baseProfile=\"full\" xmlns=\"http://www.w3.org/2000/svg\">\n", (float)WIDTH, (float)HEIGHT); | |
// clear to black background. | |
fprintf(fp,"<rect "); | |
fprintf(fp,"width=\"%d\" ", WIDTH); | |
fprintf(fp,"height=\"%d\" ", HEIGHT); | |
fprintf(fp,"x=\"0\" "); | |
fprintf(fp,"y=\"0\" "); | |
fprintf(fp,"fill=\"#FFFFFF\"/>\n"); | |
for(int j = 0; j < stars.size(); j++) { | |
Star& star = stars[j]; | |
makeSpiky(fp, star.rad, star.color); | |
star.rad+=VEL; // spiky velocity. | |
} | |
// once last spiky is big enough, spawn another one. | |
const float& lastRad = stars[stars.size()-1].rad; | |
if(lastRad > SPAWN_RAD) { | |
ic = (ic+1)%NC; | |
curColor = colors[ic]; | |
stars.push_back(Star(START_RAD, curColor)); | |
} | |
fprintf(fp, "</svg>"); | |
fclose(fp); | |
} | |
printf("created svgs\n"); | |
// system("cd temp/ && for i in out00257.svg; do rsvg-convert $i -o `echo $i | sed -e 's/svg$/png/'`; done && open out00257.png"); | |
system("cd temp/ && for i in *.svg; do rsvg-convert $i -o `echo $i | sed -e 's/svg$/png/'`; done"); | |
printf("converted svgs to png\n"); | |
// frames from (225) to (225+58) makes a good loop. | |
system("cd temp/ && ffmpeg -start_number 225 -y -framerate 30 -i out%05d.png -vframes 58 -c:v libx264 -vf \"scale=512:512\" -r 30 ../out.mp4 "); | |
printf("encoded to mp4\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment