Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor AST code in ShaderLab for performance #2486

Open
wants to merge 10 commits into
base: dev/1.4
Choose a base branch
from
2 changes: 1 addition & 1 deletion e2e/case/material-shaderLab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
VertexElementFormat,
WebGLEngine
} from "@galacean/engine";
import { ShaderLab } from "@galacean/engine-shader-lab";
import { ShaderLab } from "@galacean/engine-shaderlab";

Check warning on line 21 in e2e/case/material-shaderLab.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/material-shaderLab.ts#L21

Added line #L21 was not covered by tests
import { initScreenshot, updateForE2E } from "./.mockForE2E";

const shaderLab = new ShaderLab();
Expand Down
18 changes: 9 additions & 9 deletions e2e/case/project-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,27 @@
* @category Advance
*/
import { Logger, WebGLEngine, AssetType, Camera } from "@galacean/engine";
import { ShaderLab } from "@galacean/engine-shader-lab";
import { ShaderLab } from "@galacean/engine-shaderlab";

Check warning on line 6 in e2e/case/project-loader.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/project-loader.ts#L6

Added line #L6 was not covered by tests
import { registerIncludes } from "@galacean/engine-toolkit";
import { initScreenshot, updateForE2E } from './.mockForE2E';
import { initScreenshot, updateForE2E } from "./.mockForE2E";

Check warning on line 8 in e2e/case/project-loader.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/project-loader.ts#L8

Added line #L8 was not covered by tests

// Create ShaderLab
const shaderLab = new ShaderLab();
registerIncludes();

Logger.enable();
WebGLEngine.create({ canvas: "canvas", shaderLab }).then( (engine) => {
WebGLEngine.create({ canvas: "canvas", shaderLab }).then((engine) => {

Check warning on line 15 in e2e/case/project-loader.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/project-loader.ts#L15

Added line #L15 was not covered by tests
engine.canvas.resizeByClientSize(2);
engine.resourceManager
.load({
type: AssetType.Project,
url: "https://mdn.alipayobjects.com/oasis_be/afts/file/A*o15SSopTBh0AAAAAAAAAAAAADkp5AQ/project.json"
}).then(() => {
})
.then(() => {

Check warning on line 22 in e2e/case/project-loader.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/project-loader.ts#L21-L22

Added lines #L21 - L22 were not covered by tests
updateForE2E(engine);

const cameraEntity =
engine.sceneManager.activeScene.findEntityByName('Camera');
const camera = cameraEntity.getComponent(Camera)
initScreenshot(engine, camera)
})
const cameraEntity = engine.sceneManager.activeScene.findEntityByName("Camera");
const camera = cameraEntity.getComponent(Camera);
initScreenshot(engine, camera);
});

Check warning on line 28 in e2e/case/project-loader.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/project-loader.ts#L25-L28

Added lines #L25 - L28 were not covered by tests
});
2 changes: 1 addition & 1 deletion e2e/case/shaderLab-mrt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/

import { Camera, Color, Logger, Material, MeshRenderer, PrimitiveMesh, Shader, WebGLEngine } from "@galacean/engine";
import { ShaderLab } from "@galacean/engine-shader-lab";
import { ShaderLab } from "@galacean/engine-shaderlab";

Check warning on line 7 in e2e/case/shaderLab-mrt.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/shaderLab-mrt.ts#L7

Added line #L7 was not covered by tests
import { initScreenshot, updateForE2E } from "./.mockForE2E";

const shaderLab = new ShaderLab();
Expand Down
2 changes: 1 addition & 1 deletion e2e/case/shaderLab-renderState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
Shader,
WebGLEngine
} from "@galacean/engine";
import { ShaderLab } from "@galacean/engine-shader-lab";
import { ShaderLab } from "@galacean/engine-shaderlab";

Check warning on line 19 in e2e/case/shaderLab-renderState.ts

View check run for this annotation

Codecov / codecov/patch

e2e/case/shaderLab-renderState.ts#L19

Added line #L19 was not covered by tests
import { initScreenshot, updateForE2E } from "./.mockForE2E";

const shaderLab = new ShaderLab();
Expand Down
42 changes: 20 additions & 22 deletions examples/buffer-mesh-particle-shader-effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
Shader,
BaseMaterial,
Script,
WebGLEngine,
} from '@galacean/engine';
import { OrbitControl } from '@galacean/engine-toolkit-controls';
import { ShaderLab } from '@galacean/engine-shader-lab';
WebGLEngine
} from "@galacean/engine";
import { OrbitControl } from "@galacean/engine-toolkit-controls";
import { ShaderLab } from "@galacean/engine-shaderlab";

Check warning on line 24 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L22-L24

Added lines #L22 - L24 were not covered by tests

const shaderLab = new ShaderLab();

Expand Down Expand Up @@ -97,37 +97,35 @@
}

get texture1(): Texture2D {
return <Texture2D>this.shaderData.getTexture('texture1');
return <Texture2D>this.shaderData.getTexture("texture1");

Check warning on line 100 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L100

Added line #L100 was not covered by tests
}

set texture1(value: Texture2D) {
this.shaderData.setTexture('texture1', value);
this.shaderData.setTexture("texture1", value);

Check warning on line 104 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L104

Added line #L104 was not covered by tests
}

get texture2(): Texture2D {
return <Texture2D>this.shaderData.getTexture('texture2');
return <Texture2D>this.shaderData.getTexture("texture2");

Check warning on line 108 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L108

Added line #L108 was not covered by tests
}

set texture2(value: Texture2D) {
this.shaderData.setTexture('texture2', value);
this.shaderData.setTexture("texture2", value);

Check warning on line 112 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L112

Added line #L112 was not covered by tests
}

get progress(): number {
return <number>this.shaderData.getFloat('progress');
return <number>this.shaderData.getFloat("progress");

Check warning on line 116 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L116

Added line #L116 was not covered by tests
}

set progress(value: number) {
this.shaderData.setFloat('progress', value);
this.shaderData.setFloat("progress", value);

Check warning on line 120 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L120

Added line #L120 was not covered by tests
}
}

class AnimationComponent extends Script {
time = 0;
mtl: ParticleMeshMaterial | undefined;
onAwake() {
this.mtl = this.entity
.getComponent(MeshRenderer)!
.getMaterial() as ParticleMeshMaterial;
this.mtl = this.entity.getComponent(MeshRenderer)!.getMaterial() as ParticleMeshMaterial;

Check warning on line 128 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L128

Added line #L128 was not covered by tests
}
onUpdate(time: number) {
this.time += time;
Expand Down Expand Up @@ -232,38 +230,38 @@
new VertexBufferBinding(
new Buffer(engine, BufferBindFlag.VertexBuffer, indexBuffer),
3 * Float32Array.BYTES_PER_ELEMENT
),
)

Check warning on line 233 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L233

Added line #L233 was not covered by tests
]);

mesh.setVertexElements([
new VertexElement('POSITION', 0, VertexElementFormat.Vector3, 0),
new VertexElement('UV', 0, VertexElementFormat.Vector2, 1),
new VertexElement('INDEX', 0, VertexElementFormat.Vector3, 2),
new VertexElement("POSITION", 0, VertexElementFormat.Vector3, 0),
new VertexElement("UV", 0, VertexElementFormat.Vector2, 1),
new VertexElement("INDEX", 0, VertexElementFormat.Vector3, 2)

Check warning on line 239 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L237-L239

Added lines #L237 - L239 were not covered by tests
]);

mesh.addSubMesh(0, vertexCount);
return mesh;
}

WebGLEngine.create({ canvas: 'canvas', shaderLab }).then((engine) => {
WebGLEngine.create({ canvas: "canvas", shaderLab }).then((engine) => {

Check warning on line 246 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L246

Added line #L246 was not covered by tests
engine.canvas.resizeByClientSize();
const scene = engine.sceneManager.activeScene;
const rootEntity = scene.createRootEntity();

const particleMeshShader = Shader.create(shaderSource);

const cameraEntity = rootEntity.createChild('camera');
const cameraEntity = rootEntity.createChild("camera");

Check warning on line 253 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L253

Added line #L253 was not covered by tests
cameraEntity.addComponent(Camera);
cameraEntity.transform.position.set(0, 0, 50);
cameraEntity.addComponent(OrbitControl);

engine.resourceManager
.load([
'https://gw.alipayobjects.com/zos/OasisHub/440001901/3736/spring.jpeg',
'https://gw.alipayobjects.com/zos/OasisHub/440001901/9546/winter.jpeg',
"https://gw.alipayobjects.com/zos/OasisHub/440001901/3736/spring.jpeg",
"https://gw.alipayobjects.com/zos/OasisHub/440001901/9546/winter.jpeg"

Check warning on line 261 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L260-L261

Added lines #L260 - L261 were not covered by tests
])
.then((assets) => {
const entity = rootEntity.createChild('plane');
const entity = rootEntity.createChild("plane");

Check warning on line 264 in examples/buffer-mesh-particle-shader-effect.ts

View check run for this annotation

Codecov / codecov/patch

examples/buffer-mesh-particle-shader-effect.ts#L264

Added line #L264 was not covered by tests
const renderer = entity.addComponent(MeshRenderer);
const mesh = createPlaneParticleMesh(engine, 20, 20, 80, 80, true);
const mtl = new ParticleMeshMaterial(engine, particleMeshShader);
Expand Down
2 changes: 1 addition & 1 deletion examples/shader-lab-multi-pass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
Vector4,
WebGLEngine
} from "@galacean/engine";
import { ShaderLab } from "@galacean/engine-shader-lab";
import { ShaderLab } from "@galacean/engine-shaderlab";

Check warning on line 23 in examples/shader-lab-multi-pass.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab-multi-pass.ts#L23

Added line #L23 was not covered by tests
import { OrbitControl } from "@galacean/engine-toolkit-controls";
import * as dat from "dat.gui";

Expand Down
41 changes: 16 additions & 25 deletions examples/shader-lab-simple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*C7Y1RaI_ZJEAAAAAAAAAAAAADiR2AQ/original
*/

import { GUI } from 'dat.gui';
import { OrbitControl } from '@galacean/engine-toolkit-controls';
import { GUI } from "dat.gui";
import { OrbitControl } from "@galacean/engine-toolkit-controls";

Check warning on line 8 in examples/shader-lab-simple.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab-simple.ts#L7-L8

Added lines #L7 - L8 were not covered by tests
import {
BufferMesh,
Camera,
Expand All @@ -19,9 +19,9 @@
MeshRenderer,
Shader,
Material,
Color,
} from '@galacean/engine';
import { ShaderLab } from '@galacean/engine-shader-lab';
Color
} from "@galacean/engine";
import { ShaderLab } from "@galacean/engine-shaderlab";

Check warning on line 24 in examples/shader-lab-simple.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab-simple.ts#L23-L24

Added lines #L23 - L24 were not covered by tests

const shaderLab = new ShaderLab();

Expand Down Expand Up @@ -108,59 +108,50 @@

function createPlaneMesh(engine: WebGLEngine) {
const mesh = new BufferMesh(engine);
const vertices = new Float32Array([
-1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1,
]);
const vertexBuffer = new Buffer(
engine,
BufferBindFlag.VertexBuffer,
vertices,
BufferUsage.Static
);
const vertices = new Float32Array([-1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1]);
const vertexBuffer = new Buffer(engine, BufferBindFlag.VertexBuffer, vertices, BufferUsage.Static);

Check warning on line 112 in examples/shader-lab-simple.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab-simple.ts#L111-L112

Added lines #L111 - L112 were not covered by tests
mesh.setVertexBufferBinding(vertexBuffer, 12);
mesh.setVertexElements([
new VertexElement('POSITION', 0, VertexElementFormat.Vector3, 0),
]);
mesh.setVertexElements([new VertexElement("POSITION", 0, VertexElementFormat.Vector3, 0)]);

Check warning on line 114 in examples/shader-lab-simple.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab-simple.ts#L114

Added line #L114 was not covered by tests
mesh.addSubMesh(0, 6);
return mesh;
}

Logger.enable();
WebGLEngine.create({ canvas: 'canvas', shaderLab }).then((engine) => {
WebGLEngine.create({ canvas: "canvas", shaderLab }).then((engine) => {

Check warning on line 120 in examples/shader-lab-simple.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab-simple.ts#L120

Added line #L120 was not covered by tests
engine.canvas.resizeByClientSize();

const shaderMap = {
normal: Shader.create(normalShaderSource),
lines: Shader.create(linesShaderSource),
lines: Shader.create(linesShaderSource)

Check warning on line 125 in examples/shader-lab-simple.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab-simple.ts#L125

Added line #L125 was not covered by tests
};

const scene = engine.sceneManager.activeScene;
const rootEntity = scene.createRootEntity();

// camera
const cameraEntity = rootEntity.createChild('cameraNode');
const cameraEntity = rootEntity.createChild("cameraNode");

Check warning on line 132 in examples/shader-lab-simple.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab-simple.ts#L132

Added line #L132 was not covered by tests
cameraEntity.transform.setPosition(0, 0, 5);
cameraEntity.addComponent(Camera);
cameraEntity.addComponent(OrbitControl);

// create plane
const triangle = rootEntity.createChild('plane');
const triangle = rootEntity.createChild("plane");

Check warning on line 138 in examples/shader-lab-simple.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab-simple.ts#L138

Added line #L138 was not covered by tests
const renderer = triangle.addComponent(MeshRenderer);
renderer.mesh = createPlaneMesh(engine);
const shader = shaderMap.lines;
const material = new Material(engine, shader);
material.shaderData.setColor('u_color', new Color(1.0, 1.0, 0));
material.shaderData.setColor("u_color", new Color(1.0, 1.0, 0));

Check warning on line 143 in examples/shader-lab-simple.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab-simple.ts#L143

Added line #L143 was not covered by tests
renderer.setMaterial(material);

engine.run();

const state = {
shader: 'lines',
shader: "lines"

Check warning on line 149 in examples/shader-lab-simple.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab-simple.ts#L149

Added line #L149 was not covered by tests
};

function addGUI() {
const gui = new GUI({ name: 'Switch Shader' });
gui.add(state, 'shader', Object.keys(shaderMap)).onChange((v) => {
const gui = new GUI({ name: "Switch Shader" });
gui.add(state, "shader", Object.keys(shaderMap)).onChange((v) => {

Check warning on line 154 in examples/shader-lab-simple.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab-simple.ts#L153-L154

Added lines #L153 - L154 were not covered by tests
material.shader = shaderMap[v];
});
}
Expand Down
34 changes: 16 additions & 18 deletions examples/shader-lab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,32 @@
AmbientLight,
AssetType,
SkyBoxMaterial,
BackgroundMode,
} from '@galacean/engine';
import { OrbitControl } from '@galacean/engine-toolkit-controls';
import { ShaderLab } from '@galacean/engine-shader-lab';
BackgroundMode
} from "@galacean/engine";
import { OrbitControl } from "@galacean/engine-toolkit-controls";
import { ShaderLab } from "@galacean/engine-shaderlab";

Check warning on line 24 in examples/shader-lab.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab.ts#L22-L24

Added lines #L22 - L24 were not covered by tests

// Create ShaderLab
const shaderLab = new ShaderLab();

Logger.enable();
WebGLEngine.create({ canvas: 'canvas', shaderLab }).then((engine) => {
WebGLEngine.create({ canvas: "canvas", shaderLab }).then((engine) => {

Check warning on line 30 in examples/shader-lab.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab.ts#L30

Added line #L30 was not covered by tests
engine.canvas.resizeByClientSize();
const scene = engine.sceneManager.activeScene;
const { background } = scene;
const rootEntity = scene.createRootEntity();

const cameraEntity = rootEntity.createChild('camera_node');
const cameraEntity = rootEntity.createChild("camera_node");

Check warning on line 36 in examples/shader-lab.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab.ts#L36

Added line #L36 was not covered by tests
cameraEntity.transform.setPosition(5, 5, 10);
cameraEntity.addComponent(Camera);
cameraEntity.addComponent(OrbitControl).target = new Vector3(0, 1, 0);

const lightEntity = rootEntity.createChild('light_node');
const lightEntity = rootEntity.createChild("light_node");

Check warning on line 41 in examples/shader-lab.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab.ts#L41

Added line #L41 was not covered by tests
lightEntity.addComponent(DirectLight);
lightEntity.transform.setPosition(-10, 10, 10);
lightEntity.transform.lookAt(new Vector3(0, 0, 0));

const planeEntity = rootEntity.createChild('plane_node');
const planeEntity = rootEntity.createChild("plane_node");

Check warning on line 46 in examples/shader-lab.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab.ts#L46

Added line #L46 was not covered by tests
const renderer = planeEntity.addComponent(MeshRenderer);
renderer.mesh = PrimitiveMesh.createPlane(engine, 10, 10);
const planeMaterial = new BlinnPhongMaterial(engine);
Expand All @@ -60,9 +60,7 @@

Promise.all([
engine.resourceManager
.load<GLTFResource>(
'https://gw.alipayobjects.com/os/bmw-prod/150e44f6-7810-4c45-8029-3575d36aff30.gltf'
)
.load<GLTFResource>("https://gw.alipayobjects.com/os/bmw-prod/150e44f6-7810-4c45-8029-3575d36aff30.gltf")

Check warning on line 63 in examples/shader-lab.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab.ts#L63

Added line #L63 was not covered by tests
.then((asset) => {
const { defaultSceneRoot } = asset;
rootEntity.addChild(defaultSceneRoot);
Expand All @@ -74,30 +72,30 @@
const renderers = new Array<MeshRenderer>();
defaultSceneRoot.getComponentsIncludeChildren(MeshRenderer, renderers);

const shadowShader = Shader.find('PlanarShadow');
const shadowShader = Shader.find("PlanarShadow");

Check warning on line 75 in examples/shader-lab.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab.ts#L75

Added line #L75 was not covered by tests

for (let i = 0, n = renderers.length; i < n; i++) {
const material = renderers[i].getMaterial();
if (!material) continue;
material.shader = shadowShader;
const shaderData = material.shaderData;

shaderData.setFloat('u_planarShadowFalloff', 0.2);
shaderData.setFloat('u_planarHeight', 0.01);
shaderData.setColor('u_planarShadowColor', new Color(0, 0, 0, 1));
shaderData.setVector3('u_lightDir', lightDirection);
shaderData.setFloat("u_planarShadowFalloff", 0.2);
shaderData.setFloat("u_planarHeight", 0.01);
shaderData.setColor("u_planarShadowColor", new Color(0, 0, 0, 1));
shaderData.setVector3("u_lightDir", lightDirection);

Check warning on line 86 in examples/shader-lab.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab.ts#L83-L86

Added lines #L83 - L86 were not covered by tests
}
}),
engine.resourceManager
.load<AmbientLight>({
type: AssetType.Env,
url: 'https://gw.alipayobjects.com/os/bmw-prod/f369110c-0e33-47eb-8296-756e9c80f254.bin',
url: "https://gw.alipayobjects.com/os/bmw-prod/f369110c-0e33-47eb-8296-756e9c80f254.bin"

Check warning on line 92 in examples/shader-lab.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab.ts#L92

Added line #L92 was not covered by tests
})
.then((ambientLight) => {
scene.ambientLight = ambientLight;
skyMaterial.texture = ambientLight.specularTexture;
skyMaterial.textureDecodeRGBM = true;
}),
})

Check warning on line 98 in examples/shader-lab.ts

View check run for this annotation

Codecov / codecov/patch

examples/shader-lab.ts#L98

Added line #L98 was not covered by tests
]);

engine.run();
Expand Down
Loading
Loading