roavatar-renderer 1.9.9 → 1.9.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +123 -7
  2. package/dist/index.js +575 -230
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -33687,7 +33687,13 @@ class Instance {
33687
33687
  }
33688
33688
  return lastChild;
33689
33689
  }
33690
+ /**
33691
+ * IMPORTANT: Only works properly for instances with an InstanceWrapper
33692
+ * @param className
33693
+ * @returns
33694
+ */
33690
33695
  IsA(className) {
33696
+ if (this.className === className) return true;
33691
33697
  const wrapper = this.w;
33692
33698
  if (wrapper) {
33693
33699
  return wrapper.IsA(className);
@@ -36722,7 +36728,7 @@ class LocalOutfit {
36722
36728
  this.name = outfit.name;
36723
36729
  this.id = outfit.id;
36724
36730
  this.creator = outfit.creatorId;
36725
- this.date = Date.now();
36731
+ this.date = outfit.creationDate || Date.now();
36726
36732
  this.buffer = arrayBufferToBase64(outfit.toBuffer());
36727
36733
  }
36728
36734
  toJson() {
@@ -36740,6 +36746,7 @@ class LocalOutfit {
36740
36746
  this.name = data.name;
36741
36747
  this.id = data.id;
36742
36748
  this.creator = data.creator;
36749
+ this.date = data.date;
36743
36750
  this.image = data.image;
36744
36751
  this.buffer = data.buffer;
36745
36752
  this.bg = data.bg || 0;
@@ -36759,6 +36766,7 @@ class LocalOutfit {
36759
36766
  outfit.name = this.name;
36760
36767
  outfit.id = this.id;
36761
36768
  outfit.creatorId = this.creator;
36769
+ outfit.creationDate = this.date;
36762
36770
  await outfit.fromBuffer(base64ToArrayBuffer(this.buffer), auth);
36763
36771
  return outfit;
36764
36772
  }
@@ -36768,6 +36776,7 @@ class LocalOutfit {
36768
36776
  outfit.name = this.name;
36769
36777
  outfit.id = this.id;
36770
36778
  outfit.creatorId = this.creator;
36779
+ outfit.creationDate = this.date;
36771
36780
  await outfit.fromBuffer(base64ToArrayBuffer(this.buffer), auth);
36772
36781
  if (this.bg) {
36773
36782
  await outfit.addAssetId(this.bg, auth);
@@ -36817,9 +36826,7 @@ const AllAccessorySorts = [
36817
36826
  new ItemSort(46),
36818
36827
  new ItemSort(47)
36819
36828
  ];
36820
- if (!FLAGS.HAIR_IS_BODYPART) {
36821
- AllAccessorySorts.push(new ItemSort(41));
36822
- }
36829
+ AllAccessorySorts.push(new ItemSort(41));
36823
36830
  const AllClothingSorts = [
36824
36831
  new ItemSort(12),
36825
36832
  new ItemSort(11),
@@ -36843,9 +36850,7 @@ const AllBodyPartsSorts = [
36843
36850
  new ItemSort(31),
36844
36851
  new ItemSort(27)
36845
36852
  ];
36846
- if (FLAGS.HAIR_IS_BODYPART) {
36847
- AllBodyPartsSorts.push(new ItemSort(41));
36848
- }
36853
+ AllBodyPartsSorts.push(new ItemSort(41));
36849
36854
  const AllAnimationSorts = [
36850
36855
  new ItemSort(48),
36851
36856
  new ItemSort(50),
@@ -36906,6 +36911,7 @@ const CategoryDictionary = {
36906
36911
  "Dynamic Heads": new SortInfo([new ItemSort(2, "Outfit")]),
36907
36912
  "Adjustment": new SpecialInfo("HeadAdjustment"),
36908
36913
  "|": new SortDivision(),
36914
+ "Hair": new SortInfo([new ItemSort(41)]),
36909
36915
  "Heads": new SortInfo([new ItemSort(17)], "inventory"),
36910
36916
  "Faces": new SortInfo([new ItemSort(18)], "inventory")
36911
36917
  },
@@ -39386,6 +39392,7 @@ class Cache {
39386
39392
  map = /* @__PURE__ */ new Map();
39387
39393
  lastAccess = /* @__PURE__ */ new Map();
39388
39394
  maxEntries;
39395
+ minDeleteLifetime = 5;
39389
39396
  onDelete;
39390
39397
  constructor(maxEntries = 250) {
39391
39398
  this.maxEntries = maxEntries;
@@ -39399,12 +39406,7 @@ class Cache {
39399
39406
  set(key, value) {
39400
39407
  this.map.set(key, value);
39401
39408
  this.lastAccess.set(key, Date.now());
39402
- if (this.map.size > this.maxEntries) {
39403
- const toDelete = [...this.lastAccess.entries()].reduce((min, current) => {
39404
- return current[1] < min[1] ? current : min;
39405
- });
39406
- this.delete(toDelete[0]);
39407
- }
39409
+ this.deleteUntil();
39408
39410
  return this;
39409
39411
  }
39410
39412
  has(key) {
@@ -39416,11 +39418,28 @@ class Cache {
39416
39418
  this.lastAccess.delete(key);
39417
39419
  return toReturn;
39418
39420
  }
39421
+ deleteUntil() {
39422
+ while (this.map.size > this.maxEntries) {
39423
+ if (!this.deleteOne()) break;
39424
+ }
39425
+ }
39426
+ deleteOne() {
39427
+ if (this.map.size > this.maxEntries) {
39428
+ const toDelete = [...this.lastAccess.entries()].reduce((min, current) => {
39429
+ return current[1] < min[1] ? current : min;
39430
+ });
39431
+ if (Date.now() - toDelete[1] >= this.minDeleteLifetime * 1e3) {
39432
+ this.delete(toDelete[0]);
39433
+ return true;
39434
+ }
39435
+ }
39436
+ return false;
39437
+ }
39419
39438
  }
39420
39439
  const CACHE = {
39421
- "AssetBuffer": new Cache(250),
39440
+ "AssetBuffer": new Cache(100),
39422
39441
  "RBX": new Cache(100),
39423
- "Mesh": new Cache(250),
39442
+ "Mesh": new Cache(100),
39424
39443
  "Image": new Cache(100),
39425
39444
  "Thumbnails": new Cache(1e3),
39426
39445
  "ItemOwned": new Cache(1e3),
@@ -39429,6 +39448,54 @@ const CACHE = {
39429
39448
  "ItemDetails": new Cache(1e4),
39430
39449
  "UserInfo": void 0
39431
39450
  };
39451
+ function setCacheFootprintPreset(preset) {
39452
+ switch (preset) {
39453
+ case "none":
39454
+ CACHE.AssetBuffer.maxEntries = 0;
39455
+ CACHE.RBX.maxEntries = 0;
39456
+ CACHE.Mesh.maxEntries = 0;
39457
+ CACHE.Image.maxEntries = 0;
39458
+ CACHE.Thumbnails.maxEntries = 0;
39459
+ CACHE.ItemOwned.maxEntries = 0;
39460
+ CACHE.IsLayered.maxEntries = 0;
39461
+ CACHE.AvatarInventoryItem.maxEntries = 0;
39462
+ CACHE.ItemDetails.maxEntries = 0;
39463
+ break;
39464
+ case "low":
39465
+ CACHE.AssetBuffer.maxEntries = 10;
39466
+ CACHE.RBX.maxEntries = 10;
39467
+ CACHE.Mesh.maxEntries = 10;
39468
+ CACHE.Image.maxEntries = 10;
39469
+ CACHE.Thumbnails.maxEntries = 500;
39470
+ CACHE.ItemOwned.maxEntries = 500;
39471
+ CACHE.IsLayered.maxEntries = 100;
39472
+ CACHE.AvatarInventoryItem.maxEntries = 500;
39473
+ CACHE.ItemDetails.maxEntries = 5e3;
39474
+ break;
39475
+ case "normal":
39476
+ CACHE.AssetBuffer.maxEntries = 100;
39477
+ CACHE.RBX.maxEntries = 100;
39478
+ CACHE.Mesh.maxEntries = 100;
39479
+ CACHE.Image.maxEntries = 100;
39480
+ CACHE.Thumbnails.maxEntries = 1e3;
39481
+ CACHE.ItemOwned.maxEntries = 1e3;
39482
+ CACHE.IsLayered.maxEntries = 1e3;
39483
+ CACHE.AvatarInventoryItem.maxEntries = 1e3;
39484
+ CACHE.ItemDetails.maxEntries = 1e4;
39485
+ break;
39486
+ case "high":
39487
+ CACHE.AssetBuffer.maxEntries = 250;
39488
+ CACHE.RBX.maxEntries = 250;
39489
+ CACHE.Mesh.maxEntries = 250;
39490
+ CACHE.Image.maxEntries = 250;
39491
+ CACHE.Thumbnails.maxEntries = 1e3;
39492
+ CACHE.ItemOwned.maxEntries = 1e3;
39493
+ CACHE.IsLayered.maxEntries = 1e3;
39494
+ CACHE.AvatarInventoryItem.maxEntries = 1e3;
39495
+ CACHE.ItemDetails.maxEntries = 1e4;
39496
+ break;
39497
+ }
39498
+ }
39432
39499
  const ContentMap = /* @__PURE__ */ new Map();
39433
39500
  function createContentMap() {
39434
39501
  ContentMap.set("rbxasset://fonts/BaseballCap.mesh", "12220916");
@@ -43854,6 +43921,89 @@ GLTFExporter.Utils = {
43854
43921
  return dstAttribute;
43855
43922
  }
43856
43923
  };
43924
+ const managedTextures = /* @__PURE__ */ new Map();
43925
+ async function createTexturePromise(url, params) {
43926
+ const image = await API.Generic.LoadImage(url.replace(".dds", ".png"));
43927
+ if (!image) return void 0;
43928
+ const texture = new Texture(
43929
+ image,
43930
+ void 0,
43931
+ params?.wrapS || ClampToEdgeWrapping,
43932
+ params?.wrapT || ClampToEdgeWrapping,
43933
+ params?.magFilter,
43934
+ params?.minFilter,
43935
+ void 0,
43936
+ void 0,
43937
+ void 0,
43938
+ params?.colorSpace || SRGBColorSpace
43939
+ );
43940
+ if (params?.generateMipmaps !== void 0) texture.generateMipmaps = params?.generateMipmaps;
43941
+ texture.needsUpdate = true;
43942
+ return texture;
43943
+ }
43944
+ function createManagedTexture(url, params) {
43945
+ const textureInfo = {
43946
+ texture: void 0,
43947
+ uses: 1
43948
+ //used by texture promise (internal), so we dont try to dispose when it doesnt even exist yet
43949
+ };
43950
+ textureInfo.texture = new Promise((resolve) => {
43951
+ createTexturePromise(url, params).then((result) => {
43952
+ textureInfo.texture = result;
43953
+ finishManagedTexture(url, params);
43954
+ resolve(result);
43955
+ });
43956
+ });
43957
+ return textureInfo;
43958
+ }
43959
+ function getTextureInfoKey(url, params) {
43960
+ url = url.replace(".dds", ".png");
43961
+ if (params?.colorSpace === "srgb") delete params.colorSpace;
43962
+ if (params?.wrapS === ClampToEdgeWrapping) delete params.wrapS;
43963
+ if (params?.wrapT === ClampToEdgeWrapping) delete params.wrapT;
43964
+ if (params?.magFilter === LinearFilter) delete params.magFilter;
43965
+ if (params?.minFilter === LinearMipmapLinearFilter) delete params.minFilter;
43966
+ if (params && Object.keys(params).length > 0) {
43967
+ return url + JSON.stringify(params);
43968
+ } else {
43969
+ return url;
43970
+ }
43971
+ }
43972
+ async function getManagedTexture(url, params) {
43973
+ const key = getTextureInfoKey(url, params);
43974
+ let managedTextureInfo = managedTextures.get(key);
43975
+ if (!managedTextureInfo) {
43976
+ managedTextureInfo = createManagedTexture(url, params);
43977
+ managedTextures.set(key, managedTextureInfo);
43978
+ }
43979
+ managedTextureInfo.uses += 1;
43980
+ const disposeTimeout = managedTextureInfo.disposeTimeout;
43981
+ if (disposeTimeout) {
43982
+ clearTimeout(disposeTimeout);
43983
+ managedTextureInfo.disposeTimeout = void 0;
43984
+ }
43985
+ return managedTextureInfo.texture;
43986
+ }
43987
+ async function finishManagedTexture(url, params) {
43988
+ const key = getTextureInfoKey(url, params);
43989
+ const managedTextureInfo = managedTextures.get(key);
43990
+ if (managedTextureInfo) {
43991
+ managedTextureInfo.uses -= 1;
43992
+ if (managedTextureInfo.uses <= 0) {
43993
+ if (!managedTextureInfo.disposeTimeout) {
43994
+ const disposeTimeout = setTimeout(() => {
43995
+ if (managedTextureInfo.disposeTimeout !== disposeTimeout || managedTextureInfo.uses > 0) return;
43996
+ const texture = managedTextureInfo.texture;
43997
+ if (texture && texture instanceof Texture || texture === void 0) {
43998
+ managedTextures.delete(key);
43999
+ if (texture) texture.dispose();
44000
+ }
44001
+ }, 5e3);
44002
+ managedTextureInfo.disposeTimeout = disposeTimeout;
44003
+ }
44004
+ }
44005
+ }
44006
+ }
43857
44007
  const RenderDescClassTypes = /* @__PURE__ */ new Map();
43858
44008
  function getRenderDescForClass(className) {
43859
44009
  return RenderDescClassTypes.get(className);
@@ -43870,22 +44020,9 @@ function setTHREEObjectCF(threeObject, cframe) {
43870
44020
  threeObject.rotation.y = rad(cframe.Orientation[1]);
43871
44021
  threeObject.rotation.z = rad(cframe.Orientation[2]);
43872
44022
  }
43873
- async function getTexture(texture, colorSpace = SRGBColorSpace) {
43874
- if (texture) {
43875
- const source = texture.replace(".dds", ".png");
43876
- const image = await API.Generic.LoadImage(source);
43877
- if (image) {
43878
- const texture2 = new Texture(image);
43879
- texture2.wrapS = ClampToEdgeWrapping;
43880
- texture2.wrapT = ClampToEdgeWrapping;
43881
- texture2.colorSpace = colorSpace;
43882
- texture2.needsUpdate = true;
43883
- return texture2;
43884
- }
43885
- }
43886
- return void 0;
43887
- }
43888
44023
  class DisposableDesc {
44024
+ toDispose = [];
44025
+ managedTextures = [];
43889
44026
  disposeMesh(scene, mesh) {
43890
44027
  disposeMesh(scene, mesh);
43891
44028
  }
@@ -43901,6 +44038,22 @@ class DisposableDesc {
43901
44038
  dispose(_renderer, _scene) {
43902
44039
  throw new Error("Virtual method dispose called");
43903
44040
  }
44041
+ clearToDispose() {
44042
+ for (const disposeable of this.toDispose) {
44043
+ disposeable.dispose();
44044
+ }
44045
+ this.toDispose = [];
44046
+ for (const managedTexture of this.managedTextures) {
44047
+ finishManagedTexture(managedTexture.url, managedTexture.params);
44048
+ }
44049
+ this.managedTextures = [];
44050
+ }
44051
+ removeFromToDispose(disposable) {
44052
+ const index = this.toDispose.indexOf(disposable);
44053
+ if (index > -1) {
44054
+ this.toDispose.splice(index, 1);
44055
+ }
44056
+ }
43904
44057
  }
43905
44058
  class RenderDesc extends DisposableDesc {
43906
44059
  static classTypes = [];
@@ -46158,7 +46311,7 @@ async function promiseForMesh(url, readOnly = false) {
46158
46311
  });
46159
46312
  });
46160
46313
  }
46161
- class MeshDesc {
46314
+ class MeshDesc extends DisposableDesc {
46162
46315
  //size: Vector3 = new Vector3(1,1,1)
46163
46316
  scaleIsRelative = false;
46164
46317
  mesh;
@@ -46186,9 +46339,6 @@ class MeshDesc {
46186
46339
  fileMesh;
46187
46340
  wasAutoSkinned = false;
46188
46341
  wasDeformed = false;
46189
- dispose() {
46190
- this.instance = void 0;
46191
- }
46192
46342
  isSame(other) {
46193
46343
  const singularTrue = (
46194
46344
  //this.size.isSame(other.size) &&
@@ -46535,6 +46685,7 @@ class MeshDesc {
46535
46685
  if (wrapTextureTransferResult instanceof Response) return wrapTextureTransferResult;
46536
46686
  this.fileMesh = mesh;
46537
46687
  const geometry = fileMeshToTHREEGeometry(the_ref_mesh || mesh, this.canHaveSkinning, this.forceVertexColor);
46688
+ this.toDispose.push(geometry);
46538
46689
  let threeMesh = void 0;
46539
46690
  if (geometry.attributes.skinWeight) {
46540
46691
  threeMesh = new SkinnedMesh(geometry);
@@ -46699,6 +46850,11 @@ class MeshDesc {
46699
46850
  this.wrapTextureTargetOrigin = wrapTarget.Prop("CageOrigin").removeNaN();
46700
46851
  }
46701
46852
  }
46853
+ dispose(renderer) {
46854
+ this.instance = void 0;
46855
+ this.clearToDispose();
46856
+ this.disposeRenderLists(renderer);
46857
+ }
46702
46858
  }
46703
46859
  const compositMeshPaths = [
46704
46860
  "rbxasset://avatar/compositing/CompositFullAtlasBaseTexture.mesh",
@@ -47050,67 +47206,6 @@ const Shader_TextureComposer_Gamma = new ShaderMaterial({
47050
47206
  depthWrite: false,
47051
47207
  transparent: true
47052
47208
  });
47053
- const managedTextures = /* @__PURE__ */ new Map();
47054
- async function createTexturePromise(url, params) {
47055
- const image = await API.Generic.LoadImage(url);
47056
- if (!image) return void 0;
47057
- const texture = new Texture(image, void 0, void 0, void 0, void 0, void 0, void 0, void 0, void 0, params?.colorSpace || "srgb");
47058
- texture.needsUpdate = true;
47059
- return texture;
47060
- }
47061
- function createManagedTexture(url, params) {
47062
- const textureInfo = {
47063
- texture: void 0,
47064
- uses: 1
47065
- //used by texture promise (internal), so we dont try to dispose when it doesnt even exist yet
47066
- };
47067
- textureInfo.texture = new Promise((resolve) => {
47068
- createTexturePromise(url, params).then((result) => {
47069
- textureInfo.texture = result;
47070
- finishManagedTexture(url, params);
47071
- resolve(result);
47072
- });
47073
- });
47074
- return textureInfo;
47075
- }
47076
- function getTextureInfoKey(url, params) {
47077
- return url + JSON.stringify(params);
47078
- }
47079
- async function getManagedTexture(url, params) {
47080
- const key = getTextureInfoKey(url, params);
47081
- let managedTextureInfo = managedTextures.get(key);
47082
- if (!managedTextureInfo) {
47083
- managedTextureInfo = createManagedTexture(url, params);
47084
- managedTextures.set(key, managedTextureInfo);
47085
- }
47086
- managedTextureInfo.uses += 1;
47087
- const disposeTimeout = managedTextureInfo.disposeTimeout;
47088
- if (disposeTimeout) {
47089
- clearTimeout(disposeTimeout);
47090
- managedTextureInfo.disposeTimeout = void 0;
47091
- }
47092
- return managedTextureInfo.texture;
47093
- }
47094
- async function finishManagedTexture(url, params) {
47095
- const key = getTextureInfoKey(url, params);
47096
- const managedTextureInfo = managedTextures.get(key);
47097
- if (managedTextureInfo) {
47098
- managedTextureInfo.uses -= 1;
47099
- if (managedTextureInfo.uses <= 0) {
47100
- if (!managedTextureInfo.disposeTimeout) {
47101
- const disposeTimeout = setTimeout(() => {
47102
- if (managedTextureInfo.disposeTimeout !== disposeTimeout || managedTextureInfo.uses > 0) return;
47103
- managedTextures.delete(key);
47104
- const texture = managedTextureInfo.texture;
47105
- if (texture && texture instanceof Texture) {
47106
- texture.dispose();
47107
- }
47108
- }, 5e3);
47109
- managedTextureInfo.disposeTimeout = disposeTimeout;
47110
- }
47111
- }
47112
- }
47113
- }
47114
47209
  async function renderBodyPartClothingR15(limbId, texture) {
47115
47210
  let instruction;
47116
47211
  if (limbId !== BodyPart.Torso) {
@@ -47249,7 +47344,7 @@ class TextureLayer {
47249
47344
  return this.uvType === other.uvType && this.face === other.face && this.color === other.color && this.normal === other.normal && this.roughness === other.roughness && this.metalness === other.metalness && this.emissive === other.emissive;
47250
47345
  }
47251
47346
  }
47252
- class MaterialDesc {
47347
+ class MaterialDesc extends DisposableDesc {
47253
47348
  layers = [];
47254
47349
  isDecal = false;
47255
47350
  canHaveMipmaps = true;
@@ -47268,6 +47363,7 @@ class MaterialDesc {
47268
47363
  createdTextures = [];
47269
47364
  noTextureTransparency = false;
47270
47365
  result;
47366
+ resultRenderTarget;
47271
47367
  isSame(other) {
47272
47368
  if (this.dirty || other.dirty) return false;
47273
47369
  const propertiesSame = this.isDecal === other.isDecal && this.transparent === other.transparent && Math.round(this.transparency * 100) === Math.round(other.transparency * 100) && this.doubleSided === other.doubleSided && this.visible === other.visible && this.canHaveMipmaps === other.canHaveMipmaps && this.resampleMode === other.resampleMode;
@@ -47578,6 +47674,7 @@ class MaterialDesc {
47578
47674
  }
47579
47675
  }
47580
47676
  if (composeInsts.length === 0) {
47677
+ this.finishManagedTextures(textureType);
47581
47678
  return void 0;
47582
47679
  }
47583
47680
  TextureComposer.new(width, height, textureType === "color" ? LinearSRGBColorSpace : NoColorSpace, RepeatWrapping, noMipmaps);
@@ -47586,12 +47683,15 @@ class MaterialDesc {
47586
47683
  TextureComposer.add(inst);
47587
47684
  }
47588
47685
  const renderTarget = TextureComposer.render();
47686
+ this.toDispose.push(renderTarget);
47589
47687
  this.finishManagedTextures(textureType);
47688
+ const linearRenderTarget = renderTarget;
47590
47689
  const lineartexture = renderTarget.texture;
47591
47690
  lineartexture.wrapS = RepeatWrapping;
47592
47691
  lineartexture.wrapT = RepeatWrapping;
47593
47692
  lineartexture.needsUpdate = true;
47594
47693
  let texture = lineartexture;
47694
+ let renderTargetFinal = linearRenderTarget;
47595
47695
  if (textureType === "color") {
47596
47696
  const gammaInst = await TextureComposer.simpleMesh(
47597
47697
  "CompositQuad",
@@ -47605,11 +47705,15 @@ class MaterialDesc {
47605
47705
  TextureComposer.new(width, height, SRGBColorSpace, RepeatWrapping, noMipmaps);
47606
47706
  TextureComposer.cameraSize(camWidth, camHeight);
47607
47707
  TextureComposer.add(gammaInst);
47608
- texture = TextureComposer.render().texture;
47708
+ renderTargetFinal = TextureComposer.render();
47709
+ this.toDispose.push(renderTargetFinal);
47710
+ texture = renderTargetFinal.texture;
47609
47711
  }
47610
- if (texture !== lineartexture) {
47611
- lineartexture.dispose();
47712
+ if (linearRenderTarget !== renderTargetFinal) {
47713
+ linearRenderTarget.dispose();
47714
+ this.removeFromToDispose(linearRenderTarget);
47612
47715
  }
47716
+ this.resultRenderTarget = renderTargetFinal;
47613
47717
  texture.magFilter = this.resampleMode === ResamplerMode.Default ? LinearFilter : NearestFilter;
47614
47718
  let hasTransparency = false;
47615
47719
  const rbxRenderer = RBXRenderer.getRenderer();
@@ -47625,6 +47729,7 @@ class MaterialDesc {
47625
47729
  if (FLAGS.RENDERTARGET_TO_CANVASTEXTURE) {
47626
47730
  const ogTexture = texture;
47627
47731
  texture = imageDataToCanvasTexture(data, width, height);
47732
+ this.toDispose.push(texture);
47628
47733
  texture.colorSpace = textureType === "color" ? SRGBColorSpace : NoColorSpace;
47629
47734
  texture.wrapS = ogTexture.wrapS;
47630
47735
  texture.wrapT = ogTexture.wrapT;
@@ -47632,6 +47737,7 @@ class MaterialDesc {
47632
47737
  texture.magFilter = ogTexture.magFilter;
47633
47738
  texture.generateMipmaps = ogTexture.generateMipmaps;
47634
47739
  ogTexture.dispose();
47740
+ this.removeFromToDispose(ogTexture);
47635
47741
  }
47636
47742
  }
47637
47743
  if (!this.transparent) {
@@ -47660,6 +47766,7 @@ class MaterialDesc {
47660
47766
  throw new Error("Failed to get CanvasContext");
47661
47767
  }
47662
47768
  const texture = new CanvasTexture(canvas);
47769
+ this.toDispose.push(texture);
47663
47770
  texture.colorSpace = textureType === "color" ? SRGBColorSpace : NoColorSpace;
47664
47771
  texture.wrapS = RepeatWrapping;
47665
47772
  texture.wrapT = RepeatWrapping;
@@ -47711,21 +47818,21 @@ class MaterialDesc {
47711
47818
  }
47712
47819
  }
47713
47820
  if (textureUrl) {
47714
- const image = await API.Generic.LoadImage(textureUrl);
47715
- if (image) {
47716
- let hasTransparency = true;
47717
- if (!this.transparent) {
47718
- hasTransparency = false;
47719
- }
47720
- const texture = new Texture(image);
47721
- texture.wrapS = RepeatWrapping;
47722
- texture.wrapT = RepeatWrapping;
47723
- texture.colorSpace = textureType === "color" ? SRGBColorSpace : NoColorSpace;
47724
- texture.generateMipmaps = this.canHaveMipmaps;
47725
- texture.magFilter = this.resampleMode === ResamplerMode.Default ? LinearFilter : NearestFilter;
47726
- texture.needsUpdate = true;
47727
- return [texture, hasTransparency];
47728
- }
47821
+ let hasTransparency = true;
47822
+ if (!this.transparent) {
47823
+ hasTransparency = false;
47824
+ }
47825
+ const textureParams = {
47826
+ colorSpace: textureType === "color" ? SRGBColorSpace : NoColorSpace,
47827
+ wrapS: RepeatWrapping,
47828
+ wrapT: RepeatWrapping,
47829
+ generateMipmaps: this.canHaveMipmaps,
47830
+ //resampling mode
47831
+ magFilter: this.resampleMode === ResamplerMode.Default ? LinearFilter : NearestFilter
47832
+ };
47833
+ const texture = await getManagedTexture(textureUrl, textureParams);
47834
+ this.managedTextures.push({ url: textureUrl, params: textureParams });
47835
+ return texture ? [texture, hasTransparency] : void 0;
47729
47836
  }
47730
47837
  }
47731
47838
  getComposeType(textureType) {
@@ -47742,8 +47849,8 @@ class MaterialDesc {
47742
47849
  }
47743
47850
  }
47744
47851
  if (layer instanceof ColorLayer) {
47745
- hasColorLayer = true;
47746
47852
  if (layer.textureType === textureType) {
47853
+ hasColorLayer = true;
47747
47854
  hasLayerOfType = true;
47748
47855
  }
47749
47856
  }
@@ -48178,6 +48285,10 @@ class MaterialDesc {
48178
48285
  this.addDecals(child.parent, "Normal", true);
48179
48286
  }
48180
48287
  }
48288
+ dispose() {
48289
+ this.resultRenderTarget = void 0;
48290
+ this.clearToDispose();
48291
+ }
48181
48292
  }
48182
48293
  class BasePartWrapperData {
48183
48294
  assemblyNode;
@@ -48289,7 +48400,7 @@ function boneIsChildOf(bone, parentName) {
48289
48400
  }
48290
48401
  return false;
48291
48402
  }
48292
- class SkeletonDesc {
48403
+ class SkeletonDesc extends DisposableDesc {
48293
48404
  renderableDesc;
48294
48405
  meshDesc;
48295
48406
  skeleton;
@@ -48300,6 +48411,7 @@ class SkeletonDesc {
48300
48411
  skeletonHelper;
48301
48412
  frameCount = 0;
48302
48413
  constructor(renderableDesc, meshDesc, scene) {
48414
+ super();
48303
48415
  this.renderableDesc = renderableDesc;
48304
48416
  this.meshDesc = meshDesc;
48305
48417
  const mesh = this.meshDesc.fileMesh;
@@ -48576,14 +48688,14 @@ class SkeletonDesc {
48576
48688
  this.updateMatrixWorld();
48577
48689
  this.frameCount += 1;
48578
48690
  }
48579
- dispose(scene) {
48691
+ dispose() {
48580
48692
  if (this.skeletonHelper) {
48581
- scene.remove(this.skeletonHelper);
48693
+ this.skeletonHelper.removeFromParent();
48582
48694
  this.skeletonHelper.dispose();
48583
48695
  this.skeletonHelper = void 0;
48584
48696
  }
48585
48697
  if (this.rootBone.parent) {
48586
- this.rootBone.parent.remove(this.rootBone);
48698
+ this.rootBone.removeFromParent();
48587
48699
  }
48588
48700
  for (let i = 0; i < this.skeleton.bones.length; i++) {
48589
48701
  const bone = this.skeleton.bones[i];
@@ -48591,6 +48703,7 @@ class SkeletonDesc {
48591
48703
  bone.removeFromParent();
48592
48704
  }
48593
48705
  }
48706
+ this.skeleton.dispose();
48594
48707
  }
48595
48708
  static descNeedsSkeleton(meshDesc) {
48596
48709
  return meshDesc.canHaveSkinning && meshDesc.fileMesh && meshDesc.fileMesh.skinning && meshDesc.fileMesh.skinning.numskinnings > 0;
@@ -48694,32 +48807,10 @@ class ObjectDesc extends RenderDesc {
48694
48807
  this.meshDesc.fromInstance(child);
48695
48808
  this.materialDesc.fromInstance(child);
48696
48809
  }
48697
- disposeSkeleton(scene, skeletonDesc) {
48698
- skeletonDesc.dispose(scene);
48699
- }
48700
- //Used to dispose OLD stuff
48701
- dispose(renderer, scene) {
48702
- if (this.meshDesc) {
48703
- this.meshDesc.dispose();
48704
- }
48705
- if (this.results) {
48706
- for (const mesh of this.results) {
48707
- this.disposeMesh(scene, mesh);
48708
- }
48709
- }
48710
- if (this.skeletonDesc) {
48711
- this.disposeSkeleton(scene, this.skeletonDesc);
48712
- }
48713
- if (this.results) {
48714
- this.disposeRenderLists(renderer);
48715
- }
48716
- }
48717
- async compileResults(renderer, scene) {
48810
+ async compileResults(_renderer, scene) {
48718
48811
  const loadingLabel = this.instance ? this.instance.GetFullName() : "unknown";
48719
48812
  API.Misc.startCurrentlyLoadingAssets(loadingLabel);
48720
48813
  try {
48721
- const originalResult = this.results;
48722
- const originalSkeletonDesc = this.skeletonDesc;
48723
48814
  this.results = void 0;
48724
48815
  this.skeletonDesc = void 0;
48725
48816
  const promises = [
@@ -48756,15 +48847,6 @@ class ObjectDesc extends RenderDesc {
48756
48847
  } else {
48757
48848
  this.meshDesc.fileMesh = void 0;
48758
48849
  }
48759
- if (originalResult) {
48760
- this.disposeMeshes(scene, originalResult);
48761
- }
48762
- if (originalSkeletonDesc) {
48763
- this.disposeSkeleton(scene, originalSkeletonDesc);
48764
- }
48765
- if (originalResult) {
48766
- this.disposeRenderLists(renderer);
48767
- }
48768
48850
  } finally {
48769
48851
  API.Misc.stopCurrentlyLoadingAssets(loadingLabel);
48770
48852
  }
@@ -48840,6 +48922,17 @@ class ObjectDesc extends RenderDesc {
48840
48922
  }
48841
48923
  return !isBakedDecal && (!isDecal || isFirstDecal);
48842
48924
  }
48925
+ //Used to dispose OLD stuff
48926
+ dispose(renderer) {
48927
+ if (this.results) {
48928
+ for (const result of this.results) {
48929
+ result.removeFromParent();
48930
+ }
48931
+ }
48932
+ if (this.meshDesc) this.meshDesc.dispose(renderer);
48933
+ if (this.materialDesc) this.materialDesc.dispose();
48934
+ if (this.skeletonDesc) this.skeletonDesc.dispose();
48935
+ }
48843
48936
  }
48844
48937
  const __vite_glob_0_4$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
48845
48938
  __proto__: null,
@@ -59819,7 +59912,7 @@ const $05f6997e4b65da14$export$ed4ee5d1e55474a5 = {
59819
59912
  class RBXRendererScene {
59820
59913
  //important scene components
59821
59914
  scene = new Scene();
59822
- camera = new PerspectiveCamera(70, 1 / 1, 0.1, 100);
59915
+ camera = new PerspectiveCamera(70, 1 / 1, 0.1, 1e3);
59823
59916
  controls;
59824
59917
  shouldAnimate = true;
59825
59918
  destroyed = false;
@@ -59967,6 +60060,41 @@ class RBXRendererScene {
59967
60060
  isFullyCompiled() {
59968
60061
  return this.areInstancesCompiled(this.addedInstances);
59969
60062
  }
60063
+ /**
60064
+ * @param instances Array of instances you want to wait to be finished compiling
60065
+ * @param timeoutSeconds Default is 30 seconds
60066
+ * @returns true if successful, false if a RenderDesc failed to compile or timed out
60067
+ */
60068
+ async waitUntilFullyCompiled(instances, timeoutSeconds = 30) {
60069
+ if (this.areInstancesCompiled(instances)) return true;
60070
+ const connections = [];
60071
+ const compiledSuccessfully = await Promise.race([
60072
+ //on fail compilation
60073
+ new Promise((resolve) => {
60074
+ connections.push(this.failedRenderDesc.Connect(() => {
60075
+ resolve(false);
60076
+ }));
60077
+ }),
60078
+ //on success compilation, check if everything is successfull
60079
+ new Promise((resolve) => {
60080
+ connections.push(this.compiledRenderDesc.Connect(() => {
60081
+ if (this.areInstancesCompiled(instances)) {
60082
+ resolve(true);
60083
+ }
60084
+ }));
60085
+ }),
60086
+ //on fail due to timeout
60087
+ new Promise((resolve) => {
60088
+ setTimeout(() => {
60089
+ resolve(false);
60090
+ }, timeoutSeconds * 1e3);
60091
+ })
60092
+ ]);
60093
+ for (const connection of connections) {
60094
+ connection.Disconnect();
60095
+ }
60096
+ return compiledSuccessfully;
60097
+ }
59970
60098
  /**
59971
60099
  * Exports scene as a GLTF or GLB
59972
60100
  * @param name Name of the resulting file if autoDownload is true
@@ -60842,13 +60970,6 @@ class EmitterDesc extends DisposableDesc {
60842
60970
  this.flipbookSizeY = other.flipbookSizeY;
60843
60971
  this.flipbookStartRandom = other.flipbookStartRandom;
60844
60972
  }
60845
- dispose(renderer, scene) {
60846
- const mesh = this.result;
60847
- if (mesh) {
60848
- this.disposeMesh(scene, mesh);
60849
- this.disposeRenderLists(renderer);
60850
- }
60851
- }
60852
60973
  getFlipbookSize() {
60853
60974
  let flipbookSizeX = this.flipbookSizeX;
60854
60975
  let flipbookSizeY = this.flipbookSizeY;
@@ -60874,27 +60995,33 @@ class EmitterDesc extends DisposableDesc {
60874
60995
  }
60875
60996
  return [flipbookSizeX, flipbookSizeY];
60876
60997
  }
60877
- async compileResult(renderer, scene) {
60878
- const originalResult = this.result;
60998
+ async compileResult() {
60879
60999
  const texturePromises = [
60880
- getTexture(this.texture),
60881
- getTexture(this.alphaTexture, NoColorSpace),
60882
- getTexture(this.colorTexture)
61000
+ this.texture ? getManagedTexture(this.texture, { colorSpace: SRGBColorSpace }) : void 0,
61001
+ this.alphaTexture ? getManagedTexture(this.alphaTexture, { colorSpace: NoColorSpace }) : void 0,
61002
+ this.colorTexture ? getManagedTexture(this.colorTexture, { colorSpace: SRGBColorSpace }) : void 0
60883
61003
  ];
61004
+ if (this.texture) this.managedTextures.push({ url: this.texture, params: { colorSpace: SRGBColorSpace } });
61005
+ if (this.alphaTexture) this.managedTextures.push({ url: this.alphaTexture, params: { colorSpace: NoColorSpace } });
61006
+ if (this.colorTexture) this.managedTextures.push({ url: this.colorTexture, params: { colorSpace: SRGBColorSpace } });
60884
61007
  let [mapToUse, alphaMapToUse, colorMapToUse] = await Promise.all(texturePromises);
60885
61008
  if (!mapToUse) {
60886
61009
  mapToUse = new DataTexture(new Uint8Array([0, 0, 0, 0]), 1, 1, RGBAFormat);
60887
61010
  mapToUse.needsUpdate = true;
61011
+ this.toDispose.push(mapToUse);
60888
61012
  }
60889
61013
  if (!alphaMapToUse) {
60890
61014
  alphaMapToUse = new DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, RGBAFormat);
60891
61015
  alphaMapToUse.needsUpdate = true;
61016
+ this.toDispose.push(alphaMapToUse);
60892
61017
  }
60893
61018
  if (!colorMapToUse) {
60894
61019
  colorMapToUse = new DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, RGBAFormat);
60895
61020
  colorMapToUse.needsUpdate = true;
61021
+ this.toDispose.push(colorMapToUse);
60896
61022
  }
60897
61023
  const geometry = new PlaneGeometry(2, 2);
61024
+ this.toDispose.push(geometry);
60898
61025
  this.instanceColorBuffer = new InstancedBufferAttribute(new Float32Array(this.maxCount * 3), 3);
60899
61026
  geometry.setAttribute("instanceColor", this.instanceColorBuffer);
60900
61027
  this.instanceOpacityBuffer = new InstancedBufferAttribute(new Float32Array(this.maxCount), 1);
@@ -60960,14 +61087,12 @@ class EmitterDesc extends DisposableDesc {
60960
61087
  }
60961
61088
  ])
60962
61089
  });
61090
+ this.toDispose.push(material);
60963
61091
  this.resultMaterial = material;
60964
61092
  this.result = new InstancedMesh(geometry, material, this.maxCount);
61093
+ this.toDispose.push(this.result);
60965
61094
  this.result.name = "Particles";
60966
61095
  this.result.frustumCulled = false;
60967
- if (originalResult) {
60968
- this.disposeMesh(scene, originalResult);
60969
- this.disposeRenderLists(renderer);
60970
- }
60971
61096
  return this.result;
60972
61097
  }
60973
61098
  emit(groupDesc, force = false) {
@@ -61089,6 +61214,14 @@ class EmitterDesc extends DisposableDesc {
61089
61214
  this.instanceSeedTimeBuffer.needsUpdate = true;
61090
61215
  this.instanceFlipbookBuffer.needsUpdate = true;
61091
61216
  }
61217
+ dispose(renderer) {
61218
+ const mesh = this.result;
61219
+ if (mesh) {
61220
+ mesh.removeFromParent();
61221
+ }
61222
+ this.clearToDispose();
61223
+ this.disposeRenderLists(renderer);
61224
+ }
61092
61225
  }
61093
61226
  class EmitterGroupDesc extends RenderDesc {
61094
61227
  static classTypes = ["ParticleEmitter", "Sparkles", "Fire", "Smoke"];
@@ -61228,7 +61361,7 @@ class EmitterGroupDesc extends RenderDesc {
61228
61361
  }
61229
61362
  }
61230
61363
  fromParticleEmitter(child) {
61231
- this.emitterDir = child.Prop("EmissionDirection");
61364
+ this.emitterDir = child.PropOrDefault("EmissionDirection", this.emitterDir);
61232
61365
  const emitterDesc = new EmitterDesc(this.renderScene);
61233
61366
  if (child.HasProperty("Lifetime")) emitterDesc.lifetime = child.Prop("Lifetime");
61234
61367
  if (child.HasProperty("Rate")) emitterDesc.rate = child.Prop("Rate");
@@ -61245,7 +61378,7 @@ class EmitterGroupDesc extends RenderDesc {
61245
61378
  if (child.HasProperty("Color")) emitterDesc.color = child.Prop("Color");
61246
61379
  if (child.HasProperty("Texture")) emitterDesc.texture = child.Prop("Texture");
61247
61380
  if (child.HasProperty("Transparency")) emitterDesc.transparency = child.Prop("Transparency");
61248
- if (child.HasProperty("LightEmission")) emitterDesc.lightEmission = child.Prop("LightEmission");
61381
+ emitterDesc.lightEmission = specialClamp(child.PropOrDefault("LightEmission", emitterDesc.lightEmission), 0, 1);
61249
61382
  emitterDesc.blending = emitterDesc.lightEmission === 0 ? EmitterBlendType.Normal : EmitterBlendType.PremultipliedAdditive;
61250
61383
  if (child.HasProperty("LightInfluence")) emitterDesc.lightInfluence = child.Prop("LightInfluence");
61251
61384
  if (child.HasProperty("ZOffset")) emitterDesc.zOffset = child.Prop("ZOffset");
@@ -61381,18 +61514,10 @@ class EmitterGroupDesc extends RenderDesc {
61381
61514
  shader: EmitterShaderType.Smoke
61382
61515
  }));
61383
61516
  }
61384
- dispose(renderer, scene) {
61385
- const meshes = this.results;
61386
- if (meshes) {
61387
- this.disposeMeshes(scene, meshes);
61388
- this.disposeRenderLists(renderer);
61389
- }
61390
- }
61391
61517
  async compileResults(renderer, scene) {
61392
- const originalResults = this.results;
61393
61518
  const resultPromises = [];
61394
61519
  for (const emitterDesc of this.emitterDescs) {
61395
- resultPromises.push(emitterDesc.compileResult(renderer, scene));
61520
+ resultPromises.push(emitterDesc.compileResult());
61396
61521
  }
61397
61522
  this.results = [];
61398
61523
  const compiledResults = await Promise.all(resultPromises);
@@ -61405,10 +61530,6 @@ class EmitterGroupDesc extends RenderDesc {
61405
61530
  return compiledResult;
61406
61531
  }
61407
61532
  }
61408
- if (originalResults) {
61409
- this.disposeMeshes(scene, originalResults);
61410
- this.disposeRenderLists(renderer);
61411
- }
61412
61533
  const startFull = this.renderScene.particlesStartFull || FLAGS.PARTICLES_START_FULL;
61413
61534
  const startFullFramerate = this.renderScene.particlesStartFullFramerate;
61414
61535
  if (startFull) {
@@ -61438,6 +61559,11 @@ class EmitterGroupDesc extends RenderDesc {
61438
61559
  }
61439
61560
  }
61440
61561
  }
61562
+ dispose(renderer) {
61563
+ for (const emitterDesc of this.emitterDescs) {
61564
+ emitterDesc.dispose(renderer);
61565
+ }
61566
+ }
61441
61567
  }
61442
61568
  const __vite_glob_0_2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
61443
61569
  __proto__: null,
@@ -62172,21 +62298,20 @@ class BeamDesc extends RenderDesc {
62172
62298
  this.segments = child.PropOrDefault("Segments", this.segments);
62173
62299
  if (!FLAGS.BEAMS_ENABLED) this.enabled = false;
62174
62300
  }
62175
- async compileResults(renderer, scene) {
62176
- const originalResults = this.results;
62301
+ async compileResults() {
62177
62302
  this.results = [];
62178
62303
  if (this.enabled) {
62179
62304
  let textureResult = void 0;
62180
62305
  if (this.texture) {
62181
- textureResult = await getTexture(this.texture);
62182
- if (textureResult) {
62183
- textureResult.wrapT = RepeatWrapping;
62184
- }
62306
+ const params = { colorSpace: "srgb", wrapT: RepeatWrapping };
62307
+ textureResult = await getManagedTexture(this.texture, params);
62308
+ this.managedTextures.push({ url: this.texture, params });
62185
62309
  }
62186
62310
  if (!textureResult) {
62187
62311
  textureResult = new DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, RGBAFormat);
62188
62312
  textureResult.colorSpace = SRGBColorSpace;
62189
62313
  textureResult.needsUpdate = true;
62314
+ this.toDispose.push(textureResult);
62190
62315
  }
62191
62316
  const material = new ShaderMaterial({
62192
62317
  side: DoubleSide,
@@ -62215,17 +62340,15 @@ class BeamDesc extends RenderDesc {
62215
62340
  }
62216
62341
  ])
62217
62342
  });
62343
+ this.toDispose.push(material);
62218
62344
  const geometry = new PlaneGeometry(1, 1, this.segments, 1);
62345
+ this.toDispose.push(geometry);
62219
62346
  const colorValues = new Float32Array((this.segments + 1) * 2 * 4).fill(0);
62220
62347
  geometry.setAttribute("color", new BufferAttribute(colorValues, 4));
62221
62348
  const mesh = new Mesh(geometry, material);
62222
62349
  mesh.name = this.instance ? this.instance.PropOrDefault("Name", "Unknown") + "_Beam" : "Unknown_Beam";
62223
62350
  this.results.push(mesh);
62224
62351
  }
62225
- if (originalResults) {
62226
- this.disposeMeshes(scene, originalResults);
62227
- this.disposeRenderLists(renderer);
62228
- }
62229
62352
  this.updateResults();
62230
62353
  return this.results;
62231
62354
  }
@@ -62349,11 +62472,13 @@ class BeamDesc extends RenderDesc {
62349
62472
  }
62350
62473
  this.lastTime = this.time;
62351
62474
  }
62352
- dispose(_renderer, scene) {
62475
+ dispose(renderer) {
62353
62476
  if (!this.results) return;
62354
62477
  for (const result of this.results) {
62355
- scene.remove(result);
62478
+ result.removeFromParent();
62356
62479
  }
62480
+ this.clearToDispose();
62481
+ this.disposeRenderLists(renderer);
62357
62482
  }
62358
62483
  }
62359
62484
  const __vite_glob_0_1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -62601,21 +62726,20 @@ class TrailDesc extends RenderDesc {
62601
62726
  this.faceCamera = child.PropOrDefault("FaceCamera", this.faceCamera);
62602
62727
  if (!FLAGS.BEAMS_ENABLED) this.enabled = false;
62603
62728
  }
62604
- async compileResults(renderer, scene) {
62605
- const originalResults = this.results;
62729
+ async compileResults() {
62606
62730
  this.results = [];
62607
62731
  if (this.enabled) {
62608
62732
  let textureResult = void 0;
62609
62733
  if (this.texture) {
62610
- textureResult = await getTexture(this.texture);
62611
- if (textureResult) {
62612
- textureResult.wrapT = RepeatWrapping;
62613
- }
62734
+ const params = { colorSpace: "srgb", wrapT: RepeatWrapping };
62735
+ textureResult = await getManagedTexture(this.texture, params);
62736
+ this.managedTextures.push({ url: this.texture, params });
62614
62737
  }
62615
62738
  if (!textureResult) {
62616
62739
  textureResult = new DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, RGBAFormat);
62617
62740
  textureResult.colorSpace = SRGBColorSpace;
62618
62741
  textureResult.needsUpdate = true;
62742
+ this.toDispose.push(textureResult);
62619
62743
  }
62620
62744
  const material = new ShaderMaterial({
62621
62745
  side: DoubleSide,
@@ -62644,7 +62768,9 @@ class TrailDesc extends RenderDesc {
62644
62768
  }
62645
62769
  ])
62646
62770
  });
62771
+ this.toDispose.push(material);
62647
62772
  const geometry = new PlaneGeometry(1, 1, this.maxSegments, 1);
62773
+ this.toDispose.push(geometry);
62648
62774
  const colorValues = new Float32Array((this.maxSegments + 1) * 2 * 4).fill(1);
62649
62775
  geometry.setAttribute("color", new BufferAttribute(colorValues, 4));
62650
62776
  const mesh = new Mesh(geometry, material);
@@ -62652,10 +62778,6 @@ class TrailDesc extends RenderDesc {
62652
62778
  mesh.name = this.instance ? this.instance.PropOrDefault("Name", "Unknown") + "_Trail" : "Unknown_Trail";
62653
62779
  this.results.push(mesh);
62654
62780
  }
62655
- if (originalResults) {
62656
- this.disposeMeshes(scene, originalResults);
62657
- this.disposeRenderLists(renderer);
62658
- }
62659
62781
  this.updateResults();
62660
62782
  return this.results;
62661
62783
  }
@@ -62792,11 +62914,13 @@ class TrailDesc extends RenderDesc {
62792
62914
  segment.cframe.Position = add(segment.cframe.Position, vec);
62793
62915
  }
62794
62916
  }
62795
- dispose(_renderer, scene) {
62917
+ dispose(renderer, scene) {
62796
62918
  if (!this.results) return;
62797
62919
  for (const result of this.results) {
62798
62920
  scene.remove(result);
62799
62921
  }
62922
+ this.clearToDispose();
62923
+ this.disposeRenderLists(renderer);
62800
62924
  }
62801
62925
  }
62802
62926
  const __vite_glob_0_5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -63418,31 +63542,35 @@ class RBXRenderer {
63418
63542
  renderScene.scene.add(result);
63419
63543
  }
63420
63544
  }
63545
+ static _updateCompiledRenderDesc(oldDesc, newDesc, renderScene, instance) {
63546
+ if (!oldDesc.compiled && !oldDesc.failed) {
63547
+ oldDesc.compiled = true;
63548
+ renderScene.compiledRenderDesc.Fire(instance);
63549
+ }
63550
+ if (!oldDesc.isSame(newDesc)) {
63551
+ oldDesc.fromRenderDesc(newDesc);
63552
+ oldDesc.updateResults();
63553
+ }
63554
+ }
63421
63555
  static _addRenderDesc(instance, auth, DescClass, renderScene) {
63422
63556
  if (!RBXRenderer.renderer) return;
63423
63557
  const oldDesc = renderScene.renderDescs.get(instance);
63424
63558
  const newDesc = new DescClass(renderScene);
63425
63559
  newDesc.fromInstance(instance);
63426
63560
  if (oldDesc && !oldDesc.needsRegeneration(newDesc) && !renderScene.isRenderingMesh.get(instance)) {
63427
- if (!oldDesc.compiled && !oldDesc.failed) {
63428
- oldDesc.compiled = true;
63429
- renderScene.compiledRenderDesc.Fire(instance);
63430
- }
63431
- if (!oldDesc.isSame(newDesc)) {
63432
- oldDesc.fromRenderDesc(newDesc);
63433
- oldDesc.updateResults();
63434
- }
63561
+ RBXRenderer._updateCompiledRenderDesc(oldDesc, newDesc, renderScene, instance);
63435
63562
  } else {
63436
63563
  if (!renderScene.isRenderingMesh.get(instance)) {
63437
- if (oldDesc) newDesc.transferFrom(oldDesc);
63438
- newDesc.results = oldDesc?.results;
63564
+ if (oldDesc && Object.getPrototypeOf(oldDesc).constructor === Object.getPrototypeOf(newDesc).constructor) {
63565
+ newDesc.transferFrom(oldDesc);
63566
+ }
63439
63567
  renderScene.renderDescs.set(instance, newDesc);
63440
63568
  renderScene.isRenderingMesh.set(instance, true);
63441
63569
  newDesc.compileResults(RBXRenderer.renderer, renderScene.scene).then((results) => {
63570
+ if (RBXRenderer.renderer) oldDesc?.dispose(RBXRenderer.renderer, renderScene.scene);
63442
63571
  if (results && !(results instanceof Response)) {
63443
63572
  newDesc.updateResults();
63444
- if (renderScene.renderDescs.get(instance) && RBXRenderer.renderer) {
63445
- oldDesc?.dispose(RBXRenderer.renderer, renderScene.scene);
63573
+ if (renderScene.renderDescs.get(instance) === newDesc && RBXRenderer.renderer) {
63446
63574
  for (const result of results) {
63447
63575
  RBXRenderer._addSkeletonToResult(result, newDesc, renderScene);
63448
63576
  }
@@ -63452,9 +63580,12 @@ class RBXRenderer {
63452
63580
  newDesc.dispose(RBXRenderer.renderer, renderScene.scene);
63453
63581
  }
63454
63582
  } else {
63583
+ if (RBXRenderer.renderer) newDesc.dispose(RBXRenderer.renderer, renderScene.scene);
63455
63584
  newDesc.failed = true;
63456
- renderScene.isRenderingMesh.set(instance, false);
63457
- renderScene.failedRenderDesc.Fire(instance);
63585
+ if (renderScene.renderDescs.get(instance) === newDesc) {
63586
+ renderScene.isRenderingMesh.set(instance, false);
63587
+ renderScene.failedRenderDesc.Fire(instance);
63588
+ }
63458
63589
  warn(false, "Failed to compile mesh", this, results);
63459
63590
  }
63460
63591
  });
@@ -63469,16 +63600,26 @@ class RBXRenderer {
63469
63600
  }));
63470
63601
  }
63471
63602
  }
63472
- /**Adds an instance to the renderer or updates it */
63473
- static addInstance(instance, auth, renderScene = RBXRenderer.firstScene) {
63603
+ /** */
63604
+ /**
63605
+ * Adds an instance to the renderer or updates it, add it again to update it after changes have been made
63606
+ * @param instance The instance that will be updated (the descendants will also update)
63607
+ * @param auth This is here just in case something requires it in the future
63608
+ * @param renderScene The scene the instances will be rendered in. Default RBXRenderer.firstScene
63609
+ * @param includeDescendants If descendants should also have addInstance called on them. Default true
63610
+ * @returns
63611
+ */
63612
+ static addInstance(instance, auth, renderScene = RBXRenderer.firstScene, includeDescendants = true) {
63474
63613
  if (renderScene.destroyed) return;
63475
63614
  const RenderDescType = getRenderDescForInstance(instance);
63476
63615
  if (RenderDescType) {
63477
63616
  if (renderScene.addedInstances.indexOf(instance) < 0) renderScene.addedInstances.push(instance);
63478
63617
  RBXRenderer._addRenderDesc(instance, auth, RenderDescType, renderScene);
63479
63618
  }
63480
- for (const child of instance.GetChildren()) {
63481
- RBXRenderer.addInstance(child, auth, renderScene);
63619
+ if (includeDescendants) {
63620
+ for (const child of instance.GetDescendants()) {
63621
+ RBXRenderer.addInstance(child, auth, renderScene, false);
63622
+ }
63482
63623
  }
63483
63624
  }
63484
63625
  static setRendererSize(width, height) {
@@ -64188,8 +64329,8 @@ function getExtentsForParts(parts, includeTransform) {
64188
64329
  }
64189
64330
  function getExtents(cframe, parts) {
64190
64331
  const inverseCF = cframe.inverse();
64191
- let lowerExtents = new Vector3(0, 0, 0);
64192
- let higherExtents = new Vector3(0, 0, 0);
64332
+ let lowerExtents = new Vector3(1e6, 1e6, 1e6);
64333
+ let higherExtents = new Vector3(-1e6, -1e6, -1e5);
64193
64334
  for (const child of parts) {
64194
64335
  if (child.createWrapper()?.IsA("BasePart")) {
64195
64336
  const partCF = child.Prop("CFrame");
@@ -65070,10 +65211,11 @@ async function renderTargetToCanvas$1(renderTarget) {
65070
65211
  }
65071
65212
  async function imageThumbnailClick(renderScene, width, height, format, options) {
65072
65213
  const resultOptions = {
65073
- quality: 1
65214
+ quality: 1,
65215
+ size: [width, height]
65074
65216
  };
65075
65217
  if (options) Object.assign(resultOptions, options);
65076
- const renderTarget = renderToRenderTarget$1(width, height, renderScene);
65218
+ const renderTarget = renderToRenderTarget$1(resultOptions.size[0], resultOptions.size[1], renderScene);
65077
65219
  const canvas = await renderTargetToCanvas$1(renderTarget);
65078
65220
  renderTarget.dispose();
65079
65221
  if (canvas) {
@@ -65093,8 +65235,24 @@ async function modelThumbnailClick(renderScene, format, options) {
65093
65235
  });
65094
65236
  }
65095
65237
  function getThumbnailCameraCFrame(model, fov2, forceAngle) {
65096
- const thumbnailCamera = model.FindFirstChildOfClass("Camera");
65097
- if (thumbnailCamera) return thumbnailCamera.PropOrDefault("CFrame", new CFrame());
65238
+ const thumbnailCamera = model.FindFirstChild("ThumbnailCamera");
65239
+ if (thumbnailCamera && thumbnailCamera.IsA("Camera")) return thumbnailCamera.PropOrDefault("CFrame", new CFrame());
65240
+ const thumbnailConfiguration = model.FindFirstChild("ThumbnailConfiguration");
65241
+ if (thumbnailConfiguration) {
65242
+ const thumbnailCameraTarget = thumbnailConfiguration.FindFirstChild("ThumbnailCameraTarget");
65243
+ if (thumbnailCameraTarget && thumbnailCameraTarget.IsA("ObjectValue")) {
65244
+ const targetInstance = thumbnailCameraTarget.Prop("Value");
65245
+ if (targetInstance && targetInstance.IsA("BasePart")) {
65246
+ const targetCF = targetInstance.PropOrDefault("CFrame", new CFrame());
65247
+ const thumbnailCameraValue = thumbnailConfiguration.FindFirstChild("ThumbnailCameraValue");
65248
+ if (thumbnailCameraValue && thumbnailCameraValue.IsA("CFrameValue")) {
65249
+ const cf = thumbnailCameraValue.PropOrDefault("Value", new CFrame());
65250
+ const resultCF = targetCF.multiply(cf);
65251
+ return resultCF;
65252
+ }
65253
+ }
65254
+ }
65255
+ }
65098
65256
  let rootPart = model.PropOrDefault("PrimaryPart", void 0);
65099
65257
  if (!rootPart) rootPart = model.FindFirstChildOfClass("Part");
65100
65258
  if (!rootPart) rootPart = model.FindFirstChildOfClass("MeshPart");
@@ -65126,6 +65284,56 @@ function getThumbnailCameraCFrame(model, fov2, forceAngle) {
65126
65284
  zoomExtents(cameraCF, rootPartCF, extentsSize, fov2, 1);
65127
65285
  return cameraCF;
65128
65286
  }
65287
+ function getThumbnailCamera(model) {
65288
+ const thumbnailCamera = model.FindFirstChild("ThumbnailCamera");
65289
+ if (thumbnailCamera && thumbnailCamera.IsA("Camera")) return thumbnailCamera;
65290
+ const camera = new Instance("Camera");
65291
+ const thumbnailConfiguration = model.FindFirstChild("ThumbnailConfiguration");
65292
+ if (thumbnailConfiguration) {
65293
+ const thumbnailCameraTarget = thumbnailConfiguration.FindFirstChild("ThumbnailCameraTarget");
65294
+ if (thumbnailCameraTarget && thumbnailCameraTarget.IsA("ObjectValue")) {
65295
+ const targetInstance = thumbnailCameraTarget.Prop("Value");
65296
+ if (targetInstance && targetInstance.IsA("BasePart")) {
65297
+ const targetCF = targetInstance.PropOrDefault("CFrame", new CFrame());
65298
+ const thumbnailCameraValue = thumbnailConfiguration.FindFirstChild("ThumbnailCameraValue");
65299
+ if (thumbnailCameraValue && thumbnailCameraValue.IsA("CFrameValue")) {
65300
+ const cf = thumbnailCameraValue.PropOrDefault("Value", new CFrame());
65301
+ const resultCF = targetCF.multiply(cf);
65302
+ camera.setProperty("FieldOfView", 70);
65303
+ camera.setProperty("CFrame", resultCF);
65304
+ return camera;
65305
+ }
65306
+ }
65307
+ }
65308
+ }
65309
+ let rootPart = model.PropOrDefault("PrimaryPart", void 0);
65310
+ if (!rootPart) rootPart = model.FindFirstChildOfClass("Part");
65311
+ if (!rootPart) rootPart = model.FindFirstChildOfClass("MeshPart");
65312
+ if (!rootPart) return camera;
65313
+ const rootPartCF = rootPart.PropOrDefault("CFrame", new CFrame()).clone();
65314
+ const worldExtents = getExtentsWorld(model);
65315
+ if (!worldExtents) return camera;
65316
+ const extentsSize = worldExtents[1].minus(worldExtents[0]);
65317
+ rootPartCF.Position = getExtentsCenter(worldExtents).toVec3();
65318
+ let lookVector = rootPartCF.lookVector();
65319
+ if (Math.abs(lookVector[1]) > 0.95) {
65320
+ lookVector = [0, 0, -1];
65321
+ } else {
65322
+ lookVector[1] = 0;
65323
+ lookVector = normalize(lookVector);
65324
+ }
65325
+ let lookCF = CFrame.lookAt([0, 0, 0], lookVector);
65326
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(0, 0, rad(45)));
65327
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(rad(35), 0, 0));
65328
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(0, 0, 0));
65329
+ lookVector = lookCF.lookVector();
65330
+ lookCF.Position = add(rootPartCF.Position, multiply([10, 10, 10], lookVector));
65331
+ lookCF = CFrame.lookAt(lookCF.Position, rootPartCF.Position);
65332
+ const cameraCF = lookCF.clone();
65333
+ zoomExtents(cameraCF, rootPartCF, extentsSize, 70, 1);
65334
+ camera.setProperty("CFrame", cameraCF);
65335
+ return camera;
65336
+ }
65129
65337
  function setupThumbnailScene(renderScene) {
65130
65338
  renderScene.particlesStartFull = 4;
65131
65339
  renderScene.particlesStartFullFramerate = 20;
@@ -65214,6 +65422,135 @@ async function generateOutfitModelThumbnail(auth, outfitModel, options) {
65214
65422
  Object.assign(defaultOptions, options);
65215
65423
  return generateOutfitThumbnail(auth, outfitModel, defaultOptions.size, defaultOptions.type, defaultOptions.quality, defaultOptions.gltfAutoDownload, defaultOptions.includeAnimations);
65216
65424
  }
65425
+ function getViewExtents(camera, positions, width, height) {
65426
+ const minExtents = new Vector2(1e6, 1e6);
65427
+ const maxExtents = new Vector2(-1e6, -1e6);
65428
+ for (const pos of positions) {
65429
+ const projPos = new Vector3$1(...pos.toVec3()).project(camera);
65430
+ const x = (projPos.x / 2 + 0.5) * width;
65431
+ const y = (-projPos.y / 2 + 0.5) * height;
65432
+ if (x < minExtents.X) minExtents.X = x;
65433
+ if (x > maxExtents.X) maxExtents.X = x;
65434
+ if (y < minExtents.Y) minExtents.Y = y;
65435
+ if (y > maxExtents.Y) maxExtents.Y = y;
65436
+ }
65437
+ minExtents.X = Math.max(0, minExtents.X);
65438
+ minExtents.Y = Math.max(0, minExtents.Y);
65439
+ maxExtents.X = Math.min(width, maxExtents.X);
65440
+ maxExtents.Y = Math.min(height, maxExtents.Y);
65441
+ return [minExtents, maxExtents];
65442
+ }
65443
+ function getModelViewExtents(model, camera, width, height) {
65444
+ const worldExtents = getExtentsWorld(model);
65445
+ const corners = [
65446
+ new Vector3(worldExtents[0].X, worldExtents[0].Y, worldExtents[0].Z),
65447
+ new Vector3(worldExtents[0].X, worldExtents[0].Y, worldExtents[1].Z),
65448
+ new Vector3(worldExtents[0].X, worldExtents[1].Y, worldExtents[0].Z),
65449
+ new Vector3(worldExtents[0].X, worldExtents[1].Y, worldExtents[1].Z),
65450
+ new Vector3(worldExtents[1].X, worldExtents[0].Y, worldExtents[0].Z),
65451
+ new Vector3(worldExtents[1].X, worldExtents[0].Y, worldExtents[1].Z),
65452
+ new Vector3(worldExtents[1].X, worldExtents[1].Y, worldExtents[0].Z),
65453
+ new Vector3(worldExtents[1].X, worldExtents[1].Y, worldExtents[1].Z)
65454
+ ];
65455
+ return getViewExtents(camera, corners, width, height);
65456
+ }
65457
+ function cropCameraToViewExtents(camera, viewExtents, width, height, keepAspectRatio = true) {
65458
+ const blx = viewExtents[0].X;
65459
+ const bly = viewExtents[0].Y;
65460
+ const bhx = viewExtents[1].X;
65461
+ const bhy = viewExtents[1].Y;
65462
+ const xDiff = bhx - blx;
65463
+ const yDiff = bhy - bly;
65464
+ const cx = blx + xDiff / 2;
65465
+ const cy = bly + yDiff / 2;
65466
+ const scaleW = xDiff / width;
65467
+ const scaleH = yDiff / height;
65468
+ const maxScale = Math.max(scaleW, scaleH);
65469
+ const cropWidth = keepAspectRatio ? width * maxScale : xDiff;
65470
+ const cropHeight = keepAspectRatio ? height * maxScale : yDiff;
65471
+ const flx = cx - cropWidth / 2;
65472
+ const fly = cy - cropHeight / 2;
65473
+ const x = flx;
65474
+ const y = fly;
65475
+ camera.setViewOffset(
65476
+ width,
65477
+ height,
65478
+ x,
65479
+ y,
65480
+ cropWidth,
65481
+ cropHeight
65482
+ );
65483
+ return cropWidth / cropHeight;
65484
+ }
65485
+ function cropForModel(model, renderScene, width, height, resizeToRemoveUnusedSpace = false) {
65486
+ const viewExtents = getModelViewExtents(model, renderScene.camera, width, height);
65487
+ const targetAspectRatio = cropCameraToViewExtents(renderScene.camera, viewExtents, width, height, !resizeToRemoveUnusedSpace);
65488
+ renderScene.camera.updateProjectionMatrix();
65489
+ let newHeight = height;
65490
+ let newWidth = width;
65491
+ if (resizeToRemoveUnusedSpace) {
65492
+ newWidth = width * targetAspectRatio;
65493
+ if (newWidth > width) {
65494
+ newWidth = width;
65495
+ newHeight = height / targetAspectRatio;
65496
+ }
65497
+ }
65498
+ return [Math.ceil(newWidth), Math.ceil(newHeight)];
65499
+ }
65500
+ function createThumbnailScene() {
65501
+ const renderScene = RBXRenderer.addScene(false);
65502
+ renderScene.isForRenderTarget = true;
65503
+ setupThumbnailScene(renderScene);
65504
+ return renderScene;
65505
+ }
65506
+ async function generateAccessoryThumbnail(auth, id, type, imageOptions, isAccessoryCamera = false) {
65507
+ let renderSceneToDestroy = void 0;
65508
+ const instancesToDestroy = [];
65509
+ const cleanup = () => {
65510
+ if (renderSceneToDestroy) renderSceneToDestroy.destroy();
65511
+ for (const instance of instancesToDestroy) {
65512
+ instance.Destroy();
65513
+ }
65514
+ return void 0;
65515
+ };
65516
+ const resultOptions = {
65517
+ quality: 1,
65518
+ size: [420, 420]
65519
+ };
65520
+ if (imageOptions) Object.assign(resultOptions, imageOptions);
65521
+ const renderScene = createThumbnailScene();
65522
+ renderSceneToDestroy = renderScene;
65523
+ const rbx = await API.Asset.GetRBX(`rbxassetid://${id}`, { "Roblox-AssetFormat": "avatar_meshpart_accessory" });
65524
+ if (rbx instanceof Response) return cleanup();
65525
+ const root = rbx.generateTree();
65526
+ instancesToDestroy.push(root);
65527
+ const accessory = root.FindFirstChildOfClass("Accessory");
65528
+ if (!accessory) return cleanup();
65529
+ let camera = void 0;
65530
+ if (isAccessoryCamera) {
65531
+ camera = new Instance("Camera");
65532
+ setupAccessoryCamera(root, camera);
65533
+ } else {
65534
+ camera = getThumbnailCamera(accessory);
65535
+ }
65536
+ instancesToDestroy.push(camera);
65537
+ RBXRenderer.setCameraCFrame(camera.PropOrDefault("CFrame", new CFrame()), renderScene);
65538
+ RBXRenderer.setCameraFov(camera.PropOrDefault("FieldOfView", 70), renderScene);
65539
+ renderScene.camera.aspect = resultOptions.size[0] / resultOptions.size[1];
65540
+ renderScene.camera.updateProjectionMatrix();
65541
+ let [newWidth, newHeight] = [resultOptions.size[0], resultOptions.size[1]];
65542
+ if (!isAccessoryCamera) {
65543
+ [newWidth, newHeight] = cropForModel(accessory, renderScene, resultOptions.size[0], resultOptions.size[1]);
65544
+ }
65545
+ RBXRenderer.addInstance(accessory, auth, renderScene);
65546
+ const compiledSuccessfully = await renderScene.waitUntilFullyCompiled([accessory, ...accessory.GetChildrenDangerous()]);
65547
+ if (!compiledSuccessfully) return cleanup();
65548
+ const result = type === "gltf" || type === "glb" ? await modelThumbnailClick(renderScene, type) : await imageThumbnailClick(renderScene, newWidth, newHeight, type, {
65549
+ quality: resultOptions.quality
65550
+ });
65551
+ cleanup();
65552
+ return result;
65553
+ }
65217
65554
  async function runTests() {
65218
65555
  const auth = new Authentication();
65219
65556
  const testModel = await API.Asset.GetRBX(FLAGS.AUTOTEST_MODEL);
@@ -65394,6 +65731,7 @@ function exposeThumbnailGenerator() {
65394
65731
  globalThis.generateModelThumbnail = generateModelThumbnail;
65395
65732
  globalThis.setupThumbnailScene = setupThumbnailScene;
65396
65733
  globalThis.getThumbnailCameraCFrame = getThumbnailCameraCFrame;
65734
+ globalThis.generateAccessoryThumbnail = generateAccessoryThumbnail;
65397
65735
  }
65398
65736
  function exposeTests() {
65399
65737
  globalThis.runTests = runTests;
@@ -65593,7 +65931,10 @@ export {
65593
65931
  closestPointTriangle,
65594
65932
  createContentMap,
65595
65933
  createThumbnailCamera,
65934
+ createThumbnailScene,
65596
65935
  createWeightsForMeshChunked,
65936
+ cropCameraToViewExtents,
65937
+ cropForModel,
65597
65938
  cross,
65598
65939
  defaultPantAssetIds,
65599
65940
  defaultPantTemplateAssetIds,
@@ -65635,6 +65976,7 @@ export {
65635
65976
  getFullBodyCameraCFrame,
65636
65977
  getHeadExtents,
65637
65978
  getHeadshotCameraCFrame,
65979
+ getModelViewExtents,
65638
65980
  getOffsetArray,
65639
65981
  getOriginalAttachmentOrientation,
65640
65982
  getOriginalAttachmentPosition,
@@ -65643,9 +65985,11 @@ export {
65643
65985
  getPartsInAssembly_Generate,
65644
65986
  getRandomBetweenInclusive,
65645
65987
  getRootAssemblyPart_Generate,
65988
+ getThumbnailCamera,
65646
65989
  getThumbnailCameraCFrame,
65647
65990
  getUVtoIndexMap,
65648
65991
  getUVtoIndicesMap,
65992
+ getViewExtents,
65649
65993
  getWorkerOnMessage,
65650
65994
  hasSameVal,
65651
65995
  hasSameValFloat,
@@ -65689,6 +66033,7 @@ export {
65689
66033
  rotationMatrixToEulerAngles,
65690
66034
  saveByteArray,
65691
66035
  scaleMesh,
66036
+ setCacheFootprintPreset,
65692
66037
  setupAccessoryCamera,
65693
66038
  setupBodyPartCamera,
65694
66039
  setupCamera,