Spaces:
Running
Running
File size: 7,400 Bytes
aed627e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | /* ============================================================================
BROOD CROWD — RENDER-ONLY SWARM DENSITY
----------------------------------------------------------------------------
These bodies are deliberately NOT units. They never enter the simulation,
pathfinder, selection, targeting, fog, save, replay or network state. A
visible real Brood ground unit is the only anchor allowed to submit one
deterministic cluster, so crowd art cannot reveal a hidden army or create a
second source of combat truth.
Three LOD meshes keep the illusion honest. Close view adds one subordinate
crawler; tactical view adds a three-body knot; distant view adds four very
cheap silhouettes beneath the strategic icon tier. Every tier remains one
InstMesh draw, and one global frame budget is shared across all three.
============================================================================ */
let MF_BROOD_CROWD_STREAMS=null;
let MF_BROOD_CROWD_EPOCH=-1;
let MF_BROOD_CROWD_FRAME={time:0,span:0,perf:1,diff:1,seed:0,budget:0,density:0,queued:0};
let MF_BROOD_CROWD_STAT={
enabled:false,quality:'high',budget:0,visibleAnchors:0,eligibleAnchors:0,
clusterInstances:0,visualBodies:0,drawCalls:0,triangles:0,
skippedDensity:0,skippedBudget:0,near:0,mid:0,far:0
};
function mfBroodCrowdHash(v){
v=(v|0)^0x6d2b79f5;
v=Math.imul(v^(v>>>15),v|1);
v^=v+Math.imul(v^(v>>>7),v|61);
return (v^(v>>>14))>>>0;
}
function mfBroodCrowdStringHash(s){
s=String(s||'');
let h=2166136261;
for(let i=0;i<s.length;i++) h=Math.imul(h^s.charCodeAt(i),16777619);
return h>>>0;
}
/* One crawler is intentionally less detailed than a real Skitterling. Its
small subordinate silhouette prevents a cosmetic body being mistaken for a
target with its own health, while CHITIN/LEAF keep the live organic shader
response and animation instead of introducing a flat sprite species. */
function mfBroodCrowdCrawler(m,x,z,yaw,scale,legs){
m.translate(x,0,z);m.rotateY(yaw);m.scale3d(scale,scale,scale);
m.mat(MAT.CHITIN).team(0);
m.sphere(-.25,.72,0,1.34,5,CHIT_D,.55,false);
m.sphere(1.02,.64,0,.72,4,CHITIN,.66,false);
m.sphere(-1.22,.65,0,.62,4,CHIT_D,.58,false);
/* A small team-bearing dorsal plate reads allegiance, but most of the body
keeps authored chitin colour so a dense group does not become a neon blob. */
m.mat(MAT.CHITIN).team(1);
m.sphere(-.15,1.19,0,.48,4,BIO_TEAM,.34,true);
m.team(0).mat(MAT.LEAF);
const n=Math.max(1,legs|0);
for(let k=0;k<n;k++) for(const sd of [-1,1]){
const lx=n===1?.05:-.62+k*(1.24/Math.max(1,n-1));
const lz=sd*(1.12+(k&1)*.10);
m.box(lx,.18,lz,1.72,.22,.25,BIO_LEG,sd*(.30+k*.09));
}
m.popTransform();m.popTransform();m.popTransform();
}
function mfBroodCrowdGeo(tier){
const m=MB();
if(tier==='near'){
mfBroodCrowdCrawler(m,2.7,1.2,.28,.82,3);
}else if(tier==='mid'){
mfBroodCrowdCrawler(m,-2.8,-1.7,-.42,.76,2);
mfBroodCrowdCrawler(m, 2.4,-1.2, .34,.70,2);
mfBroodCrowdCrawler(m, -.2, 2.7,1.92,.66,2);
}else{
mfBroodCrowdCrawler(m,-2.7,-1.8,-.34,.55,1);
mfBroodCrowdCrawler(m, 2.5,-1.5, .46,.52,1);
mfBroodCrowdCrawler(m,-1.7, 2.3,2.36,.48,1);
mfBroodCrowdCrawler(m, 2.0, 2.1,1.18,.46,1);
}
return m.build();
}
function mfBroodCrowdInit(){
if(typeof gl==='undefined'||!gl||typeof InstMesh!=='function'||typeof MB!=='function') return false;
const epoch=typeof glEpoch==='number'?glEpoch:0;
if(MF_BROOD_CROWD_STREAMS&&MF_BROOD_CROWD_EPOCH===epoch) return true;
const near=mfBroodCrowdGeo('near'),mid=mfBroodCrowdGeo('mid'),far=mfBroodCrowdGeo('far');
MF_BROOD_CROWD_STREAMS={
near:new InstMesh(gl,near,64),
mid:new InstMesh(gl,mid,256),
far:new InstMesh(gl,far,256),
bodies:{near:1,mid:3,far:4},
tris:{near:near.count/3,mid:mid.count/3,far:far.count/3}
};
MF_BROOD_CROWD_EPOCH=epoch;
return true;
}
function mfBroodCrowdBeginFrame(time,ortho,perf,difficulty){
const quality=typeof mfGfxKey==='function'?mfGfxKey():'high';
const base=quality==='low'?96:quality==='medium'?160:256;
const p=Number.isFinite(perf)?perf:1;
/* Population pressure already drives perfScale. Honour that signal here
rather than making the presentation layer compete with authoritative AI. */
const budget=p<.36?Math.min(base,64):p<.56?Math.min(base,112):base;
const d=Math.max(0,Math.min(2,difficulty|0));
const density=[.28,.58,1.0][d];
const mapSeed=(typeof MAPDEFS!=='undefined'&&typeof curMap!=='undefined'&&MAPDEFS[curMap])?
(MAPDEFS[curMap].seed|0):mfBroodCrowdStringHash(typeof curMap!=='undefined'?curMap:'');
MF_BROOD_CROWD_FRAME={
time:Number.isFinite(time)?time:0,span:Number.isFinite(ortho)?ortho:0,
perf:p,diff:d,seed:mapSeed,budget,density,queued:0
};
MF_BROOD_CROWD_STAT={
enabled:budget>0,quality,budget,visibleAnchors:0,eligibleAnchors:0,
clusterInstances:0,visualBodies:0,drawCalls:0,triangles:0,
skippedDensity:0,skippedBudget:0,near:0,mid:0,far:0
};
if(!mfBroodCrowdInit()){ MF_BROOD_CROWD_STAT.enabled=false; return false; }
MF_BROOD_CROWD_STREAMS.near.clear();
MF_BROOD_CROWD_STREAMS.mid.clear();
MF_BROOD_CROWD_STREAMS.far.clear();
return true;
}
/* Called only after the real anchor passed camera and fog visibility gates.
isBrood must come from the resolved faction kit, never from an assumed team
number: an AI commander can field the Brood kit in an ordinary seat. */
function mfBroodCrowdQueue(unitIndex,type,x,y,h,yaw,T,teamColour,uLod,iconQ,moving,isBrood){
MF_BROOD_CROWD_STAT.visibleAnchors++;
if(!MF_BROOD_CROWD_STAT.enabled||!isBrood||!T||T.air||T.naval||T.cat==='hero'||T.hero||T.size>24) return false;
MF_BROOD_CROWD_STAT.eligibleAnchors++;
const F=MF_BROOD_CROWD_FRAME;
const hv=mfBroodCrowdHash((unitIndex|0)^Math.imul((type|0)+17,0x45d9f3b)^F.seed);
if((hv&65535)/65535>F.density){ MF_BROOD_CROWD_STAT.skippedDensity++; return false; }
if(F.queued>=F.budget){ MF_BROOD_CROWD_STAT.skippedBudget++; return false; }
const iq=Number.isFinite(iconQ)?iconQ:0;
let tier;
if(iq>.12||F.span>1800||uLod===1) tier='far';
else if(F.span>760) tier='mid';
else tier='near';
/* Close view is where a tethered cosmetic body is easiest to notice. Keep
only one in five eligible anchors there; mid/far carry the mass fantasy. */
if(tier==='near'&&((hv>>>16)%5)!==0){ MF_BROOD_CROWD_STAT.skippedDensity++; return false; }
const stream=MF_BROOD_CROWD_STREAMS[tier],tc=teamColour||[190,92,230];
const jitter=.88+((hv>>>24)&255)/255*.22;
const sc=Math.max(.68,Math.min(1.28,(T.size||12)/16))*jitter;
const turn=((hv>>>8)&1023)/1023*6.2831853;
const anim=tier==='far'||F.perf<.36?0:F.time*(moving?6.2:2.05)+(hv&2047)*.0137;
stream.add(x,y,h,sc,yaw+turn,tc[0],tc[1],tc[2],255,sc,anim,0);
F.queued++;
MF_BROOD_CROWD_STAT.clusterInstances++;
MF_BROOD_CROWD_STAT.visualBodies+=MF_BROOD_CROWD_STREAMS.bodies[tier];
MF_BROOD_CROWD_STAT.triangles+=MF_BROOD_CROWD_STREAMS.tris[tier];
MF_BROOD_CROWD_STAT[tier]++;
return true;
}
function mfBroodCrowdFlush(){
if(!MF_BROOD_CROWD_STREAMS||typeof gl==='undefined'||!gl) return;
for(const tier of ['near','mid','far']){
const stream=MF_BROOD_CROWD_STREAMS[tier];
if(stream.n){ MF_BROOD_CROWD_STAT.drawCalls++; stream.flush(gl); }
}
}
function mfBroodCrowdStats(){
return Object.assign({},MF_BROOD_CROWD_STAT);
}
|