mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2025-01-11 09:50:34 +00:00
3d:: converting the old vector graphics into 3D models
This commit is contained in:
parent
cb2e870a99
commit
596b4ce786
793
3d-models.cpp
Normal file
793
3d-models.cpp
Normal file
@ -0,0 +1,793 @@
|
||||
// HyperRogue
|
||||
// This file contains the routines to convert HyperRogue's old vector graphics into 3D models
|
||||
|
||||
// Copyright (C) 2011-2019 Zeno Rogue, see 'hyper.cpp' for details
|
||||
|
||||
#include "earcut.hpp"
|
||||
|
||||
namespace hr {
|
||||
|
||||
#define S (scalefactor / 0.805578)
|
||||
#define SH (scalefactor / 0.805578 * geom3::height_width / 1.5)
|
||||
|
||||
hyperpoint shcenter;
|
||||
|
||||
vector<hyperpoint> get_shape(hpcshape sh) {
|
||||
vector<hyperpoint> res;
|
||||
for(int i=sh.s; i<sh.e-1; i++) res.push_back(hpc[i]);
|
||||
return res;
|
||||
}
|
||||
|
||||
hyperpoint get_center(const vector<hyperpoint>& vh) {
|
||||
hyperpoint h = Hypc;
|
||||
using namespace hyperpoint_vec;
|
||||
for(auto h1: vh) h = h + h1;
|
||||
return normalize(h);
|
||||
}
|
||||
|
||||
ld zc(ld z) { return geom3::human_height * (z - 0.5); }
|
||||
|
||||
transmatrix zpush(ld z) {
|
||||
return cpush(2, z);
|
||||
}
|
||||
|
||||
void add_cone(ld z0, const vector<hyperpoint>& vh, ld z1) {
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
for(int i=0; i<isize(vh); i++) {
|
||||
hpcpush(zpush(z0) * vh[i]);
|
||||
hpcpush(zpush(z0) * vh[(i+1) % isize(vh)]);
|
||||
hpcpush(zpush(z1) * shcenter);
|
||||
}
|
||||
}
|
||||
|
||||
void add_prism_sync(ld z0, vector<hyperpoint> vh0, ld z1, vector<hyperpoint> vh1) {
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
for(int i=0; i<isize(vh0); i++) {
|
||||
int i1 = (i+1) % isize(vh0);
|
||||
hpcpush(zpush(z0) * vh0[i]);
|
||||
hpcpush(zpush(z1) * vh1[i]);
|
||||
hpcpush(zpush(z0) * vh0[i1]);
|
||||
hpcpush(zpush(z1) * vh1[i]);
|
||||
hpcpush(zpush(z0) * vh0[i1]);
|
||||
hpcpush(zpush(z1) * vh1[i1]);
|
||||
}
|
||||
}
|
||||
|
||||
void add_prism(ld z0, vector<hyperpoint> vh0, ld z1, vector<hyperpoint> vh1) {
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
|
||||
struct mixed {
|
||||
ld angle;
|
||||
int owner;
|
||||
hyperpoint h;
|
||||
mixed(ld a, int o, hyperpoint _h) : angle(a), owner(o), h(_h) {}
|
||||
};
|
||||
|
||||
transmatrix T0 = gpushxto0(get_center(vh0));
|
||||
transmatrix T1 = gpushxto0(get_center(vh1));
|
||||
|
||||
vector<mixed> pairs;
|
||||
for(auto h: vh0) pairs.emplace_back(atan2(T0*h), 0, h);
|
||||
for(auto h: vh1) pairs.emplace_back(atan2(T1*h), 1, h);
|
||||
sort(pairs.begin(), pairs.end(), [&] (const mixed p, const mixed q) { return p.angle < q.angle; });
|
||||
|
||||
hyperpoint lasts[2];
|
||||
for(auto pp: pairs) lasts[pp.owner] = pp.h;
|
||||
|
||||
for(auto pp: pairs) {
|
||||
int id = pp.owner;
|
||||
hpcpush(zpush(z0) * lasts[0]);
|
||||
hpcpush(zpush(z1) * lasts[1]);
|
||||
hpcpush(zpush(id == 0 ? z0 : z1) * pp.h);
|
||||
lasts[id] = pp.h;
|
||||
}
|
||||
}
|
||||
|
||||
void shift_last(ld z) {
|
||||
for(int i=last->s; i<isize(hpc); i++) hpc[i] = cpush(2, z) * hpc[i];
|
||||
}
|
||||
|
||||
void shift_shape(hpcshape& sh, ld z) {
|
||||
for(int i=sh.s; i<sh.e; i++) hpc[i] = cpush(2, z) * hpc[i];
|
||||
}
|
||||
|
||||
extern
|
||||
hpcshape
|
||||
shSemiFloorSide[SIDEPARS],
|
||||
shBFloor[2],
|
||||
shWave[8][2],
|
||||
shCircleFloor,
|
||||
shBarrel,
|
||||
shWall[2], shMineMark[2], shBigMineMark[2], shFan,
|
||||
shZebra[5],
|
||||
shSwitchDisk,
|
||||
shTower[11],
|
||||
shEmeraldFloor[6],
|
||||
shSemiFeatherFloor[2],
|
||||
shSemiFloor[2], shSemiBFloor[2], shSemiFloorShadow,
|
||||
shMercuryBridge[2],
|
||||
shTriheptaSpecial[14],
|
||||
shCross, shGiantStar[2], shLake, shMirror,
|
||||
shHalfFloor[3], shHalfMirror[3],
|
||||
shGem[2], shStar, shDisk, shDiskT, shDiskS, shDiskM, shDiskSq, shRing,
|
||||
shTinyBird, shTinyShark,
|
||||
shEgg,
|
||||
shSpikedRing, shTargetRing, shSawRing, shGearRing, shPeaceRing, shHeptaRing,
|
||||
shSpearRing, shLoveRing,
|
||||
shDaisy, shTriangle, shNecro, shStatue, shKey, shWindArrow,
|
||||
shGun,
|
||||
shFigurine, shTreat,
|
||||
shElementalShard,
|
||||
// shBranch,
|
||||
shIBranch, shTentacle, shTentacleX, shILeaf[2],
|
||||
shMovestar,
|
||||
shWolf, shYeti, shDemon, shGDemon, shEagle, shGargoyleWings, shGargoyleBody,
|
||||
shFoxTail1, shFoxTail2,
|
||||
shDogBody, shDogHead, shDogFrontLeg, shDogRearLeg, shDogFrontPaw, shDogRearPaw,
|
||||
shDogTorso,
|
||||
shHawk,
|
||||
shCatBody, shCatLegs, shCatHead, shFamiliarHead, shFamiliarEye,
|
||||
shWolf1, shWolf2, shWolf3,
|
||||
shDogStripes,
|
||||
shPBody, shPSword, shPKnife,
|
||||
shFerocityM, shFerocityF,
|
||||
shHumanFoot, shHumanLeg, shHumanGroin, shHumanNeck, shSkeletalFoot, shYetiFoot,
|
||||
shMagicSword, shMagicShovel, shSeaTentacle, shKrakenHead, shKrakenEye, shKrakenEye2,
|
||||
shArrow,
|
||||
shPHead, shPFace, shGolemhead, shHood, shArmor,
|
||||
shAztecHead, shAztecCap,
|
||||
shSabre, shTurban1, shTurban2, shVikingHelmet, shRaiderHelmet, shRaiderArmor, shRaiderBody, shRaiderShirt,
|
||||
shWestHat1, shWestHat2, shGunInHand,
|
||||
shKnightArmor, shKnightCloak, shWightCloak,
|
||||
shGhost, shEyes, shSlime, shJelly, shJoint, shWormHead, shTentHead, shShark, shWormSegment, shSmallWormSegment, shWormTail, shSmallWormTail,
|
||||
shMiniGhost, shMiniEyes,
|
||||
shHedgehogBlade, shHedgehogBladePlayer,
|
||||
shWolfBody, shWolfHead, shWolfLegs, shWolfEyes,
|
||||
shWolfFrontLeg, shWolfRearLeg, shWolfFrontPaw, shWolfRearPaw,
|
||||
shFemaleBody, shFemaleHair, shFemaleDress, shWitchDress,
|
||||
shWitchHair, shBeautyHair, shFlowerHair, shFlowerHand, shSuspenders, shTrophy,
|
||||
shBugBody, shBugArmor, shBugLeg, shBugAntenna,
|
||||
shPickAxe, shPike, shFlailBall, shFlailTrunk, shFlailChain, shHammerHead,
|
||||
shBook, shBookCover, shGrail,
|
||||
shBoatOuter, shBoatInner, shCompass1, shCompass2, shCompass3,
|
||||
shKnife, shTongue, shFlailMissile, shTrapArrow,
|
||||
shPirateHook, shPirateHood, shEyepatch, shPirateX,
|
||||
// shScratch,
|
||||
shHeptaMarker, shSnowball,
|
||||
shSkeletonBody, shSkull, shSkullEyes, shFatBody, shWaterElemental,
|
||||
shPalaceGate, shFishTail,
|
||||
shMouse, shMouseLegs, shMouseEyes,
|
||||
shPrincessDress, shPrinceDress,
|
||||
shWizardCape1, shWizardCape2,
|
||||
shBigCarpet1, shBigCarpet2, shBigCarpet3,
|
||||
shGoatHead, shRose, shThorns,
|
||||
shRatHead, shRatTail, shRatEyes, shRatCape1, shRatCape2,
|
||||
shWizardHat1, shWizardHat2,
|
||||
shTortoise[13][6],
|
||||
shDragonLegs, shDragonTail, shDragonHead, shDragonSegment, shDragonNostril,
|
||||
shDragonWings,
|
||||
shSolidBranch, shWeakBranch, shBead0, shBead1,
|
||||
shBatWings, shBatBody, shBatMouth, shBatFang, shBatEye,
|
||||
shParticle[16], shAsteroid[8],
|
||||
shReptile[5][4],
|
||||
shReptileBody, shReptileHead, shReptileFrontFoot, shReptileRearFoot,
|
||||
shReptileFrontLeg, shReptileRearLeg, shReptileTail, shReptileEye,
|
||||
|
||||
shTrylobite, shTrylobiteHead, shTrylobiteBody,
|
||||
shTrylobiteFrontLeg, shTrylobiteRearLeg, shTrylobiteFrontClaw, shTrylobiteRearClaw,
|
||||
|
||||
shBullBody, shBullHead, shBullHorn, shBullRearHoof, shBullFrontHoof,
|
||||
|
||||
shButterflyBody, shButterflyWing, shGadflyBody, shGadflyWing, shGadflyEye,
|
||||
|
||||
shTerraArmor1, shTerraArmor2, shTerraArmor3, shTerraHead, shTerraFace,
|
||||
shJiangShi, shJiangShiDress, shJiangShiCap1, shJiangShiCap2,
|
||||
|
||||
shAsymmetric,
|
||||
|
||||
shPBodyOnly, shPBodyArm, shPBodyHand, shPHeadOnly,
|
||||
|
||||
shDodeca;
|
||||
|
||||
|
||||
extern renderbuffer *floor_textures;
|
||||
|
||||
basic_textureinfo models_texture;
|
||||
|
||||
void add_texture(hpcshape& sh) {
|
||||
if(!floor_textures) return;
|
||||
auto& utt = models_texture;
|
||||
sh.tinf = &utt;
|
||||
sh.texture_offset = isize(utt.tvertices);
|
||||
for(int i=sh.s; i<isize(hpc); i++) {
|
||||
hyperpoint h = hpc[i];
|
||||
ld rad = hypot_d(3, h);
|
||||
ld factor = 0.50 + (0.17 * h[2] + 0.13 * h[1] + 0.15 * h[0]) / rad;
|
||||
utt.tvertices.push_back(glhr::makevertex(0, factor, 0));
|
||||
}
|
||||
}
|
||||
|
||||
vector<hyperpoint> scaleshape(const vector<hyperpoint>& vh, ld s) {
|
||||
vector<hyperpoint> res;
|
||||
using namespace hyperpoint_vec;
|
||||
for(hyperpoint h: vh) res.push_back(normalize(h * s + shcenter * (1-s)));
|
||||
return res;
|
||||
}
|
||||
|
||||
void make_ha_3d(hpcshape& sh, bool isarmor, ld scale) {
|
||||
shcenter = C0;
|
||||
|
||||
auto groin = get_shape(shHumanGroin);
|
||||
auto body = get_shape(shPBodyOnly);
|
||||
auto neck = get_shape(shHumanNeck);
|
||||
auto hand = get_shape(shPBodyHand);
|
||||
auto arm = get_shape(shPBodyArm);
|
||||
groin = scaleshape(groin, scale);
|
||||
neck = scaleshape(neck, scale);
|
||||
|
||||
auto fullbody = get_shape(sh);
|
||||
|
||||
auto body7 = body[7];
|
||||
auto body26 = body[26];
|
||||
body.clear();
|
||||
|
||||
bool foundplus = false, foundminus = false;
|
||||
for(hyperpoint h: fullbody) {
|
||||
if(h[1] > 0.14 * S) {
|
||||
if(foundplus) ;
|
||||
else foundplus = true, body.push_back(body7);
|
||||
}
|
||||
else if(h[1] < -0.14 * S) {
|
||||
if(foundminus) ;
|
||||
else foundminus = true, body.push_back(body26);
|
||||
}
|
||||
else body.push_back(h);
|
||||
}
|
||||
|
||||
auto arm8 = arm[8];
|
||||
bool armused = false;
|
||||
arm.clear();
|
||||
for(hyperpoint h: fullbody) {
|
||||
if(h[1] < 0.08 * S) ;
|
||||
else if(h[0] > -0.03 * S) {
|
||||
if(armused) ;
|
||||
else armused = true, arm.push_back(arm8);
|
||||
}
|
||||
else arm.push_back(h);
|
||||
}
|
||||
|
||||
auto hand0 = hand[0];
|
||||
hand.clear();
|
||||
hand.push_back(hand0);
|
||||
for(hyperpoint h: fullbody) {
|
||||
if(h[1] + h[0] > 0.13 * S) hand.push_back(h);
|
||||
}
|
||||
|
||||
bshape(sh, PPR::MONSTER_BODY);
|
||||
add_cone(zc(0.4), groin, zc(0.36));
|
||||
add_prism_sync(zc(0.4), groin, zc(0.6), groin);
|
||||
add_prism(zc(0.6), groin, zc(0.7), body);
|
||||
add_prism(zc(0.7), body, zc(0.8), neck);
|
||||
|
||||
add_cone(zc(0.8), neck, zc(0.83));
|
||||
|
||||
int at0 = isize(hpc);
|
||||
ld h = geom3::human_height;
|
||||
|
||||
if(isize(arm) > 3) {
|
||||
shcenter = get_center(arm);
|
||||
int arm0 = isize(hpc);
|
||||
add_prism_sync(geom3::BODY - h*.03, arm, geom3::BODY + h*.03, arm);
|
||||
add_cone(geom3::BODY + h*.03, arm, geom3::BODY + h*.05);
|
||||
add_cone(geom3::BODY - h*.03, arm, geom3::BODY - h*.05);
|
||||
int arm1 = isize(hpc);
|
||||
for(int i=arm0; i<arm1; i++) {
|
||||
hyperpoint h = hpc[i];
|
||||
ld zl = asinh(h[2]);
|
||||
h = zpush(-zl) * h;
|
||||
ld rad = hdist0(h);
|
||||
rad = (rad - 0.1124*S) / (0.2804*S - 0.1124*S);
|
||||
rad = 1 - rad;
|
||||
rad *= zc(0.7) - geom3::BODY;
|
||||
hpc[i] = zpush(rad) * hpc[i];
|
||||
}
|
||||
}
|
||||
// 0.2804 - keep
|
||||
// 0.1124 - move
|
||||
|
||||
if(isize(hand) > 3) {
|
||||
shcenter = get_center(hand);
|
||||
add_cone(geom3::BODY, hand, geom3::BODY + 0.05 * geom3::human_height);
|
||||
add_cone(geom3::BODY, hand, geom3::BODY - 0.05 * geom3::human_height);
|
||||
}
|
||||
|
||||
int at1 = isize(hpc);
|
||||
for(int i=at0; i<at1; i++) hpc.push_back(Mirror * hpc[i]);
|
||||
|
||||
add_texture(shPBody);
|
||||
shift_last(-geom3::BODY);
|
||||
}
|
||||
|
||||
/*
|
||||
void make_humanoid_3d(hpcshape& sh) { make_ha_3d(sh, false, 0.90); }
|
||||
void make_armor_3d(hpcshape& sh, ld scale = 1) { make_ha_3d(sh, true, scale); }
|
||||
*/
|
||||
|
||||
void make_humanoid_3d(hpcshape& sh) { make_ha_3d(sh, false, 1); }
|
||||
|
||||
void addtri(array<hyperpoint, 3> hs, int kind) {
|
||||
ld ds[3];
|
||||
ds[0] = hdist(hs[0], hs[1]);
|
||||
ds[1] = hdist(hs[1], hs[2]);
|
||||
ds[2] = hdist(hs[2], hs[0]);
|
||||
ld maxds = 0;
|
||||
for(int i=0; i<3; i++) maxds = max(ds[i], maxds) - 1e-3;
|
||||
|
||||
if(maxds > 0.02*S) for(int i=0; i<3; i++) {
|
||||
int j = (i+1) % 3;
|
||||
int k = (j+1) % 3;
|
||||
if(hdist(hs[i], hs[j]) > maxds) {
|
||||
auto hm = mid(hs[i], hs[j]);
|
||||
addtri(make_array(hm, hs[i], hs[k]), kind);
|
||||
addtri(make_array(hm, hs[j], hs[k]), kind);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(kind) {
|
||||
hyperpoint ht[3];
|
||||
ld hsh[3];
|
||||
ld shi[3];
|
||||
bool ok = true;
|
||||
for(int s=0; s<3; s++) {
|
||||
hs[s] = normalize(hs[s]);
|
||||
hyperpoint h = hs[s];
|
||||
ld zz = zc(0.78);
|
||||
hsh[s] = abs(h[1]);
|
||||
zz -= h[1] * h[1] / 0.14 / 0.14 * 0.01 / S / S * SH;
|
||||
zz -= h[0] * h[0] / 0.10 / 0.10 * 0.01 / S / S * SH;
|
||||
if(abs(h[1]) > 0.14*S) ok = false, zz -= (abs(h[1])/S - 0.14) * SH;
|
||||
if(abs(h[0]) > 0.08*S) ok = false, zz -= (abs(h[0])/S - 0.08) * (abs(h[0])/S - 0.08) * 25 * SH;
|
||||
hpcpush(ht[s] = zpush(zz) * h);
|
||||
if(hsh[s] < 0.1*S) shi[s] = -0.5;
|
||||
else if(hsh[s] < 0.12*S) shi[s] = -0.1 - 0.4 * (hsh[s]/S - 0.1) / (0.12 - 0.1);
|
||||
else shi[s] = -0.1;
|
||||
shi[s] *= geom3::human_height;
|
||||
}
|
||||
if(ok && kind == 1) for(int i=0; i<3; i++) {
|
||||
int j = (i+1) % 3;
|
||||
hpcpush(ht[i]);
|
||||
hpcpush(ht[j]);
|
||||
hpcpush(zpush(shi[i]) * ht[i]);
|
||||
hpcpush(ht[j]);
|
||||
hpcpush(zpush(shi[i]) * ht[i]);
|
||||
hpcpush(zpush(shi[i]) * ht[j]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(int s=0; s<3; s++) {
|
||||
hyperpoint h = hs[s];
|
||||
ld zz = zc(0.925);
|
||||
if(h[0] < -0.05*S) zz += (h[0]/S + 0.05) * SH;
|
||||
if(hdist0(h) <= 0.0501*S) {
|
||||
zz += sqrt(0.0026 - pow(hdist0(h)/S, 2)) * SH;
|
||||
}
|
||||
hpcpush(zpush(zz) * h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void make_armor_3d(hpcshape& sh, int kind = 1) {
|
||||
|
||||
auto body = get_shape(sh);
|
||||
vector<vector<array<ld, 2> >> pts(2);
|
||||
|
||||
for(hyperpoint h: body) {
|
||||
array<ld, 2> p;
|
||||
p[0] = h[0] / h[3];
|
||||
p[1] = h[1] / h[3];
|
||||
pts[0].emplace_back(p);
|
||||
}
|
||||
|
||||
bshape(sh, sh.prio);
|
||||
|
||||
vector<int> indices = mapbox::earcut<int> (pts);
|
||||
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
for(int k=0; k<isize(indices); k+=3) {
|
||||
addtri(make_array(body[indices[k]], body[indices[k+1]], body[indices[k+2]]), kind);
|
||||
}
|
||||
|
||||
add_texture(sh);
|
||||
if(&sh == &shHood || &sh == &shWightCloak || &sh == &shArmor)
|
||||
shift_last(-geom3::HEAD);
|
||||
else
|
||||
shift_last(-geom3::BODY);
|
||||
}
|
||||
|
||||
void make_foot_3d(hpcshape& sh) {
|
||||
auto foot = get_shape(sh);
|
||||
auto leg = get_shape(shHumanLeg);
|
||||
auto leg5 = scaleshape(leg, 0.8);
|
||||
|
||||
bshape(sh, PPR::MONSTER_BODY);
|
||||
shcenter = get_center(leg);
|
||||
add_cone(zc(0), foot, zc(0));
|
||||
add_prism(zc(0), foot, zc(0.1), leg);
|
||||
add_prism_sync(zc(0.1), leg, zc(0.4), leg5);
|
||||
add_cone(zc(0.4), leg5, zc(0.45));
|
||||
add_texture(sh);
|
||||
// shift_last(-geom3::LEG0);
|
||||
for(int i=last->s; i<isize(hpc); i++) hpc[i] = cpush(0, -0.0125*S) * hpc[i];
|
||||
}
|
||||
|
||||
void make_head_only() {
|
||||
|
||||
auto addpt = [] (int d, int u) {
|
||||
hpcpush(zpush(zc(0.925) + 0.06 * SH * sin(u * degree)) * xspinpush0(d * degree, 0.05 * S * cos(u * degree)));
|
||||
};
|
||||
|
||||
bshape(shPHeadOnly, shPHeadOnly.prio);
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
for(int d=0; d<360; d+=30)
|
||||
for(int u=-90; u<=90; u+=30) {
|
||||
addpt(d, u);
|
||||
addpt(d+30, u);
|
||||
addpt(d, u+30);
|
||||
addpt(d+30, u+30);
|
||||
addpt(d+30, u);
|
||||
addpt(d, u+30);
|
||||
}
|
||||
|
||||
add_texture(shPHeadOnly);
|
||||
shift_last(-geom3::HEAD - 0.01 * SH);
|
||||
}
|
||||
|
||||
|
||||
void make_head_3d(hpcshape& sh) {
|
||||
auto head = get_shape(sh);
|
||||
vector<vector<array<ld, 2> >> pts(2);
|
||||
|
||||
for(hyperpoint h: head) {
|
||||
array<ld, 2> p;
|
||||
p[0] = h[0] / h[3];
|
||||
p[1] = h[1] / h[3];
|
||||
pts[0].emplace_back(p);
|
||||
}
|
||||
|
||||
array<ld, 2> zero = {0,0};
|
||||
pts[1].emplace_back(zero);
|
||||
head.push_back(C0);
|
||||
|
||||
bshape(sh, sh.prio);
|
||||
|
||||
vector<int> indices = mapbox::earcut<int> (pts);
|
||||
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
for(int k=0; k<isize(indices); k+=3) {
|
||||
addtri(make_array(head[indices[k]], head[indices[k+1]], head[indices[k+2]]), 0);
|
||||
}
|
||||
|
||||
add_texture(sh);
|
||||
shift_last(-geom3::HEAD);
|
||||
}
|
||||
|
||||
void make_paw_3d(hpcshape& sh, hpcshape& legsh) {
|
||||
auto foot = get_shape(sh);
|
||||
auto leg = get_shape(legsh);
|
||||
|
||||
bshape(sh, PPR::MONSTER_BODY);
|
||||
shcenter = get_center(leg);
|
||||
add_cone(zc(0), foot, zc(0));
|
||||
add_prism(zc(0), foot, zc(0.1), leg);
|
||||
add_prism_sync(zc(0.1), leg, zc(0.4), leg);
|
||||
add_cone(zc(0.4), leg, zc(0.45));
|
||||
add_texture(sh);
|
||||
shift_last(-geom3::LEG0);
|
||||
}
|
||||
|
||||
void make_abody_3d(hpcshape& sh, ld tail) {
|
||||
auto body = get_shape(sh);
|
||||
shcenter = get_center(body);
|
||||
|
||||
vector<hyperpoint> notail;
|
||||
ld minx = 9;
|
||||
for(hyperpoint h: body) minx = min(minx, h[0]);
|
||||
for(hyperpoint h: body) if(h[0] >= minx + tail) notail.push_back(h);
|
||||
|
||||
auto body8 = scaleshape(notail, 0.8);
|
||||
|
||||
bshape(sh, PPR::MONSTER_BODY);
|
||||
add_prism(zc(0.4), body8, zc(0.45), body);
|
||||
add_prism(zc(0.45), body, zc(0.5), notail);
|
||||
add_prism_sync(zc(0.6), body8, zc(0.5), notail);
|
||||
add_cone(zc(0.4), body8, zc(0.36));
|
||||
add_cone(zc(0.6), body8, zc(0.64));
|
||||
add_texture(sh);
|
||||
}
|
||||
|
||||
void make_ahead_3d(hpcshape& sh) {
|
||||
auto body = get_shape(sh);
|
||||
shcenter = get_center(body);
|
||||
auto body8 = scaleshape(body, 0.5);
|
||||
|
||||
bshape(sh, PPR::MONSTER_BODY);
|
||||
add_prism_sync(zc(0.4), body8, zc(0.5), body);
|
||||
add_prism_sync(zc(0.6), body8, zc(0.5), body);
|
||||
add_cone(zc(0.4), body8, zc(0.36));
|
||||
add_cone(zc(0.6), body8, zc(0.64));
|
||||
add_texture(sh);
|
||||
}
|
||||
|
||||
void make_skeletal(hpcshape& sh, ld push = 0) {
|
||||
auto body = get_shape(sh);
|
||||
shcenter = get_center(body);
|
||||
|
||||
bshape(sh, PPR::MONSTER_BODY);
|
||||
add_prism_sync(zc(0.48), body, zc(0.5), body);
|
||||
add_prism_sync(zc(0.52), body, zc(0.5), body);
|
||||
add_cone(zc(0.48), body, zc(0.47));
|
||||
add_cone(zc(0.52), body, zc(0.53));
|
||||
add_texture(sh);
|
||||
shift_last(-push);
|
||||
}
|
||||
|
||||
void make_revolution(hpcshape& sh, int mx = 180, ld push = 0) {
|
||||
auto body = get_shape(sh);
|
||||
bshape(sh, PPR::MONSTER_BODY);
|
||||
int step = (mx == 360 ? 24 : 10);
|
||||
for(int i=0; i<isize(body); i++) {
|
||||
hyperpoint h0 = body[i];
|
||||
hyperpoint h1 = body[(i+1) % isize(body)];
|
||||
for(int s=0; s<mx; s+=step) {
|
||||
hpcpush(cspin(1, 2, s * degree) * h0);
|
||||
hpcpush(cspin(1, 2, s * degree) * h1);
|
||||
hpcpush(cspin(1, 2, (s+step) * degree) * h0);
|
||||
hpcpush(cspin(1, 2, s * degree) * h1);
|
||||
hpcpush(cspin(1, 2, (s+step) * degree) * h0);
|
||||
hpcpush(cspin(1, 2, (s+step) * degree) * h1);
|
||||
}
|
||||
}
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
add_texture(sh);
|
||||
shift_last(-push);
|
||||
}
|
||||
|
||||
void make_revolution_cut(hpcshape &sh, int each = 180, ld push = 0, ld width = 99) {
|
||||
auto body = get_shape(sh);
|
||||
int n = isize(body) / 2;
|
||||
|
||||
auto gbody = body;
|
||||
|
||||
int it = 0;
|
||||
|
||||
vector<int> nextid(n);
|
||||
vector<int> lastid(n);
|
||||
vector<bool> stillin(n, true);
|
||||
for(int i=0; i<n; i++) nextid[i] = i+1;
|
||||
for(int i=0; i<n; i++) lastid[i] = i-1;
|
||||
|
||||
while(true) {
|
||||
it++;
|
||||
int cand = -1;
|
||||
ld cv = 0;
|
||||
for(int i=1; i<n-1; i++) if(stillin[i]) {
|
||||
if((gbody[i][0] < gbody[lastid[i]][0] && gbody[i][0] < gbody[nextid[i]][0]) || (gbody[i][0] > gbody[lastid[i]][0] && gbody[i][0] > gbody[nextid[i]][0]) || abs(gbody[i][1]) > width)
|
||||
if(abs(gbody[i][1]) > cv)
|
||||
cand = i, cv = abs(gbody[i][1]);
|
||||
}
|
||||
if(cand == -1) break;
|
||||
int i = cand;
|
||||
lastid[nextid[i]] = lastid[i];
|
||||
nextid[lastid[i]] = nextid[i];
|
||||
stillin[i] = false;
|
||||
}
|
||||
|
||||
for(int i=n; i>=0; i--) if(!stillin[i] && !stillin[nextid[i]]) nextid[i] = nextid[nextid[i]];
|
||||
for(int i=0; i<n; i++) if(!stillin[i] && !stillin[lastid[i]]) lastid[i] = lastid[lastid[i]];
|
||||
|
||||
for(int i=0; i<n; i++) {
|
||||
using namespace hyperpoint_vec;
|
||||
if(!stillin[i]) gbody[i] = normalize(gbody[lastid[i]] * (i - lastid[i]) + gbody[nextid[i]] * (nextid[i] - i));
|
||||
}
|
||||
|
||||
bshape(sh, PPR::MONSTER_BODY);
|
||||
int step = 10;
|
||||
for(int i=0; i<n; i++) {
|
||||
for(int s=0; s<360; s+=step) {
|
||||
auto& tbody = (s % each ? gbody : body);
|
||||
auto& nbody = ((s+step) % each ? gbody : body);
|
||||
int i1 = (i+1) % isize(body);
|
||||
hyperpoint h0 = tbody[i];
|
||||
hyperpoint h1 = tbody[i1];
|
||||
hyperpoint hs0 = nbody[i];
|
||||
hyperpoint hs1 = nbody[i1];
|
||||
hpcpush(cspin(1, 2, s * degree) * h0);
|
||||
hpcpush(cspin(1, 2, s * degree) * h1);
|
||||
hpcpush(cspin(1, 2, (s+step) * degree) * hs0);
|
||||
hpcpush(cspin(1, 2, s * degree) * h1);
|
||||
hpcpush(cspin(1, 2, (s+step) * degree) * hs0);
|
||||
hpcpush(cspin(1, 2, (s+step) * degree) * hs1);
|
||||
}
|
||||
}
|
||||
last->flags |= POLY_TRIANGLES;
|
||||
add_texture(sh);
|
||||
shift_last(-push);
|
||||
}
|
||||
|
||||
void disable(hpcshape& sh) {
|
||||
sh.s = sh.e = 0;
|
||||
}
|
||||
|
||||
void make_3d_models() {
|
||||
if(DIM == 2) return;
|
||||
shcenter = C0;
|
||||
|
||||
if(floor_textures) {
|
||||
auto& utt = models_texture;
|
||||
utt.tvertices.clear();
|
||||
utt.texture_id = floor_textures->renderedTexture;
|
||||
}
|
||||
|
||||
make_humanoid_3d(shPBody);
|
||||
make_humanoid_3d(shYeti);
|
||||
make_humanoid_3d(shFemaleBody);
|
||||
make_humanoid_3d(shRaiderBody);
|
||||
make_humanoid_3d(shSkeletonBody);
|
||||
make_humanoid_3d(shFatBody);
|
||||
make_humanoid_3d(shWaterElemental);
|
||||
make_humanoid_3d(shJiangShi);
|
||||
|
||||
// shFatBody = shPBody;
|
||||
// shFemaleBody = shPBody;
|
||||
// shRaiderBody = shPBody;
|
||||
// shJiangShi = shPBody;
|
||||
|
||||
make_head_3d(shFemaleHair);
|
||||
make_head_3d(shPHead);
|
||||
make_head_3d(shTurban1);
|
||||
make_head_3d(shTurban2);
|
||||
make_head_3d(shAztecHead);
|
||||
make_head_3d(shAztecCap);
|
||||
make_head_3d(shVikingHelmet);
|
||||
make_head_3d(shRaiderHelmet);
|
||||
make_head_3d(shWestHat1);
|
||||
make_head_3d(shWestHat2);
|
||||
make_head_3d(shWitchHair);
|
||||
make_head_3d(shBeautyHair);
|
||||
make_head_3d(shFlowerHair);
|
||||
make_head_3d(shGolemhead);
|
||||
make_head_3d(shPirateHood);
|
||||
make_head_3d(shEyepatch);
|
||||
make_head_3d(shSkull);
|
||||
make_head_3d(shRatHead);
|
||||
make_head_3d(shDemon);
|
||||
make_head_3d(shGoatHead);
|
||||
make_head_3d(shRatCape1);
|
||||
make_head_3d(shJiangShiCap1);
|
||||
make_head_3d(shJiangShiCap2);
|
||||
make_head_3d(shTerraHead);
|
||||
|
||||
make_armor_3d(shKnightArmor);
|
||||
make_armor_3d(shKnightCloak, 2);
|
||||
make_armor_3d(shPrinceDress);
|
||||
make_armor_3d(shPrincessDress, 2);
|
||||
make_armor_3d(shTerraArmor1);
|
||||
make_armor_3d(shTerraArmor2);
|
||||
make_armor_3d(shTerraArmor3);
|
||||
make_armor_3d(shSuspenders);
|
||||
make_armor_3d(shJiangShiDress);
|
||||
make_armor_3d(shFemaleDress);
|
||||
make_armor_3d(shWightCloak, 2);
|
||||
make_armor_3d(shRaiderArmor);
|
||||
make_armor_3d(shRaiderShirt);
|
||||
make_armor_3d(shArmor);
|
||||
make_armor_3d(shRatCape2, 2);
|
||||
|
||||
make_armor_3d(shHood, 2);
|
||||
|
||||
make_foot_3d(shHumanFoot);
|
||||
make_foot_3d(shYetiFoot);
|
||||
make_skeletal(shSkeletalFoot);
|
||||
|
||||
make_paw_3d(shWolfFrontPaw, shWolfFrontLeg);
|
||||
make_paw_3d(shWolfRearPaw, shWolfRearLeg);
|
||||
make_paw_3d(shDogFrontPaw, shDogFrontLeg);
|
||||
make_paw_3d(shDogRearPaw, shDogRearLeg);
|
||||
|
||||
// make_abody_3d(shWolfBody, 0.01);
|
||||
// make_ahead_3d(shWolfHead);
|
||||
// make_ahead_3d(shFamiliarHead);
|
||||
make_revolution_cut(shWolfBody, 30, 0, 0.01*S);
|
||||
make_revolution_cut(shWolfHead, 180, geom3::AHEAD - geom3::ABODY);
|
||||
make_revolution_cut(shFamiliarHead, 30, geom3::AHEAD - geom3::ABODY);
|
||||
|
||||
// make_abody_3d(shDogTorso, 0.01);
|
||||
make_revolution_cut(shDogTorso, 30);
|
||||
make_revolution_cut(shDogHead, 180, geom3::AHEAD - geom3::ABODY);
|
||||
// make_ahead_3d(shDogHead);
|
||||
|
||||
// make_abody_3d(shCatBody, 0.05);
|
||||
// make_ahead_3d(shCatHead);
|
||||
make_revolution_cut(shCatBody, 30);
|
||||
make_revolution_cut(shCatHead, 180, geom3::AHEAD - geom3::ABODY);
|
||||
|
||||
make_paw_3d(shReptileFrontFoot, shReptileFrontLeg);
|
||||
make_paw_3d(shReptileRearFoot, shReptileRearLeg);
|
||||
make_abody_3d(shReptileBody, -1);
|
||||
// make_ahead_3d(shReptileHead);
|
||||
make_revolution_cut(shReptileHead, 180, geom3::AHEAD - geom3::ABODY);
|
||||
|
||||
make_paw_3d(shBullFrontHoof, shBullFrontHoof);
|
||||
make_paw_3d(shBullRearHoof, shBullRearHoof);
|
||||
// make_abody_3d(shBullBody, 0.05);
|
||||
// make_ahead_3d(shBullHead);
|
||||
// make_ahead_3d(shBullHorn);
|
||||
make_revolution_cut(shBullBody, 180);
|
||||
make_revolution_cut(shBullHead, 60, geom3::AHEAD - geom3::ABODY);
|
||||
shift_shape(shBullHorn, -(geom3::AHEAD - geom3::ABODY));
|
||||
// make_revolution_cut(shBullHorn, 180, geom3::AHEAD - geom3::ABODY);
|
||||
|
||||
make_paw_3d(shTrylobiteFrontClaw, shTrylobiteFrontLeg);
|
||||
make_paw_3d(shTrylobiteRearClaw, shTrylobiteRearLeg);
|
||||
make_abody_3d(shTrylobiteBody, 0);
|
||||
// make_ahead_3d(shTrylobiteHead);
|
||||
make_revolution_cut(shTrylobiteHead, 180, geom3::AHEAD - geom3::ABODY);
|
||||
|
||||
make_revolution_cut(shShark, 180);
|
||||
|
||||
make_revolution_cut(shGhost, 60);
|
||||
make_revolution_cut(shSlime, 60);
|
||||
|
||||
make_revolution_cut(shEagle, 180, 0, 0.05*S);
|
||||
make_revolution_cut(shHawk, 180, 0, 0.05*S);
|
||||
|
||||
make_revolution_cut(shGargoyleWings, 180, 0, 0.05*S);
|
||||
make_revolution_cut(shGargoyleBody, 180, 0, 0.05*S);
|
||||
make_revolution_cut(shGadflyWing, 180, 0, 0.05*S);
|
||||
make_revolution_cut(shBatWings, 180, 0, 0.05*S);
|
||||
make_revolution_cut(shBatBody, 180, 0, 0.05*S);
|
||||
|
||||
make_revolution_cut(shJelly, 60);
|
||||
make_revolution(shFoxTail1);
|
||||
make_revolution(shFoxTail2);
|
||||
make_revolution(shGadflyBody);
|
||||
for(int i=0; i<8; i++)
|
||||
make_revolution(shAsteroid[i], 360);
|
||||
|
||||
make_revolution_cut(shBugLeg, 60, geom3::ALEG0);
|
||||
|
||||
make_revolution(shBugArmor, 180, geom3::ABODY);
|
||||
make_revolution_cut(shBugAntenna, 90, geom3::ABODY);
|
||||
|
||||
make_revolution_cut(shButterflyBody, 180);
|
||||
|
||||
shift_shape(shWolf1, -0.088 * S);
|
||||
shift_shape(shWolf2, -0.088 * S);
|
||||
shift_shape(shWolf3, -0.098 * S);
|
||||
shift_shape(shFamiliarEye, -0.088 * S);
|
||||
shift_shape(shWolfEyes, (-0.088 - 0.01 * 0.9) * S);
|
||||
|
||||
shift_shape(shEyes, (-3.3) * S / -20);
|
||||
for(int i=shEyes.s; i<shEyes.e; i++) hpc[i] = cspin(0, 2, M_PI/2) * hpc[i];
|
||||
|
||||
disable(shWolfRearLeg);
|
||||
disable(shWolfFrontLeg);
|
||||
disable(shDogRearLeg);
|
||||
disable(shDogFrontLeg);
|
||||
disable(shReptileFrontLeg);
|
||||
disable(shReptileRearLeg);
|
||||
disable(shTrylobiteFrontLeg);
|
||||
disable(shTrylobiteRearLeg);
|
||||
disable(shPFace);
|
||||
disable(shJiangShi);
|
||||
|
||||
make_head_only();
|
||||
}
|
||||
|
||||
#undef S
|
||||
#undef SH
|
||||
|
||||
}
|
@ -65,6 +65,7 @@ namespace hr { namespace inv { bool on, activating; } }
|
||||
#include "geometry.cpp"
|
||||
#include "geometry2.cpp"
|
||||
#include "polygons.cpp"
|
||||
#include "3d-models.cpp"
|
||||
#include "floorshapes.cpp"
|
||||
#include "mapeditor.cpp"
|
||||
#if CAP_MODEL
|
||||
|
794
earcut.hpp
Normal file
794
earcut.hpp
Normal file
@ -0,0 +1,794 @@
|
||||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2015, Mapbox
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright notice
|
||||
and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
||||
THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace mapbox {
|
||||
|
||||
namespace util {
|
||||
|
||||
template <std::size_t I, typename T> struct nth {
|
||||
inline static typename std::tuple_element<I, T>::type
|
||||
get(const T& t) { return std::get<I>(t); };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename N = uint32_t>
|
||||
class Earcut {
|
||||
public:
|
||||
std::vector<N> indices;
|
||||
std::size_t vertices = 0;
|
||||
|
||||
template <typename Polygon>
|
||||
void operator()(const Polygon& points);
|
||||
|
||||
private:
|
||||
struct Node {
|
||||
Node(N index, double x_, double y_) : i(index), x(x_), y(y_) {}
|
||||
Node(const Node&) = delete;
|
||||
Node& operator=(const Node&) = delete;
|
||||
Node(Node&&) = delete;
|
||||
Node& operator=(Node&&) = delete;
|
||||
|
||||
const N i;
|
||||
const double x;
|
||||
const double y;
|
||||
|
||||
// previous and next vertice nodes in a polygon ring
|
||||
Node* prev = nullptr;
|
||||
Node* next = nullptr;
|
||||
|
||||
// z-order curve value
|
||||
int32_t z = 0;
|
||||
|
||||
// previous and next nodes in z-order
|
||||
Node* prevZ = nullptr;
|
||||
Node* nextZ = nullptr;
|
||||
|
||||
// indicates whether this is a steiner point
|
||||
bool steiner = false;
|
||||
};
|
||||
|
||||
template <typename Ring> Node* linkedList(const Ring& points, const bool clockwise);
|
||||
Node* filterPoints(Node* start, Node* end = nullptr);
|
||||
void earcutLinked(Node* ear, int pass = 0);
|
||||
bool isEar(Node* ear);
|
||||
bool isEarHashed(Node* ear);
|
||||
Node* cureLocalIntersections(Node* start);
|
||||
void splitEarcut(Node* start);
|
||||
template <typename Polygon> Node* eliminateHoles(const Polygon& points, Node* outerNode);
|
||||
void eliminateHole(Node* hole, Node* outerNode);
|
||||
Node* findHoleBridge(Node* hole, Node* outerNode);
|
||||
void indexCurve(Node* start);
|
||||
Node* sortLinked(Node* list);
|
||||
int32_t zOrder(const double x_, const double y_);
|
||||
Node* getLeftmost(Node* start);
|
||||
bool pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const;
|
||||
bool isValidDiagonal(Node* a, Node* b);
|
||||
double area(const Node* p, const Node* q, const Node* r) const;
|
||||
bool equals(const Node* p1, const Node* p2);
|
||||
bool intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2);
|
||||
bool intersectsPolygon(const Node* a, const Node* b);
|
||||
bool locallyInside(const Node* a, const Node* b);
|
||||
bool middleInside(const Node* a, const Node* b);
|
||||
Node* splitPolygon(Node* a, Node* b);
|
||||
template <typename Point> Node* insertNode(std::size_t i, const Point& p, Node* last);
|
||||
void removeNode(Node* p);
|
||||
|
||||
bool hashing;
|
||||
double minX, maxX;
|
||||
double minY, maxY;
|
||||
double inv_size = 0;
|
||||
|
||||
template <typename T, typename Alloc = std::allocator<T>>
|
||||
class ObjectPool {
|
||||
public:
|
||||
ObjectPool() { }
|
||||
ObjectPool(std::size_t blockSize_) {
|
||||
reset(blockSize_);
|
||||
}
|
||||
~ObjectPool() {
|
||||
clear();
|
||||
}
|
||||
template <typename... Args>
|
||||
T* construct(Args&&... args) {
|
||||
if (currentIndex >= blockSize) {
|
||||
currentBlock = alloc_traits::allocate(alloc, blockSize);
|
||||
allocations.emplace_back(currentBlock);
|
||||
currentIndex = 0;
|
||||
}
|
||||
T* object = ¤tBlock[currentIndex++];
|
||||
alloc_traits::construct(alloc, object, std::forward<Args>(args)...);
|
||||
return object;
|
||||
}
|
||||
void reset(std::size_t newBlockSize) {
|
||||
for (auto allocation : allocations) {
|
||||
alloc_traits::deallocate(alloc, allocation, blockSize);
|
||||
}
|
||||
allocations.clear();
|
||||
blockSize = std::max<std::size_t>(1, newBlockSize);
|
||||
currentBlock = nullptr;
|
||||
currentIndex = blockSize;
|
||||
}
|
||||
void clear() { reset(blockSize); }
|
||||
private:
|
||||
T* currentBlock = nullptr;
|
||||
std::size_t currentIndex = 1;
|
||||
std::size_t blockSize = 1;
|
||||
std::vector<T*> allocations;
|
||||
Alloc alloc;
|
||||
typedef typename std::allocator_traits<Alloc> alloc_traits;
|
||||
};
|
||||
ObjectPool<Node> nodes;
|
||||
};
|
||||
|
||||
template <typename N> template <typename Polygon>
|
||||
void Earcut<N>::operator()(const Polygon& points) {
|
||||
// reset
|
||||
indices.clear();
|
||||
vertices = 0;
|
||||
|
||||
if (points.empty()) return;
|
||||
|
||||
double x;
|
||||
double y;
|
||||
int threshold = 80;
|
||||
std::size_t len = 0;
|
||||
|
||||
for (size_t i = 0; threshold >= 0 && i < points.size(); i++) {
|
||||
threshold -= static_cast<int>(points[i].size());
|
||||
len += points[i].size();
|
||||
}
|
||||
|
||||
//estimate size of nodes and indices
|
||||
nodes.reset(len * 3 / 2);
|
||||
indices.reserve(len + points[0].size());
|
||||
|
||||
Node* outerNode = linkedList(points[0], true);
|
||||
if (!outerNode || outerNode->prev == outerNode->next) return;
|
||||
|
||||
if (points.size() > 1) outerNode = eliminateHoles(points, outerNode);
|
||||
|
||||
// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
|
||||
hashing = threshold < 0;
|
||||
if (hashing) {
|
||||
Node* p = outerNode->next;
|
||||
minX = maxX = outerNode->x;
|
||||
minY = maxY = outerNode->y;
|
||||
do {
|
||||
x = p->x;
|
||||
y = p->y;
|
||||
minX = std::min<double>(minX, x);
|
||||
minY = std::min<double>(minY, y);
|
||||
maxX = std::max<double>(maxX, x);
|
||||
maxY = std::max<double>(maxY, y);
|
||||
p = p->next;
|
||||
} while (p != outerNode);
|
||||
|
||||
// minX, minY and size are later used to transform coords into integers for z-order calculation
|
||||
inv_size = std::max<double>(maxX - minX, maxY - minY);
|
||||
inv_size = inv_size != .0 ? (1. / inv_size) : .0;
|
||||
}
|
||||
|
||||
earcutLinked(outerNode);
|
||||
|
||||
nodes.clear();
|
||||
}
|
||||
|
||||
// create a circular doubly linked list from polygon points in the specified winding order
|
||||
template <typename N> template <typename Ring>
|
||||
typename Earcut<N>::Node*
|
||||
Earcut<N>::linkedList(const Ring& points, const bool clockwise) {
|
||||
using Point = typename Ring::value_type;
|
||||
double sum = 0;
|
||||
const std::size_t len = points.size();
|
||||
std::size_t i, j;
|
||||
Node* last = nullptr;
|
||||
|
||||
// calculate original winding order of a polygon ring
|
||||
for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) {
|
||||
const auto& p1 = points[i];
|
||||
const auto& p2 = points[j];
|
||||
const double p20 = util::nth<0, Point>::get(p2);
|
||||
const double p10 = util::nth<0, Point>::get(p1);
|
||||
const double p11 = util::nth<1, Point>::get(p1);
|
||||
const double p21 = util::nth<1, Point>::get(p2);
|
||||
sum += (p20 - p10) * (p11 + p21);
|
||||
}
|
||||
|
||||
// link points into circular doubly-linked list in the specified winding order
|
||||
if (clockwise == (sum > 0)) {
|
||||
for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last);
|
||||
} else {
|
||||
for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last);
|
||||
}
|
||||
|
||||
if (last && equals(last, last->next)) {
|
||||
removeNode(last);
|
||||
last = last->next;
|
||||
}
|
||||
|
||||
vertices += len;
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
// eliminate colinear or duplicate points
|
||||
template <typename N>
|
||||
typename Earcut<N>::Node*
|
||||
Earcut<N>::filterPoints(Node* start, Node* end) {
|
||||
if (!end) end = start;
|
||||
|
||||
Node* p = start;
|
||||
bool again;
|
||||
do {
|
||||
again = false;
|
||||
|
||||
if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) {
|
||||
removeNode(p);
|
||||
p = end = p->prev;
|
||||
|
||||
if (p == p->next) break;
|
||||
again = true;
|
||||
|
||||
} else {
|
||||
p = p->next;
|
||||
}
|
||||
} while (again || p != end);
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
// main ear slicing loop which triangulates a polygon (given as a linked list)
|
||||
template <typename N>
|
||||
void Earcut<N>::earcutLinked(Node* ear, int pass) {
|
||||
if (!ear) return;
|
||||
|
||||
// interlink polygon nodes in z-order
|
||||
if (!pass && hashing) indexCurve(ear);
|
||||
|
||||
Node* stop = ear;
|
||||
Node* prev;
|
||||
Node* next;
|
||||
|
||||
int iterations = 0;
|
||||
|
||||
// iterate through ears, slicing them one by one
|
||||
while (ear->prev != ear->next) {
|
||||
iterations++;
|
||||
prev = ear->prev;
|
||||
next = ear->next;
|
||||
|
||||
if (hashing ? isEarHashed(ear) : isEar(ear)) {
|
||||
// cut off the triangle
|
||||
indices.emplace_back(prev->i);
|
||||
indices.emplace_back(ear->i);
|
||||
indices.emplace_back(next->i);
|
||||
|
||||
removeNode(ear);
|
||||
|
||||
// skipping the next vertice leads to less sliver triangles
|
||||
ear = next->next;
|
||||
stop = next->next;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
ear = next;
|
||||
|
||||
// if we looped through the whole remaining polygon and can't find any more ears
|
||||
if (ear == stop) {
|
||||
// try filtering points and slicing again
|
||||
if (!pass) earcutLinked(filterPoints(ear), 1);
|
||||
|
||||
// if this didn't work, try curing all small self-intersections locally
|
||||
else if (pass == 1) {
|
||||
ear = cureLocalIntersections(ear);
|
||||
earcutLinked(ear, 2);
|
||||
|
||||
// as a last resort, try splitting the remaining polygon into two
|
||||
} else if (pass == 2) splitEarcut(ear);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check whether a polygon node forms a valid ear with adjacent nodes
|
||||
template <typename N>
|
||||
bool Earcut<N>::isEar(Node* ear) {
|
||||
const Node* a = ear->prev;
|
||||
const Node* b = ear;
|
||||
const Node* c = ear->next;
|
||||
|
||||
if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
|
||||
|
||||
// now make sure we don't have other points inside the potential ear
|
||||
Node* p = ear->next->next;
|
||||
|
||||
while (p != ear->prev) {
|
||||
if (pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
|
||||
area(p->prev, p, p->next) >= 0) return false;
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename N>
|
||||
bool Earcut<N>::isEarHashed(Node* ear) {
|
||||
const Node* a = ear->prev;
|
||||
const Node* b = ear;
|
||||
const Node* c = ear->next;
|
||||
|
||||
if (area(a, b, c) >= 0) return false; // reflex, can't be an ear
|
||||
|
||||
// triangle bbox; min & max are calculated like this for speed
|
||||
const double minTX = std::min<double>(a->x, std::min<double>(b->x, c->x));
|
||||
const double minTY = std::min<double>(a->y, std::min<double>(b->y, c->y));
|
||||
const double maxTX = std::max<double>(a->x, std::max<double>(b->x, c->x));
|
||||
const double maxTY = std::max<double>(a->y, std::max<double>(b->y, c->y));
|
||||
|
||||
// z-order range for the current triangle bbox;
|
||||
const int32_t minZ = zOrder(minTX, minTY);
|
||||
const int32_t maxZ = zOrder(maxTX, maxTY);
|
||||
|
||||
// first look for points inside the triangle in increasing z-order
|
||||
Node* p = ear->nextZ;
|
||||
|
||||
while (p && p->z <= maxZ) {
|
||||
if (p != ear->prev && p != ear->next &&
|
||||
pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
|
||||
area(p->prev, p, p->next) >= 0) return false;
|
||||
p = p->nextZ;
|
||||
}
|
||||
|
||||
// then look for points in decreasing z-order
|
||||
p = ear->prevZ;
|
||||
|
||||
while (p && p->z >= minZ) {
|
||||
if (p != ear->prev && p != ear->next &&
|
||||
pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) &&
|
||||
area(p->prev, p, p->next) >= 0) return false;
|
||||
p = p->prevZ;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// go through all polygon nodes and cure small local self-intersections
|
||||
template <typename N>
|
||||
typename Earcut<N>::Node*
|
||||
Earcut<N>::cureLocalIntersections(Node* start) {
|
||||
Node* p = start;
|
||||
do {
|
||||
Node* a = p->prev;
|
||||
Node* b = p->next->next;
|
||||
|
||||
// a self-intersection where edge (v[i-1],v[i]) intersects (v[i+1],v[i+2])
|
||||
if (!equals(a, b) && intersects(a, p, p->next, b) && locallyInside(a, b) && locallyInside(b, a)) {
|
||||
indices.emplace_back(a->i);
|
||||
indices.emplace_back(p->i);
|
||||
indices.emplace_back(b->i);
|
||||
|
||||
// remove two nodes involved
|
||||
removeNode(p);
|
||||
removeNode(p->next);
|
||||
|
||||
p = start = b;
|
||||
}
|
||||
p = p->next;
|
||||
} while (p != start);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// try splitting polygon into two and triangulate them independently
|
||||
template <typename N>
|
||||
void Earcut<N>::splitEarcut(Node* start) {
|
||||
// look for a valid diagonal that divides the polygon into two
|
||||
Node* a = start;
|
||||
do {
|
||||
Node* b = a->next->next;
|
||||
while (b != a->prev) {
|
||||
if (a->i != b->i && isValidDiagonal(a, b)) {
|
||||
// split the polygon in two by the diagonal
|
||||
Node* c = splitPolygon(a, b);
|
||||
|
||||
// filter colinear points around the cuts
|
||||
a = filterPoints(a, a->next);
|
||||
c = filterPoints(c, c->next);
|
||||
|
||||
// run earcut on each half
|
||||
earcutLinked(a);
|
||||
earcutLinked(c);
|
||||
return;
|
||||
}
|
||||
b = b->next;
|
||||
}
|
||||
a = a->next;
|
||||
} while (a != start);
|
||||
}
|
||||
|
||||
// link every hole into the outer loop, producing a single-ring polygon without holes
|
||||
template <typename N> template <typename Polygon>
|
||||
typename Earcut<N>::Node*
|
||||
Earcut<N>::eliminateHoles(const Polygon& points, Node* outerNode) {
|
||||
const size_t len = points.size();
|
||||
|
||||
std::vector<Node*> queue;
|
||||
for (size_t i = 1; i < len; i++) {
|
||||
Node* list = linkedList(points[i], false);
|
||||
if (list) {
|
||||
if (list == list->next) list->steiner = true;
|
||||
queue.push_back(getLeftmost(list));
|
||||
}
|
||||
}
|
||||
std::sort(queue.begin(), queue.end(), [](const Node* a, const Node* b) {
|
||||
return a->x < b->x;
|
||||
});
|
||||
|
||||
// process holes from left to right
|
||||
for (size_t i = 0; i < queue.size(); i++) {
|
||||
eliminateHole(queue[i], outerNode);
|
||||
outerNode = filterPoints(outerNode, outerNode->next);
|
||||
}
|
||||
|
||||
return outerNode;
|
||||
}
|
||||
|
||||
// find a bridge between vertices that connects hole with an outer ring and and link it
|
||||
template <typename N>
|
||||
void Earcut<N>::eliminateHole(Node* hole, Node* outerNode) {
|
||||
outerNode = findHoleBridge(hole, outerNode);
|
||||
if (outerNode) {
|
||||
Node* b = splitPolygon(outerNode, hole);
|
||||
filterPoints(b, b->next);
|
||||
}
|
||||
}
|
||||
|
||||
// David Eberly's algorithm for finding a bridge between hole and outer polygon
|
||||
template <typename N>
|
||||
typename Earcut<N>::Node*
|
||||
Earcut<N>::findHoleBridge(Node* hole, Node* outerNode) {
|
||||
Node* p = outerNode;
|
||||
double hx = hole->x;
|
||||
double hy = hole->y;
|
||||
double qx = -std::numeric_limits<double>::infinity();
|
||||
Node* m = nullptr;
|
||||
|
||||
// find a segment intersected by a ray from the hole's leftmost Vertex to the left;
|
||||
// segment's endpoint with lesser x will be potential connection Vertex
|
||||
do {
|
||||
if (hy <= p->y && hy >= p->next->y && p->next->y != p->y) {
|
||||
double x = p->x + (hy - p->y) * (p->next->x - p->x) / (p->next->y - p->y);
|
||||
if (x <= hx && x > qx) {
|
||||
qx = x;
|
||||
if (x == hx) {
|
||||
if (hy == p->y) return p;
|
||||
if (hy == p->next->y) return p->next;
|
||||
}
|
||||
m = p->x < p->next->x ? p : p->next;
|
||||
}
|
||||
}
|
||||
p = p->next;
|
||||
} while (p != outerNode);
|
||||
|
||||
if (!m) return 0;
|
||||
|
||||
if (hx == qx) return m->prev;
|
||||
|
||||
// look for points inside the triangle of hole Vertex, segment intersection and endpoint;
|
||||
// if there are no points found, we have a valid connection;
|
||||
// otherwise choose the Vertex of the minimum angle with the ray as connection Vertex
|
||||
|
||||
const Node* stop = m;
|
||||
double tanMin = std::numeric_limits<double>::infinity();
|
||||
double tanCur = 0;
|
||||
|
||||
p = m->next;
|
||||
double mx = m->x;
|
||||
double my = m->y;
|
||||
|
||||
while (p != stop) {
|
||||
if (hx >= p->x && p->x >= mx && hx != p->x &&
|
||||
pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p->x, p->y)) {
|
||||
|
||||
tanCur = std::abs(hy - p->y) / (hx - p->x); // tangential
|
||||
|
||||
if ((tanCur < tanMin || (tanCur == tanMin && p->x > m->x)) && locallyInside(p, hole)) {
|
||||
m = p;
|
||||
tanMin = tanCur;
|
||||
}
|
||||
}
|
||||
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
// interlink polygon nodes in z-order
|
||||
template <typename N>
|
||||
void Earcut<N>::indexCurve(Node* start) {
|
||||
assert(start);
|
||||
Node* p = start;
|
||||
|
||||
do {
|
||||
p->z = p->z ? p->z : zOrder(p->x, p->y);
|
||||
p->prevZ = p->prev;
|
||||
p->nextZ = p->next;
|
||||
p = p->next;
|
||||
} while (p != start);
|
||||
|
||||
p->prevZ->nextZ = nullptr;
|
||||
p->prevZ = nullptr;
|
||||
|
||||
sortLinked(p);
|
||||
}
|
||||
|
||||
// Simon Tatham's linked list merge sort algorithm
|
||||
// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
|
||||
template <typename N>
|
||||
typename Earcut<N>::Node*
|
||||
Earcut<N>::sortLinked(Node* list) {
|
||||
assert(list);
|
||||
Node* p;
|
||||
Node* q;
|
||||
Node* e;
|
||||
Node* tail;
|
||||
int i, numMerges, pSize, qSize;
|
||||
int inSize = 1;
|
||||
|
||||
for (;;) {
|
||||
p = list;
|
||||
list = nullptr;
|
||||
tail = nullptr;
|
||||
numMerges = 0;
|
||||
|
||||
while (p) {
|
||||
numMerges++;
|
||||
q = p;
|
||||
pSize = 0;
|
||||
for (i = 0; i < inSize; i++) {
|
||||
pSize++;
|
||||
q = q->nextZ;
|
||||
if (!q) break;
|
||||
}
|
||||
|
||||
qSize = inSize;
|
||||
|
||||
while (pSize > 0 || (qSize > 0 && q)) {
|
||||
|
||||
if (pSize == 0) {
|
||||
e = q;
|
||||
q = q->nextZ;
|
||||
qSize--;
|
||||
} else if (qSize == 0 || !q) {
|
||||
e = p;
|
||||
p = p->nextZ;
|
||||
pSize--;
|
||||
} else if (p->z <= q->z) {
|
||||
e = p;
|
||||
p = p->nextZ;
|
||||
pSize--;
|
||||
} else {
|
||||
e = q;
|
||||
q = q->nextZ;
|
||||
qSize--;
|
||||
}
|
||||
|
||||
if (tail) tail->nextZ = e;
|
||||
else list = e;
|
||||
|
||||
e->prevZ = tail;
|
||||
tail = e;
|
||||
}
|
||||
|
||||
p = q;
|
||||
}
|
||||
|
||||
tail->nextZ = nullptr;
|
||||
|
||||
if (numMerges <= 1) return list;
|
||||
|
||||
inSize *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// z-order of a Vertex given coords and size of the data bounding box
|
||||
template <typename N>
|
||||
int32_t Earcut<N>::zOrder(const double x_, const double y_) {
|
||||
// coords are transformed into non-negative 15-bit integer range
|
||||
int32_t x = static_cast<int32_t>(32767.0 * (x_ - minX) * inv_size);
|
||||
int32_t y = static_cast<int32_t>(32767.0 * (y_ - minY) * inv_size);
|
||||
|
||||
x = (x | (x << 8)) & 0x00FF00FF;
|
||||
x = (x | (x << 4)) & 0x0F0F0F0F;
|
||||
x = (x | (x << 2)) & 0x33333333;
|
||||
x = (x | (x << 1)) & 0x55555555;
|
||||
|
||||
y = (y | (y << 8)) & 0x00FF00FF;
|
||||
y = (y | (y << 4)) & 0x0F0F0F0F;
|
||||
y = (y | (y << 2)) & 0x33333333;
|
||||
y = (y | (y << 1)) & 0x55555555;
|
||||
|
||||
return x | (y << 1);
|
||||
}
|
||||
|
||||
// find the leftmost node of a polygon ring
|
||||
template <typename N>
|
||||
typename Earcut<N>::Node*
|
||||
Earcut<N>::getLeftmost(Node* start) {
|
||||
Node* p = start;
|
||||
Node* leftmost = start;
|
||||
do {
|
||||
if (p->x < leftmost->x || (p->x == leftmost->x && p->y < leftmost->y))
|
||||
leftmost = p;
|
||||
p = p->next;
|
||||
} while (p != start);
|
||||
|
||||
return leftmost;
|
||||
}
|
||||
|
||||
// check if a point lies within a convex triangle
|
||||
template <typename N>
|
||||
bool Earcut<N>::pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const {
|
||||
return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
|
||||
(ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
|
||||
(bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
|
||||
}
|
||||
|
||||
// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
|
||||
template <typename N>
|
||||
bool Earcut<N>::isValidDiagonal(Node* a, Node* b) {
|
||||
return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) &&
|
||||
locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b);
|
||||
}
|
||||
|
||||
// signed area of a triangle
|
||||
template <typename N>
|
||||
double Earcut<N>::area(const Node* p, const Node* q, const Node* r) const {
|
||||
return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y);
|
||||
}
|
||||
|
||||
// check if two points are equal
|
||||
template <typename N>
|
||||
bool Earcut<N>::equals(const Node* p1, const Node* p2) {
|
||||
return p1->x == p2->x && p1->y == p2->y;
|
||||
}
|
||||
|
||||
// check if two segments intersect
|
||||
template <typename N>
|
||||
bool Earcut<N>::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) {
|
||||
if ((equals(p1, q1) && equals(p2, q2)) ||
|
||||
(equals(p1, q2) && equals(p2, q1))) return true;
|
||||
return (area(p1, q1, p2) > 0) != (area(p1, q1, q2) > 0) &&
|
||||
(area(p2, q2, p1) > 0) != (area(p2, q2, q1) > 0);
|
||||
}
|
||||
|
||||
// check if a polygon diagonal intersects any polygon segments
|
||||
template <typename N>
|
||||
bool Earcut<N>::intersectsPolygon(const Node* a, const Node* b) {
|
||||
const Node* p = a;
|
||||
do {
|
||||
if (p->i != a->i && p->next->i != a->i && p->i != b->i && p->next->i != b->i &&
|
||||
intersects(p, p->next, a, b)) return true;
|
||||
p = p->next;
|
||||
} while (p != a);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if a polygon diagonal is locally inside the polygon
|
||||
template <typename N>
|
||||
bool Earcut<N>::locallyInside(const Node* a, const Node* b) {
|
||||
return area(a->prev, a, a->next) < 0 ?
|
||||
area(a, b, a->next) >= 0 && area(a, a->prev, b) >= 0 :
|
||||
area(a, b, a->prev) < 0 || area(a, a->next, b) < 0;
|
||||
}
|
||||
|
||||
// check if the middle Vertex of a polygon diagonal is inside the polygon
|
||||
template <typename N>
|
||||
bool Earcut<N>::middleInside(const Node* a, const Node* b) {
|
||||
const Node* p = a;
|
||||
bool inside = false;
|
||||
double px = (a->x + b->x) / 2;
|
||||
double py = (a->y + b->y) / 2;
|
||||
do {
|
||||
if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y &&
|
||||
(px < (p->next->x - p->x) * (py - p->y) / (p->next->y - p->y) + p->x))
|
||||
inside = !inside;
|
||||
p = p->next;
|
||||
} while (p != a);
|
||||
|
||||
return inside;
|
||||
}
|
||||
|
||||
// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits
|
||||
// polygon into two; if one belongs to the outer ring and another to a hole, it merges it into a
|
||||
// single ring
|
||||
template <typename N>
|
||||
typename Earcut<N>::Node*
|
||||
Earcut<N>::splitPolygon(Node* a, Node* b) {
|
||||
Node* a2 = nodes.construct(a->i, a->x, a->y);
|
||||
Node* b2 = nodes.construct(b->i, b->x, b->y);
|
||||
Node* an = a->next;
|
||||
Node* bp = b->prev;
|
||||
|
||||
a->next = b;
|
||||
b->prev = a;
|
||||
|
||||
a2->next = an;
|
||||
an->prev = a2;
|
||||
|
||||
b2->next = a2;
|
||||
a2->prev = b2;
|
||||
|
||||
bp->next = b2;
|
||||
b2->prev = bp;
|
||||
|
||||
return b2;
|
||||
}
|
||||
|
||||
// create a node and util::optionally link it with previous one (in a circular doubly linked list)
|
||||
template <typename N> template <typename Point>
|
||||
typename Earcut<N>::Node*
|
||||
Earcut<N>::insertNode(std::size_t i, const Point& pt, Node* last) {
|
||||
Node* p = nodes.construct(static_cast<N>(i), util::nth<0, Point>::get(pt), util::nth<1, Point>::get(pt));
|
||||
|
||||
if (!last) {
|
||||
p->prev = p;
|
||||
p->next = p;
|
||||
|
||||
} else {
|
||||
assert(last);
|
||||
p->next = last->next;
|
||||
p->prev = last;
|
||||
last->next->prev = p;
|
||||
last->next = p;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename N>
|
||||
void Earcut<N>::removeNode(Node* p) {
|
||||
p->next->prev = p->prev;
|
||||
p->prev->next = p->next;
|
||||
|
||||
if (p->prevZ) p->prevZ->nextZ = p->nextZ;
|
||||
if (p->nextZ) p->nextZ->prevZ = p->prevZ;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename N = uint32_t, typename Polygon>
|
||||
std::vector<N> earcut(const Polygon& poly) {
|
||||
mapbox::detail::Earcut<N> earcut;
|
||||
earcut(poly);
|
||||
return std::move(earcut.indices);
|
||||
}
|
||||
}
|
37
graph.cpp
37
graph.cpp
@ -580,43 +580,56 @@ transmatrix otherbodyparts(const transmatrix& V, color_t col, eMonster who, doub
|
||||
|
||||
// todo
|
||||
|
||||
if(detaillevel >= 2) {
|
||||
if(detaillevel >= 2 && DIM == 2) {
|
||||
transmatrix VL = mmscale(V, geom3::LEG1);
|
||||
queuepoly(VL * xpush(rightfoot*3/4), shHumanLeg, col);
|
||||
queuepoly(VL * Mirror * xpush(-rightfoot*3/4), shHumanLeg, col);
|
||||
}
|
||||
|
||||
if(true) {
|
||||
if(DIM == 2) {
|
||||
transmatrix VL = mmscale(V, geom3::LEG);
|
||||
queuepoly(VL * xpush(rightfoot/2), shHumanLeg, col);
|
||||
queuepoly(VL * Mirror * xpush(-rightfoot/2), shHumanLeg, col);
|
||||
}
|
||||
|
||||
if(detaillevel >= 2) {
|
||||
if(detaillevel >= 2 && DIM == 2) {
|
||||
transmatrix VL = mmscale(V, geom3::LEG3);
|
||||
queuepoly(VL * xpush(rightfoot/4), shHumanLeg, col);
|
||||
queuepoly(VL * Mirror * xpush(-rightfoot/4), shHumanLeg, col);
|
||||
}
|
||||
|
||||
if(who == moWaterElemental) {
|
||||
transmatrix Tright, Tleft;
|
||||
|
||||
if(DIM == 2) {
|
||||
Tright = VFOOT * xpush(rightfoot);
|
||||
Tleft = VFOOT * Mirror * xpush(-rightfoot);
|
||||
}
|
||||
else {
|
||||
Tright = V * cspin(0, 2, rightfoot/SCALE * 3);
|
||||
Tleft = V * Mirror * cspin(2, 0, rightfoot/SCALE * 3);
|
||||
}
|
||||
|
||||
if(who == moWaterElemental && DIM == 2) {
|
||||
double fishtail = footfun(footphase / .4) / 4 * 1.5;
|
||||
queuepoly(VFOOT * xpush(fishtail), shFishTail, watercolor(100));
|
||||
}
|
||||
else if(who == moSkeleton) {
|
||||
queuepoly(VFOOT * xpush(rightfoot), shSkeletalFoot, col);
|
||||
queuepoly(VFOOT * Mirror * xpush(-rightfoot), shSkeletalFoot, col);
|
||||
queuepoly(Tright, shSkeletalFoot, col);
|
||||
queuepoly(Tleft, shSkeletalFoot, col);
|
||||
return spin(rightfoot * wobble);
|
||||
}
|
||||
else if(isTroll(who) || who == moMonkey || who == moYeti || who == moRatling || who == moRatlingAvenger || who == moGoblin) {
|
||||
queuepoly(VFOOT * xpush(rightfoot), shYetiFoot, col);
|
||||
queuepoly(VFOOT * Mirror * xpush(-rightfoot), shYetiFoot, col);
|
||||
queuepoly(Tright, shYetiFoot, col);
|
||||
queuepoly(Tleft, shYetiFoot, col);
|
||||
}
|
||||
else {
|
||||
queuepoly(VFOOT * xpush(rightfoot), shHumanFoot, col);
|
||||
queuepoly(VFOOT * Mirror * xpush(-rightfoot), shHumanFoot, col);
|
||||
queuepoly(Tright, shHumanFoot, col);
|
||||
queuepoly(Tleft, shHumanFoot, col);
|
||||
}
|
||||
|
||||
if(!mmspatial) return spin(rightfoot * wobble);
|
||||
if(DIM == 3) queuepoly(VHEAD, shPHeadOnly, col);
|
||||
|
||||
if(DIM == 3 || !mmspatial) return spin(rightfoot * wobble);
|
||||
|
||||
if(detaillevel >= 2 && who != moZombie)
|
||||
queuepoly(mmscale(V, geom3::NECK1), shHumanNeck, col);
|
||||
@ -630,8 +643,6 @@ transmatrix otherbodyparts(const transmatrix& V, color_t col, eMonster who, doub
|
||||
}
|
||||
|
||||
return spin(rightfoot * wobble);
|
||||
|
||||
return Id;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
16
polygons.cpp
16
polygons.cpp
@ -1714,6 +1714,8 @@ hpcshape
|
||||
|
||||
shAsymmetric,
|
||||
|
||||
shPBodyOnly, shPBodyArm, shPBodyHand, shPHeadOnly,
|
||||
|
||||
shDodeca;
|
||||
|
||||
vector<hpcshape> shPlainWall3D, shWireframe3D, shWall3D, shMiniWall3D;
|
||||
@ -2683,6 +2685,8 @@ void configure_floorshapes() {
|
||||
generate_floorshapes();
|
||||
}
|
||||
|
||||
extern void make_3d_models();
|
||||
|
||||
void buildpolys() {
|
||||
|
||||
symmetriesAt.clear();
|
||||
@ -2923,6 +2927,11 @@ void buildpolys() {
|
||||
bshape(shFemaleDress, PPR::MONSTER_ARMOR0, scalefactor, 97);
|
||||
bshape(shDemon, PPR::MONSTER_HAIR, scalefactor, 98);
|
||||
|
||||
bshape(shPBodyOnly, PPR::MONSTER_BODY, scalefactor, 389);
|
||||
bshape(shPBodyArm, PPR::MONSTER_BODY, scalefactor, 390);
|
||||
bshape(shPBodyHand, PPR::MONSTER_BODY, scalefactor, 391);
|
||||
bshape(shPHeadOnly, PPR::MONSTER_HEAD, scalefactor, 392);
|
||||
|
||||
bshape(shTrylobite, PPR::MONSTER_BODY, scalefactor, 99);
|
||||
bshape(shTrylobiteHead, PPR::MONSTER_HEAD, scalefactor, 100);
|
||||
bshape(shTrylobiteBody, PPR::MONSTER_BODY, scalefactor, 308);
|
||||
@ -3093,6 +3102,8 @@ void buildpolys() {
|
||||
bshape(shBead1, PPR(20), 1, 251);
|
||||
bshape(shArrow, PPR::ARROW, 1, 252);
|
||||
|
||||
make_3d_models();
|
||||
|
||||
bshapeend();
|
||||
|
||||
prehpc = isize(hpc);
|
||||
@ -4094,6 +4105,11 @@ NEWSHAPE, 386, 3, 1, 0.173768,0.275379, 0.340287,0.116342, 0.229291,-0.115277,
|
||||
NEWSHAPE, 387, 7, 1, 0.315263,-0.310217, 0.085056,-0.287538,
|
||||
NEWSHAPE, 388, 1, 1, 0.046590,0.284199, 0.028110,0.325611, 0.098711,0.333738, 0.088761,0.294314, 0.090351,0.227036, 0.092387,0.196322, 0.129546,0.192006, 0.168982,0.166667, 0.173088,0.117700, 0.022882,0.091527, 0.004586,0.133004, 0.022981,0.160866, 0.052990,0.184313, 0.085413,0.193910, 0.055297,0.184324,
|
||||
|
||||
NEWSHAPE, 389, 1, 2, -0.127943,0.000000, -0.121732,0.008437, -0.120752,0.047093, -0.114785,0.065246, -0.096531,0.082051, -0.079664,0.100183, -0.087015,0.156872, -0.056388,0.171466, -0.021870,0.150662, -0.022997,0.136774, -0.004819,0.120485, 0.007204,0.104455, 0.016748,0.083741, 0.026225,0.054833, 0.033323,0.030943, 0.034483,0.001189, 0.034483,-0.001189,
|
||||
NEWSHAPE, 390, 1, 1, -0.079664,0.100183, -0.087015,0.156872, -0.090442,0.188317, -0.085023,0.215058, -0.078296,0.241201, -0.070101,0.263835, -0.062700,0.273833, -0.053763,0.276497, -0.037212,0.273273, -0.026261,0.230095, -0.024880,0.217700, -0.022225,0.198787, -0.020850,0.180288, -0.021870,0.150662, -0.022997,0.136774, -0.036634,0.100744,
|
||||
NEWSHAPE, 391, 1, 1, -0.063645,0.226806, -0.078296,0.241201, -0.070101,0.263835, -0.062700,0.273833, -0.053763,0.276497, -0.030638,0.274461, -0.015319,0.275737, 0.001277,0.277150, 0.020384,0.271369, 0.038101,0.262896, 0.045596,0.255842, 0.062388,0.263558, 0.085371,0.258660, 0.084235,0.228817, 0.071073,0.213220, 0.048603,0.218088, 0.042541,0.228972, 0.028749,0.228742, 0.011222,0.224439, -0.012498,0.229969, -0.026261,0.230095,
|
||||
NEWSHAPE, 392, 1, 2, 0.060794,0.001192, 0.058426,0.023847, 0.050054,0.030986, 0.042896,0.038130, 0.044109,0.042917, 0.032180,0.050058, 0.017884,0.059612, 0.005963,0.064401, -0.009546,0.068015, -0.022689,0.070455, -0.053753,0.053753, -0.065710,0.040621, -0.074098,0.028683, -0.088611,0.020357, -0.087387,0.017956,
|
||||
|
||||
NEWSHAPE
|
||||
};
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user