diff --git a/packages/graphics-2d/src/components/component.ts b/packages/graphics-2d/src/components/component.ts index 259794df..95e090d9 100644 --- a/packages/graphics-2d/src/components/component.ts +++ b/packages/graphics-2d/src/components/component.ts @@ -14,6 +14,7 @@ export abstract class NfgComponent { private readonly _pipelineLayout: GPUPipelineLayout; private readonly _label: string; private _bindGroup: GPUBindGroup; + protected _duplicate: number = 1; constructor(core: GraphicsCore) { this._core = core; @@ -48,7 +49,7 @@ export abstract class NfgComponent { pass.setPipeline(this._pipeline); pass.setBindGroup(0, this._bindGroup); pass.setVertexBuffer(0, this._vertexBuffer); - pass.draw(this._vertices.length / this._vertexLength); + pass.draw(this._vertices.length / this._vertexLength, this._duplicate); } protected abstract _init(): Promise; diff --git a/packages/graphics-2d/src/components/shape/shapes/index.ts b/packages/graphics-2d/src/components/shape/shapes/index.ts index 71509e65..e306fefb 100644 --- a/packages/graphics-2d/src/components/shape/shapes/index.ts +++ b/packages/graphics-2d/src/components/shape/shapes/index.ts @@ -1 +1,2 @@ export { NfgCircle } from "./circle.shape"; +export { NfgRectangle } from "./rectangle.shape"; diff --git a/packages/graphics-2d/src/components/shape/shapes/rectangle.shape.ts b/packages/graphics-2d/src/components/shape/shapes/rectangle.shape.ts new file mode 100644 index 00000000..0c70e3a0 --- /dev/null +++ b/packages/graphics-2d/src/components/shape/shapes/rectangle.shape.ts @@ -0,0 +1,122 @@ +import { type GraphicsCore } from "../../../core"; +import { ShadersEnum } from "../../../shader/shaders.enum"; +import { type IColor, type IRectangleOptions, type IVertex2D } from "../../../types"; +import { NfgShape } from "../common/shape"; + +export class NfgRectangle extends NfgShape { + protected _shader: GPUShaderModule; + protected readonly _vertexBufferLayout: GPUVertexBufferLayout; + protected _vertexLength: number; + + private _min: IVertex2D; + private _max: IVertex2D; + private _color: IColor; + + constructor(core: GraphicsCore, options?: Partial) { + super(core); + + this._vertexBufferLayout = { + arrayStride: 32, + attributes: [ + { + format: "float32x2", + offset: 0, + shaderLocation: 0, + }, + { + format: "float32x2", + offset: 8, + shaderLocation: 1, + }, + { + format: "float32x4", + offset: 16, + shaderLocation: 2, + }, + ], + }; + this._vertexLength = 8; + + this._duplicate = 1; + + this._min = options?.min ?? { x: 0, y: 0 }; + this._max = options?.max ?? { x: 0, y: 0 }; + this._color = options?.color ?? { r: 0, g: 0, b: 0, a: 1 }; + this._updateVertices(); + } + + public setMin(pos: IVertex2D): NfgRectangle { + this._min = pos; + this._updateVertices(); + return this; + } + + public setMax(pos: IVertex2D): NfgRectangle { + this._max = pos; + this._updateVertices(); + return this; + } + + public setColor(color: IColor): NfgRectangle { + this._color = color; + this._updateVertices(); + return this; + } + + protected async _init(): Promise { + this._shader = await this._shaderManager.get(ShadersEnum.RECTANGLE); + } + + protected _updateVertices(): void { + this._setVertices([ + this._min.x, + this._min.y, + this._max.x, + this._max.y, + this._color.r, + this._color.g, + this._color.b, + this._color.a, + this._min.x, + this._min.y, + this._max.x, + this._max.y, + this._color.r, + this._color.g, + this._color.b, + this._color.a, + this._min.x, + this._min.y, + this._max.x, + this._max.y, + this._color.r, + this._color.g, + this._color.b, + this._color.a, + this._min.x, + this._min.y, + this._max.x, + this._max.y, + this._color.r, + this._color.g, + this._color.b, + this._color.a, + this._min.x, + this._min.y, + this._max.x, + this._max.y, + this._color.r, + this._color.g, + this._color.b, + this._color.a, + this._min.x, + this._min.y, + this._max.x, + this._max.y, + this._color.r, + this._color.g, + this._color.b, + this._color.a, + ]); + } +} diff --git a/packages/graphics-2d/src/factory.ts b/packages/graphics-2d/src/factory.ts index 8b3c8b8a..8575c9fe 100644 --- a/packages/graphics-2d/src/factory.ts +++ b/packages/graphics-2d/src/factory.ts @@ -1,6 +1,6 @@ -import { NfgCircle } from "./components"; +import { NfgCircle, NfgRectangle } from "./components"; import { type GraphicsCore } from "./core"; -import { type ICircleOptions } from "./types"; +import { type ICircleOptions, type IRectangleOptions } from "./types"; export class GraphicsFactory { private readonly _core: GraphicsCore; @@ -12,4 +12,8 @@ export class GraphicsFactory { createCircle(options?: Partial): Promise { return new NfgCircle(this._core, options).init(); } + + createRectangle(options?: Partial): Promise { + return new NfgRectangle(this._core, options).init(); + } } diff --git a/packages/graphics-2d/src/shader/shaders.const.ts b/packages/graphics-2d/src/shader/shaders.const.ts index 730fbb18..28a40b93 100644 --- a/packages/graphics-2d/src/shader/shaders.const.ts +++ b/packages/graphics-2d/src/shader/shaders.const.ts @@ -1,11 +1,11 @@ import { ShadersEnum } from "./shaders.enum"; export const SHADER_PATHS: Record = { - // [ShadersEnum.RECTANGLE]: "rectangle.wgsl", + [ShadersEnum.RECTANGLE]: "rectangle.wgsl", [ShadersEnum.CIRCLE]: "circle.wgsl", }; export const SHADER_NAMES: Record = { - // [ShadersEnum.RECTANGLE]: "Rectangle shader", + [ShadersEnum.RECTANGLE]: "Rectangle shader", [ShadersEnum.CIRCLE]: "Circle shader", }; diff --git a/packages/graphics-2d/src/shader/shaders.enum.ts b/packages/graphics-2d/src/shader/shaders.enum.ts index 19e57f89..d65b22f8 100644 --- a/packages/graphics-2d/src/shader/shaders.enum.ts +++ b/packages/graphics-2d/src/shader/shaders.enum.ts @@ -1,4 +1,4 @@ export enum ShadersEnum { - // RECTANGLE = 0, + RECTANGLE = 0, CIRCLE = 1, } diff --git a/packages/graphics-2d/src/shader/shaders/index.ts b/packages/graphics-2d/src/shader/shaders/index.ts index 701585a6..d361846d 100644 --- a/packages/graphics-2d/src/shader/shaders/index.ts +++ b/packages/graphics-2d/src/shader/shaders/index.ts @@ -1 +1,2 @@ import "./circle.wgsl"; +import "./rectangle.wgsl"; diff --git a/packages/graphics-2d/src/shader/shaders/rectangle.wgsl b/packages/graphics-2d/src/shader/shaders/rectangle.wgsl new file mode 100644 index 00000000..7838ee67 --- /dev/null +++ b/packages/graphics-2d/src/shader/shaders/rectangle.wgsl @@ -0,0 +1,54 @@ +struct View { + position: vec4, + scale: vec2, + size: vec2, +}; + +@group(0) +@binding(0) +var view: View; + +struct VertexInput { + @builtin(vertex_index) index: u32 +}; + +struct InstanceInput { + @location(0) min: vec2, + @location(1) max: vec2, + @location(2) color: vec4, +}; + +struct VertexOutput { + @builtin(position) clip_space: vec4, + @location(0) color: vec4, +}; + +@vertex +fn vertex_main( + vertex: VertexInput, + instance: InstanceInput, +) -> VertexOutput { + var result: VertexOutput; + + let x = view.size.x; + let y = view.size.y; + let aspect = y / x; + + var local_space = vec2(f32(vertex.index & 1u), f32(vertex.index >> 1u)); + if vertex.index >= 3 { + local_space = vec2(f32(vertex.index & 1u), f32((vertex.index >> 1u) - 1u)); + } + let position = instance.min + local_space * (instance.max - instance.min); + + let view_space = (position - view.position.xy) / view.scale.x; + let clip_space = vec4(view_space.x * aspect, view_space.y, 0.0, 1.0); + + result.clip_space = clip_space; + result.color = instance.color; + return result; +} + +@fragment +fn fragment_main(vertex: VertexOutput) -> @location(0) vec4 { + return vertex.color; +} diff --git a/packages/graphics-2d/src/types/options/final/rectangle-options.type.ts b/packages/graphics-2d/src/types/options/final/rectangle-options.type.ts index 28efe0b9..10404647 100644 --- a/packages/graphics-2d/src/types/options/final/rectangle-options.type.ts +++ b/packages/graphics-2d/src/types/options/final/rectangle-options.type.ts @@ -1,5 +1,7 @@ +import { type IVertex2D } from "../../common"; import { type IColorOption } from "../base/color.type"; -import { type IPositionOption } from "../base/position.type"; -import { type ISizeOption } from "../base/size.type"; -export interface IRectangleOptions extends IColorOption, IPositionOption, ISizeOption {} +export interface IRectangleOptions extends IColorOption { + min: IVertex2D; + max: IVertex2D; +}