From 1789ad1a33162ed2e1e73e20d8007603a000468e Mon Sep 17 00:00:00 2001 From: Zeno Rogue Date: Fri, 11 Sep 2020 11:41:23 +0200 Subject: [PATCH] improved presentation support in RogueViz --- rogueviz/presentation.cpp | 383 ++++++++++++++++++++++++++++++++++++++ rogueviz/rogueviz-all.cpp | 1 + rogueviz/rogueviz.cpp | 101 ---------- rogueviz/rogueviz.h | 2 +- 4 files changed, 385 insertions(+), 102 deletions(-) create mode 100644 rogueviz/presentation.cpp diff --git a/rogueviz/presentation.cpp b/rogueviz/presentation.cpp new file mode 100644 index 00000000..690ec20b --- /dev/null +++ b/rogueviz/presentation.cpp @@ -0,0 +1,383 @@ +#ifndef PRESENTATION_CPP +#define PRESENTATION_CPP + +#include "../rogueviz/rogueviz.h" + +namespace rogueviz { + +#if CAP_RVSLIDES +namespace pres { + +/* maks graphs in presentations */ +struct grapher { + + ld minx, miny, maxx, maxy; + + shiftmatrix T; + + grapher(ld _minx, ld _miny, ld _maxx, ld _maxy) : minx(_minx), miny(_miny), maxx(_maxx), maxy(_maxy) { + auto& cd = *current_display; + + ld xpixels = 2 * min(cd.xcenter - cd.xmin, cd.xmax - cd.xcenter); + ld ypixels = 2 * min(cd.ycenter - cd.ymin, cd.ymax - cd.ycenter); + + ld sca = min(abs(xpixels / (maxx-minx)), abs(ypixels / (maxy-miny))); + + ld medx = (minx + maxx) / 2; + ld medy = (miny + maxy) / 2; + + hyperpoint zero = atscreenpos(cd.xcenter - sca * medx, cd.ycenter + sca * medy, 1) * C0; + + hyperpoint zero10 = atscreenpos(cd.xcenter - sca * medx + sca, cd.ycenter + sca * medy, 1) * C0; + hyperpoint zero01 = atscreenpos(cd.xcenter - sca * medx, cd.ycenter + sca * medy - sca, 1) * C0; + + T = shiftless(Id); + T.T[LDIM] = zero; + T.T[0] = zero10 - zero; + T.T[1] = zero01 - zero; + + T.T = transpose(T.T); + } + + void line(hyperpoint h1, hyperpoint h2, color_t col) { + curvepoint(h1); + curvepoint(h2); + queuecurve(T, col, 0, PPR::LINE).flags |= POLY_FORCEWIDE; + } + + void arrow(hyperpoint h1, hyperpoint h2, ld sca) { + line(h1, h2, 0xFF); + hyperpoint h = h2 - h1; + ld siz = hypot_d(2, h); + h *= sca / siz; + curvepoint(h2); + curvepoint(h2 - spin(15*degree) * h); + curvepoint(h2 - spin(-15*degree) * h); + curvepoint(h2); + queuecurve(T, 0xFF, 0xFF, PPR::LINE); + } + + shiftmatrix pos(ld x, ld y, ld sca) { + transmatrix P = Id; + P[0][0] = sca; + P[1][1] = sca; + P[0][LDIM] = x; + P[1][LDIM] = y; + return T * P; + } + + }; + +hyperpoint p2(ld x, ld y) { return LDIM == 2 ? point3(x, y, 1) : point31(x, y, 0); } + +/* temporary hooks */ + +using namespace hr::tour; + +template void add_temporary_hook(int mode, hookset& m, int prio, U&& hook) { + if(mode == pmStart) { + int p = addHook(m, prio, hook); + on_restore([&m, p] { + delHook(m, p); + }); + } + } + +void add_stat(presmode mode, const bool_reaction_t& stat) { + add_temporary_hook(mode, hooks_prestats, 200, stat); + } + +void no_other_hud(presmode mode) { + add_temporary_hook(mode, hooks_prestats, 300, [] { return true; }); + } + +void empty_screen(presmode mode, color_t col = 0xFFFFFFFF) { + if(mode == pmStart) { + tour::slide_backup(nomap, true); + tour::slide_backup(backcolor, col); + tour::slide_backup(ringcolor, color_t(0)); + tour::slide_backup(dialog::dialogcolor, 0); + tour::slide_backup(forecolor, 0); + tour::slide_backup(bordcolor, 0xFFFFFFFF); + tour::slide_backup(vid.aurastr, 0); + } + } + +map textures; + +void draw_texture(texture::texture_data& tex) { + static vector rtver(4); + + ld tx = tex.tx; + ld ty = tex.ty; + ld os = max(tx, ty); + ld scalex = (vid.xres/2 - 2 * vid.fsize) / (current_display->radius * tx / os); + ld scaley = (vid.yres/2 - 2 * vid.fsize) / (current_display->radius * ty / os); + ld scale = min(scalex, scaley); + scale *= 2; + + for(int i=0; i<4; i++) { + ld cx[4] = {1,0,0,1}; + ld cy[4] = {1,1,0,0}; + rtver[i].texture[0] = (tex.base_x + (cx[i] ? tex.strx : 0.)) / tex.twidth; + rtver[i].texture[1] = (tex.base_y + (cy[i] ? tex.stry : 0.)) / tex.twidth; + rtver[i].coords[0] = (cx[i]*2-1) * scale * (tx / tex.twidth); + rtver[i].coords[1] = (cy[i]*2-1) * scale * (ty / tex.theight); + rtver[i].coords[2] = 1; + rtver[i].coords[3] = 1; + } + + println(hlog, tie(tex.tx, tex.base_x, tex.strx, tex.twidth)); + println(hlog, tie(tex.ty, tex.base_y, tex.stry, tex.theight)); + println(hlog, tie(tx, ty, os, scalex, scaley, scale)); + + glhr::be_textured(); + current_display->set_projection(0, false); + glBindTexture(GL_TEXTURE_2D, tex.textureid); + glhr::color2(0xFFFFFFFF); + glhr::id_modelview(); + current_display->set_mask(0); + glhr::prepare(rtver); + glhr::set_depthtest(false); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + +void show_picture(presmode mode, string s) { + if(mode == pmStartAll) { + auto& tex = textures[s]; + println(hlog, "rt = ", tex.readtexture(s)); + println(hlog, "gl = ", tex.loadTextureGL()); + } + add_stat(mode, [s] { + auto& tex = textures[s]; + flat_model_enabler fme; + draw_texture(tex); + return false; + }); + } + +int video_start = 0; + +void read_all(int fd, void *buf, int cnt) { + char *cbuf = (char*) buf; + while(cnt > 0) { + int qt = read(fd, cbuf, cnt); + if(qt <= 0) break; + cbuf += qt; + cnt -= qt; + } + } + +/* note: this loads the whole animation uncompressed into memory, so it is suitable only for short presentations */ +void show_animation(presmode mode, string s, int sx, int sy, int frames, int fps) { + if(mode == pmStartAll) { + array tab; + if(pipe(&tab[0])) { + addMessage(format("Error: %s", strerror(errno))); + return; + } + + int pid = fork(); + fflush(stdout); + + fprintf(stderr, "pipe is %d:%d\n", tab[0], tab[1]); + + if(pid == 0) { + fprintf(stderr, "in child\n"); + fprintf(stderr, "making fformat\n"); + string fformat = "ffmpeg -y -i " + s + " -f rawvideo -pix_fmt bgra /dev/fd/" + its(tab[1]); + int sys = system(fformat.c_str()); + ::close(tab[0]); + fprintf(stderr, "system call returned %d: %s\n", sys, strerror(errno)); + ::close(tab[1]); + exit(0); + } + + ::close(tab[1]); + for(int i=0; i M_PI/2) angle = M_PI/2; + if(angle < 0) angle = 0; + return false; + }); + + if(mode == pmKey) dir = -dir; + } + +void compare_projections(presmode mode, eModel a, eModel b) { + static function w; + if(mode == pmStart) { + w = wrap_drawfullmap; + tour::slide_backup(wrap_drawfullmap, w); + wrap_drawfullmap = [a, b] { + if(1) { + dynamicval xmin(current_display->xmin, 0); + dynamicval xmax(current_display->xmax, 0.49); + dynamicval pm(pmodel, a); + calcparam(); + w(); + current_display->xmin = .51; + current_display->xmax = 1; + pmodel = b; + calcparam(); + w(); + } + calcparam(); + }; + } + } + +/* default RogueViz tour */ + +vector rvslides; +extern vector rvslides_default; + +slide *gen_rvtour() { + rvslides = rvslides_default; + callhooks(hooks_build_rvtour, rvslides); + rvslides.emplace_back( + slide{"THE END", 99, LEGAL::ANY | FINALSLIDE, + "Press '5' to leave the presentation.", + [] (presmode mode) { + firstland = specialland = laIce; + if(mode == 4) restart_game(rg::tour); + } + }); + return &rvslides[0]; + } + +vector rvslides_default = { + {"RogueViz", 999, LEGAL::ANY, + "This is a presentation of RogueViz, which " + "is an adaptation of HyperRogue as a visualization tool " + "rather than a game. Hyperbolic space is great " + "for visualizing some kinds of data because of the vast amount " + "of space.\n\n" + "Press '5' to switch to the standard HyperRogue tutorial. " + "Press ESC to look at other functions of this presentation." + , + [] (presmode mode) { + slidecommand = "the standard presentation"; + if(mode == pmStartAll) firstland = specialland = laPalace; + if(mode == 4) { + tour::slides = default_slides; + while(tour::on) restart_game(rg::tour); + firstland = specialland = laIce; + tour::start(); + } + } + }, + {"straight lines in the Palace", 999, LEGAL::ANY, + "One simple slide about HyperRogue. Press '5' to show some hyperbolic straight lines.", + [] (presmode mode) { + using namespace linepatterns; + slidecommand = "toggle the Palace lines"; + if(mode == 4) patPalace.color = 0xFFD500FF; + if(mode == 3) patPalace.color = 0xFFD50000; + } + }, + }; + +int rvtour_hooks = + addHook(hooks_slide, 100, [] (int mode) { + if(currentslide == 0 && slides == default_slides) { + slidecommand = "RogueViz presentation"; + if(mode == 1) + help += + "\n\nYour version of HyperRogue is compiled with RogueViz. " + "Press '5' to switch to the RogueViz slides. Watching the " + "common HyperRogue tutorial first is useful too, " + "as an introduction to hyperbolic geometry."; + if(mode == 4) { + slides = gen_rvtour(); + while(tour::on) restart_game(rg::tour); + tour::start(); + } + } + }) + + addHook(tour::ss::hooks_extra_slideshows, 100, [] (tour::ss::slideshow_callback cb) { + if(rogueviz::pres::rvslides.empty()) pres::gen_rvtour(); + cb(XLAT("RogueViz mixed bag"), &pres::rvslides[0], 'r'); + }) + + 0; + +} +#endif +} + +#endif diff --git a/rogueviz/rogueviz-all.cpp b/rogueviz/rogueviz-all.cpp index cd73b57a..d249f30f 100644 --- a/rogueviz/rogueviz-all.cpp +++ b/rogueviz/rogueviz-all.cpp @@ -26,3 +26,4 @@ #include "sumotron.cpp" #include "noniso-honeycombs.cpp" #include "random-walk.cpp" +#include "presentation.cpp" diff --git a/rogueviz/rogueviz.cpp b/rogueviz/rogueviz.cpp index 327a7f39..e4be7ce9 100644 --- a/rogueviz/rogueviz.cpp +++ b/rogueviz/rogueviz.cpp @@ -971,11 +971,6 @@ int readArgs() { else if(argis("-lq")) { shift_arg_formula(linequality); } -#if CAP_RVSLIDES - else if(argis("-rvpres")) { - tour::slides = rvtour::gen_rvtour(); - } -#endif else if(argis("-nolegend")) { legend.clear(); } @@ -1132,82 +1127,6 @@ void showMenu() { dialog::display(); } -#if CAP_RVSLIDES -namespace rvtour { - -using namespace tour; - -vector rvslides; -extern vector rvslides_default; - -slide *gen_rvtour() { - rvslides = rvslides_default; - callhooks(hooks_build_rvtour, rvslides); - rvslides.emplace_back( - slide{"THE END", 99, LEGAL::ANY | FINALSLIDE, - "Press '5' to leave the presentation.", - [] (presmode mode) { - firstland = specialland = laIce; - if(mode == 4) restart_game(rg::tour); - } - }); - return &rvslides[0]; - } - -vector rvslides_default = { - {"RogueViz", 999, LEGAL::ANY, - "This is a presentation of RogueViz, which " - "is an adaptation of HyperRogue as a visualization tool " - "rather than a game. Hyperbolic space is great " - "for visualizing some kinds of data because of the vast amount " - "of space.\n\n" - "Press '5' to switch to the standard HyperRogue tutorial. " - "Press ESC to look at other functions of this presentation." - , - [] (presmode mode) { - slidecommand = "the standard presentation"; - if(mode == pmStartAll) firstland = specialland = laPalace; - if(mode == 4) { - tour::slides = default_slides; - while(tour::on) restart_game(rg::tour); - firstland = specialland = laIce; - tour::start(); - } - } - }, - {"straight lines in the Palace", 999, LEGAL::ANY, - "One simple slide about HyperRogue. Press '5' to show some hyperbolic straight lines.", - [] (presmode mode) { - using namespace linepatterns; - slidecommand = "toggle the Palace lines"; - if(mode == 4) patPalace.color = 0xFFD500FF; - if(mode == 3) patPalace.color = 0xFFD50000; - } - }, - }; - -int rvtour_hooks = - addHook(hooks_slide, 100, [] (int mode) { - if(currentslide == 0 && slides == default_slides) { - slidecommand = "RogueViz presentation"; - if(mode == 1) - help += - "\n\nYour version of HyperRogue is compiled with RogueViz. " - "Press '5' to switch to the RogueViz slides. Watching the " - "common HyperRogue tutorial first is useful too, " - "as an introduction to hyperbolic geometry."; - if(mode == 4) { - slides = gen_rvtour(); - while(tour::on) restart_game(rg::tour); - tour::start(); - } - } - }) + - 0; - -} -#endif - bool default_help() { if(!vizid) return false; @@ -1234,31 +1153,11 @@ auto hooks = addHook(shmup::hooks_kill, 100, activate) + addHook(hooks_o_key, 100, o_key) + -#if CAP_RVSLIDES - addHook(tour::ss::hooks_extra_slideshows, 100, [] (tour::ss::slideshow_callback cb) { - if(rogueviz::rvtour::rvslides.empty()) rvtour::gen_rvtour(); - cb(XLAT("RogueViz mixed bag"), &rvtour::rvslides[0], 'r'); - }) + -#endif - addHook(dialog::hooks_display_dialog, 100, [] () { if(current_screen_cfunction() == showMainMenu) { dialog::addItem(XLAT("rogueviz menu"), 'u'); dialog::add_action_push(rogueviz::showMenu); } - #if CAP_RVSLIDES - if(current_screen_cfunction() == showStartMenu) { - dialog::addBreak(100); - dialog::addBigItem(XLAT("RogueViz"), 'r'); - dialog::add_action([] () { - tour::slides = rogueviz::rvtour::gen_rvtour(); - popScreenAll(); - tour::start(); - printf("tour start\n"); - }); - dialog::addInfo(XLAT("see the visualizations")); - } - #endif }) + addHook(hooks_welcome_message, 100, [] () { if(vizid) addMessage(XLAT("Welcome to RogueViz!")); diff --git a/rogueviz/rogueviz.h b/rogueviz/rogueviz.h index c3f3e7b7..a67d0f1e 100644 --- a/rogueviz/rogueviz.h +++ b/rogueviz/rogueviz.h @@ -127,7 +127,7 @@ namespace rogueviz { void close(); extern bool showlabels; - namespace rvtour { + namespace pres { using namespace hr::tour; inline hookset&)> hooks_build_rvtour; slide *gen_rvtour();