mirror of
https://github.com/zenorogue/hyperrogue.git
synced 2024-12-26 01:50:36 +00:00
894 lines
26 KiB
C++
894 lines
26 KiB
C++
// 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 {
|
|
|
|
#if MAXMDIM >= 4
|
|
|
|
#define S (scalefactor / 0.805578)
|
|
#define SH (scalefactor / 0.805578 * geom3::height_width / 1.5)
|
|
|
|
#define revZ (WDIM == 2 ? -1 : 1)
|
|
|
|
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) {
|
|
if(WDIM == 2 && GDIM == 3)
|
|
return geom3::lev_to_factor(geom3::human_height * 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] = zshift(hpc[i], z);
|
|
}
|
|
|
|
void shift_shape(hpcshape& sh, ld z) {
|
|
for(int i=sh.s; i<sh.e; i++) hpc[i] = zshift(hpc[i], z);
|
|
}
|
|
|
|
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;
|
|
shi[s] *= revZ;
|
|
}
|
|
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 += revZ * (h[0]/S + 0.05) * SH;
|
|
if(hdist0(h) <= 0.0501*S) {
|
|
zz += revZ * 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 - revZ * 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 = make_array<ld>(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);
|
|
}
|
|
|
|
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);
|
|
if(GDIM == 3 && WDIM == 2) shift_last(-geom3::ABODY);
|
|
}
|
|
|
|
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-1; 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 clone_shape(hpcshape& sh, hpcshape& target) {
|
|
target = sh;
|
|
target.s = isize(hpc);
|
|
for(int i=sh.s; i<sh.e; i++) hpc.push_back(hpc[i]);
|
|
target.e = isize(hpc);
|
|
}
|
|
|
|
void animate_bird(hpcshape& orig, hpcshape animated[30], ld body) {
|
|
for(int i=0; i<30; i++) {
|
|
auto& tgt = animated[i];
|
|
clone_shape(orig, tgt);
|
|
ld alpha = sin(12 * degree * i) * 30 * degree;
|
|
for(int i=tgt.s; i<tgt.e; i++) {
|
|
if(abs(hpc[i][1]) > body) {
|
|
ld off = hpc[i][1] > 0 ? body : -body;
|
|
hpc[i][2] += abs(hpc[i][1] - off) * sin(alpha);
|
|
hpc[i][1] = off + (hpc[i][1] - off) * cos(alpha);
|
|
hpc[i] = normalize(hpc[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void balltriangle(hyperpoint a, hyperpoint b, hyperpoint c, ld rad, int lev) {
|
|
if(lev == 0) {
|
|
hpcpush(a);
|
|
hpcpush(b);
|
|
hpcpush(c);
|
|
}
|
|
else {
|
|
hyperpoint cx = rspintox(mid(a,b)) * xpush0(rad);
|
|
hyperpoint ax = rspintox(mid(b,c)) * xpush0(rad);
|
|
hyperpoint bx = rspintox(mid(c,a)) * xpush0(rad);
|
|
balltriangle(ax, bx, cx, rad, lev-1);
|
|
balltriangle(ax, bx, c , rad, lev-1);
|
|
balltriangle(ax, b , cx, rad, lev-1);
|
|
balltriangle(a , bx, cx, rad, lev-1);
|
|
}
|
|
}
|
|
|
|
void make_ball(hpcshape& sh, ld rad, int lev) {
|
|
bshape(sh, sh.prio);
|
|
sh.flags |= POLY_TRIANGLES;
|
|
hyperpoint tip = xpush0(rad);
|
|
hyperpoint atip = xpush0(-rad);
|
|
for(int i=0; i<5; i++) {
|
|
hyperpoint a = cspin(1, 2, (72 * i ) * degree) * spin(1) * tip;
|
|
hyperpoint b = cspin(1, 2, (72 * i-72) * degree) * spin(1) * tip;
|
|
hyperpoint c = cspin(1, 2, (72 * i+36) * degree) * spin(M_PI-1) * tip;
|
|
hyperpoint d = cspin(1, 2, (72 * i-36) * degree) * spin(M_PI-1) * tip;
|
|
balltriangle(tip, a, b, rad, lev);
|
|
balltriangle(a, b, c, rad, lev);
|
|
balltriangle(b, c, d, rad, lev);
|
|
balltriangle(c, d, atip, rad, lev);
|
|
}
|
|
add_texture(sh);
|
|
}
|
|
|
|
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);
|
|
ld g = WDIM == 2 ? geom3::ABODY - zc(0.4) : 0;
|
|
|
|
make_revolution_cut(shWolfBody, 30, g, 0.01*S);
|
|
make_revolution_cut(shWolfHead, 180, geom3::AHEAD - geom3::ABODY +g);
|
|
make_revolution_cut(shFamiliarHead, 30, geom3::AHEAD - geom3::ABODY +g);
|
|
|
|
// make_abody_3d(shDogTorso, 0.01);
|
|
make_revolution_cut(shDogTorso, 30, +g);
|
|
make_revolution_cut(shDogHead, 180, geom3::AHEAD - geom3::ABODY +g);
|
|
// make_ahead_3d(shDogHead);
|
|
|
|
// make_abody_3d(shCatBody, 0.05);
|
|
// make_ahead_3d(shCatHead);
|
|
make_revolution_cut(shCatBody, 30, +g);
|
|
make_revolution_cut(shCatHead, 180, geom3::AHEAD - geom3::ABODY +g);
|
|
|
|
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+g);
|
|
|
|
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, +g);
|
|
make_revolution_cut(shBullHead, 60, geom3::AHEAD - geom3::ABODY +g);
|
|
shift_shape(shBullHorn, g-(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 +g);
|
|
|
|
make_revolution_cut(shShark, 180, WDIM == 2 ? -geom3::FLOOR : 0);
|
|
|
|
make_revolution_cut(shGhost, 60, g);
|
|
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(shTinyBird, 180, 0, 0.025 * S);
|
|
make_revolution_cut(shTinyShark, 90);
|
|
make_revolution_cut(shMiniGhost, 60);
|
|
|
|
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, -g-0.088 * S);
|
|
shift_shape(shWolf2, -g-0.088 * S);
|
|
shift_shape(shWolf3, -g-0.098 * S);
|
|
shift_shape(shFamiliarEye, -g-0.088 * S);
|
|
shift_shape(shWolfEyes, -g+(-0.088 - 0.01 * 0.9) * S);
|
|
|
|
shift_shape(shEyes, -g+(-3.3) * S / -20);
|
|
for(int i=shEyes.s; i<shEyes.e; i++) hpc[i] = cspin(0, 2, M_PI/2) * hpc[i];
|
|
|
|
animate_bird(shEagle, shAnimatedEagle, 0.05*S);
|
|
animate_bird(shTinyBird, shAnimatedTinyEagle, 0.05*S/2);
|
|
|
|
disable(shWolfRearLeg);
|
|
disable(shWolfFrontLeg);
|
|
disable(shDogRearLeg);
|
|
disable(shDogFrontLeg);
|
|
disable(shReptileFrontLeg);
|
|
disable(shReptileRearLeg);
|
|
disable(shTrylobiteFrontLeg);
|
|
disable(shTrylobiteRearLeg);
|
|
disable(shPFace);
|
|
disable(shJiangShi);
|
|
|
|
make_revolution_cut(shDragonSegment, 60, g);
|
|
make_revolution_cut(shDragonHead, 60, g);
|
|
make_revolution_cut(shDragonTail, 60, g);
|
|
make_revolution_cut(shWormSegment, 60, g);
|
|
make_revolution_cut(shSmallWormSegment, 60, g);
|
|
make_revolution_cut(shWormHead, 60, g);
|
|
make_revolution_cut(shTentHead, 60, g);
|
|
make_revolution_cut(shKrakenHead, 60, -geom3::FLOOR);
|
|
make_revolution_cut(shSeaTentacle, 60, -geom3::FLOOR);
|
|
make_revolution_cut(shDragonLegs, 60, g);
|
|
make_revolution_cut(shDragonWings, 60, g);
|
|
disable(shDragonNostril);
|
|
|
|
make_head_only();
|
|
|
|
make_ball(shDisk, orbsize*.2, 2);
|
|
make_ball(shHeptaMarker, zhexf*.2, 1);
|
|
make_ball(shSnowball, zhexf*.1, 0);
|
|
|
|
if(WDIM == 2) {
|
|
for(int i=0; i<3; i++)
|
|
shift_shape(shHalfFloor[i], geom3::lev_to_factor(geom3::human_height * .01));
|
|
}
|
|
}
|
|
|
|
#undef S
|
|
#undef SH
|
|
#undef revZ
|
|
#endif
|
|
|
|
}
|