mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 09:09:03 -04:00
ncvisual_rotate: unify _cw/_ccw, take radians
This commit is contained in:
parent
20d0048838
commit
94fcada67c
@ -9,9 +9,8 @@ rearrangements of Notcurses.
|
||||
has been retained as a deprecated alias. It will be removed by 1.6/2.0.
|
||||
* `ncvisual_from_rgba()` and `ncvisual_from_bgra()` have been added to
|
||||
support creation of `ncvisual`s from memory, requiring no file.
|
||||
* `ncvisual_rotate_cw()` and `ncvisual_rotate_ccw()` have been added, having
|
||||
the same semantics as `ncplane_rotate_cw()` and `ncplane_rotate_ccw()`.
|
||||
They will likely be augmented in the future to support arbitrary rotations.
|
||||
* `ncvisual_rotate()` has been added, supporting rotations of arbitrary
|
||||
radians on `ncvisual` objects.
|
||||
* `ncvisual_from_plane()` has been added to support "promotion" of an
|
||||
`ncplane` to an `ncvisual`. The source plane may contain only spaces,
|
||||
half blocks, and full blocks.
|
||||
|
7
USAGE.md
7
USAGE.md
@ -2436,9 +2436,10 @@ struct ncplane* ncvisual_plane(struct ncvisual* ncv);
|
||||
// of the UTF8 text.
|
||||
char* ncvisual_subtitle(const struct ncvisual* ncv);
|
||||
|
||||
// Rotate the visual π/2 radians clockwise or counterclockwise.
|
||||
int ncvisual_rotate_cw(struct ncvisual* n);
|
||||
int ncvisual_rotate_ccw(struct ncvisual* n);
|
||||
// Rotate the visual 'rads' radians. If we own the bound plane, it is resized
|
||||
// to fit the rotated visual, if necessary. Only M_PI/2 and -M_PI/2 are
|
||||
// supported at the moment, but this will change FIXME.
|
||||
int ncvisual_rotate(struct ncvisual* n, double rads);
|
||||
```
|
||||
|
||||
It is also possible to seed an `ncvisual` directly from memory, without involving
|
||||
|
@ -46,9 +46,7 @@ typedef int (*streamcb)(struct notcurses*, struct ncvisual*, void*);
|
||||
|
||||
**struct ncplane* ncvisual_plane(struct ncvisual* ncv);**
|
||||
|
||||
**int ncvisual_rotate_cw(struct ncvisual* n);**
|
||||
|
||||
**int ncvisual_rotate_ccw(struct ncvisual* n);**
|
||||
**int ncvisual_rotate(struct ncvisual* n, double rads);**
|
||||
|
||||
**char* ncvisual_subtitle(const struct ncvisual* ncv);**
|
||||
|
||||
@ -76,8 +74,10 @@ is necessary. The resulting plane will be ceil(**rows**/2) rows, and **cols**
|
||||
columns. It will not be necessary to call **ncvisual_decode**, but it is
|
||||
still necessary to call **ncvisual_render**.
|
||||
|
||||
Both **ncvisual_rotate_cw** and **ncvisual_rotate_ccw** execute a rotation of
|
||||
π/2 radians, in the clockwise or counterclockwise direction respectively.
|
||||
**ncvisual_rotate** executes a rotation of **rads** radians, in the clockwise
|
||||
(positive) or counterclockwise (negative) direction. If the **ncvisual** owns
|
||||
(created) its underlying **ncplane**, that plane will be resized as necessary
|
||||
to display the entirety of the rotated visual.
|
||||
|
||||
**ncvisual_subtitle** will return a UTF-8-encoded subtitle corresponding to
|
||||
the current frame if such a subtitle was decoded. Note that a subtitle might
|
||||
@ -102,6 +102,11 @@ Multimedia decoding requires that Notcurses be built with either FFmpeg or
|
||||
OpenImageIO support. What formats can be decoded is totally dependent on the
|
||||
linked library. OpenImageIO does not support subtitles.
|
||||
|
||||
# BUGS
|
||||
|
||||
**ncvisual_rotate** currently supports only **M_PI**/2 and -**M_PI**/2
|
||||
radians for **rads**, but this will change soon.
|
||||
|
||||
# SEE ALSO
|
||||
|
||||
**notcurses(3)**,
|
||||
|
@ -84,14 +84,9 @@ namespace ncpp
|
||||
|
||||
Plane* get_plane () const noexcept;
|
||||
|
||||
bool rotate_cw () const NOEXCEPT_MAYBE
|
||||
bool rotate (double rads) const NOEXCEPT_MAYBE
|
||||
{
|
||||
return error_guard (ncvisual_rotate_cw (visual), -1);
|
||||
}
|
||||
|
||||
bool rotate_ccw () const noexcept
|
||||
{
|
||||
return error_guard (ncvisual_rotate_ccw (visual), -1);
|
||||
return error_guard (ncvisual_rotate (visual, rads), -1);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -1136,10 +1136,10 @@ API struct ncplane* ncplane_below(struct ncplane* n);
|
||||
API int ncplane_rotate_cw(struct ncplane* n);
|
||||
API int ncplane_rotate_ccw(struct ncplane* n);
|
||||
|
||||
// Rotate the visual π/2 radians clockwise or counterclockwise. This cannot
|
||||
// be performed on arbitrary planes, because glyphs cannot be arbitrarily rotated.
|
||||
API int ncvisual_rotate_cw(struct ncvisual* n);
|
||||
API int ncvisual_rotate_ccw(struct ncvisual* n);
|
||||
// Rotate the visual 'rads' radians. If we own the bound plane, it is resized
|
||||
// to fit the rotated visual, if necessary. Only M_PI/2 and -M_PI/2 are
|
||||
// supported at the moment, but this will change FIXME.
|
||||
API int ncvisual_rotate(struct ncvisual* n, double rads);
|
||||
|
||||
// Retrieve the current contents of the cell under the cursor. The EGC is
|
||||
// returned, or NULL on error. This EGC must be free()d by the caller. The
|
||||
|
@ -429,8 +429,7 @@ int ncplane_format(struct ncplane* n, int ystop, int xstop, uint32_t attrword);
|
||||
int ncplane_stain(struct ncplane* n, int ystop, int xstop, uint64_t ul, uint64_t ur, uint64_t ll, uint64_t lr);
|
||||
int ncplane_rotate_cw(struct ncplane* n);
|
||||
int ncplane_rotate_ccw(struct ncplane* n);
|
||||
int ncvisual_rotate_cw(struct ncvisual* n);
|
||||
int ncvisual_rotate_ccw(struct ncvisual* n);
|
||||
int ncvisual_rotate(struct ncvisual* n, double rads);
|
||||
void ncplane_translate(const struct ncplane* src, const struct ncplane* dst, int* y, int* x);
|
||||
bool ncplane_translate_abs(const struct ncplane* n, int* y, int* x);
|
||||
typedef enum {
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "version.h"
|
||||
|
||||
@ -131,43 +132,9 @@ int ncvisual_setplane(ncvisual* ncv, ncplane* n){
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ncvisual_rotate_cw(struct ncvisual* ncv){
|
||||
if(ncv->data == NULL){
|
||||
return -1;
|
||||
}
|
||||
ncplane* n = ncvisual_plane(ncv);
|
||||
ncplane* newp = rotate_plane(n);
|
||||
if(newp == NULL){
|
||||
return -1;
|
||||
}
|
||||
//fprintf(stderr, "stride: %d height: %d width: %d\n", ncv->rowstride, ncv->dstheight, ncv->dstwidth);
|
||||
assert(ncv->rowstride / 4 >= ncv->dstwidth);
|
||||
uint32_t* data = static_cast<uint32_t*>(malloc(ncv->dstheight * ncv->dstwidth * 4));
|
||||
if(data == NULL){
|
||||
ncplane_destroy(newp);
|
||||
return -1;
|
||||
}
|
||||
// targy <- x, targx <- ncv->dstheight - y - 1
|
||||
for(int targy = 0 ; targy < ncv->dstwidth ; ++targy){
|
||||
for(int targx = 0 ; targx < ncv->dstheight ; ++targx){
|
||||
const int x = targy;
|
||||
const int y = ncv->dstheight - 1 - targx;
|
||||
//fprintf(stderr, "CW: %d/%d (%08x) -> %d/%d (stride: %d)\n", y, x, ncv->data[y * (ncv->rowstride / 4) + x], targy, targx, ncv->rowstride);
|
||||
data[targy * ncv->dstheight + targx] = ncv->data[y * (ncv->rowstride / 4) + x];
|
||||
//fprintf(stderr, "wrote %08x to %d (%d)\n", data[targy * ncv->dstheight + targx], targy * ncv->dstheight + targx, (targy * ncv->dstheight + targx) * 4);
|
||||
}
|
||||
}
|
||||
int ret = ncplane_destroy(n);
|
||||
ncvisual_set_data(ncv, data, true);
|
||||
int tmp = ncv->dstwidth;
|
||||
ncv->dstwidth = ncv->dstheight;
|
||||
ncv->dstheight = tmp;
|
||||
ncv->rowstride = ncv->dstwidth * 4;
|
||||
ncv->ncp = newp;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ncvisual_rotate_ccw(struct ncvisual* ncv){
|
||||
// pi/2 rads counterclockwise
|
||||
static int
|
||||
ncvisual_rotate_ccw(struct ncvisual* ncv){
|
||||
if(ncv->data == NULL){
|
||||
return -1;
|
||||
}
|
||||
@ -205,6 +172,48 @@ int ncvisual_rotate_ccw(struct ncvisual* ncv){
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ncvisual_rotate(struct ncvisual* ncv, double rads){
|
||||
if(rads == -M_PI / 2){
|
||||
return ncvisual_rotate_ccw(ncv);
|
||||
}
|
||||
if(rads != M_PI / 2){
|
||||
return -1;
|
||||
}
|
||||
if(ncv->data == NULL){
|
||||
return -1;
|
||||
}
|
||||
ncplane* n = ncvisual_plane(ncv);
|
||||
ncplane* newp = rotate_plane(n);
|
||||
if(newp == NULL){
|
||||
return -1;
|
||||
}
|
||||
//fprintf(stderr, "stride: %d height: %d width: %d\n", ncv->rowstride, ncv->dstheight, ncv->dstwidth);
|
||||
assert(ncv->rowstride / 4 >= ncv->dstwidth);
|
||||
uint32_t* data = static_cast<uint32_t*>(malloc(ncv->dstheight * ncv->dstwidth * 4));
|
||||
if(data == NULL){
|
||||
ncplane_destroy(newp);
|
||||
return -1;
|
||||
}
|
||||
// targy <- x, targx <- ncv->dstheight - y - 1
|
||||
for(int targy = 0 ; targy < ncv->dstwidth ; ++targy){
|
||||
for(int targx = 0 ; targx < ncv->dstheight ; ++targx){
|
||||
const int x = targy;
|
||||
const int y = ncv->dstheight - 1 - targx;
|
||||
//fprintf(stderr, "CW: %d/%d (%08x) -> %d/%d (stride: %d)\n", y, x, ncv->data[y * (ncv->rowstride / 4) + x], targy, targx, ncv->rowstride);
|
||||
data[targy * ncv->dstheight + targx] = ncv->data[y * (ncv->rowstride / 4) + x];
|
||||
//fprintf(stderr, "wrote %08x to %d (%d)\n", data[targy * ncv->dstheight + targx], targy * ncv->dstheight + targx, (targy * ncv->dstheight + targx) * 4);
|
||||
}
|
||||
}
|
||||
int ret = ncplane_destroy(n);
|
||||
ncvisual_set_data(ncv, data, true);
|
||||
int tmp = ncv->dstwidth;
|
||||
ncv->dstwidth = ncv->dstheight;
|
||||
ncv->dstheight = tmp;
|
||||
ncv->rowstride = ncv->dstwidth * 4;
|
||||
ncv->ncp = newp;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ncvisual* ncvisual_from_rgba(notcurses* nc, const void* rgba, int rows,
|
||||
int rowstride, int cols){
|
||||
if(rowstride % 4){
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "main.h"
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
void RotateCW(struct notcurses* nc, struct ncplane* n) {
|
||||
@ -113,16 +114,16 @@ TEST_CASE("Rotate") {
|
||||
REQUIRE(ncv);
|
||||
CHECK(dimx * dimy / 8 <= ncvisual_render(ncv, 0, 0, -1, -1));
|
||||
CHECK(0 == notcurses_render(nc_));
|
||||
CHECK(0 == ncvisual_rotate_cw(ncv));
|
||||
CHECK(0 == ncvisual_rotate(ncv, M_PI/2));
|
||||
CHECK(dimx * dimy / 8 <= ncvisual_render(ncv, 0, 0, -1, -1));
|
||||
CHECK(0 == notcurses_render(nc_));
|
||||
CHECK(0 == ncvisual_rotate_cw(ncv));
|
||||
CHECK(0 == ncvisual_rotate(ncv, M_PI/2));
|
||||
CHECK(dimx * dimy / 8 <= ncvisual_render(ncv, 0, 0, -1, -1));
|
||||
CHECK(0 == notcurses_render(nc_));
|
||||
CHECK(0 == ncvisual_rotate_cw(ncv));
|
||||
CHECK(0 == ncvisual_rotate(ncv, M_PI/2));
|
||||
CHECK(dimx * dimy / 8 <= ncvisual_render(ncv, 0, 0, -1, -1));
|
||||
CHECK(0 == notcurses_render(nc_));
|
||||
CHECK(0 == ncvisual_rotate_cw(ncv));
|
||||
CHECK(0 == ncvisual_rotate(ncv, M_PI/2));
|
||||
CHECK(dimx * dimy / 8 <= ncvisual_render(ncv, 0, 0, -1, -1));
|
||||
CHECK(0 == notcurses_render(nc_));
|
||||
ncvisual_destroy(ncv);
|
||||
@ -135,16 +136,16 @@ TEST_CASE("Rotate") {
|
||||
REQUIRE(ncv);
|
||||
CHECK(dimx * dimy / 4 == ncvisual_render(ncv, 0, 0, -1, -1));
|
||||
CHECK(0 == notcurses_render(nc_));
|
||||
CHECK(0 == ncvisual_rotate_ccw(ncv));
|
||||
CHECK(0 == ncvisual_rotate(ncv, -M_PI/2));
|
||||
CHECK(dimx * dimy / 4 == ncvisual_render(ncv, 0, 0, -1, -1));
|
||||
CHECK(0 == notcurses_render(nc_));
|
||||
CHECK(0 == ncvisual_rotate_ccw(ncv));
|
||||
CHECK(0 == ncvisual_rotate(ncv, -M_PI/2));
|
||||
CHECK(dimx * dimy / 4 == ncvisual_render(ncv, 0, 0, -1, -1));
|
||||
CHECK(0 == notcurses_render(nc_));
|
||||
CHECK(0 == ncvisual_rotate_ccw(ncv));
|
||||
CHECK(0 == ncvisual_rotate(ncv, -M_PI/2));
|
||||
CHECK(dimx * dimy / 4 == ncvisual_render(ncv, 0, 0, -1, -1));
|
||||
CHECK(0 == notcurses_render(nc_));
|
||||
CHECK(0 == ncvisual_rotate_ccw(ncv));
|
||||
CHECK(0 == ncvisual_rotate(ncv, -M_PI/2));
|
||||
CHECK(dimx * dimy / 4 == ncvisual_render(ncv, 0, 0, -1, -1));
|
||||
CHECK(0 == notcurses_render(nc_));
|
||||
ncvisual_destroy(ncv);
|
||||
|
Loading…
x
Reference in New Issue
Block a user