diff --git a/CMakeLists.txt b/CMakeLists.txt index c57f3514d..a7d67cdbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,9 @@ pkg_check_modules(AVUTIL REQUIRED libavutil>=56.0) pkg_check_modules(SWSCALE REQUIRED libswscale>=5.0) endif() find_library(LIBRT rt) +if(${USE_TESTS}) find_package(doctest 2.3.5 REQUIRED) +endif() # libnotcurses file(GLOB NCSRCS CONFIGURE_DEPENDS src/lib/*.c) @@ -69,11 +71,13 @@ target_include_directories(notcurses-static ) target_link_libraries(notcurses PRIVATE + Threads::Threads "${TERMINFO_LIBRARIES}" "${LIBRT}" ) target_link_libraries(notcurses-static PRIVATE + Threads::Threads "${TERMINFO_STATIC_LIBRARIES}" "${LIBRT}" ) @@ -107,7 +111,6 @@ target_link_libraries(notcurses "${AVFORMAT_LIBRARIES}" "${AVUTIL_LIBRARIES}" "${SWSCALE_LIBRARIES}" - Threads::Threads ) target_link_libraries(notcurses-static PRIVATE @@ -115,7 +118,6 @@ target_link_libraries(notcurses-static "${AVFORMAT_STATIC_LIBRARIES}" "${AVUTIL_STATIC_LIBRARIES}" "${SWSCALE_STATIC_LIBRARIES}" - Threads::Threads ) target_link_directories(notcurses PUBLIC @@ -331,6 +333,7 @@ foreach(f ${POCSRCS}) add_executable(${fe} ${f}) target_include_directories(${fe} PRIVATE include "${TERMINFO_INCLUDE_DIRS}" + "${PROJECT_BINARY_DIR}/include" ) target_link_libraries(${fe} PRIVATE notcurses++ "${TERMINFO_LIBRARIES}" @@ -529,6 +532,7 @@ target_compile_definitions(notcurses-view endif() # Testing +if(${USE_TESTS}) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) include(CTest) endif() @@ -558,6 +562,7 @@ add_test( NAME notcurses-tester COMMAND notcurses-tester -p ${CMAKE_CURRENT_SOURCE_DIR}/data ) +endif() # pkg-config support configure_file(tools/notcurses.pc.in @@ -680,11 +685,13 @@ install(FILES DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) +if(${USE_FFMPEG}) file(GLOB TESTDATA CONFIGURE_DEPENDS data/*) install(FILES ${TESTDATA} DESTINATION ${CMAKE_INSTALL_DATADIR}/notcurses ) +endif() install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/" @@ -706,7 +713,9 @@ install(TARGETS notcurses-demo DESTINATION bin) install(TARGETS notcurses-input DESTINATION bin) install(TARGETS notcurses-keyplot DESTINATION bin) install(TARGETS notcurses-ncreel DESTINATION bin) +if(${USE_TESTS}) install(TARGETS notcurses-tester DESTINATION bin) +endif() install(TARGETS notcurses-tetris DESTINATION bin) if(${USE_FFMPEG}) install(TARGETS notcurses-view DESTINATION bin) diff --git a/src/demo/demo.c b/src/demo/demo.c index a38ac9cdc..555268c46 100644 --- a/src/demo/demo.c +++ b/src/demo/demo.c @@ -72,7 +72,14 @@ struct timespec demodelay = { #ifndef DFSG_BUILD #ifdef USE_FFMPEG #define NONFREE(name, fxn) { name, fxn, } +#else +#endif +#else +#define DFSG(name, fxn) { NULL, NULL, } #endif + +#ifndef DFSG +#define DFSG(name, fxn) { name, fxn, } #endif #ifndef NONFREE #define NONFREE(name, fxn) { NULL, NULL, } @@ -99,7 +106,7 @@ static struct { { "grid", grid_demo, }, { "highcon", highcontrast_demo, }, { "intro", intro, }, - NONFREE("jungle", jungle_demo), + DFSG("jungle", jungle_demo), { NULL, NULL, }, NONFREE("luigi", luigi_demo), { NULL, NULL, }, diff --git a/src/lib/libav.c b/src/lib/libav.c index cf9eb8ece..515526d8d 100644 --- a/src/lib/libav.c +++ b/src/lib/libav.c @@ -6,6 +6,95 @@ ncplane* ncvisual_plane(ncvisual* ncv){ return ncv->ncp; } +// alpha comes to us 0--255, but we have only 3 alpha values to map them to. +// settled on experimentally. +static inline bool +ffmpeg_trans_p(bool bgr, unsigned char alpha){ + if(!bgr && alpha < 192){ + return true; + } + return false; +} + +// RGBA/BGRx blitter. For incoming BGRx (no transparency), bgr == true. +static inline int +tria_blit(ncplane* nc, int placey, int placex, int linesize, const void* data, + int begy, int begx, int leny, int lenx, bool bgr){ + const int bpp = 32; + const int rpos = bgr ? 2 : 0; + const int bpos = bgr ? 0 : 2; + int dimy, dimx, x, y; + int visy = begy; + int total = 0; // number of cells written + ncplane_dim_yx(nc, &dimy, &dimx); + // FIXME not going to necessarily be safe on all architectures hrmmm + const unsigned char* dat = data; + for(y = placey ; visy < (begy + leny) && y < dimy ; ++y, visy += 2){ + if(ncplane_cursor_move_yx(nc, y, placex)){ + return -1; + } + int visx = begx; + for(x = placex ; visx < (begx + lenx) && x < dimx ; ++x, ++visx){ + const unsigned char* rgbbase_up = dat + (linesize * visy) + (visx * bpp / CHAR_BIT); + const unsigned char* rgbbase_down = dat + (linesize * (visy + 1)) + (visx * bpp / CHAR_BIT); +//fprintf(stderr, "[%04d/%04d] bpp: %d lsize: %d %02x %02x %02x %02x\n", y, x, bpp, linesize, rgbbase_up[0], rgbbase_up[1], rgbbase_up[2], rgbbase_up[3]); + cell* c = ncplane_cell_ref_yx(nc, y, x); + // use the default for the background, as that's the only way it's + // effective in that case anyway + c->channels = 0; + c->attrword = 0; + if(ffmpeg_trans_p(bgr, rgbbase_up[3]) || ffmpeg_trans_p(bgr, rgbbase_down[3])){ + cell_set_bg_alpha(c, CELL_ALPHA_TRANSPARENT); + if(ffmpeg_trans_p(bgr, rgbbase_up[3]) && ffmpeg_trans_p(bgr, rgbbase_down[3])){ + cell_set_fg_alpha(c, CELL_ALPHA_TRANSPARENT); + }else if(ffmpeg_trans_p(bgr, rgbbase_up[3])){ // down has the color + if(cell_load(nc, c, "\u2584") <= 0){ // lower half block + return -1; + } + cell_set_fg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); + }else{ // up has the color + if(cell_load(nc, c, "\u2580") <= 0){ // upper half block + return -1; + } + cell_set_fg_rgb(c, rgbbase_up[rpos], rgbbase_up[1], rgbbase_up[bpos]); + } + }else{ + if(memcmp(rgbbase_up, rgbbase_down, 3) == 0){ + cell_set_fg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); + cell_set_bg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); + if(cell_load(nc, c, " ") <= 0){ // only need the background + return -1; + } + }else{ + cell_set_fg_rgb(c, rgbbase_up[rpos], rgbbase_up[1], rgbbase_up[bpos]); + cell_set_bg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); + if(cell_load(nc, c, "\u2580") <= 0){ // upper half block + return -1; + } + } + } + ++total; + } + } + return total; +} + +// Blit a flat array 'data' of BGRx 32-bit values to the ncplane 'nc', offset +// from the upper left by 'placey' and 'placex'. Each row ought occupy +// 'linesize' bytes (this might be greater than lenx * 4 due to padding). A +// subregion of the input can be specified with 'begy'x'begx' and 'leny'x'lenx'. +int ncblit_bgrx(ncplane* nc, int placey, int placex, int linesize, + const void* data, int begy, int begx, int leny, int lenx){ + return tria_blit(nc, placey, placex, linesize, data, + begy, begx, leny, lenx, true); +} + +int ncblit_rgba(ncplane* nc, int placey, int placex, int linesize, + const void* data, int begy, int begx, int leny, int lenx){ + return tria_blit(nc, placey, placex, linesize, data, + begy, begx, leny, lenx, false); +} + void ncvisual_destroy(ncvisual* ncv){ if(ncv){ #ifdef USE_FFMPEG @@ -354,95 +443,6 @@ ncvisual* ncvisual_open_plane(notcurses* nc, const char* filename, return ncv; } -// alpha comes to us 0--255, but we have only 3 alpha values to map them to. -// settled on experimentally. -static inline bool -ffmpeg_trans_p(bool bgr, unsigned char alpha){ - if(!bgr && alpha < 192){ - return true; - } - return false; -} - -// RGBA/BGRx blitter. For incoming BGRx (no transparency), bgr == true. -static inline int -tria_blit(ncplane* nc, int placey, int placex, int linesize, const void* data, - int begy, int begx, int leny, int lenx, bool bgr){ - const int bpp = 32; - const int rpos = bgr ? 2 : 0; - const int bpos = bgr ? 0 : 2; - int dimy, dimx, x, y; - int visy = begy; - int total = 0; // number of cells written - ncplane_dim_yx(nc, &dimy, &dimx); - // FIXME not going to necessarily be safe on all architectures hrmmm - const unsigned char* dat = data; - for(y = placey ; visy < (begy + leny) && y < dimy ; ++y, visy += 2){ - if(ncplane_cursor_move_yx(nc, y, placex)){ - return -1; - } - int visx = begx; - for(x = placex ; visx < (begx + lenx) && x < dimx ; ++x, ++visx){ - const unsigned char* rgbbase_up = dat + (linesize * visy) + (visx * bpp / CHAR_BIT); - const unsigned char* rgbbase_down = dat + (linesize * (visy + 1)) + (visx * bpp / CHAR_BIT); -//fprintf(stderr, "[%04d/%04d] bpp: %d lsize: %d %02x %02x %02x %02x\n", y, x, bpp, linesize, rgbbase_up[0], rgbbase_up[1], rgbbase_up[2], rgbbase_up[3]); - cell* c = ncplane_cell_ref_yx(nc, y, x); - // use the default for the background, as that's the only way it's - // effective in that case anyway - c->channels = 0; - c->attrword = 0; - if(ffmpeg_trans_p(bgr, rgbbase_up[3]) || ffmpeg_trans_p(bgr, rgbbase_down[3])){ - cell_set_bg_alpha(c, CELL_ALPHA_TRANSPARENT); - if(ffmpeg_trans_p(bgr, rgbbase_up[3]) && ffmpeg_trans_p(bgr, rgbbase_down[3])){ - cell_set_fg_alpha(c, CELL_ALPHA_TRANSPARENT); - }else if(ffmpeg_trans_p(bgr, rgbbase_up[3])){ // down has the color - if(cell_load(nc, c, "\u2584") <= 0){ // lower half block - return -1; - } - cell_set_fg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); - }else{ // up has the color - if(cell_load(nc, c, "\u2580") <= 0){ // upper half block - return -1; - } - cell_set_fg_rgb(c, rgbbase_up[rpos], rgbbase_up[1], rgbbase_up[bpos]); - } - }else{ - if(memcmp(rgbbase_up, rgbbase_down, 3) == 0){ - cell_set_fg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); - cell_set_bg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); - if(cell_load(nc, c, " ") <= 0){ // only need the background - return -1; - } - }else{ - cell_set_fg_rgb(c, rgbbase_up[rpos], rgbbase_up[1], rgbbase_up[bpos]); - cell_set_bg_rgb(c, rgbbase_down[rpos], rgbbase_down[1], rgbbase_down[bpos]); - if(cell_load(nc, c, "\u2580") <= 0){ // upper half block - return -1; - } - } - } - ++total; - } - } - return total; -} - -// Blit a flat array 'data' of BGRx 32-bit values to the ncplane 'nc', offset -// from the upper left by 'placey' and 'placex'. Each row ought occupy -// 'linesize' bytes (this might be greater than lenx * 4 due to padding). A -// subregion of the input can be specified with 'begy'x'begx' and 'leny'x'lenx'. -int ncblit_bgrx(ncplane* nc, int placey, int placex, int linesize, - const void* data, int begy, int begx, int leny, int lenx){ - return tria_blit(nc, placey, placex, linesize, data, - begy, begx, leny, lenx, true); -} - -int ncblit_rgba(ncplane* nc, int placey, int placex, int linesize, - const void* data, int begy, int begx, int leny, int lenx){ - return tria_blit(nc, placey, placex, linesize, data, - begy, begx, leny, lenx, false); -} - int ncvisual_render(const ncvisual* ncv, int begy, int begx, int leny, int lenx){ //fprintf(stderr, "render %dx%d+%dx%d\n", begy, begx, leny, lenx); if(begy < 0 || begx < 0 || lenx < -1 || leny < -1){ @@ -610,6 +610,7 @@ char* ncvisual_subtitle(const ncvisual* ncv){ int ncvisual_init(int loglevel){ (void)loglevel; - return 0; + return 0; // allow success here } + #endif diff --git a/src/poc/menu.c b/src/poc/menu.c index 47fd585d5..ae7b69bc9 100644 --- a/src/poc/menu.c +++ b/src/poc/menu.c @@ -118,17 +118,6 @@ int main(void){ int averr; - struct ncvisual* ncv = ncplane_visual_open(n, "../data/ebolavirus_wide-0723bc3f01c644976b4df7e146a1d795aaf9d55e.jpg", &averr); - if(!ncv){ - goto err; - } - if(!ncvisual_decode(ncv, &averr)){ - goto err; - } - if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){ - goto err; - } - uint64_t channels = 0; channels_set_fg(&channels, 0x88aa00); channels_set_bg(&channels, 0x000088); @@ -144,18 +133,6 @@ int main(void){ run_menu(nc, top); ncplane_erase(n); - ncvisual_destroy(ncv); - - ncv = ncplane_visual_open(n, "../data/aidsrobots.jpeg", &averr); - if(!ncv){ - goto err; - } - if(!ncvisual_decode(ncv, &averr)){ - goto err; - } - if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){ - goto err; - } mopts.bottom = true; struct ncmenu* bottom = ncmenu_create(nc, &mopts); @@ -167,7 +144,6 @@ int main(void){ } run_menu(nc, bottom); - ncvisual_destroy(ncv); if(notcurses_stop(nc)){ return EXIT_FAILURE; } diff --git a/src/poc/multiselect.c b/src/poc/multiselect.c index 97a2987b9..f0b13a8b1 100644 --- a/src/poc/multiselect.c +++ b/src/poc/multiselect.c @@ -3,6 +3,7 @@ #include #include #include +#include "version.h" // http://theboomerbible.com/tbb112.html static struct mselector_item items[] = { @@ -81,6 +82,7 @@ int main(void){ channels_set_bg_alpha(&sopts.bgchannels, CELL_ALPHA_BLEND); struct ncplane* n = notcurses_stdplane(nc); +#ifdef USE_FFMPEG int averr; struct ncvisual* ncv = ncplane_visual_open(n, "../data/covid19.jpg", &averr); if(!ncv){ @@ -92,6 +94,7 @@ int main(void){ if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){ goto err; } +#endif ncplane_set_fg(n, 0x40f040); ncplane_putstr_aligned(n, 0, NCALIGN_RIGHT, "multiselect widget demo"); diff --git a/src/poc/selector.c b/src/poc/selector.c index a8529ccdf..f861f7096 100644 --- a/src/poc/selector.c +++ b/src/poc/selector.c @@ -3,6 +3,7 @@ #include #include #include +#include "version.h" static struct selector_item items[] = { { "first", "this is the first option", }, @@ -80,6 +81,7 @@ int main(void){ channels_set_bg_alpha(&sopts.bgchannels, CELL_ALPHA_BLEND); struct ncplane* n = notcurses_stdplane(nc); +#ifdef USE_FFMPEG int averr; struct ncvisual* ncv = ncplane_visual_open(n, "../data/changes.jpg", &averr); if(!ncv){ @@ -91,7 +93,7 @@ int main(void){ if(ncvisual_render(ncv, 0, 0, -1, -1) <= 0){ goto err; } - +#endif ncplane_set_fg(n, 0x40f040); ncplane_putstr_aligned(n, 0, NCALIGN_RIGHT, "selector widget demo"); diff --git a/src/tetris/background.h b/src/tetris/background.h index 203b3b0ce..c1bddf674 100644 --- a/src/tetris/background.h +++ b/src/tetris/background.h @@ -1,4 +1,5 @@ void DrawBackground(const std::string& s) { // drawn to the standard plane +#ifdef USE_FFMPEG int averr; try{ backg_ = std::make_unique(s.c_str(), &averr, 0, 0, ncpp::NCScale::Stretch); @@ -12,6 +13,9 @@ void DrawBackground(const std::string& s) { // drawn to the standard plane throw TetrisNotcursesErr("render(): " + s); } backg_->get_plane()->greyscale(); +#else + (void)s; +#endif } void DrawBoard() { // draw all fixed components of the game diff --git a/tools/notcurses.spec b/tools/notcurses.spec new file mode 100644 index 000000000..069efd6ee --- /dev/null +++ b/tools/notcurses.spec @@ -0,0 +1,50 @@ +Name: notcurses +Version: 1.2.5 +Release: 1 +Summary: Character graphics and TUI library +License: ASL 2.0 +Source0: https://github.com/dankamongmen/%{name}/archive/v%{version}.tar.gz +Source1: https://github.com/dankamongmen/%{name}/releases/v%{version}/v%{version}.tar.gz.asc +Source2: https://dank.qemfd.net/dankamongmen.gpg +BuildRequires: gnupg2 cmake make gcc-c++ ncurses-devel pandoc python3-devel + +%description +notcurses facilitates the creation of modern TUI programs, +making full use of Unicode and 24-bit direct color. It presents +an API similar to that of Curses, and rides atop libtinfo. + +%prep +%{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}' +%setup + +%build +%cmake -DUSE_FFMPEG=off -DUSE_TEST=off . +%make_build + +%install +%make_install + +%files +/usr/bin/notcurses-demo +/usr/bin/notcurses-input +/usr/bin/notcurses-keyplot +/usr/bin/notcurses-ncreel +/usr/bin/notcurses-pydemo +/usr/bin/notcurses-tester +/usr/bin/notcurses-tetris +/usr/bin/notcurses-view +/usr/include/notcurses/nckeys.h +/usr/include/notcurses/notcurses.h +/usr/lib/x86_64-linux-gnu/libnotcurses.so.{version} +/usr/lib/x86_64-linux-gnu/libnotcurses.so.1 +/usr/lib/x86_64-linux-gnu/libnotcurses.so +/usr/lib/x86_64-linux-gnu/cmake/notcurses/notcursesConfig.cmake +/usr/lib/x86_64-linux-gnu/cmake/notcurses/notcursesConfigVersion.cmake +/usr/lib/x86_64-linux-gnu/libnotcurses.a +/usr/lib/x86_64-linux-gnu/pkgconfig +/usr/lib/x86_64-linux-gnu/pkgconfig/notcurses.pc +%license LICENSE + +%changelog +* Tue, Apr 07 2020 Nick Black - 1.2.5-1 +- Initial Fedora packaging