/** * ASCII spinning glboe */ #include "colors.h" #include #include #include #include #include #include #include static const double GOLDEN_RATIO = 1.6180339887498948482045868343656381; #define NUM_WAVES 7 // Randomly generated x/y offsets: static const double OFFSETS[2*NUM_WAVES] = { 0.5459919526, 0.6072439135, 0.6217563193, 0.5444045324, 0.8923452588, 0.4626828607, 0.9422234679, 0.7870886548, 0.7425605127, 0.1510923405, 0.3889282293, 0.3730024274, 0.1450487012, 0.9051931355, }; // 0.83^n amplitudes static const double AMPLITUDES[NUM_WAVES] = { 0.83, 0.6889, 0.571787, 0.47458321, 0.3939040643, 0.326940373369, 0.27136050989627 }; // See: https://blog.bruce-hill.com/hill-noise/ static double hillnoise(double x, double y) { double noise = 0; double sigma = 0; for (int i = 0; i < NUM_WAVES; i++) { // Rotate coordinates double rotation = fmod(((float)i)*GOLDEN_RATIO, 1.0)*2.0*M_PI; double u = x*cos(rotation) - y*sin(rotation); double v = -x*sin(rotation) - y*cos(rotation); double size = AMPLITUDES[i]; double offsetx = OFFSETS[2*i]; double offsety = OFFSETS[2*i+1]; noise += (size/2.)*(sin(u/size + offsetx) + sin(v/size + offsety)); sigma += size*size; } sigma = sqrt(sigma)/2.; noise /= 2.*sigma; return (0.5*(noise < 0 ? -1. : 1.)*sqrt(1 - exp(-2./M_PI * noise*noise)) + 0.5); } static double mix(double a, double b, double amount) { return (1.-amount)*a + amount*b; } void draw_stars(double t) { int rows,cols; getmaxyx(stdscr,rows,cols); attron(COLOR_PAIR(WHITE)); for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { double n = hillnoise(r*1,c*2+(t*.04)); if (n > .8) { mvaddch(r,c,n > .9 ? '*' : '.'); } } } attroff(COLOR_PAIR(WHITE)); } static double get_rotation(double t) { return t * (2*M_PI)/60. + M_PI; } void draw_globe(double t, double zoom) { int rows,cols; getmaxyx(stdscr,rows,cols); double rotation = get_rotation(t); const double rho = rows/2.; for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { double y = (c - cols/2) * 0.5 / zoom; double z = (r - rows/2) * 1.0 / zoom; double x = sqrt(rho*rho - z*z - y*y); if (z*z + y*y > rho*rho) { continue; } double theta = atan2(z, sqrt(x*x + y*y)); double phi = fmod(atan2(y, x) + rotation, 2.*M_PI); double elevation = hillnoise(theta*4., phi*4.); double clouds = hillnoise(theta*12., phi*6. - 1.*rotation - 140.); int color; int ch; if ((fabs(z)/rho) > .9) { elevation = elevation + mix(.0, 1., 10.*(fabs(z)/rho - .9)) > .6 ? 1. : 0.; } if (clouds < .4) { continue; } else if (elevation < .55) { // Water ch = '~'; color = COLOR_PAIR(BLUE); } else if (elevation < .65) { // Sand ch = ':'; color = COLOR_PAIR(YELLOW); } else if (elevation < .75) { // Grass ch = ',' | A_BOLD; color = COLOR_PAIR(GREEN); } else if (elevation < .85) { // Forest ch = '&'; color = COLOR_PAIR(GREEN); } else { // Mountain ch = '#'; color = COLOR_PAIR(WHITE); } attron(color); mvaddch(r,c,ch); attroff(color); } } } void draw_clouds(double t, double zoom) { int rows,cols; getmaxyx(stdscr,rows,cols); double rotation = get_rotation(t); const double rho = rows/2.; for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { double y = (c - cols/2) * 0.5 / zoom; double z = (r - rows/2) * 1.0 / zoom; double x = sqrt(rho*rho - z*z - y*y); if (z*z + y*y > rho*rho) { continue; } double theta = atan2(z, sqrt(x*x + y*y)); double phi = fmod(atan2(y, x) + rotation, 2.*M_PI); double clouds = hillnoise(theta*12., phi*6. - 1.*rotation - 140.); int color; int ch; if (clouds < .4) { ch = (clouds < .3 ? '0' : '%') | A_BOLD; color = COLOR_PAIR(WHITE); attron(color); mvaddch(r,c,ch); attroff(color); } } } } int latlon_to_rc(double t, double zoom, double lat, double lon, int *r, int *c) { int rows,cols; getmaxyx(stdscr,rows,cols); const double rho = rows/2.; double theta = lat; double phi = lon + get_rotation(t); double x = rho*sin(theta)*cos(phi); double y = rho*sin(theta)*sin(phi); double z = rho*cos(theta); *r = z / (1.0/zoom) + rows/2; *c = y / (.5/zoom) + cols/2; return x < 0; } const double target_lat = M_PI/2*1.01; const double target_lon = M_PI + 2.6; // return 1 if visible, else 0 int get_target_pos(double t, double zoom, int *targetr, int *targetc) { return latlon_to_rc(t, zoom, target_lat, target_lon, targetr, targetc); }