roavatar-renderer 1.9.9 → 1.9.11

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 +126 -8
  2. package/dist/index.js +591 -239
  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);
@@ -35104,37 +35110,45 @@ class ItemInfo {
35104
35110
  class AssetType {
35105
35111
  _id;
35106
35112
  //67
35107
- name;
35113
+ _name;
35108
35114
  //JacketAccessory
35109
35115
  constructor() {
35110
35116
  this._id = 2;
35111
- this.name = "TShirt";
35117
+ this._name = "TShirt";
35112
35118
  }
35113
35119
  clone() {
35114
35120
  const copy = new AssetType();
35115
35121
  copy.id = this.id;
35116
- copy.name = this.name;
35122
+ copy._name = this._name;
35117
35123
  return copy;
35118
35124
  }
35119
35125
  toJson() {
35120
35126
  return {
35121
35127
  "id": this.id,
35122
- "name": this.name
35128
+ "name": this._name
35123
35129
  };
35124
35130
  }
35125
35131
  fromJson(assetTypeJson) {
35126
35132
  if (assetTypeJson.id)
35127
35133
  this.id = assetTypeJson.id;
35128
35134
  if (assetTypeJson.name)
35129
- this.name = assetTypeJson.name;
35135
+ this._name = assetTypeJson.name;
35130
35136
  }
35131
35137
  set id(newId) {
35132
35138
  this._id = newId;
35133
- this.name = AssetTypes[Number(newId)];
35139
+ this._name = AssetTypes[Number(newId)];
35134
35140
  }
35135
35141
  get id() {
35136
35142
  return this._id;
35137
35143
  }
35144
+ set name(newName) {
35145
+ const newId = AssetTypeNameToId.get(newName);
35146
+ this._id = newId || this._id;
35147
+ this._name = newName;
35148
+ }
35149
+ get name() {
35150
+ return this._name;
35151
+ }
35138
35152
  }
35139
35153
  function cloneVecXYZ(vec) {
35140
35154
  return { X: vec.X, Y: vec.Y, Z: vec.Z };
@@ -36722,7 +36736,7 @@ class LocalOutfit {
36722
36736
  this.name = outfit.name;
36723
36737
  this.id = outfit.id;
36724
36738
  this.creator = outfit.creatorId;
36725
- this.date = Date.now();
36739
+ this.date = outfit.creationDate || Date.now();
36726
36740
  this.buffer = arrayBufferToBase64(outfit.toBuffer());
36727
36741
  }
36728
36742
  toJson() {
@@ -36740,6 +36754,7 @@ class LocalOutfit {
36740
36754
  this.name = data.name;
36741
36755
  this.id = data.id;
36742
36756
  this.creator = data.creator;
36757
+ this.date = data.date;
36743
36758
  this.image = data.image;
36744
36759
  this.buffer = data.buffer;
36745
36760
  this.bg = data.bg || 0;
@@ -36759,6 +36774,7 @@ class LocalOutfit {
36759
36774
  outfit.name = this.name;
36760
36775
  outfit.id = this.id;
36761
36776
  outfit.creatorId = this.creator;
36777
+ outfit.creationDate = this.date;
36762
36778
  await outfit.fromBuffer(base64ToArrayBuffer(this.buffer), auth);
36763
36779
  return outfit;
36764
36780
  }
@@ -36768,6 +36784,7 @@ class LocalOutfit {
36768
36784
  outfit.name = this.name;
36769
36785
  outfit.id = this.id;
36770
36786
  outfit.creatorId = this.creator;
36787
+ outfit.creationDate = this.date;
36771
36788
  await outfit.fromBuffer(base64ToArrayBuffer(this.buffer), auth);
36772
36789
  if (this.bg) {
36773
36790
  await outfit.addAssetId(this.bg, auth);
@@ -36817,9 +36834,7 @@ const AllAccessorySorts = [
36817
36834
  new ItemSort(46),
36818
36835
  new ItemSort(47)
36819
36836
  ];
36820
- if (!FLAGS.HAIR_IS_BODYPART) {
36821
- AllAccessorySorts.push(new ItemSort(41));
36822
- }
36837
+ AllAccessorySorts.push(new ItemSort(41));
36823
36838
  const AllClothingSorts = [
36824
36839
  new ItemSort(12),
36825
36840
  new ItemSort(11),
@@ -36843,9 +36858,7 @@ const AllBodyPartsSorts = [
36843
36858
  new ItemSort(31),
36844
36859
  new ItemSort(27)
36845
36860
  ];
36846
- if (FLAGS.HAIR_IS_BODYPART) {
36847
- AllBodyPartsSorts.push(new ItemSort(41));
36848
- }
36861
+ AllBodyPartsSorts.push(new ItemSort(41));
36849
36862
  const AllAnimationSorts = [
36850
36863
  new ItemSort(48),
36851
36864
  new ItemSort(50),
@@ -36906,6 +36919,7 @@ const CategoryDictionary = {
36906
36919
  "Dynamic Heads": new SortInfo([new ItemSort(2, "Outfit")]),
36907
36920
  "Adjustment": new SpecialInfo("HeadAdjustment"),
36908
36921
  "|": new SortDivision(),
36922
+ "Hair": new SortInfo([new ItemSort(41)]),
36909
36923
  "Heads": new SortInfo([new ItemSort(17)], "inventory"),
36910
36924
  "Faces": new SortInfo([new ItemSort(18)], "inventory")
36911
36925
  },
@@ -39386,6 +39400,7 @@ class Cache {
39386
39400
  map = /* @__PURE__ */ new Map();
39387
39401
  lastAccess = /* @__PURE__ */ new Map();
39388
39402
  maxEntries;
39403
+ minDeleteLifetime = 5;
39389
39404
  onDelete;
39390
39405
  constructor(maxEntries = 250) {
39391
39406
  this.maxEntries = maxEntries;
@@ -39399,12 +39414,7 @@ class Cache {
39399
39414
  set(key, value) {
39400
39415
  this.map.set(key, value);
39401
39416
  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
- }
39417
+ this.deleteUntil();
39408
39418
  return this;
39409
39419
  }
39410
39420
  has(key) {
@@ -39416,11 +39426,28 @@ class Cache {
39416
39426
  this.lastAccess.delete(key);
39417
39427
  return toReturn;
39418
39428
  }
39429
+ deleteUntil() {
39430
+ while (this.map.size > this.maxEntries) {
39431
+ if (!this.deleteOne()) break;
39432
+ }
39433
+ }
39434
+ deleteOne() {
39435
+ if (this.map.size > this.maxEntries) {
39436
+ const toDelete = [...this.lastAccess.entries()].reduce((min, current) => {
39437
+ return current[1] < min[1] ? current : min;
39438
+ });
39439
+ if (Date.now() - toDelete[1] >= this.minDeleteLifetime * 1e3) {
39440
+ this.delete(toDelete[0]);
39441
+ return true;
39442
+ }
39443
+ }
39444
+ return false;
39445
+ }
39419
39446
  }
39420
39447
  const CACHE = {
39421
- "AssetBuffer": new Cache(250),
39448
+ "AssetBuffer": new Cache(100),
39422
39449
  "RBX": new Cache(100),
39423
- "Mesh": new Cache(250),
39450
+ "Mesh": new Cache(100),
39424
39451
  "Image": new Cache(100),
39425
39452
  "Thumbnails": new Cache(1e3),
39426
39453
  "ItemOwned": new Cache(1e3),
@@ -39429,6 +39456,54 @@ const CACHE = {
39429
39456
  "ItemDetails": new Cache(1e4),
39430
39457
  "UserInfo": void 0
39431
39458
  };
39459
+ function setCacheFootprintPreset(preset) {
39460
+ switch (preset) {
39461
+ case "none":
39462
+ CACHE.AssetBuffer.maxEntries = 0;
39463
+ CACHE.RBX.maxEntries = 0;
39464
+ CACHE.Mesh.maxEntries = 0;
39465
+ CACHE.Image.maxEntries = 0;
39466
+ CACHE.Thumbnails.maxEntries = 0;
39467
+ CACHE.ItemOwned.maxEntries = 0;
39468
+ CACHE.IsLayered.maxEntries = 0;
39469
+ CACHE.AvatarInventoryItem.maxEntries = 0;
39470
+ CACHE.ItemDetails.maxEntries = 0;
39471
+ break;
39472
+ case "low":
39473
+ CACHE.AssetBuffer.maxEntries = 10;
39474
+ CACHE.RBX.maxEntries = 10;
39475
+ CACHE.Mesh.maxEntries = 10;
39476
+ CACHE.Image.maxEntries = 10;
39477
+ CACHE.Thumbnails.maxEntries = 500;
39478
+ CACHE.ItemOwned.maxEntries = 500;
39479
+ CACHE.IsLayered.maxEntries = 100;
39480
+ CACHE.AvatarInventoryItem.maxEntries = 500;
39481
+ CACHE.ItemDetails.maxEntries = 5e3;
39482
+ break;
39483
+ case "normal":
39484
+ CACHE.AssetBuffer.maxEntries = 100;
39485
+ CACHE.RBX.maxEntries = 100;
39486
+ CACHE.Mesh.maxEntries = 100;
39487
+ CACHE.Image.maxEntries = 100;
39488
+ CACHE.Thumbnails.maxEntries = 1e3;
39489
+ CACHE.ItemOwned.maxEntries = 1e3;
39490
+ CACHE.IsLayered.maxEntries = 1e3;
39491
+ CACHE.AvatarInventoryItem.maxEntries = 1e3;
39492
+ CACHE.ItemDetails.maxEntries = 1e4;
39493
+ break;
39494
+ case "high":
39495
+ CACHE.AssetBuffer.maxEntries = 250;
39496
+ CACHE.RBX.maxEntries = 250;
39497
+ CACHE.Mesh.maxEntries = 250;
39498
+ CACHE.Image.maxEntries = 250;
39499
+ CACHE.Thumbnails.maxEntries = 1e3;
39500
+ CACHE.ItemOwned.maxEntries = 1e3;
39501
+ CACHE.IsLayered.maxEntries = 1e3;
39502
+ CACHE.AvatarInventoryItem.maxEntries = 1e3;
39503
+ CACHE.ItemDetails.maxEntries = 1e4;
39504
+ break;
39505
+ }
39506
+ }
39432
39507
  const ContentMap = /* @__PURE__ */ new Map();
39433
39508
  function createContentMap() {
39434
39509
  ContentMap.set("rbxasset://fonts/BaseballCap.mesh", "12220916");
@@ -43854,6 +43929,89 @@ GLTFExporter.Utils = {
43854
43929
  return dstAttribute;
43855
43930
  }
43856
43931
  };
43932
+ const managedTextures = /* @__PURE__ */ new Map();
43933
+ async function createTexturePromise(url, params) {
43934
+ const image = await API.Generic.LoadImage(url.replace(".dds", ".png"));
43935
+ if (!image) return void 0;
43936
+ const texture = new Texture(
43937
+ image,
43938
+ void 0,
43939
+ params?.wrapS || ClampToEdgeWrapping,
43940
+ params?.wrapT || ClampToEdgeWrapping,
43941
+ params?.magFilter,
43942
+ params?.minFilter,
43943
+ void 0,
43944
+ void 0,
43945
+ void 0,
43946
+ params?.colorSpace || SRGBColorSpace
43947
+ );
43948
+ if (params?.generateMipmaps !== void 0) texture.generateMipmaps = params?.generateMipmaps;
43949
+ texture.needsUpdate = true;
43950
+ return texture;
43951
+ }
43952
+ function createManagedTexture(url, params) {
43953
+ const textureInfo = {
43954
+ texture: void 0,
43955
+ uses: 1
43956
+ //used by texture promise (internal), so we dont try to dispose when it doesnt even exist yet
43957
+ };
43958
+ textureInfo.texture = new Promise((resolve) => {
43959
+ createTexturePromise(url, params).then((result) => {
43960
+ textureInfo.texture = result;
43961
+ finishManagedTexture(url, params);
43962
+ resolve(result);
43963
+ });
43964
+ });
43965
+ return textureInfo;
43966
+ }
43967
+ function getTextureInfoKey(url, params) {
43968
+ url = url.replace(".dds", ".png");
43969
+ if (params?.colorSpace === "srgb") delete params.colorSpace;
43970
+ if (params?.wrapS === ClampToEdgeWrapping) delete params.wrapS;
43971
+ if (params?.wrapT === ClampToEdgeWrapping) delete params.wrapT;
43972
+ if (params?.magFilter === LinearFilter) delete params.magFilter;
43973
+ if (params?.minFilter === LinearMipmapLinearFilter) delete params.minFilter;
43974
+ if (params && Object.keys(params).length > 0) {
43975
+ return url + JSON.stringify(params);
43976
+ } else {
43977
+ return url;
43978
+ }
43979
+ }
43980
+ async function getManagedTexture(url, params) {
43981
+ const key = getTextureInfoKey(url, params);
43982
+ let managedTextureInfo = managedTextures.get(key);
43983
+ if (!managedTextureInfo) {
43984
+ managedTextureInfo = createManagedTexture(url, params);
43985
+ managedTextures.set(key, managedTextureInfo);
43986
+ }
43987
+ managedTextureInfo.uses += 1;
43988
+ const disposeTimeout = managedTextureInfo.disposeTimeout;
43989
+ if (disposeTimeout) {
43990
+ clearTimeout(disposeTimeout);
43991
+ managedTextureInfo.disposeTimeout = void 0;
43992
+ }
43993
+ return managedTextureInfo.texture;
43994
+ }
43995
+ async function finishManagedTexture(url, params) {
43996
+ const key = getTextureInfoKey(url, params);
43997
+ const managedTextureInfo = managedTextures.get(key);
43998
+ if (managedTextureInfo) {
43999
+ managedTextureInfo.uses -= 1;
44000
+ if (managedTextureInfo.uses <= 0) {
44001
+ if (!managedTextureInfo.disposeTimeout) {
44002
+ const disposeTimeout = setTimeout(() => {
44003
+ if (managedTextureInfo.disposeTimeout !== disposeTimeout || managedTextureInfo.uses > 0) return;
44004
+ const texture = managedTextureInfo.texture;
44005
+ if (texture && texture instanceof Texture || texture === void 0) {
44006
+ managedTextures.delete(key);
44007
+ if (texture) texture.dispose();
44008
+ }
44009
+ }, 5e3);
44010
+ managedTextureInfo.disposeTimeout = disposeTimeout;
44011
+ }
44012
+ }
44013
+ }
44014
+ }
43857
44015
  const RenderDescClassTypes = /* @__PURE__ */ new Map();
43858
44016
  function getRenderDescForClass(className) {
43859
44017
  return RenderDescClassTypes.get(className);
@@ -43870,22 +44028,9 @@ function setTHREEObjectCF(threeObject, cframe) {
43870
44028
  threeObject.rotation.y = rad(cframe.Orientation[1]);
43871
44029
  threeObject.rotation.z = rad(cframe.Orientation[2]);
43872
44030
  }
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
44031
  class DisposableDesc {
44032
+ toDispose = [];
44033
+ managedTextures = [];
43889
44034
  disposeMesh(scene, mesh) {
43890
44035
  disposeMesh(scene, mesh);
43891
44036
  }
@@ -43901,6 +44046,22 @@ class DisposableDesc {
43901
44046
  dispose(_renderer, _scene) {
43902
44047
  throw new Error("Virtual method dispose called");
43903
44048
  }
44049
+ clearToDispose() {
44050
+ for (const disposeable of this.toDispose) {
44051
+ disposeable.dispose();
44052
+ }
44053
+ this.toDispose = [];
44054
+ for (const managedTexture of this.managedTextures) {
44055
+ finishManagedTexture(managedTexture.url, managedTexture.params);
44056
+ }
44057
+ this.managedTextures = [];
44058
+ }
44059
+ removeFromToDispose(disposable) {
44060
+ const index = this.toDispose.indexOf(disposable);
44061
+ if (index > -1) {
44062
+ this.toDispose.splice(index, 1);
44063
+ }
44064
+ }
43904
44065
  }
43905
44066
  class RenderDesc extends DisposableDesc {
43906
44067
  static classTypes = [];
@@ -45676,6 +45837,7 @@ class ModelLayersDesc {
45676
45837
  }
45677
45838
  const targetCage = meshMap.get(this.targetCages[i]);
45678
45839
  targetCage.removeDuplicateVertices();
45840
+ offsetMesh(targetCage, this.targetOffsets[i]);
45679
45841
  inheritSkeleton(targetCage, targetMesh);
45680
45842
  targetCage.setBoneSource(this.getTargetName(i));
45681
45843
  targetCage.setBoneSourceSize();
@@ -45683,14 +45845,12 @@ class ModelLayersDesc {
45683
45845
  const distDeformer = this.targetDeformers[0];
45684
45846
  const dist_mesh = distDeformer ? meshMap.get(distDeformer.targetCage).clone() : meshMap.get(this.targetCages[0]).clone();
45685
45847
  const dist_mesh_mesh = meshMap.get(this.targetMeshes[0]);
45686
- offsetMesh(dist_mesh, this.targetOffsets[0]);
45687
45848
  scaleMesh(dist_mesh, this.targetSizes[0].divide(new Vector3().fromVec3(dist_mesh_mesh.size)));
45688
45849
  offsetMesh(dist_mesh, this.targetCFrames[0]);
45689
45850
  for (let i = 1; i < this.targetCages.length; i++) {
45690
45851
  const deformer = this.targetDeformers[i];
45691
45852
  const targetCage = deformer ? meshMap.get(deformer.targetCage).clone() : meshMap.get(this.targetCages[i]).clone();
45692
45853
  const targetMesh = meshMap.get(this.targetMeshes[i]);
45693
- offsetMesh(targetCage, this.targetOffsets[i]);
45694
45854
  scaleMesh(targetCage, this.targetSizes[i].divide(new Vector3().fromVec3(targetMesh.size)));
45695
45855
  offsetMesh(targetCage, this.targetCFrames[i]);
45696
45856
  dist_mesh.combine(targetCage);
@@ -46158,7 +46318,7 @@ async function promiseForMesh(url, readOnly = false) {
46158
46318
  });
46159
46319
  });
46160
46320
  }
46161
- class MeshDesc {
46321
+ class MeshDesc extends DisposableDesc {
46162
46322
  //size: Vector3 = new Vector3(1,1,1)
46163
46323
  scaleIsRelative = false;
46164
46324
  mesh;
@@ -46186,9 +46346,6 @@ class MeshDesc {
46186
46346
  fileMesh;
46187
46347
  wasAutoSkinned = false;
46188
46348
  wasDeformed = false;
46189
- dispose() {
46190
- this.instance = void 0;
46191
- }
46192
46349
  isSame(other) {
46193
46350
  const singularTrue = (
46194
46351
  //this.size.isSame(other.size) &&
@@ -46535,6 +46692,7 @@ class MeshDesc {
46535
46692
  if (wrapTextureTransferResult instanceof Response) return wrapTextureTransferResult;
46536
46693
  this.fileMesh = mesh;
46537
46694
  const geometry = fileMeshToTHREEGeometry(the_ref_mesh || mesh, this.canHaveSkinning, this.forceVertexColor);
46695
+ this.toDispose.push(geometry);
46538
46696
  let threeMesh = void 0;
46539
46697
  if (geometry.attributes.skinWeight) {
46540
46698
  threeMesh = new SkinnedMesh(geometry);
@@ -46699,6 +46857,11 @@ class MeshDesc {
46699
46857
  this.wrapTextureTargetOrigin = wrapTarget.Prop("CageOrigin").removeNaN();
46700
46858
  }
46701
46859
  }
46860
+ dispose(renderer) {
46861
+ this.instance = void 0;
46862
+ this.clearToDispose();
46863
+ this.disposeRenderLists(renderer);
46864
+ }
46702
46865
  }
46703
46866
  const compositMeshPaths = [
46704
46867
  "rbxasset://avatar/compositing/CompositFullAtlasBaseTexture.mesh",
@@ -47050,67 +47213,6 @@ const Shader_TextureComposer_Gamma = new ShaderMaterial({
47050
47213
  depthWrite: false,
47051
47214
  transparent: true
47052
47215
  });
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
47216
  async function renderBodyPartClothingR15(limbId, texture) {
47115
47217
  let instruction;
47116
47218
  if (limbId !== BodyPart.Torso) {
@@ -47249,7 +47351,7 @@ class TextureLayer {
47249
47351
  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
47352
  }
47251
47353
  }
47252
- class MaterialDesc {
47354
+ class MaterialDesc extends DisposableDesc {
47253
47355
  layers = [];
47254
47356
  isDecal = false;
47255
47357
  canHaveMipmaps = true;
@@ -47268,6 +47370,7 @@ class MaterialDesc {
47268
47370
  createdTextures = [];
47269
47371
  noTextureTransparency = false;
47270
47372
  result;
47373
+ resultRenderTarget;
47271
47374
  isSame(other) {
47272
47375
  if (this.dirty || other.dirty) return false;
47273
47376
  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 +47681,7 @@ class MaterialDesc {
47578
47681
  }
47579
47682
  }
47580
47683
  if (composeInsts.length === 0) {
47684
+ this.finishManagedTextures(textureType);
47581
47685
  return void 0;
47582
47686
  }
47583
47687
  TextureComposer.new(width, height, textureType === "color" ? LinearSRGBColorSpace : NoColorSpace, RepeatWrapping, noMipmaps);
@@ -47586,12 +47690,15 @@ class MaterialDesc {
47586
47690
  TextureComposer.add(inst);
47587
47691
  }
47588
47692
  const renderTarget = TextureComposer.render();
47693
+ this.toDispose.push(renderTarget);
47589
47694
  this.finishManagedTextures(textureType);
47695
+ const linearRenderTarget = renderTarget;
47590
47696
  const lineartexture = renderTarget.texture;
47591
47697
  lineartexture.wrapS = RepeatWrapping;
47592
47698
  lineartexture.wrapT = RepeatWrapping;
47593
47699
  lineartexture.needsUpdate = true;
47594
47700
  let texture = lineartexture;
47701
+ let renderTargetFinal = linearRenderTarget;
47595
47702
  if (textureType === "color") {
47596
47703
  const gammaInst = await TextureComposer.simpleMesh(
47597
47704
  "CompositQuad",
@@ -47605,17 +47712,21 @@ class MaterialDesc {
47605
47712
  TextureComposer.new(width, height, SRGBColorSpace, RepeatWrapping, noMipmaps);
47606
47713
  TextureComposer.cameraSize(camWidth, camHeight);
47607
47714
  TextureComposer.add(gammaInst);
47608
- texture = TextureComposer.render().texture;
47715
+ renderTargetFinal = TextureComposer.render();
47716
+ this.toDispose.push(renderTargetFinal);
47717
+ texture = renderTargetFinal.texture;
47609
47718
  }
47610
- if (texture !== lineartexture) {
47611
- lineartexture.dispose();
47719
+ if (linearRenderTarget !== renderTargetFinal) {
47720
+ linearRenderTarget.dispose();
47721
+ this.removeFromToDispose(linearRenderTarget);
47612
47722
  }
47723
+ this.resultRenderTarget = renderTargetFinal;
47613
47724
  texture.magFilter = this.resampleMode === ResamplerMode.Default ? LinearFilter : NearestFilter;
47614
47725
  let hasTransparency = false;
47615
47726
  const rbxRenderer = RBXRenderer.getRenderer();
47616
47727
  if (!hasColorLayer && rbxRenderer || FLAGS.RENDERTARGET_TO_CANVASTEXTURE && rbxRenderer) {
47617
47728
  const data = new Uint8Array(width * height * 4);
47618
- await rbxRenderer.readRenderTargetPixelsAsync(renderTarget, 0, 0, width, height, data);
47729
+ await rbxRenderer.readRenderTargetPixelsAsync(renderTargetFinal, 0, 0, width, height, data);
47619
47730
  for (let i = 3; i < data.length; i += 4) {
47620
47731
  if (data[i] < 255) {
47621
47732
  hasTransparency = true;
@@ -47625,6 +47736,7 @@ class MaterialDesc {
47625
47736
  if (FLAGS.RENDERTARGET_TO_CANVASTEXTURE) {
47626
47737
  const ogTexture = texture;
47627
47738
  texture = imageDataToCanvasTexture(data, width, height);
47739
+ this.toDispose.push(texture);
47628
47740
  texture.colorSpace = textureType === "color" ? SRGBColorSpace : NoColorSpace;
47629
47741
  texture.wrapS = ogTexture.wrapS;
47630
47742
  texture.wrapT = ogTexture.wrapT;
@@ -47632,6 +47744,7 @@ class MaterialDesc {
47632
47744
  texture.magFilter = ogTexture.magFilter;
47633
47745
  texture.generateMipmaps = ogTexture.generateMipmaps;
47634
47746
  ogTexture.dispose();
47747
+ this.removeFromToDispose(ogTexture);
47635
47748
  }
47636
47749
  }
47637
47750
  if (!this.transparent) {
@@ -47660,6 +47773,7 @@ class MaterialDesc {
47660
47773
  throw new Error("Failed to get CanvasContext");
47661
47774
  }
47662
47775
  const texture = new CanvasTexture(canvas);
47776
+ this.toDispose.push(texture);
47663
47777
  texture.colorSpace = textureType === "color" ? SRGBColorSpace : NoColorSpace;
47664
47778
  texture.wrapS = RepeatWrapping;
47665
47779
  texture.wrapT = RepeatWrapping;
@@ -47711,21 +47825,21 @@ class MaterialDesc {
47711
47825
  }
47712
47826
  }
47713
47827
  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
- }
47828
+ let hasTransparency = true;
47829
+ if (!this.transparent) {
47830
+ hasTransparency = false;
47831
+ }
47832
+ const textureParams = {
47833
+ colorSpace: textureType === "color" ? SRGBColorSpace : NoColorSpace,
47834
+ wrapS: RepeatWrapping,
47835
+ wrapT: RepeatWrapping,
47836
+ generateMipmaps: this.canHaveMipmaps,
47837
+ //resampling mode
47838
+ magFilter: this.resampleMode === ResamplerMode.Default ? LinearFilter : NearestFilter
47839
+ };
47840
+ const texture = await getManagedTexture(textureUrl, textureParams);
47841
+ this.managedTextures.push({ url: textureUrl, params: textureParams });
47842
+ return texture ? [texture, hasTransparency] : void 0;
47729
47843
  }
47730
47844
  }
47731
47845
  getComposeType(textureType) {
@@ -47742,8 +47856,8 @@ class MaterialDesc {
47742
47856
  }
47743
47857
  }
47744
47858
  if (layer instanceof ColorLayer) {
47745
- hasColorLayer = true;
47746
47859
  if (layer.textureType === textureType) {
47860
+ hasColorLayer = true;
47747
47861
  hasLayerOfType = true;
47748
47862
  }
47749
47863
  }
@@ -48178,6 +48292,10 @@ class MaterialDesc {
48178
48292
  this.addDecals(child.parent, "Normal", true);
48179
48293
  }
48180
48294
  }
48295
+ dispose() {
48296
+ this.resultRenderTarget = void 0;
48297
+ this.clearToDispose();
48298
+ }
48181
48299
  }
48182
48300
  class BasePartWrapperData {
48183
48301
  assemblyNode;
@@ -48289,7 +48407,7 @@ function boneIsChildOf(bone, parentName) {
48289
48407
  }
48290
48408
  return false;
48291
48409
  }
48292
- class SkeletonDesc {
48410
+ class SkeletonDesc extends DisposableDesc {
48293
48411
  renderableDesc;
48294
48412
  meshDesc;
48295
48413
  skeleton;
@@ -48300,6 +48418,7 @@ class SkeletonDesc {
48300
48418
  skeletonHelper;
48301
48419
  frameCount = 0;
48302
48420
  constructor(renderableDesc, meshDesc, scene) {
48421
+ super();
48303
48422
  this.renderableDesc = renderableDesc;
48304
48423
  this.meshDesc = meshDesc;
48305
48424
  const mesh = this.meshDesc.fileMesh;
@@ -48576,14 +48695,14 @@ class SkeletonDesc {
48576
48695
  this.updateMatrixWorld();
48577
48696
  this.frameCount += 1;
48578
48697
  }
48579
- dispose(scene) {
48698
+ dispose() {
48580
48699
  if (this.skeletonHelper) {
48581
- scene.remove(this.skeletonHelper);
48700
+ this.skeletonHelper.removeFromParent();
48582
48701
  this.skeletonHelper.dispose();
48583
48702
  this.skeletonHelper = void 0;
48584
48703
  }
48585
48704
  if (this.rootBone.parent) {
48586
- this.rootBone.parent.remove(this.rootBone);
48705
+ this.rootBone.removeFromParent();
48587
48706
  }
48588
48707
  for (let i = 0; i < this.skeleton.bones.length; i++) {
48589
48708
  const bone = this.skeleton.bones[i];
@@ -48591,6 +48710,7 @@ class SkeletonDesc {
48591
48710
  bone.removeFromParent();
48592
48711
  }
48593
48712
  }
48713
+ this.skeleton.dispose();
48594
48714
  }
48595
48715
  static descNeedsSkeleton(meshDesc) {
48596
48716
  return meshDesc.canHaveSkinning && meshDesc.fileMesh && meshDesc.fileMesh.skinning && meshDesc.fileMesh.skinning.numskinnings > 0;
@@ -48694,32 +48814,10 @@ class ObjectDesc extends RenderDesc {
48694
48814
  this.meshDesc.fromInstance(child);
48695
48815
  this.materialDesc.fromInstance(child);
48696
48816
  }
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) {
48817
+ async compileResults(_renderer, scene) {
48718
48818
  const loadingLabel = this.instance ? this.instance.GetFullName() : "unknown";
48719
48819
  API.Misc.startCurrentlyLoadingAssets(loadingLabel);
48720
48820
  try {
48721
- const originalResult = this.results;
48722
- const originalSkeletonDesc = this.skeletonDesc;
48723
48821
  this.results = void 0;
48724
48822
  this.skeletonDesc = void 0;
48725
48823
  const promises = [
@@ -48756,15 +48854,6 @@ class ObjectDesc extends RenderDesc {
48756
48854
  } else {
48757
48855
  this.meshDesc.fileMesh = void 0;
48758
48856
  }
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
48857
  } finally {
48769
48858
  API.Misc.stopCurrentlyLoadingAssets(loadingLabel);
48770
48859
  }
@@ -48840,6 +48929,17 @@ class ObjectDesc extends RenderDesc {
48840
48929
  }
48841
48930
  return !isBakedDecal && (!isDecal || isFirstDecal);
48842
48931
  }
48932
+ //Used to dispose OLD stuff
48933
+ dispose(renderer) {
48934
+ if (this.results) {
48935
+ for (const result of this.results) {
48936
+ result.removeFromParent();
48937
+ }
48938
+ }
48939
+ if (this.meshDesc) this.meshDesc.dispose(renderer);
48940
+ if (this.materialDesc) this.materialDesc.dispose();
48941
+ if (this.skeletonDesc) this.skeletonDesc.dispose();
48942
+ }
48843
48943
  }
48844
48944
  const __vite_glob_0_4$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
48845
48945
  __proto__: null,
@@ -59819,7 +59919,7 @@ const $05f6997e4b65da14$export$ed4ee5d1e55474a5 = {
59819
59919
  class RBXRendererScene {
59820
59920
  //important scene components
59821
59921
  scene = new Scene();
59822
- camera = new PerspectiveCamera(70, 1 / 1, 0.1, 100);
59922
+ camera = new PerspectiveCamera(70, 1 / 1, 0.1, 1e3);
59823
59923
  controls;
59824
59924
  shouldAnimate = true;
59825
59925
  destroyed = false;
@@ -59967,6 +60067,41 @@ class RBXRendererScene {
59967
60067
  isFullyCompiled() {
59968
60068
  return this.areInstancesCompiled(this.addedInstances);
59969
60069
  }
60070
+ /**
60071
+ * @param instances Array of instances you want to wait to be finished compiling
60072
+ * @param timeoutSeconds Default is 30 seconds
60073
+ * @returns true if successful, false if a RenderDesc failed to compile or timed out
60074
+ */
60075
+ async waitUntilFullyCompiled(instances, timeoutSeconds = 30) {
60076
+ if (this.areInstancesCompiled(instances)) return true;
60077
+ const connections = [];
60078
+ const compiledSuccessfully = await Promise.race([
60079
+ //on fail compilation
60080
+ new Promise((resolve) => {
60081
+ connections.push(this.failedRenderDesc.Connect(() => {
60082
+ resolve(false);
60083
+ }));
60084
+ }),
60085
+ //on success compilation, check if everything is successfull
60086
+ new Promise((resolve) => {
60087
+ connections.push(this.compiledRenderDesc.Connect(() => {
60088
+ if (this.areInstancesCompiled(instances)) {
60089
+ resolve(true);
60090
+ }
60091
+ }));
60092
+ }),
60093
+ //on fail due to timeout
60094
+ new Promise((resolve) => {
60095
+ setTimeout(() => {
60096
+ resolve(false);
60097
+ }, timeoutSeconds * 1e3);
60098
+ })
60099
+ ]);
60100
+ for (const connection of connections) {
60101
+ connection.Disconnect();
60102
+ }
60103
+ return compiledSuccessfully;
60104
+ }
59970
60105
  /**
59971
60106
  * Exports scene as a GLTF or GLB
59972
60107
  * @param name Name of the resulting file if autoDownload is true
@@ -60842,13 +60977,6 @@ class EmitterDesc extends DisposableDesc {
60842
60977
  this.flipbookSizeY = other.flipbookSizeY;
60843
60978
  this.flipbookStartRandom = other.flipbookStartRandom;
60844
60979
  }
60845
- dispose(renderer, scene) {
60846
- const mesh = this.result;
60847
- if (mesh) {
60848
- this.disposeMesh(scene, mesh);
60849
- this.disposeRenderLists(renderer);
60850
- }
60851
- }
60852
60980
  getFlipbookSize() {
60853
60981
  let flipbookSizeX = this.flipbookSizeX;
60854
60982
  let flipbookSizeY = this.flipbookSizeY;
@@ -60874,27 +61002,33 @@ class EmitterDesc extends DisposableDesc {
60874
61002
  }
60875
61003
  return [flipbookSizeX, flipbookSizeY];
60876
61004
  }
60877
- async compileResult(renderer, scene) {
60878
- const originalResult = this.result;
61005
+ async compileResult() {
60879
61006
  const texturePromises = [
60880
- getTexture(this.texture),
60881
- getTexture(this.alphaTexture, NoColorSpace),
60882
- getTexture(this.colorTexture)
61007
+ this.texture ? getManagedTexture(this.texture, { colorSpace: SRGBColorSpace }) : void 0,
61008
+ this.alphaTexture ? getManagedTexture(this.alphaTexture, { colorSpace: NoColorSpace }) : void 0,
61009
+ this.colorTexture ? getManagedTexture(this.colorTexture, { colorSpace: SRGBColorSpace }) : void 0
60883
61010
  ];
61011
+ if (this.texture) this.managedTextures.push({ url: this.texture, params: { colorSpace: SRGBColorSpace } });
61012
+ if (this.alphaTexture) this.managedTextures.push({ url: this.alphaTexture, params: { colorSpace: NoColorSpace } });
61013
+ if (this.colorTexture) this.managedTextures.push({ url: this.colorTexture, params: { colorSpace: SRGBColorSpace } });
60884
61014
  let [mapToUse, alphaMapToUse, colorMapToUse] = await Promise.all(texturePromises);
60885
61015
  if (!mapToUse) {
60886
61016
  mapToUse = new DataTexture(new Uint8Array([0, 0, 0, 0]), 1, 1, RGBAFormat);
60887
61017
  mapToUse.needsUpdate = true;
61018
+ this.toDispose.push(mapToUse);
60888
61019
  }
60889
61020
  if (!alphaMapToUse) {
60890
61021
  alphaMapToUse = new DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, RGBAFormat);
60891
61022
  alphaMapToUse.needsUpdate = true;
61023
+ this.toDispose.push(alphaMapToUse);
60892
61024
  }
60893
61025
  if (!colorMapToUse) {
60894
61026
  colorMapToUse = new DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, RGBAFormat);
60895
61027
  colorMapToUse.needsUpdate = true;
61028
+ this.toDispose.push(colorMapToUse);
60896
61029
  }
60897
61030
  const geometry = new PlaneGeometry(2, 2);
61031
+ this.toDispose.push(geometry);
60898
61032
  this.instanceColorBuffer = new InstancedBufferAttribute(new Float32Array(this.maxCount * 3), 3);
60899
61033
  geometry.setAttribute("instanceColor", this.instanceColorBuffer);
60900
61034
  this.instanceOpacityBuffer = new InstancedBufferAttribute(new Float32Array(this.maxCount), 1);
@@ -60960,14 +61094,12 @@ class EmitterDesc extends DisposableDesc {
60960
61094
  }
60961
61095
  ])
60962
61096
  });
61097
+ this.toDispose.push(material);
60963
61098
  this.resultMaterial = material;
60964
61099
  this.result = new InstancedMesh(geometry, material, this.maxCount);
61100
+ this.toDispose.push(this.result);
60965
61101
  this.result.name = "Particles";
60966
61102
  this.result.frustumCulled = false;
60967
- if (originalResult) {
60968
- this.disposeMesh(scene, originalResult);
60969
- this.disposeRenderLists(renderer);
60970
- }
60971
61103
  return this.result;
60972
61104
  }
60973
61105
  emit(groupDesc, force = false) {
@@ -61089,6 +61221,14 @@ class EmitterDesc extends DisposableDesc {
61089
61221
  this.instanceSeedTimeBuffer.needsUpdate = true;
61090
61222
  this.instanceFlipbookBuffer.needsUpdate = true;
61091
61223
  }
61224
+ dispose(renderer) {
61225
+ const mesh = this.result;
61226
+ if (mesh) {
61227
+ mesh.removeFromParent();
61228
+ }
61229
+ this.clearToDispose();
61230
+ this.disposeRenderLists(renderer);
61231
+ }
61092
61232
  }
61093
61233
  class EmitterGroupDesc extends RenderDesc {
61094
61234
  static classTypes = ["ParticleEmitter", "Sparkles", "Fire", "Smoke"];
@@ -61228,7 +61368,7 @@ class EmitterGroupDesc extends RenderDesc {
61228
61368
  }
61229
61369
  }
61230
61370
  fromParticleEmitter(child) {
61231
- this.emitterDir = child.Prop("EmissionDirection");
61371
+ this.emitterDir = child.PropOrDefault("EmissionDirection", this.emitterDir);
61232
61372
  const emitterDesc = new EmitterDesc(this.renderScene);
61233
61373
  if (child.HasProperty("Lifetime")) emitterDesc.lifetime = child.Prop("Lifetime");
61234
61374
  if (child.HasProperty("Rate")) emitterDesc.rate = child.Prop("Rate");
@@ -61245,7 +61385,7 @@ class EmitterGroupDesc extends RenderDesc {
61245
61385
  if (child.HasProperty("Color")) emitterDesc.color = child.Prop("Color");
61246
61386
  if (child.HasProperty("Texture")) emitterDesc.texture = child.Prop("Texture");
61247
61387
  if (child.HasProperty("Transparency")) emitterDesc.transparency = child.Prop("Transparency");
61248
- if (child.HasProperty("LightEmission")) emitterDesc.lightEmission = child.Prop("LightEmission");
61388
+ emitterDesc.lightEmission = specialClamp(child.PropOrDefault("LightEmission", emitterDesc.lightEmission), 0, 1);
61249
61389
  emitterDesc.blending = emitterDesc.lightEmission === 0 ? EmitterBlendType.Normal : EmitterBlendType.PremultipliedAdditive;
61250
61390
  if (child.HasProperty("LightInfluence")) emitterDesc.lightInfluence = child.Prop("LightInfluence");
61251
61391
  if (child.HasProperty("ZOffset")) emitterDesc.zOffset = child.Prop("ZOffset");
@@ -61381,18 +61521,10 @@ class EmitterGroupDesc extends RenderDesc {
61381
61521
  shader: EmitterShaderType.Smoke
61382
61522
  }));
61383
61523
  }
61384
- dispose(renderer, scene) {
61385
- const meshes = this.results;
61386
- if (meshes) {
61387
- this.disposeMeshes(scene, meshes);
61388
- this.disposeRenderLists(renderer);
61389
- }
61390
- }
61391
61524
  async compileResults(renderer, scene) {
61392
- const originalResults = this.results;
61393
61525
  const resultPromises = [];
61394
61526
  for (const emitterDesc of this.emitterDescs) {
61395
- resultPromises.push(emitterDesc.compileResult(renderer, scene));
61527
+ resultPromises.push(emitterDesc.compileResult());
61396
61528
  }
61397
61529
  this.results = [];
61398
61530
  const compiledResults = await Promise.all(resultPromises);
@@ -61405,10 +61537,6 @@ class EmitterGroupDesc extends RenderDesc {
61405
61537
  return compiledResult;
61406
61538
  }
61407
61539
  }
61408
- if (originalResults) {
61409
- this.disposeMeshes(scene, originalResults);
61410
- this.disposeRenderLists(renderer);
61411
- }
61412
61540
  const startFull = this.renderScene.particlesStartFull || FLAGS.PARTICLES_START_FULL;
61413
61541
  const startFullFramerate = this.renderScene.particlesStartFullFramerate;
61414
61542
  if (startFull) {
@@ -61438,6 +61566,11 @@ class EmitterGroupDesc extends RenderDesc {
61438
61566
  }
61439
61567
  }
61440
61568
  }
61569
+ dispose(renderer) {
61570
+ for (const emitterDesc of this.emitterDescs) {
61571
+ emitterDesc.dispose(renderer);
61572
+ }
61573
+ }
61441
61574
  }
61442
61575
  const __vite_glob_0_2 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
61443
61576
  __proto__: null,
@@ -62172,21 +62305,20 @@ class BeamDesc extends RenderDesc {
62172
62305
  this.segments = child.PropOrDefault("Segments", this.segments);
62173
62306
  if (!FLAGS.BEAMS_ENABLED) this.enabled = false;
62174
62307
  }
62175
- async compileResults(renderer, scene) {
62176
- const originalResults = this.results;
62308
+ async compileResults() {
62177
62309
  this.results = [];
62178
62310
  if (this.enabled) {
62179
62311
  let textureResult = void 0;
62180
62312
  if (this.texture) {
62181
- textureResult = await getTexture(this.texture);
62182
- if (textureResult) {
62183
- textureResult.wrapT = RepeatWrapping;
62184
- }
62313
+ const params = { colorSpace: "srgb", wrapT: RepeatWrapping };
62314
+ textureResult = await getManagedTexture(this.texture, params);
62315
+ this.managedTextures.push({ url: this.texture, params });
62185
62316
  }
62186
62317
  if (!textureResult) {
62187
62318
  textureResult = new DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, RGBAFormat);
62188
62319
  textureResult.colorSpace = SRGBColorSpace;
62189
62320
  textureResult.needsUpdate = true;
62321
+ this.toDispose.push(textureResult);
62190
62322
  }
62191
62323
  const material = new ShaderMaterial({
62192
62324
  side: DoubleSide,
@@ -62215,17 +62347,15 @@ class BeamDesc extends RenderDesc {
62215
62347
  }
62216
62348
  ])
62217
62349
  });
62350
+ this.toDispose.push(material);
62218
62351
  const geometry = new PlaneGeometry(1, 1, this.segments, 1);
62352
+ this.toDispose.push(geometry);
62219
62353
  const colorValues = new Float32Array((this.segments + 1) * 2 * 4).fill(0);
62220
62354
  geometry.setAttribute("color", new BufferAttribute(colorValues, 4));
62221
62355
  const mesh = new Mesh(geometry, material);
62222
62356
  mesh.name = this.instance ? this.instance.PropOrDefault("Name", "Unknown") + "_Beam" : "Unknown_Beam";
62223
62357
  this.results.push(mesh);
62224
62358
  }
62225
- if (originalResults) {
62226
- this.disposeMeshes(scene, originalResults);
62227
- this.disposeRenderLists(renderer);
62228
- }
62229
62359
  this.updateResults();
62230
62360
  return this.results;
62231
62361
  }
@@ -62349,11 +62479,13 @@ class BeamDesc extends RenderDesc {
62349
62479
  }
62350
62480
  this.lastTime = this.time;
62351
62481
  }
62352
- dispose(_renderer, scene) {
62482
+ dispose(renderer) {
62353
62483
  if (!this.results) return;
62354
62484
  for (const result of this.results) {
62355
- scene.remove(result);
62485
+ result.removeFromParent();
62356
62486
  }
62487
+ this.clearToDispose();
62488
+ this.disposeRenderLists(renderer);
62357
62489
  }
62358
62490
  }
62359
62491
  const __vite_glob_0_1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -62601,21 +62733,20 @@ class TrailDesc extends RenderDesc {
62601
62733
  this.faceCamera = child.PropOrDefault("FaceCamera", this.faceCamera);
62602
62734
  if (!FLAGS.BEAMS_ENABLED) this.enabled = false;
62603
62735
  }
62604
- async compileResults(renderer, scene) {
62605
- const originalResults = this.results;
62736
+ async compileResults() {
62606
62737
  this.results = [];
62607
62738
  if (this.enabled) {
62608
62739
  let textureResult = void 0;
62609
62740
  if (this.texture) {
62610
- textureResult = await getTexture(this.texture);
62611
- if (textureResult) {
62612
- textureResult.wrapT = RepeatWrapping;
62613
- }
62741
+ const params = { colorSpace: "srgb", wrapT: RepeatWrapping };
62742
+ textureResult = await getManagedTexture(this.texture, params);
62743
+ this.managedTextures.push({ url: this.texture, params });
62614
62744
  }
62615
62745
  if (!textureResult) {
62616
62746
  textureResult = new DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, RGBAFormat);
62617
62747
  textureResult.colorSpace = SRGBColorSpace;
62618
62748
  textureResult.needsUpdate = true;
62749
+ this.toDispose.push(textureResult);
62619
62750
  }
62620
62751
  const material = new ShaderMaterial({
62621
62752
  side: DoubleSide,
@@ -62644,7 +62775,9 @@ class TrailDesc extends RenderDesc {
62644
62775
  }
62645
62776
  ])
62646
62777
  });
62778
+ this.toDispose.push(material);
62647
62779
  const geometry = new PlaneGeometry(1, 1, this.maxSegments, 1);
62780
+ this.toDispose.push(geometry);
62648
62781
  const colorValues = new Float32Array((this.maxSegments + 1) * 2 * 4).fill(1);
62649
62782
  geometry.setAttribute("color", new BufferAttribute(colorValues, 4));
62650
62783
  const mesh = new Mesh(geometry, material);
@@ -62652,10 +62785,6 @@ class TrailDesc extends RenderDesc {
62652
62785
  mesh.name = this.instance ? this.instance.PropOrDefault("Name", "Unknown") + "_Trail" : "Unknown_Trail";
62653
62786
  this.results.push(mesh);
62654
62787
  }
62655
- if (originalResults) {
62656
- this.disposeMeshes(scene, originalResults);
62657
- this.disposeRenderLists(renderer);
62658
- }
62659
62788
  this.updateResults();
62660
62789
  return this.results;
62661
62790
  }
@@ -62792,11 +62921,13 @@ class TrailDesc extends RenderDesc {
62792
62921
  segment.cframe.Position = add(segment.cframe.Position, vec);
62793
62922
  }
62794
62923
  }
62795
- dispose(_renderer, scene) {
62924
+ dispose(renderer, scene) {
62796
62925
  if (!this.results) return;
62797
62926
  for (const result of this.results) {
62798
62927
  scene.remove(result);
62799
62928
  }
62929
+ this.clearToDispose();
62930
+ this.disposeRenderLists(renderer);
62800
62931
  }
62801
62932
  }
62802
62933
  const __vite_glob_0_5 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
@@ -63418,31 +63549,35 @@ class RBXRenderer {
63418
63549
  renderScene.scene.add(result);
63419
63550
  }
63420
63551
  }
63552
+ static _updateCompiledRenderDesc(oldDesc, newDesc, renderScene, instance) {
63553
+ if (!oldDesc.compiled && !oldDesc.failed) {
63554
+ oldDesc.compiled = true;
63555
+ renderScene.compiledRenderDesc.Fire(instance);
63556
+ }
63557
+ if (!oldDesc.isSame(newDesc)) {
63558
+ oldDesc.fromRenderDesc(newDesc);
63559
+ oldDesc.updateResults();
63560
+ }
63561
+ }
63421
63562
  static _addRenderDesc(instance, auth, DescClass, renderScene) {
63422
63563
  if (!RBXRenderer.renderer) return;
63423
63564
  const oldDesc = renderScene.renderDescs.get(instance);
63424
63565
  const newDesc = new DescClass(renderScene);
63425
63566
  newDesc.fromInstance(instance);
63426
63567
  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
- }
63568
+ RBXRenderer._updateCompiledRenderDesc(oldDesc, newDesc, renderScene, instance);
63435
63569
  } else {
63436
63570
  if (!renderScene.isRenderingMesh.get(instance)) {
63437
- if (oldDesc) newDesc.transferFrom(oldDesc);
63438
- newDesc.results = oldDesc?.results;
63571
+ if (oldDesc && Object.getPrototypeOf(oldDesc).constructor === Object.getPrototypeOf(newDesc).constructor) {
63572
+ newDesc.transferFrom(oldDesc);
63573
+ }
63439
63574
  renderScene.renderDescs.set(instance, newDesc);
63440
63575
  renderScene.isRenderingMesh.set(instance, true);
63441
63576
  newDesc.compileResults(RBXRenderer.renderer, renderScene.scene).then((results) => {
63577
+ if (RBXRenderer.renderer) oldDesc?.dispose(RBXRenderer.renderer, renderScene.scene);
63442
63578
  if (results && !(results instanceof Response)) {
63443
63579
  newDesc.updateResults();
63444
- if (renderScene.renderDescs.get(instance) && RBXRenderer.renderer) {
63445
- oldDesc?.dispose(RBXRenderer.renderer, renderScene.scene);
63580
+ if (renderScene.renderDescs.get(instance) === newDesc && RBXRenderer.renderer) {
63446
63581
  for (const result of results) {
63447
63582
  RBXRenderer._addSkeletonToResult(result, newDesc, renderScene);
63448
63583
  }
@@ -63452,9 +63587,12 @@ class RBXRenderer {
63452
63587
  newDesc.dispose(RBXRenderer.renderer, renderScene.scene);
63453
63588
  }
63454
63589
  } else {
63590
+ if (RBXRenderer.renderer) newDesc.dispose(RBXRenderer.renderer, renderScene.scene);
63455
63591
  newDesc.failed = true;
63456
- renderScene.isRenderingMesh.set(instance, false);
63457
- renderScene.failedRenderDesc.Fire(instance);
63592
+ if (renderScene.renderDescs.get(instance) === newDesc) {
63593
+ renderScene.isRenderingMesh.set(instance, false);
63594
+ renderScene.failedRenderDesc.Fire(instance);
63595
+ }
63458
63596
  warn(false, "Failed to compile mesh", this, results);
63459
63597
  }
63460
63598
  });
@@ -63469,16 +63607,26 @@ class RBXRenderer {
63469
63607
  }));
63470
63608
  }
63471
63609
  }
63472
- /**Adds an instance to the renderer or updates it */
63473
- static addInstance(instance, auth, renderScene = RBXRenderer.firstScene) {
63610
+ /** */
63611
+ /**
63612
+ * Adds an instance to the renderer or updates it, add it again to update it after changes have been made
63613
+ * @param instance The instance that will be updated (the descendants will also update)
63614
+ * @param auth This is here just in case something requires it in the future
63615
+ * @param renderScene The scene the instances will be rendered in. Default RBXRenderer.firstScene
63616
+ * @param includeDescendants If descendants should also have addInstance called on them. Default true
63617
+ * @returns
63618
+ */
63619
+ static addInstance(instance, auth, renderScene = RBXRenderer.firstScene, includeDescendants = true) {
63474
63620
  if (renderScene.destroyed) return;
63475
63621
  const RenderDescType = getRenderDescForInstance(instance);
63476
63622
  if (RenderDescType) {
63477
63623
  if (renderScene.addedInstances.indexOf(instance) < 0) renderScene.addedInstances.push(instance);
63478
63624
  RBXRenderer._addRenderDesc(instance, auth, RenderDescType, renderScene);
63479
63625
  }
63480
- for (const child of instance.GetChildren()) {
63481
- RBXRenderer.addInstance(child, auth, renderScene);
63626
+ if (includeDescendants) {
63627
+ for (const child of instance.GetDescendants()) {
63628
+ RBXRenderer.addInstance(child, auth, renderScene, false);
63629
+ }
63482
63630
  }
63483
63631
  }
63484
63632
  static setRendererSize(width, height) {
@@ -64188,8 +64336,8 @@ function getExtentsForParts(parts, includeTransform) {
64188
64336
  }
64189
64337
  function getExtents(cframe, parts) {
64190
64338
  const inverseCF = cframe.inverse();
64191
- let lowerExtents = new Vector3(0, 0, 0);
64192
- let higherExtents = new Vector3(0, 0, 0);
64339
+ let lowerExtents = new Vector3(1e6, 1e6, 1e6);
64340
+ let higherExtents = new Vector3(-1e6, -1e6, -1e5);
64193
64341
  for (const child of parts) {
64194
64342
  if (child.createWrapper()?.IsA("BasePart")) {
64195
64343
  const partCF = child.Prop("CFrame");
@@ -65070,10 +65218,11 @@ async function renderTargetToCanvas$1(renderTarget) {
65070
65218
  }
65071
65219
  async function imageThumbnailClick(renderScene, width, height, format, options) {
65072
65220
  const resultOptions = {
65073
- quality: 1
65221
+ quality: 1,
65222
+ size: [width, height]
65074
65223
  };
65075
65224
  if (options) Object.assign(resultOptions, options);
65076
- const renderTarget = renderToRenderTarget$1(width, height, renderScene);
65225
+ const renderTarget = renderToRenderTarget$1(resultOptions.size[0], resultOptions.size[1], renderScene);
65077
65226
  const canvas = await renderTargetToCanvas$1(renderTarget);
65078
65227
  renderTarget.dispose();
65079
65228
  if (canvas) {
@@ -65093,8 +65242,24 @@ async function modelThumbnailClick(renderScene, format, options) {
65093
65242
  });
65094
65243
  }
65095
65244
  function getThumbnailCameraCFrame(model, fov2, forceAngle) {
65096
- const thumbnailCamera = model.FindFirstChildOfClass("Camera");
65097
- if (thumbnailCamera) return thumbnailCamera.PropOrDefault("CFrame", new CFrame());
65245
+ const thumbnailCamera = model.FindFirstChild("ThumbnailCamera");
65246
+ if (thumbnailCamera && thumbnailCamera.IsA("Camera")) return thumbnailCamera.PropOrDefault("CFrame", new CFrame());
65247
+ const thumbnailConfiguration = model.FindFirstChild("ThumbnailConfiguration");
65248
+ if (thumbnailConfiguration) {
65249
+ const thumbnailCameraTarget = thumbnailConfiguration.FindFirstChild("ThumbnailCameraTarget");
65250
+ if (thumbnailCameraTarget && thumbnailCameraTarget.IsA("ObjectValue")) {
65251
+ const targetInstance = thumbnailCameraTarget.Prop("Value");
65252
+ if (targetInstance && targetInstance.IsA("BasePart")) {
65253
+ const targetCF = targetInstance.PropOrDefault("CFrame", new CFrame());
65254
+ const thumbnailCameraValue = thumbnailConfiguration.FindFirstChild("ThumbnailCameraValue");
65255
+ if (thumbnailCameraValue && thumbnailCameraValue.IsA("CFrameValue")) {
65256
+ const cf = thumbnailCameraValue.PropOrDefault("Value", new CFrame());
65257
+ const resultCF = targetCF.multiply(cf);
65258
+ return resultCF;
65259
+ }
65260
+ }
65261
+ }
65262
+ }
65098
65263
  let rootPart = model.PropOrDefault("PrimaryPart", void 0);
65099
65264
  if (!rootPart) rootPart = model.FindFirstChildOfClass("Part");
65100
65265
  if (!rootPart) rootPart = model.FindFirstChildOfClass("MeshPart");
@@ -65126,6 +65291,56 @@ function getThumbnailCameraCFrame(model, fov2, forceAngle) {
65126
65291
  zoomExtents(cameraCF, rootPartCF, extentsSize, fov2, 1);
65127
65292
  return cameraCF;
65128
65293
  }
65294
+ function getThumbnailCamera(model) {
65295
+ const thumbnailCamera = model.FindFirstChild("ThumbnailCamera");
65296
+ if (thumbnailCamera && thumbnailCamera.IsA("Camera")) return thumbnailCamera;
65297
+ const camera = new Instance("Camera");
65298
+ const thumbnailConfiguration = model.FindFirstChild("ThumbnailConfiguration");
65299
+ if (thumbnailConfiguration) {
65300
+ const thumbnailCameraTarget = thumbnailConfiguration.FindFirstChild("ThumbnailCameraTarget");
65301
+ if (thumbnailCameraTarget && thumbnailCameraTarget.IsA("ObjectValue")) {
65302
+ const targetInstance = thumbnailCameraTarget.Prop("Value");
65303
+ if (targetInstance && targetInstance.IsA("BasePart")) {
65304
+ const targetCF = targetInstance.PropOrDefault("CFrame", new CFrame());
65305
+ const thumbnailCameraValue = thumbnailConfiguration.FindFirstChild("ThumbnailCameraValue");
65306
+ if (thumbnailCameraValue && thumbnailCameraValue.IsA("CFrameValue")) {
65307
+ const cf = thumbnailCameraValue.PropOrDefault("Value", new CFrame());
65308
+ const resultCF = targetCF.multiply(cf);
65309
+ camera.setProperty("FieldOfView", 70);
65310
+ camera.setProperty("CFrame", resultCF);
65311
+ return camera;
65312
+ }
65313
+ }
65314
+ }
65315
+ }
65316
+ let rootPart = model.PropOrDefault("PrimaryPart", void 0);
65317
+ if (!rootPart) rootPart = model.FindFirstChildOfClass("Part");
65318
+ if (!rootPart) rootPart = model.FindFirstChildOfClass("MeshPart");
65319
+ if (!rootPart) return camera;
65320
+ const rootPartCF = rootPart.PropOrDefault("CFrame", new CFrame()).clone();
65321
+ const worldExtents = getExtentsWorld(model);
65322
+ if (!worldExtents) return camera;
65323
+ const extentsSize = worldExtents[1].minus(worldExtents[0]);
65324
+ rootPartCF.Position = getExtentsCenter(worldExtents).toVec3();
65325
+ let lookVector = rootPartCF.lookVector();
65326
+ if (Math.abs(lookVector[1]) > 0.95) {
65327
+ lookVector = [0, 0, -1];
65328
+ } else {
65329
+ lookVector[1] = 0;
65330
+ lookVector = normalize(lookVector);
65331
+ }
65332
+ let lookCF = CFrame.lookAt([0, 0, 0], lookVector);
65333
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(0, 0, rad(45)));
65334
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(rad(35), 0, 0));
65335
+ lookCF = lookCF.multiply(CFrame.fromEulerAngles(0, 0, 0));
65336
+ lookVector = lookCF.lookVector();
65337
+ lookCF.Position = add(rootPartCF.Position, multiply([10, 10, 10], lookVector));
65338
+ lookCF = CFrame.lookAt(lookCF.Position, rootPartCF.Position);
65339
+ const cameraCF = lookCF.clone();
65340
+ zoomExtents(cameraCF, rootPartCF, extentsSize, 70, 1);
65341
+ camera.setProperty("CFrame", cameraCF);
65342
+ return camera;
65343
+ }
65129
65344
  function setupThumbnailScene(renderScene) {
65130
65345
  renderScene.particlesStartFull = 4;
65131
65346
  renderScene.particlesStartFullFramerate = 20;
@@ -65214,6 +65429,135 @@ async function generateOutfitModelThumbnail(auth, outfitModel, options) {
65214
65429
  Object.assign(defaultOptions, options);
65215
65430
  return generateOutfitThumbnail(auth, outfitModel, defaultOptions.size, defaultOptions.type, defaultOptions.quality, defaultOptions.gltfAutoDownload, defaultOptions.includeAnimations);
65216
65431
  }
65432
+ function getViewExtents(camera, positions, width, height) {
65433
+ const minExtents = new Vector2(1e6, 1e6);
65434
+ const maxExtents = new Vector2(-1e6, -1e6);
65435
+ for (const pos of positions) {
65436
+ const projPos = new Vector3$1(...pos.toVec3()).project(camera);
65437
+ const x = (projPos.x / 2 + 0.5) * width;
65438
+ const y = (-projPos.y / 2 + 0.5) * height;
65439
+ if (x < minExtents.X) minExtents.X = x;
65440
+ if (x > maxExtents.X) maxExtents.X = x;
65441
+ if (y < minExtents.Y) minExtents.Y = y;
65442
+ if (y > maxExtents.Y) maxExtents.Y = y;
65443
+ }
65444
+ minExtents.X = Math.max(0, minExtents.X);
65445
+ minExtents.Y = Math.max(0, minExtents.Y);
65446
+ maxExtents.X = Math.min(width, maxExtents.X);
65447
+ maxExtents.Y = Math.min(height, maxExtents.Y);
65448
+ return [minExtents, maxExtents];
65449
+ }
65450
+ function getModelViewExtents(model, camera, width, height) {
65451
+ const worldExtents = getExtentsWorld(model);
65452
+ const corners = [
65453
+ new Vector3(worldExtents[0].X, worldExtents[0].Y, worldExtents[0].Z),
65454
+ new Vector3(worldExtents[0].X, worldExtents[0].Y, worldExtents[1].Z),
65455
+ new Vector3(worldExtents[0].X, worldExtents[1].Y, worldExtents[0].Z),
65456
+ new Vector3(worldExtents[0].X, worldExtents[1].Y, worldExtents[1].Z),
65457
+ new Vector3(worldExtents[1].X, worldExtents[0].Y, worldExtents[0].Z),
65458
+ new Vector3(worldExtents[1].X, worldExtents[0].Y, worldExtents[1].Z),
65459
+ new Vector3(worldExtents[1].X, worldExtents[1].Y, worldExtents[0].Z),
65460
+ new Vector3(worldExtents[1].X, worldExtents[1].Y, worldExtents[1].Z)
65461
+ ];
65462
+ return getViewExtents(camera, corners, width, height);
65463
+ }
65464
+ function cropCameraToViewExtents(camera, viewExtents, width, height, keepAspectRatio = true) {
65465
+ const blx = viewExtents[0].X;
65466
+ const bly = viewExtents[0].Y;
65467
+ const bhx = viewExtents[1].X;
65468
+ const bhy = viewExtents[1].Y;
65469
+ const xDiff = bhx - blx;
65470
+ const yDiff = bhy - bly;
65471
+ const cx = blx + xDiff / 2;
65472
+ const cy = bly + yDiff / 2;
65473
+ const scaleW = xDiff / width;
65474
+ const scaleH = yDiff / height;
65475
+ const maxScale = Math.max(scaleW, scaleH);
65476
+ const cropWidth = keepAspectRatio ? width * maxScale : xDiff;
65477
+ const cropHeight = keepAspectRatio ? height * maxScale : yDiff;
65478
+ const flx = cx - cropWidth / 2;
65479
+ const fly = cy - cropHeight / 2;
65480
+ const x = flx;
65481
+ const y = fly;
65482
+ camera.setViewOffset(
65483
+ width,
65484
+ height,
65485
+ x,
65486
+ y,
65487
+ cropWidth,
65488
+ cropHeight
65489
+ );
65490
+ return cropWidth / cropHeight;
65491
+ }
65492
+ function cropForModel(model, renderScene, width, height, resizeToRemoveUnusedSpace = false) {
65493
+ const viewExtents = getModelViewExtents(model, renderScene.camera, width, height);
65494
+ const targetAspectRatio = cropCameraToViewExtents(renderScene.camera, viewExtents, width, height, !resizeToRemoveUnusedSpace);
65495
+ renderScene.camera.updateProjectionMatrix();
65496
+ let newHeight = height;
65497
+ let newWidth = width;
65498
+ if (resizeToRemoveUnusedSpace) {
65499
+ newWidth = width * targetAspectRatio;
65500
+ if (newWidth > width) {
65501
+ newWidth = width;
65502
+ newHeight = height / targetAspectRatio;
65503
+ }
65504
+ }
65505
+ return [Math.ceil(newWidth), Math.ceil(newHeight)];
65506
+ }
65507
+ function createThumbnailScene() {
65508
+ const renderScene = RBXRenderer.addScene(false);
65509
+ renderScene.isForRenderTarget = true;
65510
+ setupThumbnailScene(renderScene);
65511
+ return renderScene;
65512
+ }
65513
+ async function generateAccessoryThumbnail(auth, id, type, imageOptions, isAccessoryCamera = false) {
65514
+ let renderSceneToDestroy = void 0;
65515
+ const instancesToDestroy = [];
65516
+ const cleanup = () => {
65517
+ if (renderSceneToDestroy) renderSceneToDestroy.destroy();
65518
+ for (const instance of instancesToDestroy) {
65519
+ instance.Destroy();
65520
+ }
65521
+ return void 0;
65522
+ };
65523
+ const resultOptions = {
65524
+ quality: 1,
65525
+ size: [420, 420]
65526
+ };
65527
+ if (imageOptions) Object.assign(resultOptions, imageOptions);
65528
+ const renderScene = createThumbnailScene();
65529
+ renderSceneToDestroy = renderScene;
65530
+ const rbx = await API.Asset.GetRBX(`rbxassetid://${id}`, { "Roblox-AssetFormat": "avatar_meshpart_accessory" });
65531
+ if (rbx instanceof Response) return cleanup();
65532
+ const root = rbx.generateTree();
65533
+ instancesToDestroy.push(root);
65534
+ const accessory = root.FindFirstChildOfClass("Accessory");
65535
+ if (!accessory) return cleanup();
65536
+ let camera = void 0;
65537
+ if (isAccessoryCamera) {
65538
+ camera = new Instance("Camera");
65539
+ setupAccessoryCamera(root, camera);
65540
+ } else {
65541
+ camera = getThumbnailCamera(accessory);
65542
+ }
65543
+ instancesToDestroy.push(camera);
65544
+ RBXRenderer.setCameraCFrame(camera.PropOrDefault("CFrame", new CFrame()), renderScene);
65545
+ RBXRenderer.setCameraFov(camera.PropOrDefault("FieldOfView", 70), renderScene);
65546
+ renderScene.camera.aspect = resultOptions.size[0] / resultOptions.size[1];
65547
+ renderScene.camera.updateProjectionMatrix();
65548
+ let [newWidth, newHeight] = [resultOptions.size[0], resultOptions.size[1]];
65549
+ if (!isAccessoryCamera) {
65550
+ [newWidth, newHeight] = cropForModel(accessory, renderScene, resultOptions.size[0], resultOptions.size[1]);
65551
+ }
65552
+ RBXRenderer.addInstance(accessory, auth, renderScene);
65553
+ const compiledSuccessfully = await renderScene.waitUntilFullyCompiled([accessory, ...accessory.GetChildrenDangerous()]);
65554
+ if (!compiledSuccessfully) return cleanup();
65555
+ const result = type === "gltf" || type === "glb" ? await modelThumbnailClick(renderScene, type) : await imageThumbnailClick(renderScene, newWidth, newHeight, type, {
65556
+ quality: resultOptions.quality
65557
+ });
65558
+ cleanup();
65559
+ return result;
65560
+ }
65217
65561
  async function runTests() {
65218
65562
  const auth = new Authentication();
65219
65563
  const testModel = await API.Asset.GetRBX(FLAGS.AUTOTEST_MODEL);
@@ -65394,6 +65738,7 @@ function exposeThumbnailGenerator() {
65394
65738
  globalThis.generateModelThumbnail = generateModelThumbnail;
65395
65739
  globalThis.setupThumbnailScene = setupThumbnailScene;
65396
65740
  globalThis.getThumbnailCameraCFrame = getThumbnailCameraCFrame;
65741
+ globalThis.generateAccessoryThumbnail = generateAccessoryThumbnail;
65397
65742
  }
65398
65743
  function exposeTests() {
65399
65744
  globalThis.runTests = runTests;
@@ -65593,7 +65938,10 @@ export {
65593
65938
  closestPointTriangle,
65594
65939
  createContentMap,
65595
65940
  createThumbnailCamera,
65941
+ createThumbnailScene,
65596
65942
  createWeightsForMeshChunked,
65943
+ cropCameraToViewExtents,
65944
+ cropForModel,
65597
65945
  cross,
65598
65946
  defaultPantAssetIds,
65599
65947
  defaultPantTemplateAssetIds,
@@ -65635,6 +65983,7 @@ export {
65635
65983
  getFullBodyCameraCFrame,
65636
65984
  getHeadExtents,
65637
65985
  getHeadshotCameraCFrame,
65986
+ getModelViewExtents,
65638
65987
  getOffsetArray,
65639
65988
  getOriginalAttachmentOrientation,
65640
65989
  getOriginalAttachmentPosition,
@@ -65643,9 +65992,11 @@ export {
65643
65992
  getPartsInAssembly_Generate,
65644
65993
  getRandomBetweenInclusive,
65645
65994
  getRootAssemblyPart_Generate,
65995
+ getThumbnailCamera,
65646
65996
  getThumbnailCameraCFrame,
65647
65997
  getUVtoIndexMap,
65648
65998
  getUVtoIndicesMap,
65999
+ getViewExtents,
65649
66000
  getWorkerOnMessage,
65650
66001
  hasSameVal,
65651
66002
  hasSameValFloat,
@@ -65689,6 +66040,7 @@ export {
65689
66040
  rotationMatrixToEulerAngles,
65690
66041
  saveByteArray,
65691
66042
  scaleMesh,
66043
+ setCacheFootprintPreset,
65692
66044
  setupAccessoryCamera,
65693
66045
  setupBodyPartCamera,
65694
66046
  setupCamera,