// HyperRogue, shapes used for the vector graphics // also the implementation of the rendering queue and svg renderer // Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details namespace hr { ld signum(ld x) { return x<0?-1:x>0?1:0; } bool asign(ld y1, ld y2) { return signum(y1) != signum(y2); } ld xcross(ld x1, ld y1, ld x2, ld y2) { return x1 + (x2 - x1) * y1 / (y1 - y2); } hyperpoint intester; // draw the lines static const int POLY_DRAWLINES = 1; // draw the area static const int POLY_DRAWAREA = 2; // draw the inverse -- useful in stereographic projection static const int POLY_INVERSE = 4; // never draw in inverse static const int POLY_ISSIDE = 8; // there are points behind the camera static const int POLY_BEHIND = 16; // some coordinates are too large -- best not to draw to avoid glitches static const int POLY_TOOLARGE = 32; // on the sphere (orthogonal projection), do not draw without any points in front static const int POLY_INFRONT = 64; // floor shapes which have their sidewalls static const int POLY_HASWALLS = 128; // plain floors static const int POLY_PLAIN = 256; // full floors static const int POLY_FULL = 512; // floor shapes which have their shadows, or can use shFloorShadow static const int POLY_HASSHADOW = 1024; // Goldberg shapes static const int POLY_GP = 2048; // Convex shape (vertex) static const int POLY_VCONVEX = 4096; // Convex shape (central) static const int POLY_CCONVEX = 8192; // new system of side checking static const int POLY_CENTERIN = 16384; // force wide lines static const int POLY_FORCEWIDE = (1<<15); // points not in front static const int POLY_NOTINFRONT = (1<<16); // points moved to the outline cross the image, disable static const int POLY_NIF_ERROR = (1<<17); vector hpc; int prehpc; bool first; bool fatborder; int poly_outline; // #define STLSORT #define NEWSHAPE (-13.5) #define WOLF (-15.5) extern long double polydata[]; hpcshape *last = NULL; vector ptds; polytodraw& lastptd() { return ptds[isize(ptds)-1]; } polytodraw& nextptd() { ptds.resize(isize(ptds)+1); return lastptd(); } bool ptdsort(const polytodraw& p1, const polytodraw& p2) { return p1.prio < p2.prio; } void hpcpush(hyperpoint h) { if(sphere) h = mid(h,h); ld threshold = (sphere ? (ISMOBWEB || NONSTDVAR ? .04 : .001) : 0.1) * pow(.25, vid.linequality); if(/*vid.usingGL && */!first && intval(hpc.back(), h) > threshold) { hyperpoint md = mid(hpc.back(), h); hpcpush(md); hpcpush(h); return; } first = false; hpc.push_back(h); } bool validsidepar[SIDEPARS]; void chasmifyPoly(double fac, double fac2, int k) { for(int i=isize(hpc)-1; i >= last->s; i--) { hyperpoint H; for(int j=0; j<3; j++) { H[j] = hpc[i][j] * fac; hpc[i][j] *= fac2; } hpc.push_back(H); } hpc.push_back(hpc[last->s]); last->flags |= POLY_ISSIDE; } void shift(hpcshape& sh, double dx, double dy, double dz) { hyperpoint H = hpxyz(dx, dy, dz); transmatrix m = rgpushxto0(H); for(int i=sh.s; i ptds2; #define POLYMAX 60000 vector> glcoords, ourshape; void initPolyForGL() { ourshape.clear(); for(auto& h: hpc) ourshape.push_back(glhr::pointtogl(h)); glhr::store_in_buffer(ourshape); } void extra_vertices() { while(isize(ourshape) < isize(hpc)) ourshape.push_back(glhr::pointtogl(hpc[isize(ourshape)])); glhr::store_in_buffer(ourshape); glhr::current_vertices = NULL; prehpc = isize(hpc); } #endif #if CAP_POLY int polyi; int polyx[POLYMAX], polyxr[POLYMAX], polyy[POLYMAX]; int poly_flags; void add1(const hyperpoint& H) { glcoords.push_back(make_array(H[0], H[1], H[2])); } int spherespecial, spherephase; bool is_behind(const hyperpoint& H) { return pmodel == mdDisk && vid.alpha + H[2] <= BEHIND_LIMIT; } hyperpoint be_just_on_view(const hyperpoint& H1, const hyperpoint &H2) { using namespace hyperpoint_vec; // H1[2] * t + H2[2] * (1-t) == BEHIND_LIMIT - vid.alpha // H2[2]- BEHIND_LIMIT + vid.alpha = t * (H2[2] - H1[2]) ld t = (H2[2] - BEHIND_LIMIT + vid.alpha) / (H2[2] - H1[2]); return H1 * t + H2 * (1-t); } bool last_infront; bool nif_error_in(ld x1, ld y1, ld x2, ld y2) { return pow(x1 * x2 + y2 * y2, 2) < (x1*x1+y1*y1)*(x2*x2+y2*y2)*.5; } bool knowgood; hyperpoint goodpoint; vector> tofix; bool correct_side(const hyperpoint& H) { double curnorm = H[0]*H[0]+H[1]*H[1]+H[2]*H[2]; double horizon = curnorm / vid.alpha; return (spherespecial>0) ^ (H[2] <= -horizon); } void fixpoint(array& hscr, hyperpoint H) { hyperpoint bad = H, good = goodpoint; for(int i=0; i<10; i++) { hyperpoint mid = midz(bad, good); if(correct_side(mid)) good = mid; else bad = mid; } hyperpoint Hscr; applymodel(good, Hscr); hscr = make_array(Hscr[0]*vid.radius, Hscr[1]*vid.radius*vid.stretch, Hscr[2]*vid.radius); } void addpoint(const hyperpoint& H) { if(true) { ld z = vid.radius; // if(vid.alpha + H[2] <= BEHIND_LIMIT && pmodel == mdDisk) poly_flags |= POLY_BEHIND; if(spherespecial) { if(correct_side(H)) { poly_flags |= POLY_INFRONT, last_infront = false; if(!knowgood || (spherespecial > 0 ? H[2]>goodpoint[2] : H[2] &tab, int ofs, int cnt) { tofix.clear(); knowgood = false; hyperpoint last = V * glhr::gltopoint(tab[ofs]); bool last_behind = is_behind(last); if(!last_behind) addpoint(last); hyperpoint enter = C0; hyperpoint firstleave; int start_behind = last_behind ? 1 : 0; for(int i=ofs+1; i(Hscr[0]*vid.radius+10, Hscr[1]*vid.radius*vid.stretch, Hscr[2]*vid.radius)); glcoords.push_back(make_array(Hscr[0]*vid.radius, Hscr[1]*vid.radius*vid.stretch+10, Hscr[2]*vid.radius)); glcoords.push_back(make_array(Hscr[0]*vid.radius-10, Hscr[1]*vid.radius*vid.stretch, Hscr[2]*vid.radius)); glcoords.push_back(make_array(Hscr[0]*vid.radius, Hscr[1]*vid.radius*vid.stretch-10, Hscr[2]*vid.radius)); glcoords.push_back(make_array(Hscr[0]*vid.radius+10, Hscr[1]*vid.radius*vid.stretch, Hscr[2]*vid.radius)); */ } } #if CAP_SDLGFX void aapolylineColor(SDL_Surface *s, int*x, int *y, int polyi, int col) { for(int i=1; i spx(px, px + polyi); std::vector spy(py, py + polyi); filledPolygonColor(s, spx.data(), spy.data(), polyi, col); } #endif #if CAP_TEXTURE void drawTexturedTriangle(SDL_Surface *s, int *px, int *py, glvertex *tv, int col) { transmatrix source = {{{ld(px[0]),ld(px[1]),ld(px[2])}, {ld(py[0]),ld(py[1]),ld(py[2])}, {1,1,1}}}; transmatrix target = {{{tv[0][0],tv[1][0],tv[2][0]}, {tv[0][1],tv[1][1],tv[2][1]}, {1,1,1}}}; transmatrix isource = inverse(source); int minx = px[0], maxx = px[0]; int miny = py[0], maxy = py[0]; for(int i=1; i<3; i++) minx = min(minx, px[i]), maxx = max(maxx, px[i]), miny = min(miny, py[i]), maxy = max(maxy, py[i]); for(int mx=minx; mx= -1e-7 && h[1] >= -1e-7 && h[2] >= -1e-7) { hyperpoint ht = target * h; int tw = texture::config.data.twidth; int x = int(ht[0] * tw) & (tw-1); int y = int(ht[1] * tw) & (tw-1); int c = texture::config.data.texture_pixels[y * tw + x]; auto& pix = qpixel(s, mx, my); for(int p=0; p<3; p++) { int alpha = part(c, 3) * part(col, 0); auto& v = part(pix, p); v = ((255*255 - alpha) * 255 * v + alpha * part(col, p+1) * part(c, p) + 255 * 255 * 255/2 + 1) / (255 * 255 * 255); } } } } #endif #if CAP_GL void glapplymatrix(const transmatrix& V) { GLfloat mat[16]; int id = 0; for(int y=0; y<3; y++) { for(int x=0; x<3; x++) mat[id++] = V[x][y]; mat[id++] = 0; } mat[12] = 0; mat[13] = 0; mat[14] = GLfloat(vid.alpha); mat[15] = 1; if(vid.stretch != 1) mat[1] *= vid.stretch, mat[5] *= vid.stretch, mat[9] *= vid.stretch, mat[13] *= vid.stretch; glhr::set_modelview(glhr::as_glmatrix(mat)); } #ifndef MINIMIZE_GL_CALLS #ifdef EMSCRIPTEN #define MINIMIZE_GL_CALLS 1 #else #define MINIMIZE_GL_CALLS 0 #endif #endif void gldraw(const transmatrix& V, const vector& v, int ps, int pq, int col, int outline, int flags, textureinfo *tinf) { if(tinf) { #if CAP_TEXTURE glhr::be_textured(); glBindTexture(GL_TEXTURE_2D, tinf->texture_id); glhr::vertices_texture(v, tinf->tvertices); #endif } else { glhr::be_nontextured(); #if !ISANDROID glhr::vertices(v); #else if(glhr::current_vertices != &v[ps]) { glhr::current_vertices = &v[ps]; glVertexAttribPointer(glhr::aPosition, 3, GL_FLOAT, GL_FALSE, sizeof(glvertex), &v[ps]); // glVertexPointer(3, GL_FLOAT, sizeof(glvertex), &v[ps]); // glhr::vertices(v); } ps = 0; #endif } for(int ed = stereo::active() ? -1 : 0; ed<2; ed+=2) { if(ed) stereo::set_projection(ed), stereo::set_viewport(ed); bool draw = col; if(using_perspective) glapplymatrix(V); if(draw) { if((flags & POLY_VCONVEX) && MINIMIZE_GL_CALLS) { glhr::vertices(v); glhr::color2(col); glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, ps, pq); } else if((flags & POLY_CCONVEX) && MINIMIZE_GL_CALLS) { glhr::vertices(v); glhr::color2(col); glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, ps-1, pq+1); } else { glEnable(GL_STENCIL_TEST); glColorMask( GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE ); glhr::set_depthtest(false); glStencilOp( GL_INVERT, GL_INVERT, GL_INVERT); glStencilFunc( GL_ALWAYS, 0x1, 0x1 ); glhr::color2(0xFFFFFFFF); glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, ps, pq); stereo::set_mask(ed); glhr::color2(col); glhr::set_depthtest(model_needs_depth()); if(flags & POLY_INVERSE) { glStencilOp( GL_ZERO, GL_ZERO, GL_ZERO); glStencilFunc( GL_NOTEQUAL, 1, 1); GLfloat xx = vid.xres; GLfloat yy = vid.yres; GLfloat dist = using_perspective ? stereo::scrdist : 0; vector scr = { make_array(-xx, -yy, dist), make_array(+xx, -yy, dist), make_array(+xx, +yy, dist), make_array(-xx, +yy, dist) }; glhr::vertices(scr); glhr::id_modelview(); glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, 0, 4); glhr::vertices(v); if(using_perspective) glapplymatrix(V); } else { glStencilOp( GL_ZERO, GL_ZERO, GL_ZERO); glStencilFunc( GL_EQUAL, 1, 1); glDrawArrays(tinf ? GL_TRIANGLES : GL_TRIANGLE_FAN, ps, pq); } glDisable(GL_STENCIL_TEST); } } if(outline) { glhr::color2(outline); glhr::set_depthtest(model_needs_depth()); glDrawArrays(GL_LINE_STRIP, ps, pq); } } if(stereo::active()) stereo::set_projection(0), stereo::set_viewport(0), stereo::set_mask(0); } #endif double linewidthat(const hyperpoint& h, double linewidth, int flags) { if((vid.antialias & AA_LINEWIDTH) && hyperbolic && !(flags & POLY_FORCEWIDE)) { double dz = h[2]; if(dz < 1 || abs(dz-stereo::scrdist) < 1e-6) return vid.linewidth; else { double dx = sqrt(dz * dz - 1); double dfc = dx/(dz+1); dfc = 1 - dfc*dfc; return max(dfc, linewidth) * vid.linewidth; } } return vid.linewidth; } // -radius to +3radius int mercator_coord; int mercator_loop_min = 0, mercator_loop_max = 0; ld mercator_period; void fixMercator(bool tinf) { if(pmodel == mdBand) mercator_period = 4 * vid.radius; else mercator_period = 2 * vid.radius; if(pmodel == mdSinusoidal) for(int i = 0; i hperiod) glcoords[0][mercator_coord] -= mercator_period; } ld first = glcoords[0][mercator_coord]; ld next = first; ld mincoord = first, maxcoord = first; for(int i = 0; i next + hperiod) glcoords[i][mercator_coord] -= mercator_period; next = glcoords[i][mercator_coord]; mincoord = min(mincoord, glcoords[i][mercator_coord]); maxcoord = max(maxcoord, glcoords[i][mercator_coord]); } if(abs(mincoord) > 50000 || abs(maxcoord) > 50000 || std::isnan(mincoord) || std::isnan(maxcoord)) { mercator_loop_max--; return; } ld last = first; while(last < next - hperiod) last += mercator_period; while(last > next + hperiod) last -= mercator_period; if(first == last) { while(mincoord > cmin) mercator_loop_min--, mincoord -= mercator_period; while(maxcoord < cmax) mercator_loop_max++, maxcoord += mercator_period; if(pmodel == mdSinusoidal) for(int i = 0; i cmin) { for(int i=0; i %d\n", base, qglcoords); for(int a=0; a 0) any = true; } if(!any) return; } if(sphere && pp.tinf && pp.cnt > 3) { int i = pp.cnt; pp.cnt = 3; for(int j=0; j phases[MAX_PHASE]; extern int twopoint_sphere_flips; extern bool twopoint_do_flips; int pha; if(twopoint_do_flips) { for(int i=0; i 0) continue; ld c1 = h1[1], c2 = -h2[1]; if(c1 < 0) c1 = -c1, c2 = -c2; hyperpoint h = h1 * c1 + h2 * c2; h /= hypot3(h); if(h[2] < 0 && abs(h[0]) < sin(vid.twopoint_param)) cpha = 1-cpha, pha = 2; } if(cpha == 1) pha = 0; } } vector tv; if(pp.tinf) { for(int i=0; itvertices[pp.offset+i]); swap(pp.tinf->tvertices, tv); } dynamicval d1(pmodel, mdUnchanged); dynamicval d2(pp.V, Id); dynamicval d3(pp.offset, 0); dynamicval d4(pp.tab, pp.tab); for(int j=0; j d5(pp.cnt, isize(phases[j])); pp.tab = &phases[j]; drawpolyline(p); } if(pp.tinf) swap(pp.tinf->tvertices, tv); return; } if(spherespecial && p.prio == PPR::MOBILE_ARROW) { if(spherephase == 0) return; dynamicval ss(spherespecial, 0); drawpolyline(p); return; } #if CAP_GL if(vid.usingGL && using_perspective) { glLineWidth(linewidthat(tC0(pp.V), pp.linewidth, pp.flags)); gldraw(pp.V, *pp.tab, pp.offset, pp.cnt, p.col, pp.outline, pp.flags &~ POLY_INVERSE, pp.tinf); return; } #endif glcoords.clear(); poly_flags = pp.flags; double d = 0, curradius = 0; if(sphere) { d = det(pp.V); curradius = pow(abs(d), 1/3.); } /* pp.outline = 0x80808080; p.col = 0; */ last_infront = false; addpoly(pp.V, *pp.tab, pp.offset, pp.cnt); if(!(sphere && vid.alpha < .9)) for(int i=1; i vid.xres * 2 || dy > vid.yres * 2) return; } if(poly_flags & POLY_BEHIND) return; if(isize(glcoords) <= 1) return; mercator_loop_min = mercator_loop_max = 0; if(sphere && mdBandAny()) fixMercator(pp.tinf); int poly_limit = max(vid.xres, vid.yres) * 2; if(0) for(auto& p: glcoords) { if(abs(p[0]) > poly_limit || abs(p[1]) > poly_limit) return; // too large! } bool equi = mdAzimuthalEqui() || pmodel == mdFisheye; bool nofill = false; if(poly_flags & POLY_NIF_ERROR) return; if(spherespecial == 1 && (poly_flags & POLY_INFRONT) && (poly_flags & POLY_NOTINFRONT) && vid.alpha <= 1) { bool around_center = false; for(int i=0; i 0 || (sphere && equi)) && !(poly_flags & POLY_ISSIDE)) { if(!pp.tinf) { hyperpoint hscr; hyperpoint h1 = pp.V * intester; if(is_behind(h1)) { if(sphere) { for(int i=0; i<3; i++) h1[i] = -h1[i]; poly_flags &= ~POLY_CENTERIN; } else nofill = true; } applymodel(h1, hscr); hscr[0] *= vid.radius; hscr[1] *= vid.radius * vid.stretch; for(int i=0; i0) poly_flags ^= POLY_INVERSE; } if(poly_flags & POLY_INVERSE) { if(curradius < vid.alpha - 1e-6) return; } } else poly_flags &=~ POLY_INVERSE; if(spherespecial) { if(!hiliteclick && !(poly_flags & POLY_INFRONT)) return; } int lastl = 0; for(int l=mercator_loop_min; l <= mercator_loop_max; l++) { if(l || lastl) { for(int i=0; i(vid.radius * sin(a), vid.radius * vid.stretch * cos(a), stereo::scrdist)); } poly_flags ^= POLY_INVERSE; } else { // If we are on a zlevel, the algorithm above will not work correctly. // It is hard to tell what to do in this case. Just fill neither side nofill = true; } } #if CAP_GL if(vid.usingGL) { // if(pmodel == 0) for(int i=0; i tv; for(int i=0; itvertices[pp.offset+i]); swap(pp.tinf->tvertices, tv); gldraw(Id, glcoords, 0, isize(glcoords), p.col, pp.outline, poly_flags, pp.tinf); swap(pp.tinf->tvertices, tv); } else gldraw(Id, glcoords, 0, isize(glcoords), nofill ? 0 : p.col, pp.outline, poly_flags, nofill ? NULL : pp.tinf); continue; } #endif #if CAP_SVG==1 if(svg::in) { coords_to_poly(); int col = p.col; if(poly_flags & POLY_INVERSE) col = 0; svg::polygon(polyx, polyy, polyi, col, pp.outline, pp.linewidth); continue; } #endif coords_to_poly(); #if CAP_XGD==1 gdpush(1); gdpush(p.col); gdpush(pp.outline); gdpush(polyi); for(int i=0; itvertices[pp.offset + i], p.col); #endif } else if(poly_flags & POLY_INVERSE) { int i = polyi; if(true) { polyx[i] = 0; polyy[i] = 0; i++; polyx[i] = vid.xres; polyy[i] = 0; i++; polyx[i] = vid.xres; polyy[i] = vid.yres; i++; polyx[i] = 0; polyy[i] = vid.yres; i++; polyx[i] = 0; polyy[i] = 0; i++; } filledPolygonColorI(s, polyx, polyy, polyi+5, p.col); } else filledPolygonColorI(s, polyx, polyy, polyi, p.col); if(stereo::active()) filledPolygonColorI(aux, polyxr, polyy, polyi, p.col); // part(pp.outline, 0) = part(pp.outline, 0) * linewidthat(tC0(pp.V), pp.minwidth); ((vid.antialias & AA_NOGL) ?aapolylineColor:polylineColor)(s, polyx, polyy, polyi, pp.outline); if(stereo::active()) aapolylineColor(aux, polyxr, polyy, polyi, pp.outline); if(vid.xres >= 2000 || fatborder) { int xmi = 3000, xma = -3000; for(int t=0; t xmi + 20) for(int x=-1; x<2; x++) for(int y=-1; y<=2; y++) if(x*x+y*y == 1) { for(int t=0; t prettylinepoints; void prettypoint(const hyperpoint& h) { prettylinepoints.push_back(glhr::pointtogl(h)); } void prettylinesub(const hyperpoint& h1, const hyperpoint& h2, int lev) { if(lev >= 0) { hyperpoint h3 = midz(h1, h2); prettylinesub(h1, h3, lev-1); prettylinesub(h3, h2, lev-1); } else prettypoint(h2); } void prettyline(hyperpoint h1, hyperpoint h2, int col, int lev) { prettylinepoints.clear(); prettypoint(h1); prettylinesub(h1, h2, lev); polytodraw p; auto& pp = p.u.poly; pp.V = Id; pp.tab = &prettylinepoints; pp.offset = 0; pp.cnt = isize(prettylinepoints); pp.linewidth = vid.linewidth; p.col = 0; pp.outline = col; pp.flags = POLY_ISSIDE; pp.tinf = NULL; drawpolyline(p); } void prettypoly(const vector& t, int fillcol, int linecol, int lev) { prettylinepoints.clear(); prettypoint(t[0]); for(int i=0; i curvedata; int curvestart = 0; bool keep_curvedata = false; hookset *hooks_specialdraw; void drawqueueitem(polytodraw& ptd) { // if(ptd.prio == 46) printf("eye size %d\n", polyi); switch(ptd.kind) { case pkLink: #if CAP_SVG svg::link = ptd.u.link.link; #endif break; case pkSpecial: callhooks(hooks_specialdraw, ptd); break; case pkResetModel: pmodel = eModel(ptd.col); stereo::set_projection(0); break; case pkPoly: drawpolyline(ptd); break; case pkLine: { dynamicval d(vid.linewidth, ptd.u.line.width); prettyline(ptd.u.line.H1, ptd.u.line.H2, ptd.col, ptd.u.line.prf); break; } case pkString: { qchr& q(ptd.u.chr); #if ISMOBILE==0 if(svg::in) svg::text(q.x, q.y, q.size, q.str, q.frame, ptd.col, q.align); else { int fr = q.frame & 255; displayfrSP(q.x, q.y, q.shift, fr, q.size, q.str, ptd.col, q.align, q.frame >> 8); } #else displayfr(q.x, q.y, q.frame, q.size, q.str, ptd.col, q.align); #endif break; } case pkCircle: { #if ISMOBILE==0 if(svg::in) svg::circle(ptd.u.cir.x, ptd.u.cir.y, ptd.u.cir.size, ptd.col); else #endif drawCircle(ptd.u.cir.x, ptd.u.cir.y, ptd.u.cir.size, ptd.col); break; } case pkShape: ; } } void initquickqueue() { ptds.clear(); poly_outline = OUTLINE_NONE; } void sortquickqueue() { for(int i=1; i= PMAX) { printf("Illegal priority %d of kind %d\n", pd, ptds[i].kind); ptds[i].prio = PPR(rand() % int(PPR::MAX)); } qp[pd]++; } int total = 0; for(int a=0; au.poly.V * xpush0(.1)) < xintval(p2->u.poly.V * xpush0(.1)); }); #endif profile_stop(3); #if CAP_SDL if(stereo::active() && !vid.usingGL) { if(aux && (aux->w != s->w || aux->h != s->h)) SDL_FreeSurface(aux); if(!aux) { aux = SDL_CreateRGBSurface(SDL_SWSURFACE,s->w,s->h,32,0,0,0,0); } // SDL_LockSurface(aux); // memset(aux->pixels, 0, vid.xres * vid.yres * 4); // SDL_UnlockSurface(aux); SDL_BlitSurface(s, NULL, aux, NULL); } #endif #ifdef STLSORT #define GET_PTD(i) polytodraw& ptd (ptds[i]); #else #define GET_PTD(i) polytodraw& ptd (*ptds2[i]); #endif spherespecial = 0; spherephase = 0; stereo::set_projection(0); // on the sphere, parts on the back are drawn first if(sphere && pmodel == 0) { // in SVG, draw boundary circle first if(svg::in) for(int i=0; i=0; i--) { GET_PTD(i); if(ptd.kind == pkPoly || ptd.kind == pkLine) { unsigned c = ptd.col; int alpha = ptd.col & 255; if(vid.alpha <= 1) { ptd.col = 0; } else if(alpha == 255) ptd.col = (gradient(backcolor, c>>8, 0, backbrightness, 1)<<8) | 0xFF; else ptd.col = ptd.col - alpha + int(backbrightness * alpha); drawqueueitem(ptd); ptd.col = c; } } #ifndef STLSORT for(PPR p: {PPR::REDWALLs, PPR::REDWALLs2, PPR::REDWALLs3, PPR::WALL3s, PPR::LAKEWALL, PPR::INLAKEWALL, PPR::BELOWBOTTOM}) reverse(&ptds2[qp0[int(p)]], &ptds2[qp[int(p)]]); #endif spherespecial *= -1; spherephase = 1; stereo::set_projection(0); } for(int i=0; iw * s->h; int *a = (int*) s->pixels; int *b = (int*) aux->pixels; SDL_LockSurface(aux); while(qty) { *a = ((*a) & 0xFF0000) | ((*b) & 0x00FFFF); a++; b++; qty--; } SDL_UnlockSurface(aux); } if(stereo::mode == stereo::sLR && !vid.usingGL) { SDL_LockSurface(aux); for(int y=0; y list; bool sym; int rots; int color; hyperpoint shift, spin; hpcshape sh; }; struct usershape { usershapelayer d[USERLAYERS]; }; array, mapeditor::USERSHAPEGROUPS> usershapes; transmatrix ddi(int a, ld x) { return xspinpush(a * M_PI / S42, x); } void drawTentacle(hpcshape &h, ld rad, ld var, ld divby) { double tlength = max(crossf, hexhexdist * gp::scale * irr::scale); if(archimedean) tlength = arcm::current.scale(); int max = int(20 * pow(2, vid.linequality)); for(ld i=0; i<=max; i++) hpcpush(ddi(S21, rad + var * sin(i * M_PI/divby)) * ddi(0, tlength * i/max) * C0); for(ld i=max; i>=0; i--) hpcpush(ddi(S21*3, rad - var * sin(i * M_PI/divby)) * ddi(0, tlength * i/max) * C0); hpcpush(ddi(S21, rad + var * sin(0 * M_PI/divby)) * C0); } hyperpoint hpxd(ld d, ld x, ld y, ld z) { hyperpoint H = hpxyz(d*x, d*y, z); H = mid(H, H); return H; } double scalef; hyperpoint hpxyzsc(double x, double y, double z) { if(!BITRUNCATED) return hpxd(scalef, x, y, z); else return hpxyz(x,y,z); } hyperpoint turtlevertex(int u, double x, double y, double z) { ld scale = BITRUNCATED ? 1 : scalef; if(u) scale /= 2; return hpxd(scale, x, y, z); } vector allshapes; void finishshape() { last->e = isize(hpc); double area = 0; for(int i=last->s; ie-1; i++) area += hpc[i][0] * hpc[i+1][1] - hpc[i+1][0] * hpc[i][1]; if(abs(area) < 1e-9) last->flags |= POLY_ISSIDE; if(area >= 0) last->flags |= POLY_INVERSE; for(int i=last->s; ie-1; i++) { ld x1 = hpc[i][0] - intester[0], y1 = hpc[i][1] - intester[1], x2 = hpc[i+1][0] - intester[0], y2 = hpc[i+1][1] - intester[1]; if(asign(y1, y2)) { ld x = xcross(x1, y1, x2, y2); if(abs(x) < 1e-6 && !(last->flags & POLY_ISSIDE)) { printf("close call, x = %lf\n", x); } if(x < 0) last->flags ^= POLY_CENTERIN; } } bool allplus = true, allminus = true; for(int i=last->s; ie-1; i++) { ld v = hpc[i][0] * hpc[i+1][1] - hpc[i+1][0] * hpc[i][1]; if(v > 1e-6) allplus = false; if(v < -1e-6) allminus = false; } if(allminus || allplus) last->flags |= POLY_CCONVEX; allplus = true, allminus = true; ld cx = hpc[last->s][0], cy = hpc[last->s][1]; for(int i=last->s; ie-1; i++) { ld v = (hpc[i][0]-cx) * (hpc[i+1][1]-cy) - (hpc[i+1][0]-cx) * (hpc[i][1]-cy); if(v > 1e-6) allplus = false; if(v < -1e-6) allminus = false; } if(allminus || allplus) last->flags |= POLY_VCONVEX; allshapes.push_back(last); /* if(isnan(area)) ; else if(intval(hpc[last->s], hpc[last->e-1]) > 1e-6) printf("bad end\n"); */ } void bshape(hpcshape& sh, PPR prio) { if(last) finishshape(); hpc.push_back(hpxy(0,0)); last = &sh; last->s = isize(hpc), last->prio = prio; last->flags = 0; first = true; } vector> symmetriesAt; #ifndef SCALETUNER static const #endif double bscale7 = 1, brot7 = 0, bscale6 = 1, brot6 = 0; void bshape(hpcshape& sh, PPR prio, double shzoom, int shapeid, double bonus = 0, flagtype flags = 0) { bshape(sh, prio); int whereis = 0; while(polydata[whereis] != NEWSHAPE || polydata[whereis+1] != shapeid) whereis++; int rots = polydata[whereis+2]; int sym = polydata[whereis+3]; array arr; arr[0] = isize(hpc); arr[1] = rots; arr[2] = sym; symmetriesAt.emplace_back(arr); whereis += 4; int qty = 0; while(polydata[whereis + 2*qty] != NEWSHAPE) qty++; double shzoomx = shzoom; double shzoomy = shzoom; if(shzoom == WOLF) shzoomx = 1.5 * (!BITRUNCATED && !archimedean ? crossf / hcrossf : 1), shzoomy = 1.6 * (!BITRUNCATED && !archimedean ? crossf / hcrossf : 1); int rots2 = rots; // shapes 368..370 are specially designed if(!(shapeid >= 368 && shapeid <= 370)) { if(flags&1) { rots2 = 6; } else if(rots == 7) { rots2 = S7; if(rots2 != 7 && !euclid) bonus += M_PI; shzoomx *= bscale7; shzoomy *= bscale7; bonus += brot7; if(euclid) shzoomx *= .9, shzoomy *= .9, bonus += .3; } if(rots == 3) { rots2 = S3; shzoomx *= bscale6; shzoomy *= bscale6; if(S6 == 8) bonus += .4; bonus += brot6; } if(rots == 6) { rots2 = S6; shzoomx *= bscale6; shzoomy *= bscale6; if(S6 == 8) bonus += .4; bonus += brot6; } } else shzoomx *= bscale7, shzoomy *= bscale7; double bonusf = /* sphere ? M_PI*4/35 : */ (rots-rots2+.0) / rots2; auto ipoint = [&] (int i, int mul) { hyperpoint h = hpxy(polydata[whereis+2*i] * shzoomx, polydata[whereis+2*i+1] * shzoomy * mul); if(rots == rots2 && !bonus) return h; double d = atan2(h[0], h[1]); return spin(bonus + bonusf * d) * h; }; for(int r=0; r=0; i--) hpcpush(spin(2*M_PI*r/rots2) * ipoint(i, -1)); } hpcpush(ipoint(0, 1)); } void copyshape(hpcshape& sh, hpcshape& orig, PPR prio) { if(last) last->e = isize(hpc); sh = orig; sh.prio = prio; } void zoomShape(hpcshape& old, hpcshape& newsh, double factor, PPR prio) { bshape(newsh, prio); for(int i=old.s; i=0; i--) hpcpush(T * spin(2*M_PI*r/ds.rots) * mirrortrans * ds.list[i]); } } hpcpush(T * ds.list[0]); } ld gsca() { return 1; } ld grot() { return 0; } template ld gsca(bool geometry, ld factor, T... t) { if(geometry) return factor * gsca(t...); else return gsca(t...); } template ld grot(bool geometry, ld factor, T... t) { if(geometry) return factor + grot(t...); else return grot(t...); } ld dlow_table[SIDEPARS], dhi_table[SIDEPARS]; #define SHADMUL (S3==4 ? 1.05 : 1.3) void buildpolys() { intester = hpxy(1e-3, 1.3e-3); symmetriesAt.clear(); allshapes.clear(); geom3::compute(); gp::clear_plainshapes(); DEBB(DF_INIT, (debugfile,"buildpolys\n")); // printf("crossf = %f euclid = %d sphere = %d\n", float(crossf), euclid, sphere); hpc.clear(); bshape(shMovestar, PPR::MOVESTAR); for(int i=0; i<=8; i++) { hpcpush(xspinpush0(M_PI * i/4, crossf)); if(i != 8) hpcpush(xspinpush0(M_PI * i/4 + M_PI/8, crossf/4)); } // scales scalef = BITRUNCATED ? hcrossf / hcrossf7 : crossf / hcrossf7; ld xcrossf = crossf; if(euclid) scalef *= .52/crossf; double spzoom6 = sphere ? 1.2375 : 1; double spzoom7 = sphere ? .8 : 1; double spzoomd7 = (!BITRUNCATED && sphere) ? 1 : spzoom7; double fac80 = a45 ? 1.4 : a46 ? 1.2 : (a38) ? .7 : .8; double fac94 = euclid ? .8 : a4 ? (BITRUNCATED ? .9 : 1.1) : .94; if(euclid) fac80 = fac94 = .9; if(geometry == g47 || geometry == gSmallSphere || geometry == gTinySphere || geometry == gSmallElliptic) fac80 *= 1.2, fac94 *= .94; if(geometry == gTinySphere) fac80 *= 1.2, fac94 *= .94; // procedural floors double zhexf = BITRUNCATED ? hexf : crossf* .55; double p = -.006; int td = ((!BITRUNCATED || euclid) && !(S7&1)) ? S42+S6 : 0; double trihepta0 = scalef*spzoom6*(.2776+p) * gsca(a4, 1.3, a46, .975, a47, .85, a38, .9) * bscale6; double trihepta1 = (sphere ? .54 : scalef*spzoom6*(.5273-2*p)) * gsca(a4, .8, a46, 1.075, sphere4, 1.3) * bscale7; double eps = hexhexdist * .05; if(euclid) trihepta0 = hexhexdist * .5 - eps * sqrt(3)/2, trihepta1 = hexhexdist * sqrt(3)/2 - eps; // .5-.1; .75-.05 if(euclid4) trihepta0 = trihepta1 = crossf * 1.35 / 2; if(sphere&&S7==3) trihepta0 *= 1.3, trihepta1 *= 1.6; if(!BITRUNCATED) { ld hedge = hdist(xspinpush0(M_PI/S7, rhexf), xspinpush0(-M_PI/S7, rhexf)); trihepta1 = hdist0(xpush(tessf) * xspinpush0(2*M_PI*2/S7, tessf)) / 2 * .98; trihepta0 = hdist0(xpush(-tessf) * xspinpush0(M_PI/S7, rhexf+hedge/2)) * .98; } if(binarytiling) hexvdist = rhexf = 1, tessf = 1, gp::scale = 1, scalef = 1, crossf *= .8; double floorrad0 = hexvdist*0.92; double floorrad1 = rhexf / gp::scale *0.94; ld goldbf = 1; if(GOLDBERG) goldbf = gp::scale * 1.6; if(IRREGULAR) goldbf = irr::scale * 1.6; if(GOLDBERG) floorrad1 /= 1.6; double triangleside = hcrossf*.94; if(!BITRUNCATED) triangleside = tessf * .94; if(euclid4) { if(!BITRUNCATED) floorrad0 = floorrad1 = rhexf * .94; else floorrad0 = hexvdist * .9, floorrad1 = rhexf * .8; } if(archimedean) { triangleside = xcrossf = arcm::current.scale(); goldbf = 1; scalef = xcrossf / hcrossf7; floorrad0 = floorrad1 = triangleside * .45; zhexf = xcrossf * .55; } // sidewall parameters for the 3D mode for(int k=0; k 0 && dhi > 0) || (dlow < 0 && dhi < 0); bshape(shSemiFloorSide[k], PPR::LAKEWALL); for(int t=0; t<=3; t+=3) hpcpush(ddi(S7 + (3+t)*S14, floorrad0) * C0); chasmifyPoly(dlow, dhi, k); } bshape(shCircleFloor, PPR::FLOOR); for(int t=0; t<=S84; t+=2) hpcpush(ddi(t, floorrad1*gp::scale*.9) * C0); for(int i=0; i<3; i++) for(int j=0; j<3; j++) shadowmulmatrix[i][j] = i==2&&j==2 ? 1: i==j ? SHADMUL: 0; for(int d=0; d<2; d++) { bshape(shSemiFloor[d], PPR::FLOOR); for(int t=0; t<=4; t++) hpcpush(ddi(S7 + (3+3*d+t%4)*S14, floorrad0) * C0); } // todo not shexf bshape(shBigCarpet1, PPR::GFLOORa); for(int t=0; t<=S7; t++) hpcpush(ddi(t*12, -zhexf*2.1) * C0); bshape(shBigCarpet2, PPR::GFLOORb); for(int t=0; t<=S7; t++) hpcpush(ddi(t*12, -zhexf*1.9) * C0); bshape(shBigCarpet3, PPR::GFLOORc); for(int t=0; t<=S7; t++) hpcpush(ddi(t*12*3, -zhexf*1.7) * C0); bshape(shBFloor[0], PPR::BFLOOR); for(int t=0; t<=S6; t++) hpcpush(ddi(S7 + t*S14, floorrad0*.1) * C0); bshape(shBFloor[1], PPR::BFLOOR); for(int t=0; t<=S7; t++) hpcpush(ddi(t*S12, floorrad1*.1) * C0); bshape(shMineMark[0], PPR::MINEMARK); for(int t=0; t<=S6; t++) hpcpush(ddi(S7 + t*S14, floorrad0*.1) * C0); bshape(shMineMark[1], PPR::MINEMARK); for(int t=0; t<=S7; t++) hpcpush(ddi(t*S12, floorrad1*.1) * C0); for(int d=0; d<2; d++) { bshape(shSemiBFloor[d], PPR::BFLOOR); for(int t=0; t<=4; t++) hpcpush(ddi(S7 + (3+3*d+t%4)*S14, floorrad0*.1) * C0); } // walls etc bshape(shGiantStar[1], PPR::GFLOORa); for(int t=0; t<=S7; t++) hpcpush(ddi(t*S36, -zhexf*2.4) * C0); bshape(shGiantStar[0], PPR::GFLOORa); for(int t=0; t<=S6; t++) { hpcpush(ddi(t*S14, -zhexf*2.4) * C0); hpcpush(ddi(t*S14+S7, zhexf*1.5) * C0); } hpcpush(ddi(0, -zhexf*2.4) * C0); bshape(shMirror, PPR::WALL); if(PURE) { for(int t=0; t<=S7; t++) hpcpush(ddi(t*12, floorrad1*7/8 * gp::scale) * C0); } else { for(int t=0; t<=6; t++) hpcpush(ddi(S7 + t*S14, floorrad0*7/8 * gp::scale) * C0); } if(binarytiling) { for(int i=0; i<2; i++) { bshape(shWall[i], PPR::WALL); horopoint(log(2)/8, .1); horopoint(log(2)/8, -.1); horopoint(-log(2)/8, 0); } } else { bshape(shWall[0], PPR::WALL); for(int t=0; t<=S6; t++) { hpcpush(ddi(S7 + t*S14, floorrad0 * goldbf) * C0); if(t != S6) hpcpush(ddi(S14 + t*S14, floorrad0 * goldbf/4) * C0); } bshape(shWall[1], PPR::WALL); if(S7 == 6 || S7 == 4) { for(int t=0; t<=S6; t++) { hpcpush(ddi(S7 + t*S14, floorrad1 * goldbf) * C0); if(t != S6) hpcpush(ddi(S14 + t*S14, floorrad1 * goldbf/4) * C0); } } else for(int t=0; t<=S7; t++) hpcpush(ddi(t*S36+td, floorrad1 * goldbf) * C0); } bshape(shCross, PPR::WALL); for(int i=0; i<=84; i+=7) hpcpush(xspinpush0(2*M_PI*i/84, zhexf * (i%3 ? 0.8 : 0.3))); // items bshape(shGem[0], PPR::ITEM); for(int t=0; t<=S6; t++) { hpcpush(ddi(S7 + t*S14, zhexf*.4) * C0); if(t != S6) hpcpush(ddi(S14 + t*S14, zhexf*.1) * C0); } bshape(shGem[1], PPR::ITEM); if(S7 == 6) { for(int t=0; t<=S6; t++) { hpcpush(ddi(S7 + t*S14, zhexf*.4) * C0); if(t != S6) hpcpush(ddi(S14 + t*S14, zhexf*.1) * C0); } } else for(int t=0; t<=S7; t++) hpcpush(ddi(t*S36, zhexf*.5) * C0); bshape(shStar, PPR::ITEM); for(int t=0; t<=S84; t+=S6) { hpcpush(ddi(t, zhexf*.2) * C0); if(t != S84) hpcpush(ddi(t+3, zhexf*.6) * C0); } bshape(shDaisy, PPR::ITEM); for(int t=0; t<=S6; t++) { hpcpush(ddi(t*S14, zhexf*.8*3/4) * C0); if(t != S6) hpcpush(ddi(t*S14+S7, zhexf*-.5*3/4) * C0); } hpcpush(ddi(0, zhexf*.6) * C0); bshape(shTriangle, PPR::ITEM); for(int t=0; t<=S3; t++) { hpcpush(ddi(t*S28, zhexf*.5) * C0); } double disksize = xcrossf; if(PURE && a38) disksize *= 2; else if(a38) disksize *= 1.5; else if(!BITRUNCATED && S6 == 8) disksize *= 1.5; if(a38 && GOLDBERG) disksize /= 2; bshape(shDisk, PPR::ITEM); for(int i=0; i<=S84; i+=S3) hpcpush(ddi(i, disksize * .2) * C0); bshape(shDiskT, PPR::ITEM); for(int i=0; i<=S84; i+=S28) hpcpush(ddi(i, disksize * .2) * C0); bshape(shDiskS, PPR::ITEM); for(int i=0; i<=S84; i+=S21) { hpcpush(ddi(i, disksize * .2) * C0); if(i != S84) { hpcpush(ddi(i+S21/3, disksize * .1) * C0); hpcpush(ddi(i+S21-S21/3, disksize * .1) * C0); } } bshape(shDiskM, PPR::ITEM); for(int i=0; i<=S84; i+=S3) { hpcpush(ddi(i, disksize * .1) * C0); } bshape(shDiskSq, PPR::ITEM); for(int i=0; i<=S84; i+=S21) { hpcpush(ddi(i, disksize * .15) * C0); } bshape(shEgg, PPR::ITEM); RING(i) hpcpush(hpxy(sin(i*2*M_PI/S84)*.15, cos(i*2*M_PI/S84)*.11)); bshape(shRing, PPR::ITEM); RING(i) hpcpush(ddi(i, disksize * .25) * C0); REVPRING(i) hpcpush(ddi(i, disksize * .30) * C0); hpcpush(ddi(0, disksize * .25) * C0); bshape(shSpikedRing, PPR::ITEM); RING(i) hpcpush(ddi(i, disksize * .25) * C0); REVPRING(i) hpcpush(ddi(i, disksize * (int(i)&1?.35:.30)) * C0); hpcpush(ddi(0, disksize * .25) * C0); bshape(shTargetRing, PPR::ITEM); RING(i) hpcpush(ddi(i, disksize * .25) * C0); REVPRING(i) hpcpush(ddi(i, disksize * (i >= S42-6 && i <= S42+6 ?.36:.30)) * C0); hpcpush(ddi(0, disksize * .25) * C0); bshape(shSpearRing, PPR::ITEM); RING(i) hpcpush(ddi(i, disksize * .25) * C0); REVPRING(i) { double d = i - S42; if(d<0) d = -d; d = 8 - 2 * d; if(d<0) d = 0; hpcpush(ddi(i, disksize * (.3 + .04 * d)) * C0); } hpcpush(ddi(0, disksize * .25) * C0); /* three nice spikes bshape(shLoveRing, PPR::ITEM); for(int i=0; i<=S84; i+=3) hpcpush(ddi(i, disksize * .25) * C0); for(int i=S84; i>=0; i--) { int j = i*3 % S84; int d = j - S42; if(d<0) d = -d; d = 8 - 2 * d; if(d<0) d = 0; hpcpush(ddi(i, disksize * (.3 + .02 * d)) * C0); } hpcpush(ddi(0, disksize * .25) * C0); */ bshape(shLoveRing, PPR::ITEM); RING(i) hpcpush(ddi(i, disksize * .25) * C0); REVPRING(i) { double j = i*3; while(j >= S84) j -= S84; double d = j - S42; d = d / 9; if(d<0) d = -d; d = 8 - 2 * d; if(d<0) d = 0; if(d >= 6) d -= (d-6)/3; hpcpush(ddi(i, disksize * (.27 + .02 * d)) * C0); } hpcpush(ddi(0, disksize * .25) * C0); auto dmod = [] (ld a, ld b) { return a - int(a/b)*b; }; bshape(shSawRing, PPR::ITEM); RING(i) hpcpush(ddi(i, disksize * .25) * C0); REVPRING(i) hpcpush(ddi(i, disksize * (.3 + (int(i) & 3) * .02)) * C0); hpcpush(ddi(0, disksize * .25) * C0); bshape(shGearRing, PPR::ITEM); RING(i) hpcpush(ddi(i, disksize * .25) * C0); REVPRING(i) hpcpush(ddi(i, disksize * ((dmod(i, 6)<3)?.3:.36)) * C0); hpcpush(ddi(0, disksize * .25) * C0); bshape(shPeaceRing, PPR::ITEM); RING(i) hpcpush(ddi(i, disksize * .25) * C0); REVPRING(i) hpcpush(ddi(i, disksize * (dmod(i, S28) < S7?.36 : .3)) * C0); hpcpush(ddi(0, disksize * .25) * C0); bshape(shHeptaRing, PPR::ITEM); RING(i) hpcpush(ddi(i, disksize * .25) * C0); REVPRING(i) hpcpush(ddi(i, disksize * (dmod(i, S12) < S3?.4 : .27)) * C0); hpcpush(ddi(0, disksize * .25) * C0); bshape(shCompass1, PPR::ITEM); RING(i) hpcpush(ddi(i, xcrossf * .35) * C0); bshape(shCompass2, PPR::ITEMa); RING(i) hpcpush(ddi(i, xcrossf * .3) * C0); bshape(shCompass3, PPR::ITEMb); hpcpush(ddi(0, xcrossf * .29) * C0); hpcpush(ddi(S21, xcrossf * .04) * C0); hpcpush(ddi(-S21, xcrossf * .04) * C0); hpcpush(ddi(0, xcrossf * .29) * C0); /* bshape(shBranch, 32); hpcpush(ddi(21, xcrossf/5) * C0); hpcpush(ddi(21, -xcrossf/5) * C0); hpcpush(ddi(21, -xcrossf/5) * ddi(0, xcrossf) * C0); hpcpush(ddi(21, xcrossf/5) * ddi(0, xcrossf) * C0); */ bshape(shILeaf[0], PPR::ONTENTACLE); for(int t=0; t<=S6; t++) { hpcpush(ddi(S7 + t*S14, zhexf*.7) * C0); if(t != S6) hpcpush(ddi(S14 + t*S14, zhexf*.15) * C0); } bshape(shILeaf[1], PPR::ONTENTACLE); if(S3 == 3) for(int t=0; t<=S7; t++) hpcpush(ddi(t*S36, zhexf*.8) * C0); else { for(int t=0; t<=S7; t++) { hpcpush(ddi(t*S12, zhexf*.8) * C0); if(t != S6) hpcpush(ddi(t*S12 + S6, zhexf*.2) * C0); } } bshape(shSlime, PPR::MONSTER_BODY); PRING(i) hpcpush(ddi(i, xcrossf * (0.7 + .2 * sin(i * M_PI * 2 / S84 * 9))) * C0); bshape(shJelly, PPR::MONSTER_BODY); PRING(i) hpcpush(ddi(i, xcrossf * (0.4 + .03 * sin(i * M_PI * 2 / S84 * 7))) * C0); bshape(shHeptaMarker, PPR::HEPTAMARK); for(int t=0; t<=S7; t++) hpcpush(ddi(t*S12, zhexf*.2) * C0); bshape(shSnowball, PPR::ITEM); for(int t=0; t<=S7*4; t++) hpcpush(ddi(t*S3, zhexf*.1) * C0); bshape(shRose, PPR::ITEM); PRING(t) hpcpush(xspinpush0(M_PI * t / (S42+.0), xcrossf * (0.2 + .15 * sin(M_PI * t / (S42+.0) * 3)))); bshape(shThorns, PPR::THORNS); for(int t=0; t<=60; t++) hpcpush(xspinpush0(M_PI * t / 30.0, xcrossf * ((t&1) ? 0.3 : 0.6))); for(int i=0; i<16; i++) { bshape(shParticle[i], PPR::PARTICLE); for(int t=0; t<6; t++) hpcpush(xspinpush0(M_PI * t * 2 / 6 + M_PI * 2/6 * hrand(100) / 150., (0.03 + hrand(100) * 0.0003) * goldbf)); hpc.push_back(hpc[last->s]); } // hand-drawn shapes if(a38) spzoom6 *= .9; if(a4 && BITRUNCATED) spzoom6 *= 1.9, spzoom7 *= .9, spzoomd7 *= .9; if(a46 && BITRUNCATED) spzoom6 *= .9; if(a47 && BITRUNCATED) spzoom6 *= .85; if(archimedean) shFullFloor.configure(arcm::current.scale()/2, arcm::current.scale()/2); else shFullFloor.configure(hexvdist, rhexf); shFloor.configure(floorrad0, floorrad1); shMFloor.configure(floorrad0*7/8, floorrad1*7/8); shMFloor2.configure(floorrad0*6/8, floorrad1*6/8); shMFloor3.configure(floorrad0*5/8, floorrad1*5/8); shMFloor4.configure(floorrad0*4/8, floorrad1*4/8); shBigTriangle.configure(triangleside, 0); shBigTriangle.prio = PPR::FLOOR_TOWER; shBigHepta.configure(0, (!BITRUNCATED ? tessf : xcrossf) * .97); shTriheptaFloor.configure(trihepta0, trihepta1); shDragonFloor.prio = PPR::FLOOR_DRAGON; shPowerFloor.prio = PPR::FLOOR_DRAGON; for(int i=0; i<3; i++) shRedRockFloor[i].scale = .9 - .1 * i; generate_floorshapes(); bshape(shHalfFloor[0], PPR::FLOOR, scalef*spzoom6, 329); bshape(shHalfFloor[1], PPR::FLOOR, scalef*spzoom6, 327); bshape(shHalfFloor[2], PPR::FLOOR, scalef*spzoom6, 331); bshape(shHalfMirror[0], PPR::WALL, scalef*spzoom6, 330); bshape(shHalfMirror[1], PPR::WALL, scalef*spzoom6, 328); bshape(shHalfMirror[2], PPR::WALL, scalef*spzoom6, 332); bshape(shAsymmetric, PPR::TEXT, scalef, 374); bshape(shTriheptaSpecial[2], PPR::FLOOR, scalef, 32); bshape(shTriheptaSpecial[3], PPR::FLOOR, scalef, 33); bshape(shTriheptaSpecial[4], PPR::FLOOR, scalef, 34); bshape(shTriheptaSpecial[5], PPR::FLOOR, scalef, 35); bshape(shTriheptaSpecial[6], PPR::FLOOR, scalef, 36); bshape(shTriheptaSpecial[7], PPR::FLOOR, scalef, 37); bshape(shTriheptaSpecial[12], PPR::FLOOR, scalef, 373); bshape(shTriheptaSpecial[9], PPR::FLOOR, scalef, 38); bshape(shTriheptaSpecial[10], PPR::FLOOR, scalef, 39); bshape(shTriheptaSpecial[11], PPR::FLOOR, scalef, 372); bshape(shSemiFloorShadow, PPR::FLOOR, scalef, 263); bshape(shMercuryBridge[0], PPR::FLOOR, scalef*spzoom6, 365); bshape(shMercuryBridge[1], PPR::FLOOR, scalef*spzoomd7, 366); bshape(shWindArrow, PPR::HEPTAMARK, scalef, 367); bshape(shPalaceGate, PPR::STRUCT1, scalef, 47); bshape(shSemiFeatherFloor[0], PPR::FLOOR, scalef*spzoom6, 48); bshape(shSemiFeatherFloor[1], PPR::FLOOR, scalef*spzoom6, 49); bshape(shSwitchDisk, PPR::FLOOR); for(int i=0; i<=S84; i+=S3) hpcpush(ddi(i, .06) * C0); bshape(shZebra[0], PPR::FLOOR, scalef, 162); bshape(shZebra[1], PPR::FLOOR, scalef, 163); bshape(shZebra[2], PPR::FLOOR, scalef, 164); bshape(shZebra[3], PPR::FLOOR, scalef, 165); bshape(shZebra[4], PPR::FLOOR, 1, 166); // for pure bshape(shEmeraldFloor[0], PPR::FLOOR, scalef, 167); // 4 bshape(shEmeraldFloor[1], PPR::FLOOR, scalef, 168); // 12 bshape(shEmeraldFloor[2], PPR::FLOOR, scalef, 169); // 16 bshape(shEmeraldFloor[3], PPR::FLOOR, scalef, 170); // 20 bshape(shEmeraldFloor[4], PPR::FLOOR, scalef, 171); // 28 bshape(shEmeraldFloor[5], PPR::FLOOR, scalef, 172); // 36 bshape(shTower[0], PPR::FLOOR_TOWER, scalef, 196); // 4 bshape(shTower[1], PPR::FLOOR_TOWER, scalef, 197); // 5 bshape(shTower[2], PPR::FLOOR_TOWER, scalef, 198); // 6 bshape(shTower[3], PPR::FLOOR_TOWER, scalef, 199); // 8 bshape(shTower[4], PPR::FLOOR_TOWER, scalef, 200); // 9 bshape(shTower[5], PPR::FLOOR_TOWER, scalef, 201); // 10 bshape(shTower[6], PPR::FLOOR_TOWER, scalef, 202); // 10 bshape(shTower[7], PPR::FLOOR_TOWER, 1, 203); // pure 7 bshape(shTower[8], PPR::FLOOR_TOWER, 1, 204); // pure 11 bshape(shTower[9], PPR::FLOOR_TOWER, 1, 205); // pure 15 bshape(shTower[10], PPR::FLOOR_TOWER, scalef, 206); // Euclidean // structures & walls bshape(shBoatOuter, PPR::STRUCT0, scalef, 154); bshape(shBoatInner, PPR::STRUCT1, scalef, 155); bshape(shSolidBranch, PPR::STRUCT0, scalef, 235); bshape(shWeakBranch, PPR::STRUCT0, scalef, 236); bshape(shFan, PPR::WALL, scalef, 59); // items: bshape(shElementalShard, PPR::ITEM, scalef, 60); bshape(shNecro, PPR::ITEM, scalef, 61); bshape(shFigurine, PPR::ITEM, scalef, 62); bshape(shStatue, PPR::ITEM, scalef, 63); bshape(shBook, PPR::ITEM, scalef, 64); bshape(shBookCover, PPR::ITEMa, scalef, 65); bshape(shGrail, PPR::ITEM, scalef, 66); bshape(shGun, PPR::ITEM, scalef, 67); bshape(shKey, PPR::ITEM, scalef, 68); bshape(shPirateX, PPR::ITEM, scalef, 124); bshape(shTreat, PPR::ITEM, scalef, 253); // first layer monsters bshape(shTentacleX, PPR::TENTACLE0); drawTentacle(shTentacleX, xcrossf * .25, xcrossf * .1, 10); bshape(shIBranch, PPR::TENTACLE1); drawTentacle(shIBranch, xcrossf * .1, xcrossf * .2, 5); bshape(shTentacle, PPR::TENTACLE1); drawTentacle(shTentacle, xcrossf * .2, xcrossf * .1, 10); copyshape(shJoint, shDisk, PPR::ONTENTACLE); bshape(shTentHead, PPR::ONTENTACLE, scalef, 79); bshape(shWormHead, PPR::ONTENTACLE, scalef, 80); bshape(shWormSegment, PPR::TENTACLE1); RING(i) hpcpush(ddi(i, .20 * scalef) * C0); bshape(shSmallWormSegment, PPR::TENTACLE1); RING(i) hpcpush(ddi(i, .16 * scalef) * C0); bshape(shWormTail, PPR::TENTACLE1, scalef, 383); bshape(shSmallWormTail, PPR::TENTACLE1, scalef, 384); if(!BITRUNCATED) bshape(shDragonSegment, PPR::TENTACLE1, gp::scale * irr::scale, 233); else bshape(shDragonSegment, PPR::TENTACLE1, scalef, 234); bshape(shDragonWings, PPR::ONTENTACLE, scalef, 237); bshape(shDragonLegs, PPR::TENTACLE0, scalef, 238); if(!BITRUNCATED) bshape(shDragonTail, PPR::TENTACLE1, gp::scale * irr::scale, 239); else bshape(shDragonTail, PPR::TENTACLE1, scalef, 240); bshape(shDragonNostril, PPR::ONTENTACLE_EYES, scalef, 241); bshape(shDragonHead, PPR::ONTENTACLE, scalef, 242); ld krsc = 1; if(sphere) krsc *= 1.4; if(S7 ==8) krsc *= 1.3; if(PURE && !euclid4) { tentacle_length = 1.52; bshape(shSeaTentacle, PPR::TENTACLE1, 1, 245); } else if(NONSTDVAR) { tentacle_length = 0.566256 * 1.6 * gp::scale * irr::scale * krsc; bshape(shSeaTentacle, PPR::TENTACLE1, 1.6 * gp::scale * irr::scale * krsc, 246); } else { tentacle_length = 0.566256 * gp::scale * irr::scale; bshape(shSeaTentacle, PPR::TENTACLE1, gp::scale * irr::scale, 246); } ld ksc = (!BITRUNCATED ? 1.8 : 1.5) * gp::scale * irr::scale * krsc; if(euclid4 && PURE) ksc *= .5; bshape(shKrakenHead, PPR::ONTENTACLE, ksc, 247); bshape(shKrakenEye, PPR::ONTENTACLE_EYES, ksc, 248); bshape(shKrakenEye2, PPR::ONTENTACLE_EYES2, ksc, 249); // monsters bshape(shGhost, PPR::MONSTER_BODY, scalef, 69); bshape(shGargoyleWings, PPR::MONSTER_CLOAK, scalef, 70); bshape(shGargoyleBody, PPR::MONSTER_BODY, scalef, 71); bshape(shDogStripes, PPR::MONSTER_ARMOR1, scalef, 72); bshape(shWolf, PPR::MONSTER_BODY, scalef, 73); bshape(shWolf1, PPR::MONSTER_EYE0, scalef, 74); bshape(shWolf2, PPR::MONSTER_EYE0, scalef, 75); bshape(shWolf3, PPR::MONSTER_EYE0, scalef, 76); bshape(shFoxTail1, PPR::MONSTER_BODY, scalef, 363); bshape(shFoxTail2, PPR::MONSTER_BODY, scalef, 364); bshape(shHawk, PPR::MONSTER_BODY, scalef, 77); bshape(shEagle, PPR::MONSTER_BODY, scalef, 78); bshape(shWaterElemental, PPR::MONSTER_BODY, scalef, 81); bshape(shMouse, PPR::MONSTER_BODY, scalef, 82); bshape(shMouseLegs, PPR::MONSTER_LEG, scalef, 83); bshape(shMouseEyes, PPR::MONSTER_EYE0, scalef, 84); bshape(shHumanFoot, PPR::MONSTER_FOOT, scalef, 259); bshape(shHumanLeg, PPR::MONSTER_LEG, scalef, 260); bshape(shHumanGroin, PPR::MONSTER_GROIN, scalef, 261); bshape(shHumanNeck, PPR::MONSTER_NECK, scalef, 262); bshape(shSkeletalFoot, PPR::MONSTER_FOOT, scalef, 264); bshape(shYetiFoot, PPR::MONSTER_FOOT, scalef, 276); for(int i=0; i<5; i++) for(int j=0; j<4; j++) bshape(shReptile[i][j], j >= 2 ? PPR::LIZEYE : j == 1 ? PPR::FLOORa : PPR::FLOOR_DRAGON, scalef * gsca(euclid, 1.16), 277+i*4+j); shift(shReptile[1][2], 0.316534, -0.136547, 1.057752); shift(shReptile[1][3], 0.340722, -0.059946, 1.058152); shift(shReptile[2][2], -0.124134, -0.286631, 1.047648); shift(shReptile[2][3], -0.054108, -0.298966, 1.045136); shift(shReptile[3][2], -0.229759, 0.191918, 1.043849); shift(shReptile[3][3], -0.173583, 0.236900, 1.042234); shift(shReptile[4][2], 0.05, 0, 1.00124921972503929); shift(shReptile[4][3], -0.05, 0, 1.00124921972503929); bshape(shReptileBody, PPR::MONSTER_BODY, scalef, 297); bshape(shReptileHead, PPR::MONSTER_HEAD, scalef, 298); bshape(shReptileFrontFoot, PPR::MONSTER_FOOT, scalef, 299); bshape(shReptileRearFoot, PPR::MONSTER_FOOT, scalef, 300); bshape(shReptileFrontLeg, PPR::MONSTER_LEG, scalef, 301); bshape(shReptileRearLeg, PPR::MONSTER_LEG, scalef, 302); bshape(shReptileTail, PPR::MONSTER_BODY, scalef, 303); bshape(shReptileEye, PPR::MONSTER_EYE0, scalef, 304); bshape(shDodeca, PPR::ITEM, scalef, 305); bshape(shTerraArmor1, PPR::MONSTER_BODY, scalef, 349); bshape(shTerraArmor2, PPR::MONSTER_BODY, scalef, 350); bshape(shTerraArmor3, PPR::MONSTER_BODY, scalef, 351); bshape(shTerraHead, PPR::MONSTER_HEAD, scalef, 352); bshape(shTerraFace, PPR::MONSTER_FACE, scalef, 353); bshape(shJiangShi, PPR::MONSTER_BODY, scalef, 355); bshape(shJiangShiDress, PPR::MONSTER_BODY, scalef, 356); bshape(shJiangShiCap1, PPR::MONSTER_HAT0, scalef, 357); bshape(shJiangShiCap2, PPR::MONSTER_HAT1, scalef, 358); bshape(shPBody, PPR::MONSTER_BODY, scalef, 85); bshape(shYeti, PPR::MONSTER_BODY, scalef, 86); bshape(shPSword, PPR::MONSTER_WPN, scalef, 90); bshape(shFerocityM, PPR::MONSTER_WPN, scalef, 361); bshape(shFerocityF, PPR::MONSTER_WPN, scalef, 362); bshape(shPKnife, PPR::MONSTER_WPN, scalef, 91); bshape(shPirateHook, PPR::MONSTER_WPN, scalef, 92); bshape(shSabre, PPR::MONSTER_WPN, scalef, 93); bshape(shHedgehogBlade, PPR::MONSTER_WPN, scalef, 94); bshape(shHedgehogBladePlayer, PPR::MONSTER_WPN, scalef, 95); bshape(shFemaleBody, PPR::MONSTER_BODY, scalef, 96); bshape(shFemaleDress, PPR::MONSTER_ARMOR0, scalef, 97); bshape(shDemon, PPR::MONSTER_HAIR, scalef, 98); bshape(shTrylobite, PPR::MONSTER_BODY, scalef, 99); bshape(shTrylobiteHead, PPR::MONSTER_HEAD, scalef, 100); bshape(shTrylobiteBody, PPR::MONSTER_BODY, scalef, 308); bshape(shTrylobiteFrontClaw, PPR::MONSTER_FOOT, scalef, 309); bshape(shTrylobiteRearClaw, PPR::MONSTER_FOOT, scalef, 310); bshape(shTrylobiteFrontLeg, PPR::MONSTER_LEG, scalef, 311); bshape(shTrylobiteRearLeg, PPR::MONSTER_LEG, scalef, 312); bshape(shBullBody, PPR::MONSTER_BODY, scalef, 315); bshape(shBullHorn, PPR::MONSTER_HEAD, scalef, 316); bshape(shBullRearHoof, PPR::MONSTER_FOOT, scalef, 317); bshape(shBullFrontHoof, PPR::MONSTER_FOOT, scalef, 318); bshape(shBullHead, PPR::MONSTER_HEAD, scalef, 319); bshape(shButterflyBody, PPR::MONSTER_BODY, scalef, 320); bshape(shButterflyWing, PPR::MONSTER_BODY, scalef, 321); bshape(shGadflyBody, PPR::MONSTER_BODY, scalef * 1.5, 322); bshape(shGadflyWing, PPR::MONSTER_BODY, scalef * 1.5, 323); bshape(shGadflyEye, PPR::MONSTER_BODY, scalef * 1.5, 324); bshape(shGoatHead, PPR::MONSTER_HAIR, scalef, 101); bshape(shRatHead, PPR::MONSTER_HEAD, scalef, 102); bshape(shRatEyes, PPR::MONSTER_EYE0, scalef, 103); bshape(shRatTail, PPR::MONSTER_LEG, scalef, 104); bshape(shRatCape1, PPR::MONSTER_HOODCLOAK2, scalef, 105); bshape(shRatCape2, PPR::MONSTER_HOODCLOAK1, scalef, 106); bshape(shKnightArmor, PPR::MONSTER_ARMOR0, scalef, 107); bshape(shWightCloak, PPR::MONSTER_CLOAK, scalef, 108); bshape(shKnightCloak, PPR::MONSTER_CLOAK, scalef, 109); bshape(shPrincessDress, PPR::MONSTER_ARMOR1, scalef, 110); bshape(shWizardCape1, PPR::MONSTER_HOODCLOAK1, 1, 111); bshape(shWizardCape2, PPR::MONSTER_HOODCLOAK2, 1, 112); bshape(shPrinceDress, PPR::MONSTER_ARMOR0, scalef, 113); bshape(shArmor, PPR::MONSTER_HAT0, scalef, 114); bshape(shTurban1, PPR::MONSTER_HAT0, scalef, 115); bshape(shTurban2, PPR::MONSTER_HAT1, scalef, 116); bshape(shWizardHat1, PPR::MONSTER_HAT0, 1, 117); bshape(shWizardHat2, PPR::MONSTER_HAT1, 1, 118); bshape(shWestHat1, PPR::MONSTER_HAT0, scalef, 119); bshape(shWestHat2, PPR::MONSTER_HAT1, scalef, 120); bshape(shGunInHand, PPR::MONSTER_WPN, scalef, 121); bshape(shVikingHelmet, PPR::MONSTER_HAT0, scalef, 122); bshape(shRaiderHelmet, PPR::MONSTER_HAT0, scalef, 375); bshape(shRaiderArmor, PPR::MONSTER_BODY, scalef, 380); bshape(shRaiderBody, PPR::MONSTER_BODY, scalef, 381); bshape(shRaiderShirt, PPR::MONSTER_BODY, scalef, 382); bshape(shHood, PPR::MONSTER_HAT0, scalef, 123); bshape(shPirateHood, PPR::MONSTER_HAT0, scalef, 125); bshape(shEyepatch, PPR::MONSTER_HAT1, scalef, 126); bshape(shPHead, PPR::MONSTER_HEAD, scalef, 127); shGolemhead = shDisk; shGolemhead.prio = PPR::MONSTER_HEAD; bshape(shFemaleHair, PPR::MONSTER_HAIR, scalef, 128); bshape(shWitchHair, PPR::MONSTER_HAIR, scalef, 129); bshape(shBeautyHair, PPR::MONSTER_HAIR, scalef, 130); bshape(shFlowerHair, PPR::MONSTER_HAT0, scalef, 131); bshape(shSuspenders, PPR::MONSTER_ARMOR1, scalef, 132); bshape(shFlowerHand, PPR::MONSTER_WPN, scalef, 133); bshape(shPFace, PPR::MONSTER_FACE, scalef, 134); bshape(shEyes, PPR::MONSTER_EYE0, scalef, 135); bshape(shShark, PPR::MONSTER_BODY, scalef, 136); bshape(shBugBody, PPR::MONSTER_BODY, scalef, 137); bshape(shBugArmor, PPR::MONSTER_ARMOR0, scalef, 138); bshape(shBugLeg, PPR::MONSTER_BODY, scalef, 306); bshape(shBugAntenna, PPR::MONSTER_BODY, scalef, 307); bshape(shCatBody, PPR::MONSTER_BODY, scalef, 139); bshape(shCatLegs, PPR::MONSTER_LEG, scalef, 140); bshape(shFamiliarHead, PPR::MONSTER_HEAD, scalef, 141); bshape(shFamiliarEye, PPR::MONSTER_EYE1, scalef, 142); bshape(shCatHead, PPR::MONSTER_HEAD, scalef, 143); bshape(shWolfBody, PPR::MONSTER_BODY, WOLF, 144); bshape(shWolfHead, PPR::MONSTER_HEAD, WOLF, 145); bshape(shWolfLegs, PPR::MONSTER_LEG, WOLF, 146); bshape(shWolfEyes, PPR::MONSTER_EYE0, WOLF, 147); bshape(shWitchDress, PPR::MONSTER_ARMOR0, scalef, 148); bshape(shPickAxe, PPR::MONSTER_WPN, scalef, 149); bshape(shPike, PPR::MONSTER_WPN, scalef, 150); bshape(shFlailBall, PPR::MONSTER_WPN, scalef, 151); bshape(shFlailTrunk, PPR::MONSTER_WPN, scalef, 152); bshape(shFlailChain, PPR::MONSTER_SUBWPN, scalef, 153); bshape(shHammerHead, PPR::MONSTER_WPN, scalef, 376); // bshape(shScratch, 17, scalef, 156); bshape(shSkeletonBody, PPR::MONSTER_BODY, scalef, 157); bshape(shSkull, PPR::MONSTER_HEAD, scalef, 158); bshape(shSkullEyes, PPR::MONSTER_EYE0, scalef, 159); bshape(shFishTail, PPR::MONSTER_LEG, scalef, 160); bshape(shFatBody, PPR::MONSTER_BODY, scalef, 161); bshape(shAztecHead, PPR::MONSTER_HEAD, scalef, 179); bshape(shAztecCap, PPR::MONSTER_HAT0, scalef, 180); // 1 114 5 [000000] bshape(shBatWings, PPR::MONSTER_LEG, scalef, 254); bshape(shBatBody, PPR::MONSTER_BODY, scalef, 255); bshape(shBatMouth, PPR::MONSTER_EYE0, scalef, 256); bshape(shBatFang, PPR::MONSTER_EYE1, scalef, 257); bshape(shBatEye, PPR::MONSTER_EYE0, scalef, 258); bshape(shDogBody, PPR::MONSTER_BODY, scalef, 265); bshape(shDogHead, PPR::MONSTER_HEAD, scalef, 266); bshape(shDogTorso, PPR::MONSTER_BODY, scalef, 267); bshape(shDogFrontPaw, PPR::MONSTER_FOOT, scalef, 268); bshape(shDogRearPaw, PPR::MONSTER_FOOT, scalef, 269); bshape(shDogFrontLeg, PPR::MONSTER_LEG, scalef, 270); bshape(shDogRearLeg, PPR::MONSTER_LEG, scalef, 271); bshape(shWolfFrontPaw, PPR::MONSTER_FOOT, scalef, 272); bshape(shWolfRearPaw, PPR::MONSTER_FOOT, scalef, 273); bshape(shWolfFrontLeg, PPR::MONSTER_LEG, scalef, 274); bshape(shWolfRearLeg, PPR::MONSTER_LEG, scalef, 275); // missiles bshape(shKnife, PPR::MISSILE, scalef, 87); bshape(shTrapArrow, PPR::MISSILE, scalef, 354); bshape(shTongue, PPR::MISSILE, scalef, 88); bshape(shFlailMissile, PPR::MISSILE, scalef, 89); for(int u=0; u<=2; u+=2) { PPR sh = u ? PPR::ITEM : PPR::MONSTER_LEG; int uz = u?2:1; PPR sh1 = PPR(sh + 1); PPR sh2 = PPR(sh + 2); bshape(shTortoise[0][0+u], sh1, scalef/uz, 207); bshape(shTortoise[1][0+u], sh2, scalef/uz, 208); bshape(shTortoise[2][0+u], sh2, scalef/uz, 209); bshape(shTortoise[3][0+u], sh2, scalef/uz, 210); bshape(shTortoise[4][0+u], sh2, scalef/uz, 211); bshape(shTortoise[5][0+u], sh2, scalef/uz, 212); bshape(shTortoise[6][0+u], sh2, scalef/uz, 213); bshape(shTortoise[7][0+u], sh2, scalef/uz, 214); bshape(shTortoise[8][0+u], sh, scalef/uz, 215); bshape(shTortoise[9][0+u], sh, scalef/uz, 217); bshape(shTortoise[10][0+u], sh, scalef/uz, 218); bshape(shTortoise[11][0+u], sh, scalef/uz, 219); bshape(shTortoise[12][0+u], sh2, scalef/uz, 216); bshape(shTortoise[0][1+u], sh1, scalef/uz, 220); bshape(shTortoise[1][1+u], sh2, scalef/uz, 221); bshape(shTortoise[2][1+u], sh2, scalef/uz, 222); bshape(shTortoise[3][1+u], sh2, scalef/uz, 223); bshape(shTortoise[4][1+u], sh2, scalef/uz, 224); bshape(shTortoise[5][1+u], sh2, scalef/uz, 225); bshape(shTortoise[6][1+u], sh2, scalef/uz, 226); bshape(shTortoise[7][1+u], sh2, scalef/uz, 227); bshape(shTortoise[8][1+u], sh, scalef/uz, 228); bshape(shTortoise[9][1+u], sh, scalef/uz, 230); bshape(shTortoise[10][1+u], sh, scalef/uz, 231); bshape(shTortoise[11][1+u], sh, scalef/uz, 232); bshape(shTortoise[12][1+u], sh2, scalef/uz, 229); } for(int v=0; v<13; v++) for(int z=0; z<2; z++) copyshape(shTortoise[v][4+z], shTortoise[v][2+z], PPR(shTortoise[v][2+z].prio + (PPR::CARRIED-PPR::ITEM))); if(!BITRUNCATED) bshape(shMagicSword, PPR::MAGICSWORD, euclid4 ? gp::scale * irr::scale / 2 : gp::scale * irr::scale, 243); else bshape(shMagicSword, PPR::MAGICSWORD, 1, 244); if(!BITRUNCATED) bshape(shMagicShovel, PPR::MAGICSWORD, euclid4 ? gp::scale * irr::scale / 2 : gp::scale * irr::scale, 333); else bshape(shMagicShovel, PPR::MAGICSWORD, 1, 333); bshape(shBead0, PPR(20), 1, 250); bshape(shBead1, PPR(20), 1, 251); bshape(shArrow, PPR::ARROW, 1, 252); bshapeend(); prehpc = isize(hpc); DEBB(DF_INIT, (debugfile,"hpc = %d\n", prehpc)); for(int i=0; id[l].sh, us->d[l].sh.prio); pushShape(us->d[l]); finishshape(); } } static int qhpc0; int qhpc = isize(hpc); if(qhpc != qhpc0 && debug_geometry) { printf("qhpc = %d (%d+%d)\n", qhpc0 = qhpc, prehpc, qhpc-prehpc); printf("shapes = %d\n", isize(allshapes)); int inve=0, issi=0, vcon=0, ccon=0; for(auto sh: allshapes) { if(sh->flags & POLY_INVERSE) inve++; if(sh->flags & POLY_ISSIDE) issi++; if(sh->flags & POLY_VCONVEX) vcon++; if(sh->flags & POLY_CCONVEX) ccon++; } printf("triangle flags = %x\n", shTriangle.flags); printf("plain floor flags = %x\n", shFloor.b[0].flags); printf("ball flags = %x\n", shDisk.flags); printf("inverse = %d isside = %d vcon = %d ccon = %d\n", inve, issi, vcon, ccon); } initPolyForGL(); } void initShape(int sg, int id) { if(!usershapes[sg][id]) { usershape *us = new usershape; usershapes[sg][id] = us; for(int i=0; id[i].sh.prio = PPR((sg >= 3 ? 1:50) + i); us->d[i].rots = 1; us->d[i].sym = 0; us->d[i].shift = C0; us->d[i].spin = Cx1; us->d[i].color = 0; } } } void queuepolyat(const transmatrix& V, const hpcshape& h, int col, PPR prio) { if(prio == PPR::DEFAULT) prio = h.prio; polytodraw& ptd = nextptd(); ptd.kind = pkPoly; ptd.u.poly.V = V; ptd.u.poly.offset = h.s; ptd.u.poly.cnt = h.e-h.s; ptd.u.poly.tab = &ourshape; if(cblind) { // protanopia /* int r = (56 * part(col,3) + 43 * part(col,2)) / 100; int g = (58 * part(col,3) + 42 * part(col,2)) / 100; int b = (24 * part(col,2) + 75 * part(col,1)) / 100; */ // deuteranopia /* int r = (625 * part(col,3) + 375 * part(col,2)) / 1000; int g = (700 * part(col,3) + 300 * part(col,2)) / 1000; int b = (300 * part(col,2) + 700 * part(col,1)) / 1000; part(col,3) = r; part(col,2) = g; part(col,1) = b; */ part(col,2) = part(col,3) = (part(col,2) * 2 + part(col,3) + 1)/3; } ptd.col = (darkened(col >> 8) << 8) + (col & 0xFF); ptd.prio = prio; ptd.u.poly.outline = poly_outline; ptd.u.poly.linewidth = vid.linewidth; ptd.u.poly.flags = h.flags; ptd.u.poly.tinf = NULL; } void addfloats(vector& v, hyperpoint h) { for(int i=0; i<3; i++) v.push_back(h[i]); } void queuereset(eModel md, PPR prio) { polytodraw& ptd = nextptd(); ptd.kind = pkResetModel; ptd.col = md; ptd.prio = prio; } void queuetable(const transmatrix& V, const vector& f, int cnt, int linecol, int fillcol, PPR prio) { polytodraw& ptd = nextptd(); ptd.kind = pkPoly; ptd.u.poly.V = V; ptd.u.poly.tab = &f; ptd.u.poly.offset = 0; ptd.u.poly.cnt = cnt; ptd.col = fillcol; ptd.prio = prio; ptd.u.poly.outline = linecol; ptd.u.poly.linewidth = vid.linewidth; ptd.u.poly.flags = 0; ptd.u.poly.tinf = NULL; } void queuepoly(const transmatrix& V, const hpcshape& h, int col) { queuepolyat(V,h,col,h.prio); } void queuepolyb(const transmatrix& V, const hpcshape& h, int col, int b) { queuepolyat(V,h,col,PPR(h.prio+b)); } void curvepoint(const hyperpoint& H1) { curvedata.push_back(glhr::pointtogl(H1)); } void queuecurve(int linecol, int fillcol, PPR prio) { queuetable(Id, curvedata, isize(curvedata)-curvestart, linecol, fillcol, prio); lastptd().u.poly.offset = curvestart; curvestart = isize(curvedata); } void queuelink(const string *link, PPR prio) { polytodraw& ptd = nextptd(); ptd.kind = pkLink; ptd.prio = prio; ptd.u.link.link = link; } void queueline(const hyperpoint& H1, const hyperpoint& H2, int col, int prf, PPR prio) { polytodraw& ptd = nextptd(); ptd.kind = pkLine; ptd.u.line.H1 = H1; ptd.u.line.H2 = H2; ptd.u.line.prf = prf; ptd.u.line.width = (linewidthat(H1, vid.linewidth, 0) + linewidthat(H2, vid.linewidth, 0)) / 2; ptd.col = (darkened(col >> 8) << 8) + (col & 0xFF); ptd.prio = prio; } void queuestr(int x, int y, int shift, int size, string str, int col, int frame, int align) { polytodraw& ptd = nextptd(); ptd.kind = pkString; ptd.u.chr.x = x; ptd.u.chr.y = y; int ss = (int) str.size(); if(ss>=MAXQCHR) ss=MAXQCHR-1; {for(int i=0; i