You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
248 lines
6.3 KiB
C
248 lines
6.3 KiB
C
#include "demo.h"
|
|
#include <math.h>
|
|
#include <complex.h>
|
|
|
|
static int
|
|
rotate_plane(struct notcurses* nc, struct ncplane* n){
|
|
struct timespec scaled;
|
|
timespec_div(&demodelay, 2, &scaled);
|
|
// we can't rotate a plane unless it has an even number of columns :/
|
|
int nx;
|
|
if((nx = ncplane_dim_x(n)) % 2){
|
|
if(ncplane_resize_simple(n, ncplane_dim_y(n), --nx)){
|
|
return -1;
|
|
}
|
|
}
|
|
for(int i = 0 ; i < 16 ; ++i){
|
|
demo_nanosleep(nc, &scaled);
|
|
int centy, centx;
|
|
ncplane_center_abs(n, ¢y, ¢x);
|
|
if(ncplane_rotate_cw(n)){
|
|
return -1;
|
|
}
|
|
int cent2y, cent2x;
|
|
int absy, absx;
|
|
ncplane_center_abs(n, ¢2y, ¢2x);
|
|
ncplane_yx(n, &absy, &absx);
|
|
ncplane_move_yx(n, absy + centy - cent2y, absx + centx - cent2x);
|
|
DEMO_RENDER(nc);
|
|
timespec_mul(&scaled, 2, &scaled);
|
|
timespec_div(&scaled, 3, &scaled);
|
|
}
|
|
timespec_div(&demodelay, 2, &scaled);
|
|
for(int i = 0 ; i < 16 ; ++i){
|
|
demo_nanosleep(nc, &scaled);
|
|
int centy, centx;
|
|
ncplane_center_abs(n, ¢y, ¢x);
|
|
if(ncplane_rotate_ccw(n)){
|
|
return -1;
|
|
}
|
|
int cent2y, cent2x;
|
|
int absy, absx;
|
|
ncplane_center_abs(n, ¢2y, ¢2x);
|
|
ncplane_yx(n, &absy, &absx);
|
|
ncplane_move_yx(n, absy + centy - cent2y, absx + centx - cent2x);
|
|
DEMO_RENDER(nc);
|
|
timespec_mul(&scaled, 2, &scaled);
|
|
timespec_div(&scaled, 3, &scaled);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
rotate_visual(struct notcurses* nc, struct ncplane* n, int dy, int dx){
|
|
struct timespec scaled;
|
|
int r = 0;
|
|
timespec_div(&demodelay, 8, &scaled);
|
|
int fromy = 0, fromx = 0;
|
|
if(dy * 2 > dx){
|
|
fromy = (dy * 2 - dx) / 2;
|
|
dy = dx / 2;
|
|
}else{
|
|
fromx = (dx - dy * 2) / 2;
|
|
dx = dy * 2;
|
|
}
|
|
//fprintf(stderr, "ASK %d/%d @ %d/%d: %p\n", dy, dx, fromy, fromx);
|
|
struct ncvisual* ncv = ncvisual_from_plane(n, NCBLIT_DEFAULT, fromy, fromx, dy, dx);
|
|
//fprintf(stderr, "%d/%d @ %d/%d: %p\n", dy, dx, fromy, fromx, ncv);
|
|
if(!ncv){
|
|
ncvisual_destroy(ncv);
|
|
return -1;
|
|
}
|
|
ncplane_destroy(n);
|
|
int dimy, dimx;
|
|
struct ncplane* stdn = notcurses_stddim_yx(nc, &dimy, &dimx);
|
|
const int ROTATIONS = 32;
|
|
timespec_div(&demodelay, ROTATIONS / 2, &scaled);
|
|
struct ncvisual_options vopts = { };
|
|
ncplane_erase(stdn);
|
|
struct ncvisual* nncv = NULL;
|
|
if(notcurses_canopen_images(nc)){
|
|
char* path = find_data("normal.png");
|
|
if(path){
|
|
nncv = ncvisual_from_file(path);
|
|
if(nncv){
|
|
struct ncvisual_options nvopts = {
|
|
.n = stdn,
|
|
.scaling = NCSCALE_STRETCH,
|
|
};
|
|
if(ncvisual_render(nc, nncv, &nvopts) == NULL){
|
|
return -1;
|
|
}
|
|
}
|
|
free(path);
|
|
}
|
|
}
|
|
for(double i = 0 ; i < ROTATIONS ; ++i){
|
|
demo_nanosleep(nc, &scaled);
|
|
if(ncvisual_rotate(ncv, -M_PI / (i / 8 + 2))){
|
|
r = -1;
|
|
break;
|
|
}
|
|
vopts.x = NCALIGN_CENTER;
|
|
vopts.y = NCALIGN_CENTER;
|
|
vopts.flags |= NCVISUAL_OPTION_HORALIGNED | NCVISUAL_OPTION_VERALIGNED;
|
|
struct ncplane* newn;
|
|
if((newn = ncvisual_render(nc, ncv, &vopts)) == NULL){
|
|
r = -1;
|
|
break;
|
|
}
|
|
if( (r = demo_render(nc)) ){
|
|
break;
|
|
}
|
|
ncplane_destroy(newn);
|
|
}
|
|
ncvisual_destroy(nncv);
|
|
ncvisual_destroy(ncv);
|
|
return r;
|
|
}
|
|
|
|
static const int ITERMAX = 256;
|
|
|
|
static int
|
|
mandelbrot(int y, int x, int dy, int dx){
|
|
float complex c = (x - dx / 2.0) * 4.0 / dx + I * (y - dy / 2.0) * 4.0 / dx;
|
|
float fx = 0;
|
|
float fy = 0;
|
|
int iter = 0;
|
|
while(fx * fx + fy * fy <= 4 && iter < ITERMAX){
|
|
float ffx = fx * fx - fy * fy + crealf(c);
|
|
fy = 2 * fx * fy + cimagf(c);
|
|
fx = ffx;
|
|
++iter;
|
|
}
|
|
return iter;
|
|
}
|
|
|
|
// write an rgba pixel
|
|
static int
|
|
mcell(uint32_t* c, int y, int x, int dy, int dx){
|
|
int iter = mandelbrot(y, x, dy, dx);
|
|
int color = sqrt((double)iter / ITERMAX) * 255;
|
|
*c = ncpixel(color, color, color);
|
|
return 0;
|
|
}
|
|
|
|
static uint32_t*
|
|
offset(uint32_t* rgba, int y, int x, int dx){
|
|
return rgba + y * dx + x;
|
|
}
|
|
|
|
// make a pixel array out from the center, blitting it as we go
|
|
int normal_demo(struct notcurses* nc){
|
|
int dy, dx;
|
|
int r = -1;
|
|
struct ncplane* nstd = notcurses_stddim_yx(nc, &dy, &dx);
|
|
ncplane_erase(nstd);
|
|
nccell c = CELL_TRIVIAL_INITIALIZER;
|
|
nccell_set_fg_rgb8(&c, 0x0, 0x0, 0x0);
|
|
nccell_set_bg_rgb8(&c, 0x0, 0x0, 0x0);
|
|
ncplane_set_base_cell(nstd, &c);
|
|
nccell_release(nstd, &c);
|
|
struct ncplane* n = NULL;
|
|
struct ncvisual_options vopts = {
|
|
.n = nstd,
|
|
};
|
|
int yscale, xscale;
|
|
ncvisual_blitter_geom(nc, NULL, &vopts, NULL, NULL, &yscale, &xscale, NULL);
|
|
dy *= yscale;
|
|
dx *= xscale;
|
|
uint32_t* rgba = malloc(sizeof(*rgba) * dy * dx);
|
|
if(!rgba){
|
|
goto err;
|
|
}
|
|
for(int off = 0 ; off < dy * dx ; ++off){
|
|
rgba[off] = 0xff000000;
|
|
}
|
|
int y;
|
|
if(dy / yscale % 2){
|
|
y = dy / yscale + 1;
|
|
for(int x = 0 ; x < dx ; ++x){
|
|
if(mcell(offset(rgba, y, x, dx), y, x, dy / yscale, dx)){
|
|
goto err;
|
|
}
|
|
}
|
|
}
|
|
struct timespec scaled;
|
|
timespec_div(&demodelay, dy, &scaled);
|
|
for(y = 0 ; y <= dy / 2 ; ++y){
|
|
for(int x = 0 ; x < dx ; ++x){
|
|
if(mcell(offset(rgba, dy / 2 - y, x, dx), dy / 2 - y, x, dy, dx)){
|
|
goto err;
|
|
}
|
|
if(mcell(offset(rgba, dy / 2 + y - 1, x, dx), dy / 2 + y - 1, x, dy, dx)){
|
|
goto err;
|
|
}
|
|
}
|
|
vopts.leny = dy;
|
|
vopts.lenx = dx;
|
|
if(ncblit_rgba(rgba, dx * sizeof(*rgba), &vopts) < 0){
|
|
goto err;
|
|
}
|
|
if( (r = demo_render(nc)) ){
|
|
goto err;
|
|
}
|
|
r = -1;
|
|
demo_nanosleep(nc, &scaled);
|
|
}
|
|
free(rgba);
|
|
rgba = NULL;
|
|
// we can't resize (and thus can't rotate) the standard plane, so dup it
|
|
n = ncplane_dup(nstd, NULL);
|
|
if(n == NULL){
|
|
goto err;
|
|
}
|
|
if(notcurses_canutf8(nc)){
|
|
ncplane_erase(nstd);
|
|
ncplane_home(n);
|
|
if( (r = rotate_plane(nc, n)) ){
|
|
goto err;
|
|
}
|
|
}
|
|
ncplane_home(n);
|
|
uint64_t tl, tr, bl, br;
|
|
tl = tr = bl = br = 0;
|
|
ncchannels_set_fg_rgb8(&tl, 0, 0, 0);
|
|
ncchannels_set_fg_rgb8(&tr, 0, 0xff, 0);
|
|
ncchannels_set_fg_rgb8(&bl, 0xff, 0, 0xff);
|
|
ncchannels_set_fg_rgb8(&br, 0, 0, 0);
|
|
ncplane_dim_yx(n, &dy, &dx);
|
|
if(ncplane_stain(n, dy - 1, dx - 1, tl, tr, bl, br) < 0){
|
|
goto err;
|
|
}
|
|
DEMO_RENDER(nc);
|
|
timespec_div(&demodelay, 2, &scaled);
|
|
demo_nanosleep(nc, &scaled);
|
|
nccell_set_fg_rgb8(&c, 0, 0, 0);
|
|
nccell_set_bg_rgb8(&c, 0, 0, 0);
|
|
ncplane_set_base_cell(nstd, &c);
|
|
nccell_release(nstd, &c);
|
|
r = rotate_visual(nc, n, dy, dx);
|
|
return r;
|
|
|
|
err:
|
|
free(rgba);
|
|
ncplane_destroy(n);
|
|
return r;
|
|
}
|