// Hyperbolic Rogue -- screenshots in SVG and PNG formats // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details namespace hr { #if ISMOBILE==1 namespace svg { bool in = false; } #endif #if ISMOBILE==0 // svg renderer namespace svg { FILE *f; bool in = false; ld cta(int col) { // col >>= 24; col &= 0xFF; return col / 255.0; } bool invisible(int col) { return (col & 0xFF) == 0; } ld gamma = .5; void fixgamma(unsigned int& color) { unsigned char *c = (unsigned char*) (&color); for(int i=1; i<4; i++) c[i] = 255 * pow(float(c[i] / 255.0), float(gamma)); } int svgsize; int divby = 10; const char* coord(int val) { static char buf[10][20]; static int id; id++; id %= 10; if(divby == 1) { sprintf(buf[id], "%d", val); return buf[id]; } else if(divby <= 10) { sprintf(buf[id], "%.1f", val*1./divby); return buf[id]; } else { sprintf(buf[id], "%.2f", val*1./divby); return buf[id]; } } char* stylestr(unsigned int fill, unsigned int stroke, ld width=1) { fixgamma(fill); fixgamma(stroke); static char buf[600]; // printf("fill = %08X stroke = %08x\n", fill, stroke); if(stroke == 0xFF00FF) { stroke = 0x000000FF; if(fill == 0x332a22ff) fill = 0x000000FF; else if(fill == 0x686868FF) fill = 0x000000FF; else if(fill == 0xd0d0d0FF) fill = 0x000000FF; else fill = 0xFFFFFFFF; } sprintf(buf, "style=\"stroke:#%06x;stroke-opacity:%.3" PLDF ";stroke-width:%" PLDF "px;fill:#%06x;fill-opacity:%.3" PLDF "\"", (stroke>>8) & 0xFFFFFF, cta(stroke), width/divby, (fill>>8) & 0xFFFFFF, cta(fill) ); return buf; } void circle(int x, int y, int size, int col) { int ba = (backcolor << 8) + 0xFF; if(!invisible(col)) { if(vid.stretch == 1) fprintf(f, "\n", coord(x), coord(y), coord(size), stylestr(ba, col)); else fprintf(f, "\n", coord(x), coord(y), coord(size), coord(size*vid.stretch), stylestr(ba, col)); } } const string *link; void startstring() { if(link) fprintf(f, "", link->c_str()); } void stopstring() { if(link) fprintf(f, ""); } string font = "Times"; void text(int x, int y, int size, const string& str, bool frame, int col, int align) { double dfc = (x - vid.xcenter) * (x - vid.xcenter) + (y - vid.ycenter) * (y - vid.ycenter); dfc /= vid.radius; dfc /= vid.radius; // 0 = center, 1 = edge dfc = 1 - dfc; col = 0xFF + (col << 8); bool uselatex = font == "latex"; if(!invisible(col)) { startstring(); string str2 = ""; for(int i=0; i<(int) str.size(); i++) if(str[i] == '&') str2 += "&"; else if(str[i] == '<') str2 += "<"; else if(str[i] == '>') str2 += ">"; else if(uselatex && str[i] == '#') str2 += "\\#"; else str2 += str[i]; if(uselatex) str2 = string("\\myfont{")+coord(size)+"}{" + str2 + "}"; fprintf(f, "%s", stylestr(col, frame ? 0x0000000FF : 0, (1<(dfc, 1) * linewidth; } else dfc = .8 * linewidth; startstring(); for(int i=0; i", stylestr(col, outline, (hyperbolic ? vid.radius : vid.scrsize) *dfc/256)); stopstring(); fprintf(f, "\n"); } void render(const char *fname) { if(cheater) doOvergenerate(); dynamicval v(vid, vid); dynamicval v2(in, true); dynamicval v5(ringcolor, 0x808080FF); vid.usingGL = false; vid.xres = vid.yres = svgsize ? svgsize : min(1 << (get_sightrange()+7), 16384); calcparam(); dynamicval v6(inHighQual, true); darken = 0; time_t timer; timer = time(NULL); char buf[128]; strftime(buf, 128, "svgshot-%y%m%d-%H%M%S.svg", localtime(&timer)); if(!fname) fname = buf; f = fopen(fname, "wt"); fprintf(f, "\n", coord(vid.xres), coord(vid.yres)); drawfullmap(); fprintf(f, "\n"); fclose(f); addMessage(XLAT("Saved the SVG shot to %1 (sightrange %2)", fname, its(get_sightrange()))); } #if CAP_COMMANDLINE int read_args() { using namespace arg; if(argis("-svgsize")) { shift(); sscanf(argcs(), "%d/%d", &svg::svgsize, &svg::divby); } else if(argis("-svgfont")) { shift(); svg::font = args(); // note: use '-svgfont latex' to produce text output as: \myfont{size}{text} // (this is helpful with Inkscape's PDF+TeX output feature; define \myfont yourself) } else if(argis("-svggamma")) { shift(); svg::gamma = argf(); } else if(argis("-svgshot")) { PHASE(3); shift(); start_game(); printf("saving SVG screenshot to %s\n", argcs()); svg::render(argcs()); } else return 1; return 0; } auto ah = addHook(hooks_args, 0, read_args); #endif } #endif #if CAP_SDL int pngres = 2000; int pngformat = 0; #if CAP_PNG void IMAGESAVE(SDL_Surface *s, const char *fname) { SDL_Surface *s2 = SDL_PNGFormatAlpha(s); SDL_SavePNG(s2, fname); SDL_FreeSurface(s2); } #endif hookset *hooks_hqshot; void saveHighQualityShot(const char *fname, const char *caption, int fade) { resetbuffer rb; // int maxrange = getDistLimit() * 3/2; // dynamicval v3(sightrange, (cheater && sightrange < maxrange) ? maxrange : sightrange); if(cheater) doOvergenerate(); time_t timer; timer = time(NULL); dynamicval v(vid, vid); dynamicval v2(inHighQual, true); dynamicval v6(auraNOGL, fname ? true : false); vid.xres = vid.yres = pngres; if(pngformat == 1) vid.xres = vid.yres * 4/3; if(pngformat == 2) vid.xres = vid.yres * 16/9; if(pngformat == 3) { vid.xres = vid.yres * 22/16; while(vid.xres & 15) vid.xres++; } // if(vid.pmodel == 0) vid.scale = 0.99; calcparam(); renderbuffer glbuf(vid.xres, vid.yres, vid.usingGL); glbuf.enable(); stereo::set_viewport(0); // printf("format = %d, %d x %d\n", pngformat, vid.xres, vid.yres); darken = 0; int numi = (fname?1:2); for(int i=0; i