Skip to content

Commit

Permalink
feat(graphic): move graphic3D to @orillusion/graphic (Orillusion#427)
Browse files Browse the repository at this point in the history
  • Loading branch information
lslzl3000 authored Jul 23, 2024
1 parent af74bb1 commit a1d1b2a
Show file tree
Hide file tree
Showing 69 changed files with 272 additions and 1,142 deletions.
17 changes: 15 additions & 2 deletions packages/graphic/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export * from "./compute/grass/GrassAnimCompute_cs"
export * from "./compute/grass/GrassGeometryCompute_cs"
export * from "./renderer/GrassRenderer"
export * from "./renderer/Shape3DRenderer"
export * from "./renderer/Shape3DMaker"
Expand All @@ -12,3 +10,18 @@ export * from "./renderer/shape3d/LineShape3D"
export * from "./renderer/shape3d/Shape3D"
export * from "./renderer/shape3d/Path3DShape3D"
export * from "./renderer/shape3d/Path2DShape3D"

export * from "./renderer/Graphics3DShape"
export * from "./renderer/Graphic3DRender"
export * from "./renderer/Graphic3DBatchRenderer"
export * from "./renderer/Graphic3DLineBatchRenderer"
export * from "./renderer/Graphic3DFixedRenderMaterial"
export * from "./renderer/Graphic3DFillRenderer"
export * from "./renderer/graphic3d/DynamicDrawStruct"
export * from "./renderer/graphic3d/DynamicFaceRenderer"
export * from "./renderer/graphic3d/Float32ArrayUtil"
export * from "./renderer/graphic3d/Graphic3DFaceRenderer"
export * from "./renderer/graphic3d/Graphic3DMesh"
export * from "./renderer/graphic3d/Graphic3DMeshRenderer"
export * from "./renderer/graphic3d/Graphic3DRibbonRenderer"
export * from "./renderer/graphic3d/ShapeInfo"
4 changes: 2 additions & 2 deletions packages/graphic/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@orillusion/graphic",
"version": "0.1.1",
"version": "0.2.0",
"author": "Orillusion",
"description": "Orillusion graphic Plugin",
"main": "./dist/graphic.umd.js",
Expand All @@ -22,7 +22,7 @@
"url": "git+https://github.com/Orillusion/orillusion.git"
},
"dependencies": {
"@orillusion/core": "^0.7.0",
"@orillusion/core": "^0.8.0",
"earcut": "^2.2.4"
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { RenderNode } from "../../../../components/renderer/RenderNode";
import { View3D } from "../../../../core/View3D";
import { Color } from "../../../../math/Color";
import { Vector3 } from "../../../../math/Vector3";
import { RendererPassState } from "../state/RendererPassState";
import { PassType } from "../state/PassType";

import { ClusterLightingBuffer, Color, GeometryBase, PassType, RendererMask, RendererPassState, RenderNode, Vector3, VertexAttributeName, View3D } from "@orillusion/core";
import { Graphics3DShape } from "./Graphics3DShape";
import { ClusterLightingBuffer } from "../cluster/ClusterLightingBuffer";
import { GeometryBase, Graphic3DFixedRenderMaterial, VertexAttributeName } from "../../../..";
import { Graphic3DFixedRenderMaterial } from "./Graphic3DFixedRenderMaterial";

/**
* @internal
Expand All @@ -29,6 +24,7 @@ export class Graphic3DBatchRenderer extends RenderNode {

public init() {
super.init();
this.addRendererMask(RendererMask.Graphic3D);
this.castGI = false;
this.castShadow = false;
this.geometry = new GeometryBase();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GPUPrimitiveTopology } from "../../../graphics/webGpu/WebGPUConst";
import { GPUPrimitiveTopology } from "@orillusion/core";
import { Graphic3DBatchRenderer } from "./Graphic3DBatchRenderer";

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Engine3D, GPUPrimitiveTopology, RenderShaderPass, Shader, ShaderLib, Texture } from "../../../..";
import { Graphic3DShader } from "../../../../assets/shader/graphic/Graphic3DShader";
import { Material } from "../../../../materials/Material";
import { GPUPrimitiveTopology, RenderShaderPass, Shader, ShaderLib, Material } from "@orillusion/core";
import { Graphic3DShader } from "../compute/graphic3d/Graphic3DShader";

/**
* @internal
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GPUPrimitiveTopology } from "../../../graphics/webGpu/WebGPUConst";
import { GPUPrimitiveTopology } from "@orillusion/core";
import { Graphic3DBatchRenderer } from "./Graphic3DBatchRenderer";

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
import { GeometryBase } from "../../../../core/geometry/GeometryBase";
import { Color } from "../../../../math/Color";
import { Vector3 } from "../../../../math/Vector3";
import { DEGREES_TO_RADIANS } from "../../../../math/MathUtil";
import { Transform } from "../../../../components/Transform";
import { BoundingBox } from "../../../../core/bound/BoundingBox";
import { Camera3D } from "../../../../core/Camera3D";
import { CameraType } from "../../../../core/CameraType";
import { Object3D } from "../../../../core/entities/Object3D";
import { BoundingBox, BoundUtil, Camera3D, CameraType, Color, DEGREES_TO_RADIANS, GeometryBase, Object3D, Transform, Vector3 } from "@orillusion/core";
import { Graphics3DShape } from "./Graphics3DShape";
import { Graphic3DFillRenderer } from "./Graphic3DFillRenderer";
import { Graphic3DLineRenderer } from "./Graphic3DLineBatchRenderer";
import { BoundUtil } from "../../../../util/BoundUtil";

export class Graphic3D extends Object3D {
protected mLineRender: Graphic3DLineRenderer;
protected mFillRender: Graphic3DFillRenderer;

constructor() {
super();
this.name = 'graphic3D';
this.mLineRender = this.addComponent(Graphic3DLineRenderer);
this.mFillRender = this.addComponent(Graphic3DFillRenderer);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { Color } from "../../../../math/Color";
import { DEGREES_TO_RADIANS } from "../../../../math/MathUtil";
import { Vector3 } from "../../../../math/Vector3";
import { Color, DEGREES_TO_RADIANS, Vector3 } from "@orillusion/core";

/**
* @internal
Expand Down
5 changes: 4 additions & 1 deletion packages/graphic/renderer/GrassRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@

import { ComputeShader, DynamicDrawStruct, DynamicFaceRenderer, Struct, graphicDynamicCompute } from "@orillusion/core";
import { ComputeShader } from "@orillusion/core";
import { graphicDynamicCompute } from "../compute/graphic3d/GraphicDynamicCompute";
import { GrassGeometryCompute_cs } from "../compute/grass/GrassGeometryCompute_cs";
import { DynamicDrawStruct } from "./graphic3d/DynamicDrawStruct";
import { DynamicFaceRenderer } from "./graphic3d/DynamicFaceRenderer";

export class GrassNodeStruct extends DynamicDrawStruct {
grassCount: number = 1;
Expand Down
3 changes: 2 additions & 1 deletion packages/graphic/renderer/Shape3DMaker.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BitmapTexture2DArray, Graphic3DMesh, Scene3D, Vector2, Vector3 } from "@orillusion/core";
import { BitmapTexture2DArray, Scene3D, Vector2 } from "@orillusion/core";
import { Shape3DRenderer } from "./Shape3DRenderer";
import { RoundRectShape3D } from "./shape3d/RoundRectShape3D";
import { EllipseShape3D } from "./shape3d/EllipseShape3D";
Expand All @@ -9,6 +9,7 @@ import { QuadraticCurveShape3D } from "./shape3d/QuadraticCurveShape3D";
import { CurveShape3D } from "./shape3d/CurveShape3D";
import { Path2DShape3D } from "./shape3d/Path2DShape3D";
import { Path3DShape3D } from "./shape3d/Path3DShape3D";
import { Graphic3DMesh } from "./graphic3d/Graphic3DMesh";


/**
Expand Down
5 changes: 4 additions & 1 deletion packages/graphic/renderer/Shape3DRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@

import { BitmapTexture2DArray, ComputeShader, Ctor, DynamicDrawStruct, DynamicFaceRenderer, Matrix4, Object3D, OrderMap, StorageGPUBuffer, UniformGPUBuffer, Vector2, Vector3, Vector4, View3D, graphicDynamicCompute } from "@orillusion/core";
import { BitmapTexture2DArray, ComputeShader, Ctor, Object3D, OrderMap, StorageGPUBuffer, UniformGPUBuffer, Vector3, Vector4, View3D } from "@orillusion/core";
import { Shape3DVertexCompute_cs } from "../compute/shape3d/Shape3DVertexCompute_cs";
import { Shape3DKeyPointCompute_cs } from "../compute/shape3d/Shape3DKeyPointCompute_cs";
import { Shape3D } from "./shape3d/Shape3D";
import { Shape3DVertexFillZero_cs } from "../compute/shape3d/Shape3DVertexFillZero_cs";
import { DynamicFaceRenderer } from "./graphic3d/DynamicFaceRenderer";
import { DynamicDrawStruct } from "./graphic3d/DynamicDrawStruct";
import { graphicDynamicCompute } from "../compute/graphic3d/GraphicDynamicCompute";

export class Shape3DRenderer extends DynamicFaceRenderer {
private _destPathBuffer: StorageGPUBuffer;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Struct } from "../../../../../util/struct/Struct";
import { Struct } from "@orillusion/core";

export class DynamicDrawStruct extends Struct {
// @NonSerialize
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Vector4 } from "../../../../..";
import { Vector4 } from "@orillusion/core";

export class Float32ArrayUtil {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,7 @@
import { GraphicLineCompute } from "../../../../../assets/shader/graphic/GraphicLineCompute";
import { MeshRenderer } from "../../../../../components/renderer/MeshRenderer";
import { View3D } from "../../../../../core/View3D";
import { Object3D } from "../../../../../core/entities/Object3D";
import { UnLitTexArrayMaterial } from "../../../../../materials/UnLitTexArrayMaterial";
import { Color } from "../../../../../math/Color";
import { Vector3 } from "../../../../../math/Vector3";
import { Vector4 } from "../../../../../math/Vector4";
import { TriGeometry } from "../../../../../shape/TriGeometry";
import { BitmapTexture2DArray } from "../../../../../textures/BitmapTexture2DArray";
import { GeometryUtil } from "../../../../../util/GeometryUtil";
import { Struct } from "../../../../../util/struct/Struct";
import { GlobalBindGroup } from "../../../../graphics/webGpu/core/bindGroups/GlobalBindGroup";
import { StorageGPUBuffer } from "../../../../graphics/webGpu/core/buffer/StorageGPUBuffer";
import { StructStorageGPUBuffer } from "../../../../graphics/webGpu/core/buffer/StructStorageGPUBuffer";
import { ComputeShader } from "../../../../graphics/webGpu/shader/ComputeShader";
import { GPUContext } from "../../../GPUContext";
import { Float32ArrayUtil } from "./Float32ArrayUtil";
import { Struct, MeshRenderer, BitmapTexture2DArray, StorageGPUBuffer, ComputeShader, StructStorageGPUBuffer, TriGeometry, UnLitTexArrayMaterial, Object3D, Color, Vector4, GlobalBindGroup, View3D, GPUContext } from "@orillusion/core";
import { ShapeInfo } from "./ShapeInfo";
import { GraphicLineCompute } from "../../compute/graphic3d/GraphicLineCompute";


export enum LineJoin {
bevel = 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { Scene3D } from "../../../../../core/Scene3D";
import { Object3D } from "../../../../../core/entities/Object3D";
import { GeometryBase } from "../../../../../core/geometry/GeometryBase";
import { BitmapTexture2DArray } from "../../../../../textures/BitmapTexture2DArray";
import { GeometryBase, Scene3D, BitmapTexture2DArray, Object3D, Ctor } from "@orillusion/core";
import { Graphic3DMeshRenderer } from "./Graphic3DMeshRenderer";
import { Graphic3DRibbonRenderer } from "./Graphic3DRibbonRenderer";
import { Graphic3DFaceRenderer } from "./Graphic3DFaceRenderer";
import { DynamicFaceRenderer } from "./DynamicFaceRenderer";
import { Ctor } from "../../../../..";
import { DynamicDrawStruct } from "./DynamicDrawStruct";

export class Graphic3DMesh {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,4 @@
import { MeshRenderer } from "../../../../../components/renderer/MeshRenderer";
import { View3D } from "../../../../../core/View3D";
import { Object3D } from "../../../../../core/entities/Object3D";
import { GeometryBase } from "../../../../../core/geometry/GeometryBase";
import { UnLitTexArrayMaterial } from "../../../../../materials/UnLitTexArrayMaterial";
import { Color } from "../../../../../math/Color";
import { Vector3 } from "../../../../../math/Vector3";
import { Vector4 } from "../../../../../math/Vector4";
import { BitmapTexture2DArray } from "../../../../../textures/BitmapTexture2DArray";
import { GeometryUtil } from "../../../../../util/GeometryUtil";
import { StorageGPUBuffer } from "../../../../graphics/webGpu/core/buffer/StorageGPUBuffer";
import { ComputeShader } from "../../../../graphics/webGpu/shader/ComputeShader";
import { GPUContext } from "../../../GPUContext";
import { MeshRenderer, StorageGPUBuffer, GeometryBase, BitmapTexture2DArray, Object3D, ComputeShader, UnLitTexArrayMaterial, Vector3, Color, Vector4, GeometryUtil, View3D, GPUContext } from "@orillusion/core";

export class Graphic3DMeshRenderer extends MeshRenderer {
public transformBuffer: StorageGPUBuffer;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,5 @@
import { graphicTrailCompute } from "../../../../../assets/shader/graphic/GraphicTrailCompute";
import { MeshRenderer } from "../../../../../components/renderer/MeshRenderer";
import { View3D } from "../../../../../core/View3D";
import { Object3D } from "../../../../../core/entities/Object3D";
import { GeometryBase } from "../../../../../core/geometry/GeometryBase";
import { UnLitTexArrayMaterial } from "../../../../../materials/UnLitTexArrayMaterial";
import { Color } from "../../../../../math/Color";
import { Vector2 } from "../../../../../math/Vector2";
import { Vector4 } from "../../../../../math/Vector4";
import { TrailGeometry } from "../../../../../shape/TrailGeometry";
import { BitmapTexture2DArray } from "../../../../../textures/BitmapTexture2DArray";
import { GeometryUtil } from "../../../../../util/GeometryUtil";
import { NonSerialize } from "../../../../../util/SerializeDecoration";
import { Struct } from "../../../../../util/struct/Struct";
import { GlobalBindGroup } from "../../../../graphics/webGpu/core/bindGroups/GlobalBindGroup";
import { StorageGPUBuffer } from "../../../../graphics/webGpu/core/buffer/StorageGPUBuffer";
import { StructStorageGPUBuffer } from "../../../../graphics/webGpu/core/buffer/StructStorageGPUBuffer";
import { ComputeShader } from "../../../../graphics/webGpu/shader/ComputeShader";
import { GPUContext } from "../../../GPUContext";
import { BitmapTexture2DArray, Color, ComputeShader, GeometryBase, GeometryUtil, GlobalBindGroup, GPUContext, MeshRenderer, NonSerialize, Object3D, StorageGPUBuffer, Struct, StructStorageGPUBuffer, TrailGeometry, UnLitTexArrayMaterial, Vector2, Vector4, View3D } from "@orillusion/core";
import { graphicTrailCompute } from '../../compute/graphic3d/GraphicTrailCompute'

export enum FaceMode {
FaceToCamera,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { Vector4 } from "../../../../../math/Vector4";
import { NonSerialize } from "../../../../../util/SerializeDecoration";
import { Struct } from "../../../../../util/struct/Struct";
import { NonSerialize, Struct, Vector4 } from "@orillusion/core";

export class ShapeInfo extends Struct {
public shapeIndex: number = 0; //face,poly,line,cycle,rectangle,box,sphere
Expand Down
2 changes: 1 addition & 1 deletion packages/graphic/renderer/shape3d/LineShape3D.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Vector3, LineJoin } from "@orillusion/core";
import { LineJoin } from "../graphic3d/Graphic3DFaceRenderer";
import { Point3D, Shape3D, ShapeTypeEnum } from "./Shape3D";
import earcut from 'earcut';

Expand Down
3 changes: 2 additions & 1 deletion packages/graphic/renderer/shape3d/Path3DShape3D.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Vector2, deg2Rad, Vector3, Matrix4, rad2Deg, LineJoin } from "@orillusion/core";
import { Vector2, deg2Rad, Vector3, Matrix4, rad2Deg } from "@orillusion/core";
import { Point3D, Shape3DStruct, ShapeTypeEnum } from "./Shape3D";
import { LineShape3D } from "./LineShape3D";
import { LineJoin } from "../graphic3d/Graphic3DFaceRenderer";

/**
* Define class for drawing path in 3D space.
Expand Down
3 changes: 2 additions & 1 deletion packages/graphic/renderer/shape3d/Shape3D.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DynamicDrawStruct, Matrix3, LineJoin, Vector2, Color, Vector4, Vector3 } from "@orillusion/core";
import { Color, Vector4 } from "@orillusion/core";
import { DynamicDrawStruct } from "../graphic3d/DynamicDrawStruct";

export class Shape3DStruct extends DynamicDrawStruct {
public shapeType: number = 0;
Expand Down
3 changes: 2 additions & 1 deletion packages/graphic/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"paths": {
"@orillusion/core": ["../../src"],
"@orillusion/*": ["../*"]
}
},
"experimentalDecorators": true
}
}
18 changes: 12 additions & 6 deletions samples/animation/Sample_CameraPathAnimation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Engine3D, Scene3D, View3D, Object3D, Color, Vector3, AtmosphericComponent, CameraUtil, HoverCameraController, DirectLight, KelvinUtil, Time, Object3DUtil, lerpVector3, Camera3D, AxisObject, ColliderComponent, PointerEvent3D, ComponentBase, Plane } from '@orillusion/core';
import { Stats } from '@orillusion/stats';
import { Graphic3D } from '@orillusion/graphic';
import * as dat from 'dat.gui';

interface PathInfo {
Expand All @@ -19,6 +20,7 @@ enum CameraModes {
class Sample_CameraPathAnimation {
view: View3D;
camera: Camera3D;
graphic3D: Graphic3D;

cameraMode = CameraModes.DualOrbit;
guiControl: dat.GUIController<object>;
Expand Down Expand Up @@ -89,6 +91,10 @@ class Sample_CameraPathAnimation {
view.camera = this.camera = camera;
view.scene = scene;

// init Graphic3D to draw lines
this.graphic3D = new Graphic3D()
scene.addChild(this.graphic3D)

Engine3D.startRenderView(view);

await this.initScene(scene, hoverCtrl);
Expand Down Expand Up @@ -211,8 +217,8 @@ class Sample_CameraPathAnimation {
pathInfo.curvePoints.splice(dataStartIndex, curveSegmentPoints.length, ...curveSegmentPoints);
}

this.view.graphic3D.Clear(pathInfo.name);
this.view.graphic3D.drawLines(pathInfo.name, pathInfo.curvePoints, pathInfo.color);
this.graphic3D.Clear(pathInfo.name);
this.graphic3D.drawLines(pathInfo.name, pathInfo.curvePoints, pathInfo.color);
}

public generateOrUpdateCurve(points: Vector3[], samples: number = 20, tension: number = 0.5, indicesToUpdate?: number[]): Vector3[] {
Expand Down Expand Up @@ -310,13 +316,13 @@ class Sample_CameraPathAnimation {

const changeLine = (show: boolean) => {
if (show) {
this.view.graphic3D.drawLines(this.cameraPathInfo.name, this.cameraPathInfo.curvePoints, this.cameraPathInfo.color);
this.view.graphic3D.drawLines(this.targetPathInfo.name, this.targetPathInfo.curvePoints, this.targetPathInfo.color);
this.graphic3D.drawLines(this.cameraPathInfo.name, this.cameraPathInfo.curvePoints, this.cameraPathInfo.color);
this.graphic3D.drawLines(this.targetPathInfo.name, this.targetPathInfo.curvePoints, this.targetPathInfo.color);
console.log('camerabasePoints', this.cameraPathInfo.basePoints);
console.log('targetbasePoints', this.targetPathInfo.basePoints);
} else {
this.view.graphic3D.Clear(this.cameraPathInfo.name);
this.view.graphic3D.Clear(this.targetPathInfo.name);
this.graphic3D.Clear(this.cameraPathInfo.name);
this.graphic3D.Clear(this.targetPathInfo.name);
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions samples/base/Sample_BoundingBox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { GUIHelp } from '@orillusion/debug/GUIHelp';
import { Color, Engine3D, Object3D, Object3DUtil, Transform, View3D, } from '@orillusion/core';
import { GUIUtil } from '@samples/utils/GUIUtil';
import { createExampleScene, createSceneParam } from '@samples/utils/ExampleScene';
import { Graphic3D } from '@orillusion/graphic';

// A sample to show boundingbox
class Sample_BoundingBox {
view: View3D;
box: Object3D;
container: Object3D;
graphic3D: Graphic3D
async run() {
// init engine
await Engine3D.init({ renderLoop: () => { this.loop() } });
Expand All @@ -25,6 +27,9 @@ class Sample_BoundingBox {

this.box = box;
this.view = exampleScene.view;
// add a graphic3D to draw lines
this.graphic3D = new Graphic3D();
exampleScene.scene.addChild(this.graphic3D);

let parent = this.container = new Object3D();
parent.addChild(box);
Expand All @@ -46,8 +51,8 @@ class Sample_BoundingBox {
red = new Color(1, 0, 0, 1);
green = new Color(0, 1, 0, 1);
loop() {
this.view.graphic3D.drawBoundingBox(this.box.instanceID, this.box.bound as any, this.green);
this.view.graphic3D.drawBoundingBox(this.container.instanceID, this.container.bound as any, this.red);
this.graphic3D.drawBoundingBox(this.box.instanceID, this.box.bound as any, this.green);
this.graphic3D.drawBoundingBox(this.container.instanceID, this.container.bound as any, this.red);
}
}

Expand Down
2 changes: 0 additions & 2 deletions samples/base/Sample_ComponentLife.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { Engine3D, Scene3D, CameraUtil, View3D, AtmosphericComponent, ComponentBase, Time, AxisObject, Object3DUtil, KelvinUtil, DirectLight, Object3D, HoverCameraController } from "@orillusion/core";
import { GUIHelp } from "@orillusion/debug/GUIHelp";
import { GUIUtil } from "@samples/utils/GUIUtil";

// sample use component
class Sample_ComponentLife {
Expand Down
Loading

0 comments on commit a1d1b2a

Please sign in to comment.