@galacean/effects-core 2.0.0-alpha.8 → 2.0.0-alpha.9

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.
@@ -1,81 +1,7 @@
1
- import * as spec from '@galacean/effects-specification';
2
1
  import { Downloader } from './downloader';
3
- import type { Scene } from './scene';
2
+ import type { Scene, SceneLoadOptions, SceneType } from './scene';
4
3
  import type { Disposable } from './utils';
5
4
  import type { Renderer } from './render';
6
- /**
7
- * 场景加载参数
8
- */
9
- export interface SceneLoadOptions {
10
- /**
11
- * 动态数据的参数
12
- * key 是 JSON 中配置的字段名
13
- * value 是要使用的值,图片使用 url 链接
14
- * 图片链接可以使用数组传递,如果第一个加载失败,将尝试使用第二个地址
15
- *
16
- * @example
17
- * ``` ts
18
- * {
19
- * variables: {
20
- * bg: ['url','fallback_url'], // 如果两个图片都失败,将会触发加载失败
21
- * fg: 'url' // 如果图片加载失败,将会触发加载失败,
22
- * amount: 88.8,
23
- * name: 'abc'
24
- * }
25
- * }
26
- * ```
27
- */
28
- variables?: Record<string, number | string | string[]>;
29
- /**
30
- * 是否使用压缩纹理
31
- */
32
- useCompressedTexture?: boolean;
33
- /**
34
- * 渲染分级。
35
- * 分级之后,只会加载当前渲染等级的资源。
36
- * 当渲染等级被设置为 B 后,player 的 fps 会降到 30 帧
37
- * @default 's'
38
- */
39
- renderLevel?: spec.RenderLevel;
40
- /**
41
- * 资源加载超时,时间单位秒
42
- * @default 10s
43
- */
44
- timeout?: number;
45
- /***
46
- * 用于给 plugin 的加载数据
47
- * key/value 的内容由 plugin 自己实现
48
- */
49
- pluginData?: Record<string, any>;
50
- /**
51
- * 场景加载时的环境(加载后把 env 结果写入 scene)
52
- * @default '' - 编辑器中为 'editor'
53
- */
54
- env?: string;
55
- /**
56
- * 加载后是否自动播放
57
- * @default true
58
- */
59
- autoplay?: boolean;
60
- /**
61
- * 合成播放完成后是否需要再使用,是的话生命周期结束后不会 `dispose`
62
- * @default false
63
- */
64
- reusable?: boolean;
65
- /**
66
- * 播放速度,当速度为负数时,合成倒播
67
- */
68
- speed?: number;
69
- }
70
- /**
71
- * 接受用于加载的数据类型
72
- */
73
- export type SceneType = string | Scene | Record<string, unknown>;
74
- export type SceneWithOptionsType = {
75
- scene: SceneType;
76
- options: SceneLoadOptions;
77
- };
78
- export type SceneLoadType = SceneType | SceneWithOptionsType;
79
5
  /**
80
6
  * 资源管理器
81
7
  * 用于加载和动效中所有的资源文件,包括图片、插件、图层粒子数据等
@@ -0,0 +1,10 @@
1
+ declare class CanvasPool {
2
+ readonly elements: HTMLCanvasElement[];
3
+ constructor();
4
+ dispose(): void;
5
+ getCanvas(): HTMLCanvasElement;
6
+ saveCanvas(canvas: HTMLCanvasElement): void;
7
+ }
8
+ export declare const canvasPool: CanvasPool;
9
+ export declare function getDefaultTemplateCanvasPool(): CanvasPool;
10
+ export {};
@@ -7,13 +7,12 @@ import type { PluginSystem } from './plugin-system';
7
7
  import type { EventSystem, Region } from './plugins';
8
8
  import type { MeshRendererOptions, Renderer } from './render';
9
9
  import { RenderFrame } from './render';
10
- import type { Scene } from './scene';
10
+ import type { Scene, SceneType } from './scene';
11
11
  import type { Texture } from './texture';
12
12
  import { Transform } from './transform';
13
13
  import type { Disposable, LostHandler } from './utils';
14
14
  import type { VFXItemContent, VFXItemProps } from './vfx-item';
15
15
  import { VFXItem } from './vfx-item';
16
- import type { SceneType } from './asset-manager';
17
16
  export interface CompositionStatistic {
18
17
  loadTime: number;
19
18
  loadStart: number;
@@ -239,6 +238,12 @@ export declare class Composition implements Disposable, LostHandler {
239
238
  * @param speed - 速度
240
239
  */
241
240
  setSpeed(speed: number): void;
241
+ /**
242
+ * 设置合成的可见性
243
+ * @since 2.0.0
244
+ * @param visible - 是否可见
245
+ */
246
+ setVisible(visible: boolean): void;
242
247
  /**
243
248
  * 获取合成的动画速度
244
249
  * @returns
package/dist/index.d.ts CHANGED
@@ -22,7 +22,6 @@ export * from './plugin-system';
22
22
  export * from './plugins';
23
23
  export * from './render';
24
24
  export * from './scene';
25
- export * from './semantic-map';
26
25
  export * from './shader';
27
26
  export * from './shape';
28
27
  export * from './template-image';
@@ -32,3 +31,4 @@ export * from './ticker';
32
31
  export * from './transform';
33
32
  export * from './utils';
34
33
  export * from './vfx-item';
34
+ export * from './canvas-pool';
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * Description: Galacean Effects runtime core for the web
4
4
  * Author: Ant Group CO., Ltd.
5
5
  * Contributors: 燃然,飂兮,十弦,云垣,茂安,意绮
6
- * Version: v2.0.0-alpha.8
6
+ * Version: v2.0.0-alpha.9
7
7
  */
8
8
 
9
9
  'use strict';
@@ -8991,6 +8991,22 @@ let seed$8 = 1;
8991
8991
  /**
8992
8992
  * Texture 抽象类
8993
8993
  */ class Texture extends EffectsObject {
8994
+ /**
8995
+ * 通过 URL 创建 Texture 对象。
8996
+ * @param url - 要创建的 Texture URL
8997
+ * @since 2.0.0
8998
+ */ static fromImage(url, engine) {
8999
+ return _async_to_generator(function*() {
9000
+ const image = yield loadImage(url);
9001
+ const texture = Texture.create(engine, {
9002
+ sourceType: exports.TextureSourceType.image,
9003
+ image,
9004
+ id: generateGUID$1()
9005
+ });
9006
+ texture.initialize();
9007
+ return texture;
9008
+ })();
9009
+ }
8994
9010
  get isDestroyed() {
8995
9011
  return this.destroyed;
8996
9012
  }
@@ -9789,14 +9805,10 @@ let seed$6 = 1;
9789
9805
  if (!this.getVisible()) {
9790
9806
  return;
9791
9807
  }
9792
- const material = this.material;
9793
- const geo = this.geometry;
9794
9808
  if (renderer.renderingData.currentFrame.globalUniforms) {
9795
9809
  renderer.setGlobalMatrix('effects_ObjectToWorld', this.worldMatrix);
9796
9810
  }
9797
- // 执行 Geometry 的数据刷新
9798
- geo.flush();
9799
- renderer.drawGeometry(geo, material);
9811
+ renderer.drawGeometry(this.geometry, this.material);
9800
9812
  }
9801
9813
  /**
9802
9814
  * 获取当前 Mesh 的第一个 geometry。
@@ -12739,6 +12751,23 @@ class SpriteComponent extends RendererComponent {
12739
12751
  */ getVisible() {
12740
12752
  return this.visible;
12741
12753
  }
12754
+ /**
12755
+ * 设置当前图层的颜色
12756
+ * > Tips: 透明度也属于颜色的一部分,当有透明度/颜色 K 帧变化时,该 API 会失效
12757
+ * @since 2.0.0
12758
+ * @param color - 颜色值
12759
+ */ setColor(color) {
12760
+ this.color = color;
12761
+ this.material.setVector4('_Color', new Vector4().setFromArray(color));
12762
+ }
12763
+ /**
12764
+ * 设置当前 Mesh 的纹理
12765
+ * @since 2.0.0
12766
+ * @param texture - 纹理对象
12767
+ */ setTexture(texture) {
12768
+ this.renderer.texture = texture;
12769
+ this.material.setTexture('uSampler0', texture);
12770
+ }
12742
12771
  render(renderer) {
12743
12772
  if (!this.getVisible()) {
12744
12773
  return;
@@ -12749,8 +12778,6 @@ class SpriteComponent extends RendererComponent {
12749
12778
  renderer.setGlobalMatrix('effects_ObjectToWorld', this.transform.getWorldMatrix());
12750
12779
  }
12751
12780
  this.material.setVector2('_Size', this.transform.size);
12752
- // 执行 Geometry 的数据刷新
12753
- geo.flush();
12754
12781
  renderer.drawGeometry(geo, material);
12755
12782
  }
12756
12783
  start() {
@@ -13170,7 +13197,7 @@ SpriteComponent = __decorate([
13170
13197
 
13171
13198
  const RUNTIME_ENV = 'runtime_env';
13172
13199
  const RENDER_PREFER_LOOKUP_TEXTURE = 'lookup_texture';
13173
- // 数据模板使用 offscreen canvas 绘制
13200
+ // 文本元素使用 offscreen canvas 绘制
13174
13201
  const TEMPLATE_USE_OFFSCREEN_CANVAS = 'offscreen_canvas';
13175
13202
  // 后处理配置相关
13176
13203
  const POST_PROCESS_SETTINGS = 'post_process_settings';
@@ -16950,21 +16977,14 @@ class TextStyle {
16950
16977
  }
16951
16978
  }
16952
16979
 
16953
- const DEFAULT_FONTS = [
16954
- 'serif',
16955
- 'sans-serif',
16956
- 'monospace',
16957
- 'courier'
16958
- ];
16959
16980
  class CanvasPool {
16960
16981
  dispose() {
16961
16982
  this.elements.forEach((e)=>e.remove());
16962
- // @ts-expect-error
16963
- this.elements = [];
16983
+ // clearing the array
16984
+ this.elements.length = 0;
16964
16985
  }
16965
16986
  getCanvas() {
16966
- if (this.elements.length) {
16967
- // @ts-expect-error
16987
+ if (this.elements.length !== 0) {
16968
16988
  return this.elements.shift();
16969
16989
  }
16970
16990
  if (getConfig(TEMPLATE_USE_OFFSCREEN_CANVAS)) {
@@ -16979,12 +16999,13 @@ class CanvasPool {
16979
16999
  return defCanvas;
16980
17000
  }
16981
17001
  }
16982
- saveCanvas(cvs) {
16983
- cvs.width = cvs.height = 1;
17002
+ saveCanvas(canvas) {
17003
+ canvas.width = 1;
17004
+ canvas.height = 1;
16984
17005
  if (this.elements.length < 3) {
16985
- addItem(this.elements, cvs);
17006
+ addItem(this.elements, canvas);
16986
17007
  } else {
16987
- cvs.remove();
17008
+ canvas.remove();
16988
17009
  }
16989
17010
  }
16990
17011
  constructor(){
@@ -16995,62 +17016,13 @@ const canvasPool = new CanvasPool();
16995
17016
  function getDefaultTemplateCanvasPool() {
16996
17017
  return canvasPool;
16997
17018
  }
16998
- function getBackgroundImage(template, variables) {
16999
- let templateBackground;
17000
- var _template_background;
17001
- const { name, url } = (_template_background = template == null ? void 0 : template.background) != null ? _template_background : {};
17002
- if (name) {
17003
- if (variables && variables[name]) {
17004
- templateBackground = variables[name];
17005
- } else if (url) {
17006
- templateBackground = url;
17007
- }
17008
- }
17009
- return templateBackground;
17010
- }
17011
- function drawImageByTemplate(image, template, variables) {
17012
- return _drawImageByTemplate.apply(this, arguments);
17013
- }
17014
- function _drawImageByTemplate() {
17015
- _drawImageByTemplate = _async_to_generator(function*(image, template, variables) {
17016
- if (!image) {
17017
- throw Error('image not provided');
17018
- }
17019
- if (!template) {
17020
- return image;
17021
- }
17022
- let drawImage = image;
17023
- // 获取动态换图的图片对象或 url 地址
17024
- const templateBackground = getBackgroundImage(template, variables);
17025
- if (templateBackground && templateBackground !== image.src) {
17026
- drawImage = isString(templateBackground) ? yield loadImage(templateBackground) : templateBackground;
17027
- }
17028
- return drawImage;
17029
- });
17030
- return _drawImageByTemplate.apply(this, arguments);
17031
- }
17032
- /**
17033
- * @param url
17034
- * @param template
17035
- * @param variables
17036
- * @param options
17037
- * @returns
17038
- */ function combineImageTemplate(url, template, variables) {
17039
- return _combineImageTemplate.apply(this, arguments);
17040
- }
17041
- function _combineImageTemplate() {
17042
- _combineImageTemplate = _async_to_generator(function*(url, template, variables) {
17043
- let image;
17044
- if (typeof url === 'string') {
17045
- image = yield loadImage(url);
17046
- } else {
17047
- image = url;
17048
- }
17049
- return drawImageByTemplate(image, template, variables);
17050
- });
17051
- return _combineImageTemplate.apply(this, arguments);
17052
- }
17053
17019
 
17020
+ const DEFAULT_FONTS = [
17021
+ 'serif',
17022
+ 'sans-serif',
17023
+ 'monospace',
17024
+ 'courier'
17025
+ ];
17054
17026
  class TextComponent extends SpriteComponent {
17055
17027
  /**
17056
17028
  * 设置字号大小
@@ -17400,14 +17372,10 @@ class EffectComponent extends RendererComponent {
17400
17372
  this.item.getHitTestParams = this.getHitTestParams;
17401
17373
  }
17402
17374
  render(renderer) {
17403
- const material = this.material;
17404
- const geo = this.geometry;
17405
17375
  if (renderer.renderingData.currentFrame.globalUniforms) {
17406
17376
  renderer.setGlobalMatrix('effects_ObjectToWorld', this.transform.getWorldMatrix());
17407
17377
  }
17408
- // 执行 Geometry 的数据刷新
17409
- geo.flush();
17410
- renderer.drawGeometry(geo, material);
17378
+ renderer.drawGeometry(this.geometry, this.material);
17411
17379
  }
17412
17380
  /**
17413
17381
  * 获取当前 Mesh 的可见性。
@@ -20205,10 +20173,64 @@ function passRenderLevel(l, renderLevel) {
20205
20173
  return false;
20206
20174
  }
20207
20175
 
20208
- function isScene(scene) {
20176
+ function isSceneJSON(scene) {
20209
20177
  // TODO: 判断不太优雅,后期试情况优化
20210
20178
  return isObject(scene) && 'jsonScene' in scene;
20211
20179
  }
20180
+ function isSceneURL(scene) {
20181
+ return isObject(scene) && 'url' in scene;
20182
+ }
20183
+ function isSceneWithOptions(scene) {
20184
+ // TODO: 判断不太优雅,后期试情况优化
20185
+ return isObject(scene) && 'options' in scene;
20186
+ }
20187
+
20188
+ function getBackgroundImage(template, variables) {
20189
+ let templateBackground;
20190
+ var _template_background;
20191
+ const { name, url } = (_template_background = template == null ? void 0 : template.background) != null ? _template_background : {};
20192
+ if (name) {
20193
+ if (variables && variables[name]) {
20194
+ templateBackground = variables[name];
20195
+ } else if (url) {
20196
+ templateBackground = url;
20197
+ }
20198
+ }
20199
+ return templateBackground;
20200
+ }
20201
+ /**
20202
+ * @param url
20203
+ * @param template
20204
+ * @param variables
20205
+ * @param options
20206
+ * @returns
20207
+ */ function combineImageTemplate(url, template, variables) {
20208
+ return _combineImageTemplate.apply(this, arguments);
20209
+ }
20210
+ function _combineImageTemplate() {
20211
+ _combineImageTemplate = _async_to_generator(function*(url, template, variables) {
20212
+ let image;
20213
+ if (typeof url === 'string') {
20214
+ image = yield loadImage(url);
20215
+ } else {
20216
+ image = url;
20217
+ }
20218
+ if (!image) {
20219
+ throw new Error('image not provided.');
20220
+ }
20221
+ if (!template) {
20222
+ return image;
20223
+ }
20224
+ let drawImage = image;
20225
+ // 获取动态换图的图片对象或 url 地址
20226
+ const templateBackground = getBackgroundImage(template, variables);
20227
+ if (templateBackground && isString(templateBackground) && templateBackground !== image.src) {
20228
+ drawImage = isString(templateBackground) ? yield loadImage(templateBackground) : templateBackground;
20229
+ }
20230
+ return drawImage;
20231
+ });
20232
+ return _combineImageTemplate.apply(this, arguments);
20233
+ }
20212
20234
 
20213
20235
  let seed = 1;
20214
20236
  /**
@@ -20225,22 +20247,19 @@ let seed = 1;
20225
20247
  }
20226
20248
  /**
20227
20249
  * 根据用户传入的参数修改场景数据
20228
- */ updateSceneData(compositions) {
20250
+ */ updateSceneData(items) {
20229
20251
  const variables = this.options.variables;
20230
- if (!variables || Object.keys(variables).length <= 0) {
20231
- return compositions;
20232
- }
20233
- compositions.forEach((composition)=>{
20234
- composition.items.forEach((item)=>{
20235
- if (item.type === ItemType$1.text) {
20236
- const textVariable = variables[item.name];
20237
- if (textVariable) {
20238
- item.content.options.text = textVariable;
20239
- }
20252
+ if (!variables || Object.keys(variables).length === 0) {
20253
+ return;
20254
+ }
20255
+ items.forEach((item)=>{
20256
+ if (item.type === ItemType$1.text) {
20257
+ const textVariable = variables[item.name];
20258
+ if (textVariable) {
20259
+ item.content.options.text = textVariable;
20240
20260
  }
20241
- });
20261
+ }
20242
20262
  });
20243
- return compositions;
20244
20263
  }
20245
20264
  /**
20246
20265
  * 场景创建,通过 json 创建出场景对象,并进行提前编译等工作
@@ -20268,7 +20287,7 @@ let seed = 1;
20268
20287
  cancelLoading = true;
20269
20288
  _this.removeTimer(loadTimer);
20270
20289
  const totalTime = performance.now() - startTime;
20271
- reject(`Load time out: totalTime: ${totalTime.toFixed(4)}ms ${timeInfos.join(' ')}, url: ${assetUrl}`);
20290
+ reject(new Error(`Load time out: totalTime: ${totalTime.toFixed(4)}ms ${timeInfos.join(' ')}, url: ${assetUrl}`));
20272
20291
  }, _this.timeout * 1000);
20273
20292
  _this.timers.push(loadTimer);
20274
20293
  });
@@ -20280,10 +20299,10 @@ let seed = 1;
20280
20299
  timeInfos.push(`[${label}: ${(performance.now() - st).toFixed(2)}]`);
20281
20300
  return result;
20282
20301
  } catch (e) {
20283
- throw new Error(`load error in ${label}, ${e}`);
20302
+ throw new Error(`Load error in ${label}, ${e}`);
20284
20303
  }
20285
20304
  }
20286
- throw new Error('load canceled.');
20305
+ throw new Error('Load canceled.');
20287
20306
  });
20288
20307
  const loadResourcePromise = /*#__PURE__*/ _async_to_generator(function*() {
20289
20308
  let scene;
@@ -20298,7 +20317,7 @@ let seed = 1;
20298
20317
  _this.baseUrl = url;
20299
20318
  rawJSON = yield hookTimeInfo('loadJSON', ()=>_this.loadJSON(url));
20300
20319
  }
20301
- if (isScene(rawJSON)) {
20320
+ if (isSceneJSON(rawJSON)) {
20302
20321
  // 已经加载过的 可能需要更新数据模板
20303
20322
  scene = _extends({}, rawJSON);
20304
20323
  if (_this.options && _this.options.variables && Object.keys(_this.options.variables).length !== 0) {
@@ -20315,7 +20334,7 @@ let seed = 1;
20315
20334
  for(let i = 0; i < scene.images.length; i++){
20316
20335
  scene.textureOptions[i].image = scene.images[i];
20317
20336
  }
20318
- scene.jsonScene.compositions = _this.updateSceneData(scene.jsonScene.compositions);
20337
+ _this.updateSceneData(scene.jsonScene.items);
20319
20338
  }
20320
20339
  } else {
20321
20340
  // TODO: JSONScene 中 bins 的类型可能为 ArrayBuffer[]
@@ -20328,7 +20347,7 @@ let seed = 1;
20328
20347
  ]);
20329
20348
  yield hookTimeInfo('processFontURL', ()=>_this.processFontURL(fonts));
20330
20349
  const loadedTextures = yield hookTimeInfo('processTextures', ()=>_this.processTextures(loadedImages, loadedBins, jsonScene));
20331
- jsonScene.compositions = _this.updateSceneData(jsonScene.compositions);
20350
+ _this.updateSceneData(jsonScene.items);
20332
20351
  scene = {
20333
20352
  url: url,
20334
20353
  renderLevel: _this.options.renderLevel,
@@ -20465,11 +20484,9 @@ let seed = 1;
20465
20484
  if ('template' in img) {
20466
20485
  // 1. 数据模板
20467
20486
  const template = img.template;
20468
- // 判断是否为新版数据模板
20469
- const isTemplateV2 = 'v' in template && template.v === 2 && template.background;
20470
- // 获取新版数据模板 background 参数
20471
- const background = isTemplateV2 ? template.background : undefined;
20472
- if (isTemplateV2 && background) {
20487
+ // 获取数据模板 background 参数
20488
+ const background = template.background;
20489
+ if (background) {
20473
20490
  const url = getBackgroundImage(template, variables);
20474
20491
  const isVideo = background.type === BackgroundType$1.video;
20475
20492
  // 根据背景类型确定加载函数
@@ -20490,21 +20507,7 @@ let seed = 1;
20490
20507
  } catch (e) {
20491
20508
  throw new Error(`Failed to load. Check the template or if the URL is ${isVideo ? 'video' : 'image'} type, URL: ${url}.`);
20492
20509
  }
20493
- } else {
20494
- // 旧版模板或没有背景的处理
20495
- try {
20496
- const resultImage = yield loadWebPOptional(imageURL, webpURL);
20497
- return yield combineImageTemplate(resultImage.image, template, variables);
20498
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
20499
- } catch (e) {
20500
- throw new Error(`Failed to load. Check the template, URL: ${imageURL}.`);
20501
- }
20502
20510
  }
20503
- } else if ('type' in img && img.type === 'video') {
20504
- // 视频
20505
- // TODO: 2024.03.28 后面考虑下掉非推荐的视频元素使用方式
20506
- console.warn('The video element is deprecated. Use template BackgroundType.video instead.');
20507
- return loadVideo(img.url);
20508
20511
  } else if ('compressed' in img && useCompressedTexture && compressedTexture) {
20509
20512
  // 2. 压缩纹理
20510
20513
  const { compressed } = img;
@@ -20523,6 +20526,7 @@ let seed = 1;
20523
20526
  return _this.loadBins(bufferURL);
20524
20527
  }
20525
20528
  } else if ('sourceType' in img) {
20529
+ // TODO: 确定是否有用
20526
20530
  return img;
20527
20531
  } else if (img instanceof HTMLImageElement || img instanceof HTMLCanvasElement || img instanceof HTMLVideoElement || img instanceof Texture) {
20528
20532
  return img;
@@ -21230,6 +21234,15 @@ const tmpScale = new Vector3(1, 1, 1);
21230
21234
  this.speed = speed;
21231
21235
  }
21232
21236
  /**
21237
+ * 设置合成的可见性
21238
+ * @since 2.0.0
21239
+ * @param visible - 是否可见
21240
+ */ setVisible(visible) {
21241
+ this.items.forEach((item)=>{
21242
+ item.setVisible(visible);
21243
+ });
21244
+ }
21245
+ /**
21233
21246
  * 获取合成的动画速度
21234
21247
  * @returns
21235
21248
  */ getSpeed() {
@@ -22992,7 +23005,9 @@ exports.isArray = isArray;
22992
23005
  exports.isFunction = isFunction;
22993
23006
  exports.isIOS = isIOS;
22994
23007
  exports.isObject = isObject;
22995
- exports.isScene = isScene;
23008
+ exports.isSceneJSON = isSceneJSON;
23009
+ exports.isSceneURL = isSceneURL;
23010
+ exports.isSceneWithOptions = isSceneWithOptions;
22996
23011
  exports.isSimulatorCellPhone = isSimulatorCellPhone;
22997
23012
  exports.isString = isString;
22998
23013
  exports.isUniformStruct = isUniformStruct;