notcurses/tests/rotate.cpp
nick black 354152b48b
Redefine CELL_ALPHA_ in their natural forms
CELL_ALPHA_OPAQUE et al were defined as 0..3, meaning
CELL_ALPHA_SHIFT had to be used to compare them to their
channel representations. Instead, define them in said
representation outright, eliminating the need to shift while
retaining arithmetic properties, and zero initialization for
CELL_ALPHA_OPAQUE. Eliminate CELL_ALPHA_SHIFT #738.
2020-06-28 01:53:42 -04:00

216 lines
7.5 KiB
C++

#include "main.h"
#include <cmath>
#include <vector>
void RotateCW(struct notcurses* nc, struct ncplane* n) {
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_cw(n));
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_cw(n));
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_cw(n));
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_cw(n));
CHECK(0 == notcurses_render(nc));
}
void RotateCCW(struct notcurses* nc, struct ncplane* n) {
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_ccw(n));
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_ccw(n));
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_ccw(n));
CHECK(0 == notcurses_render(nc));
CHECK(0 == ncplane_rotate_ccw(n));
CHECK(0 == notcurses_render(nc));
}
TEST_CASE("Rotate") {
if(!enforce_utf8()){
return;
}
auto nc_ = testing_notcurses();
if(!nc_){
return;
}
int dimy, dimx;
struct ncplane* n_ = notcurses_stddim_yx(nc_, &dimy, &dimx);
REQUIRE(n_);
uint64_t ul, ur, ll, lr;
ul = ur = ll = lr = 0;
channels_set_fg(&ul, 0x40f040);
channels_set_bg(&ul, 0x40f040);
channels_set_fg(&ll, 0xf040f0);
channels_set_bg(&ll, 0xf040f0);
channels_set_fg(&ur, 0x40f040);
channels_set_bg(&ur, 0x40f040);
channels_set_fg(&lr, 0xf040f0);
channels_set_bg(&lr, 0xf040f0);
SUBCASE("RotateTransparentCW") {
struct ncplane* testn = ncplane_new(nc_, 8, 16, dimy / 2, dimx / 2, nullptr);
uint64_t channels = 0;
CHECK(0 == channels_set_fg_alpha(&channels, CELL_ALPHA_TRANSPARENT));
CHECK(0 == channels_set_bg_alpha(&channels, CELL_ALPHA_TRANSPARENT));
REQUIRE(0 >= ncplane_set_base(testn, "", 0, channels));
cell tl = CELL_TRIVIAL_INITIALIZER; cell tr = CELL_TRIVIAL_INITIALIZER;
cell bl = CELL_TRIVIAL_INITIALIZER; cell br = CELL_TRIVIAL_INITIALIZER;
cell hl = CELL_TRIVIAL_INITIALIZER; cell vl = CELL_TRIVIAL_INITIALIZER;
CHECK(-1 < cell_prime(testn, &tl, "", 0, ul));
CHECK(-1 < cell_prime(testn, &tr, "", 0, ur));
CHECK(-1 < cell_prime(testn, &bl, "", 0, ll));
CHECK(-1 < cell_prime(testn, &br, "", 0, lr));
CHECK(-1 < cell_prime(testn, &hl, "", 0, ll));
CHECK(-1 < cell_prime(testn, &vl, "", 0, lr));
CHECK(0 == ncplane_perimeter(testn, &tl, &tr, &bl, &br, &hl, &vl, 0));
RotateCW(nc_, testn);
cell_release(testn, &tl); cell_release(testn, &tr);
cell_release(testn, &bl); cell_release(testn, &br);
cell_release(testn, &hl); cell_release(testn, &vl);
CHECK(0 == ncplane_destroy(testn));
}
SUBCASE("RotateGradientCW") {
// should be a square, and should remain a square through rotations
struct ncplane* testn = ncplane_new(nc_, 8, 16, dimy / 2, dimx / 2, nullptr);
REQUIRE(0 < ncplane_gradient_sized(testn, " ", 0, ul, ur, ll, lr, 8, 16));
RotateCW(nc_, testn);
CHECK(0 == ncplane_destroy(testn));
}
SUBCASE("RotateRectangleCW") {
// should be a square, and should remain a square through rotations
struct ncplane* testn = ncplane_new(nc_, 8, 32, dimy / 2, dimx / 2, nullptr);
REQUIRE(0 < ncplane_gradient_sized(testn, " ", 0, ul, ur, ll, lr, 8, 32));
RotateCW(nc_, testn);
CHECK(0 == ncplane_destroy(testn));
}
SUBCASE("RotateGradientCCW") {
// should be a square, and should remain a square through rotations
struct ncplane* testn = ncplane_new(nc_, 8, 16, dimy / 2, dimx / 2, nullptr);
REQUIRE(0 < ncplane_gradient_sized(testn, " ", 0, ul, ur, ll, lr, 8, 16));
RotateCCW(nc_, testn);
CHECK(0 == ncplane_destroy(testn));
}
SUBCASE("RotateRectangleCCW") {
// should be a square, and should remain a square through rotations
struct ncplane* testn = ncplane_new(nc_, 8, 32, 0, 0, nullptr);
REQUIRE(0 < ncplane_gradient_sized(testn, " ", 0, ul, ur, ll, lr, 8, 32));
RotateCCW(nc_, testn);
CHECK(0 == ncplane_destroy(testn));
}
// use half of each dimension
SUBCASE("RotateRGBACW") {
int height = dimy / 2;
int width = dimx / 2;
std::vector<uint32_t> rgba(width * height, 0xffbbccff);
for(int i = 0 ; i < height * width / 2 ; ++i){
CHECK(0xffbbccff == rgba[i]);
}
auto ncv = ncvisual_from_rgba(rgba.data(), height, width * 4, width);
REQUIRE(ncv);
ncvisual_options opts{};
auto rendered = ncvisual_render(nc_, ncv, &opts);
REQUIRE(rendered);
uint32_t* rgbaret = ncplane_rgba(rendered, NCBLIT_DEFAULT, 0, 0, -1, -1);
REQUIRE(rgbaret);
for(int i = 0 ; i < height * width / 2 ; ++i){
if(rgbaret[i] & CELL_BG_RGB_MASK){
CHECK(rgbaret[i] == rgba[i]);
}
}
free(rgbaret);
CHECK(0 == notcurses_render(nc_));
for(int x = 0 ; x < width ; ++x){
uint32_t attrword;
uint64_t channels;
char* c = notcurses_at_yx(nc_, 0, x, &attrword, &channels);
REQUIRE(c);
CHECK(0 == strcmp(c, " "));
if(channels_fg(channels) & CELL_BG_RGB_MASK){
CHECK(0xffccbb == channels_fg(channels));
}
if(channels_bg(channels) & CELL_BG_RGB_MASK){
CHECK(0xffccbb == channels_bg(channels));
}
free(c);
}
opts.n = rendered;
// FIXME check pixels after all rotations
CHECK(0 == ncvisual_rotate(ncv, M_PI / 2));
CHECK(ncvisual_render(nc_, ncv, &opts));
CHECK(0 == notcurses_render(nc_));
CHECK(0 == ncvisual_rotate(ncv, M_PI / 2));
CHECK(ncvisual_render(nc_, ncv, &opts));
CHECK(0 == notcurses_render(nc_));
CHECK(0 == ncvisual_rotate(ncv, M_PI / 2));
CHECK(ncvisual_render(nc_, ncv, &opts));
CHECK(0 == notcurses_render(nc_));
CHECK(0 == ncvisual_rotate(ncv, M_PI / 2));
CHECK(ncvisual_render(nc_, ncv, &opts));
CHECK(0 == notcurses_render(nc_));
ncvisual_destroy(ncv);
ncplane_destroy(rendered);
CHECK(0 == notcurses_render(nc_));
}
SUBCASE("RotateRGBACCW") {
int height = dimy / 2;
int width = dimx / 2;
std::vector<uint32_t> rgba(width * height, 0xffbbccff);
auto ncv = ncvisual_from_rgba(rgba.data(), height, width * 4, width);
REQUIRE(ncv);
ncvisual_options opts{};
auto rendered = ncvisual_render(nc_, ncv, &opts);
REQUIRE(rendered);
uint32_t* rgbaret = ncplane_rgba(rendered, NCBLIT_DEFAULT, 0, 0, -1, -1);
REQUIRE(rgbaret);
for(int i = 0 ; i < height * width / 2 ; ++i){
if(rgbaret[i] & CELL_BG_RGB_MASK){
CHECK(rgbaret[i] == rgba[i]);
}
}
free(rgbaret);
CHECK(0 == notcurses_render(nc_));
for(int x = 0 ; x < width ; ++x){
uint32_t attrword;
uint64_t channels;
char* c = notcurses_at_yx(nc_, 0, x, &attrword, &channels);
REQUIRE(c);
CHECK(0 == strcmp(c, " "));
if(channels_fg(channels) & CELL_BG_RGB_MASK){
CHECK(0xffccbb == channels_fg(channels));
}
if(channels_bg(channels) & CELL_BG_RGB_MASK){
CHECK(0xffccbb == channels_bg(channels));
}
free(c);
}
// FIXME check pixels after all rotations
opts.n = rendered;
CHECK(0 == ncvisual_rotate(ncv, -M_PI / 2));
CHECK(ncvisual_render(nc_, ncv, &opts));
CHECK(0 == notcurses_render(nc_));
CHECK(0 == ncvisual_rotate(ncv, -M_PI / 2));
CHECK(ncvisual_render(nc_, ncv, &opts));
CHECK(0 == notcurses_render(nc_));
CHECK(0 == ncvisual_rotate(ncv, -M_PI / 2));
CHECK(ncvisual_render(nc_, ncv, &opts));
CHECK(0 == notcurses_render(nc_));
CHECK(0 == ncvisual_rotate(ncv, -M_PI / 2));
CHECK(ncvisual_render(nc_, ncv, &opts));
CHECK(0 == notcurses_render(nc_));
ncvisual_destroy(ncv);
ncplane_destroy(rendered);
CHECK(0 == notcurses_render(nc_));
}
CHECK(0 == notcurses_stop(nc_));
}