1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-11-23 21:07:17 +00:00
hyperrogue/rogueviz/rogueviz.h
2024-06-16 16:22:19 +02:00

409 lines
11 KiB
C++

#ifndef _ROGUEVIZ_H_
#define _ROGUEVIZ_H_
// See: http://www.roguetemple.com/z/hyper/rogueviz.php
#include "../hyper.h"
#define RVPATH HYPERPATH "rogueviz/"
#ifndef CAP_NCONF
#define CAP_NCONF 0
#endif
#ifndef CAP_RVSLIDES
#define CAP_RVSLIDES (CAP_TOUR && !ISWEB)
#endif
#ifndef CAP_MODELS
#define CAP_MODELS (!ISWEB)
#endif
namespace rogueviz {
using namespace hr;
constexpr flagtype RV_GRAPH = 1;
constexpr flagtype RV_WHICHWEIGHT = 2; // sag
constexpr flagtype RV_AUTO_MAXWEIGHT = 4; // sag
constexpr flagtype RV_COMPRESS_LABELS = 8; // do not display some labels
constexpr flagtype RV_COLOR_TREE = 16; // color vertex together with tree parents
constexpr flagtype RV_HAVE_WEIGHT = 32; // edges have weights
constexpr flagtype RV_INVERSE_WEIGHT = 64; // edit weight, not 1/weight
inline flagtype vizflags;
extern string weight_label;
extern ld maxweight;
extern ld ggamma;
extern bool highlight_target;
extern int vertex_shape;
extern int search_for;
void drawExtra();
void close();
void init(flagtype flags);
void graph_rv_hooks();
struct edgetype {
double visible_from;
double visible_from_hi;
unsigned color, color_hi;
string name;
};
edgetype *add_edgetype(const string& name);
static constexpr unsigned DEFAULT_COLOR = 0x471293B5;
extern edgetype default_edgetype;
extern vector<shared_ptr<edgetype>> edgetypes;
struct edgeinfo {
int i, j;
double weight, weight2;
vector<glvertex> prec;
basic_textureinfo tinf;
cell *orig;
int lastdraw;
edgetype *type;
edgeinfo(edgetype *t) { orig = NULL; lastdraw = -1; type = t; }
};
extern vector<edgeinfo*> edgeinfos;
void addedge0(int i, int j, edgeinfo *ei);
void addedge(int i, int j, edgeinfo *ei);
void addedge(int i, int j, double wei, bool subdiv, edgetype *t);
extern vector<int> legend;
extern vector<cell*> named;
int readLabel(fhstream& f);
#if CAP_TEXTURE
struct rvimage {
basic_textureinfo tinf;
texture::texture_data tdata;
vector<hyperpoint> vertices;
};
#endif
extern int brm_limit;
struct colorpair {
color_t color1, color2;
char shade;
#if CAP_TEXTURE
shared_ptr<rvimage> img;
#endif
colorpair(color_t col = 0xC0C0C0FF) { shade = 0; color1 = color2 = col; }
};
struct vertexdata {
vector<pair<int, edgeinfo*> > edges;
string name;
colorpair cp;
edgeinfo *virt;
bool special;
int data;
string *info;
shmup::monster *m;
vertexdata() { virt = NULL; m = NULL; info = NULL; special = false; }
};
extern vector<vertexdata> vdata;
void storeall(int from = 0);
extern vector<reaction_t> cleanup;
void do_cleanup();
inline void on_cleanup_or_next(const reaction_t& del) {
#if CAP_TOUR
if(tour::on) tour::on_restore(del);
else
#endif
cleanup.push_back(del);
}
template<class T> void rv_change(T& variable, const T& value) {
T backup = variable;
variable = value;
on_cleanup_or_next([backup, &variable] { variable = backup; });
}
template<class T> void rv_keep(T& variable) {
T backup = variable;
on_cleanup_or_next([backup, &variable] { variable = backup; });
}
template<class T, class U> void rv_hook(hookset<T>& m, int prio, U&& hook) {
int p = addHook(m, prio, hook);
auto del = [&m, p] {
delHook(m, p);
};
on_cleanup_or_next(del);
}
extern bool showlabels;
extern bool rog3;
extern bool rvwarp;
extern colorpair dftcolor;
inline hookset<void(vertexdata&, cell*, shmup::monster*, int)> hooks_drawvertex;
inline hookset<bool(edgeinfo*, bool store)> hooks_alt_edges;
inline purehookset hooks_rvmenu;
inline hookset<bool()> hooks_rvmenu_replace;
inline hookset<bool(int&, string&, FILE*)> hooks_readcolor;
inline purehookset hooks_close;
void readcolor(const string& cfname);
void close();
extern bool showlabels;
namespace pres {
using namespace hr::tour;
#if CAP_RVSLIDES
inline hookset<void(string, vector<slide>&)> hooks_build_rvtour;
slide *gen_rvtour();
#if CAP_TEXTURE
void draw_texture(texture::texture_data& tex, ld dx = 0, ld dy = 0, ld scale = 1);
#endif
extern map<string, texture::texture_data> textures;
inline void setCanvasChar(presmode mode, char c) {
if(c == '0') {
setCanvasColor(mode, 0x101010, [] {});
}
if(c == 'd') {
setCanvas(mode, &ccolor::landscape_dark);
}
}
template<class T, class U> function<void(presmode)> roguevizslide(char c, const T& t, const U& f) {
return [c,t,f] (presmode mode) {
f(mode);
setCanvasChar(mode, c);
if(mode == 1 || mode == pmGeometryStart) t();
if(mode == 3 || mode == pmGeometry || mode == pmGeometryReset) {
rogueviz::close();
shmup::clearMonsters();
if(mode == pmGeometryReset && !(slides[currentslide].flags & QUICKGEO)) t();
}
slidecommand = "toggle the player";
if(mode == 4)
mapeditor::drawplayer = !mapeditor::drawplayer;
pd_from = NULL;
};
}
template<class T> function<void(presmode)> roguevizslide(char c, const T& t) { return roguevizslide(c, t, [] (presmode mode) {}); }
template<class T, class U>
function<void(presmode)> roguevizslide_action(char c, const T& t, const U& act) {
return [c,t,act] (presmode mode) {
setCanvasChar(mode, c);
if(mode == pmStart || mode == pmGeometryStart) t();
act(mode);
if(mode == pmStop || mode == pmGeometry || mode == pmGeometryReset) {
rogueviz::close();
shmup::clearMonsters();
if(mode == pmGeometryReset && !(slides[currentslide].flags & QUICKGEO)) t();
}
};
}
void add_end(vector<slide>& s);
template<class T, class U> void add_temporary_hook(int mode, hookset<T>& m, int prio, U&& hook) {
using namespace tour;
if(mode == pmStart) {
int p = addHook(m, prio, hook);
on_restore([&m, p] {
delHook(m, p);
});
}
}
/* maks graphs in presentations */
struct grapher {
ld minx, miny, maxx, maxy;
shiftmatrix T;
grapher(ld _minx, ld _miny, ld _maxx, ld _maxy);
void line(hyperpoint h1, hyperpoint h2, color_t col);
void arrow(hyperpoint h1, hyperpoint h2, ld sca, color_t col = 0xFF);
shiftmatrix pos(ld x, ld y, ld sca);
};
void add_stat(presmode mode, const bool_reaction_t& stat);
void compare_projections(presmode mode, eModel a, eModel b);
void no_other_hud(presmode mode);
void non_game_slide(presmode mode);
void non_game_slide_scroll(presmode mode);
void white_screen(presmode mode, color_t col = 0xFFFFFFFF);
void empty_screen(presmode mode, color_t col = 0xFFFFFFFF);
void show_picture(presmode mode, string s, flagtype flags = 0);
void sub_picture(string s, flagtype flags = 0, ld dx = 0, ld dy = 0, ld scale = 1);
void show_animation(presmode mode, string s, int sx, int sy, int frames, int fps);
void use_angledir(presmode mode, bool reset);
void slide_error(presmode mode, string s);
static constexpr flagtype LATEX_COLOR = 1;
void show_latex(presmode mode, string s);
void dialog_add_latex(string s, color_t color, int size = 100, flagtype flag = 0);
void dialog_may_latex(string latex, string normal, color_t col = dialog::dialogcolor, int size = 100, flagtype flag = 0);
void uses_game(presmode mode, string name, reaction_t launcher, reaction_t restore);
void latex_slide(presmode mode, string s, flagtype flags = 0, int size = 100);
inline purehookset hooks_latex_slide;
inline ld angle = 0;
inline int dir = -1;
hyperpoint p2(ld x, ld y);
#endif
}
void createViz(int id, cell *c, transmatrix at);
extern map<string, int> labeler;
bool id_known(const string& s);
int getid(const string& s);
int getnewid(string s);
extern string fname;
bool rv_ignore(char c);
colorpair perturb(colorpair cp);
void queuedisk(const shiftmatrix& V, const colorpair& cp, bool legend, const string* info, int i);
/* 3D models */
namespace objmodels {
using tf_result = pair<int, hyperpoint>;
using transformer = std::function<tf_result(hyperpoint)>;
using subdivider = std::function<int(vector<hyperpoint>&)>;
inline ld prec = 1;
inline bool shift_to_ctr = false;
struct object {
hpcshape sh;
string mtlname;
basic_textureinfo tv;
color_t color;
};
struct model_data : gi_extension {
ld prec_used;
vector<shared_ptr<object>> objs;
vector<int> objindex;
void render(const shiftmatrix& V);
};
#if CAP_TEXTURE
struct model {
string path, fname;
bool is_available, av_checked;
model(string path = "", string fn = "") : path(path), fname(fn) { av_checked = false; }
map<string, texture::texture_data> materials;
map<string, color_t> colors;
/* private */
virtual void load_obj(model_data& objects);
virtual model_data& get();
virtual void prepare() {}
virtual void postprocess() {}
virtual color_t read_color(ld a, ld b, ld c);
virtual hyperpoint transform(hyperpoint h);
virtual int subdivision(vector<hyperpoint>& hys);
virtual void render(const shiftmatrix& V) { get().render(V); }
virtual void process_triangle(vector<hyperpoint>& hys, vector<hyperpoint>& tot, bool textured, object *co);
bool available();
virtual ~model() {}
};
void add_model_settings();
#endif
}
#if CAP_RVSLIDES
#define addHook_rvslides(x, y) addHook(rogueviz::pres::hooks_build_rvtour, x, y)
#define addHook_slideshows(x, y) addHook(tour::ss::hooks_extra_slideshows, x, y)
#define addHook_rvtour(x, y) addHook(pres::hooks_build_rvtour, x, y)
#else
#define addHook_rvslides(x, y) 0
#define addHook_slideshows(x, y) 0
#define addHook_rvtour(x, y) 0
#endif
/* parallelize a computation */
inline int threads = 1;
#if CAP_THREAD
template<class T> auto parallelize(long long N, T action) -> decltype(action(0,0)) {
if(threads == 1) return action(0,N);
std::vector<std::thread> v;
typedef decltype(action(0,0)) Res;
std::vector<Res> results(threads);
for(int k=0; k<threads; k++)
v.emplace_back([&,k] () {
results[k] = action(N*k/threads, N*(k+1)/threads);
});
for(std::thread& t:v) t.join();
Res res = 0;
for(Res r: results) res += r;
return res;
}
#else
template<class T> auto parallelize(long long N, T action) -> decltype(action(0,0)) {
return action(0, N);
}
#endif
namespace smoothcam {
void save_animation(hstream& f);
void load_animation(hstream& f);
void handle_animation(ld);
void enable();
extern bool animate_on;
extern ld last_time;
void enable_and_show();
void backup();
void append_backup();
}
}
#endif