#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