From 9d2bf4055d2bea4fd08a564bc3ab76886a13c513 Mon Sep 17 00:00:00 2001 From: Heaust Azure <54670936+Heaust-ops@users.noreply.github.com> Date: Tue, 6 May 2025 18:53:21 +0530 Subject: [PATCH] =?UTF-8?q?added=20a=20shitty=20ecs=20that=20I'm=20confide?= =?UTF-8?q?nt=20is=20way=20worse=20than=20just=20looping=20=E2=80=A6=20(#4?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * added a shitty ecs that I'm confident is way worse than just looping objects lol * mader a rendering system based on ecs --- core/connection/mainThread.ts | 15 +-- core/connection/workerThread.ts | 33 +++-- core/ecs/ecs.ts | 110 ++++++++++++++++ core/gl/index.ts | 156 ---------------------- core/gl/vertices.ts | 22 ---- core/global.d.ts | 1 + core/renderer/engine.ts | 31 +++++ core/renderer/gl.ts | 107 +++++++++++++++ core/renderer/scene.ts | 197 ++++++++++++++++++++++++++++ core/shaders/triangle/frag.glsl | 16 +++ core/shaders/triangle/vertex.glsl | 20 +++ package.json | 3 +- public/shaders/triangle/frag.glsl | 13 -- public/shaders/triangle/vertex.glsl | 18 --- src/main.ts | 3 + vite.config.ts | 6 + yarn.lock | 31 +++++ 17 files changed, 549 insertions(+), 233 deletions(-) create mode 100644 core/ecs/ecs.ts delete mode 100644 core/gl/index.ts delete mode 100644 core/gl/vertices.ts create mode 100644 core/global.d.ts create mode 100644 core/renderer/engine.ts create mode 100644 core/renderer/gl.ts create mode 100644 core/renderer/scene.ts create mode 100644 core/shaders/triangle/frag.glsl create mode 100644 core/shaders/triangle/vertex.glsl delete mode 100644 public/shaders/triangle/frag.glsl delete mode 100644 public/shaders/triangle/vertex.glsl create mode 100644 vite.config.ts diff --git a/core/connection/mainThread.ts b/core/connection/mainThread.ts index 988fcfd..9b3baf5 100644 --- a/core/connection/mainThread.ts +++ b/core/connection/mainThread.ts @@ -58,11 +58,11 @@ const connectWorker = (worker: Worker) => { document.addEventListener( "pointermove", - eventPassers[EventTypes.pointermove] + eventPassers[EventTypes.pointermove], ); document.addEventListener( "pointerdown", - eventPassers[EventTypes.pointerdown] + eventPassers[EventTypes.pointerdown], ); document.addEventListener("pointerup", eventPassers[EventTypes.pointerup]); // @@ -72,15 +72,15 @@ const connectWorker = (worker: Worker) => { const disconnectWorker = () => { document.removeEventListener( "pointermove", - eventPassers[EventTypes.pointermove] + eventPassers[EventTypes.pointermove], ); document.removeEventListener( "pointerdown", - eventPassers[EventTypes.pointerdown] + eventPassers[EventTypes.pointerdown], ); document.removeEventListener( "pointerup", - eventPassers[EventTypes.pointerup] + eventPassers[EventTypes.pointerup], ); // document.removeEventListener("keydown", eventPassers[EventTypes.keydown]); @@ -97,11 +97,6 @@ const attachCanvas = (worker: Worker, canvas: HTMLCanvasElement | string) => { throw new Error("Fatal: Canvas Not Found!"); } - // set canvas dimensions - // if this is not done, the canvas passed to the web worker - // will have the default size of 300x150 - // this will cause the viewport to be set to the default size - // and eveything will be messed up canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; diff --git a/core/connection/workerThread.ts b/core/connection/workerThread.ts index a16e876..4817afb 100644 --- a/core/connection/workerThread.ts +++ b/core/connection/workerThread.ts @@ -1,7 +1,14 @@ -import { Attribute, draw, ProgramData } from "../gl"; -import { cubeVertices } from "../gl/vertices"; +import { Engine } from "../renderer/engine"; import { MessageType } from "./mainThread"; +const cubeVertices = [ + 1, -1, 1, -1, -1, 1, -1, 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, -1, -1, 1, + -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, -1, + 1, 1, 1, -1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, + -1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, 1, 1, -1, 1, 1, 1, + 1, -1, 1, 1, -1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, 1, +]; + const handleConnection = (msg: MessageEvent) => { const { data } = msg; @@ -12,19 +19,19 @@ const handleConnection = (msg: MessageEvent) => { case MessageType.attachCanvas: const canvas = data[1]; - const ctxWorker = canvas.getContext("webgl2"); - var p: ProgramData> = { - vertexShaderSource: "/shaders/triangle/vertex.glsl", - fragmentShaderSource: "/shaders/triangle/frag.glsl", - attributes: [ - { - name: "position", - data: new Float32Array(cubeVertices), - }, - ], + const engine = new Engine(canvas); + const scene = engine.createScene(); + scene.addMesh("box", cubeVertices); + scene.addCamera("cam", true); + + const raf = () => { + requestAnimationFrame(() => { + scene.runSystems(); + raf(); + }); }; - requestAnimationFrame(() => draw(ctxWorker, p)); + raf(); break; } diff --git a/core/ecs/ecs.ts b/core/ecs/ecs.ts new file mode 100644 index 0000000..d55a23d --- /dev/null +++ b/core/ecs/ecs.ts @@ -0,0 +1,110 @@ +type ComponentMap = { + uid: (number | null)[]; +} & { + [K in keyof CT]?: Array; +}; + +namespace ECS { + export type System> = ( + arg: ComponentsType & { uid: (number | null)[] }, + ) => Partial | null; +} + +class ECS> { + private components: ComponentMap = { uid: [] }; + private componentDefaults: Record< + string, + null | ComponentsType[keyof ComponentsType] + > = { uid: null }; + private systems: Record> = {}; + + /** + * System + */ + runSystems() { + const limit = this.components.uid.length; + for (let i = 0; i < limit; i++) { + const obj = {} as Record; + + for (const key in this.components) { + obj[key] = this.components[key]![i]; + } + + const systems = Object.values(this.systems); + for (let j = 0; j < systems.length; j++) { + const res = systems[j]( + obj as ComponentsType & { uid: (number | null)[] }, + ); + if (!res) continue; + + for (const key in res) { + if (!this.components[key]) continue; + this.components[key][i] = res[key]!; + } + } + } + } + + addSystem(system: ECS.System) { + const id = crypto.randomUUID(); + this.systems[id] = system; + return id; + } + + removeSystem(id: string) { + delete this.systems[id]; + } + + getById(uid: number) { + if (this.components.uid.length <= uid) return {}; + + const obj = {} as Record; + + for (const key in this.components) { + obj[key] = this.components[key]![uid]; + } + + return obj; + } + + /** + * Entity + */ + addEntity(components: ComponentsType) { + for (const key in this.components) { + if (key === "uid") { + this.components[key].push(this.components[key].length); + continue; + } + + this.components[key]!.push( + components[key] ?? this.componentDefaults[key], + ); + } + + return this.components.uid.length - 1; + } + + /** + * Component + */ + addComponent( + name: keyof ComponentsType, + fillValue = null as null | ComponentsType[keyof ComponentsType], + defaultValue = null as null | ComponentsType[keyof ComponentsType], + ) { + if (this.components[name]) throw new Error("Component already exists"); + + this.components[name] = new Array(this.components.uid.length).fill( + fillValue, + ) as ComponentMap[keyof ComponentsType]; + + this.componentDefaults[name as string] = defaultValue; + } + + removeComponent(name: keyof ComponentsType) { + delete this.components[name]; + } +} + +export { ECS }; diff --git a/core/gl/index.ts b/core/gl/index.ts deleted file mode 100644 index 0fc7068..0000000 --- a/core/gl/index.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { mat4 } from "gl-matrix"; -import { cubeVertices } from "./vertices"; - -type AttributeDataTypes = Float32Array | Int32Array; - -export interface Attribute { - name: string; - data: T; -} - -export interface Dimensions { - width: number; - height: number; -} - -export interface ProgramData> { - vertexShaderSource: string; - fragmentShaderSource: string; - attributes: T[]; -} - -async function fetchShader(path: string) { - const response = await fetch(path); - return response.text(); -} - -async function createShader( - gl: WebGL2RenderingContext, - type: number, - sourceFile: string -) { - const source = await fetchShader(sourceFile); - - var shader = gl.createShader(type); - if (!shader) return; - - gl.shaderSource(shader, source); - gl.compileShader(shader); - var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); - if (!success) { - console.error(gl.getShaderInfoLog(shader)); // eslint-disable-line - gl.deleteShader(shader); - } - - return shader; -} - -async function setupProgram>( - gl: WebGL2RenderingContext, - programData: ProgramData -) { - var program = gl.createProgram(); - if (!program) return; - - var vertexShader = await createShader( - gl, - gl.VERTEX_SHADER, - programData.vertexShaderSource - ); - if (!vertexShader) return; - - var fragmentShader = await createShader( - gl, - gl.FRAGMENT_SHADER, - programData.fragmentShaderSource - ); - if (!fragmentShader) return; - - gl.attachShader(program, vertexShader); - gl.attachShader(program, fragmentShader); - gl.linkProgram(program); - - var success = gl.getProgramParameter(program, gl.LINK_STATUS); - if (!success) { - console.error(gl.getProgramInfoLog(program)); - gl.deleteProgram(program); - } - - return program; -} - -function setupAttribute>( - gl: WebGL2RenderingContext, - program: WebGLProgram, - attribute: T -) { - const location = gl.getAttribLocation(program, attribute.name); - if (location === -1) return; - - // setup a buffer for the attribute data - const buffer = gl.createBuffer(); - if (!buffer) return; - - gl.bindBuffer(gl.ARRAY_BUFFER, buffer); - gl.bufferData(gl.ARRAY_BUFFER, attribute.data, gl.STATIC_DRAW); - - const vao = gl.createVertexArray(); - if (!vao) return; - - gl.bindVertexArray(vao); - - gl.enableVertexAttribArray(location); - gl.vertexAttribPointer(location, 3, gl.FLOAT, false, 5 * 4, 0); -} - -export async function draw>( - gl: WebGL2RenderingContext, - programData: ProgramData -) { - gl.enable(gl.DEPTH_TEST); - - const program = await setupProgram(gl, programData); - if (!program) { - console.error("failed to setup program"); - return; - } - - gl.useProgram(program); - - for (const attribute of programData.attributes) { - setupAttribute(gl, program, attribute); - } - - let view = mat4.create(); - view = mat4.translate(view, view, [0, 0, -5]); - - let model = mat4.create(); - const angle = Date.now() * 0.001; - model = mat4.rotate(model, model, angle, [0.5, 1, 0]); - - const projection = mat4.create(); - mat4.perspective( - projection, - 45, - gl.canvas.width / gl.canvas.height, - 0.1, - 100.0 - ); - - const viewLoc = gl.getUniformLocation(program, "view"); - const modelLoc = gl.getUniformLocation(program, "model"); - const projectionLoc = gl.getUniformLocation(program, "projection"); - - gl.uniformMatrix4fv(viewLoc, false, view); - gl.uniformMatrix4fv(modelLoc, false, model); - gl.uniformMatrix4fv(projectionLoc, false, projection); - - gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); - - gl.clearColor(0.0, 0.0, 0.0, 1.0); - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - gl.drawArrays(gl.TRIANGLES, 0, 36); - - requestAnimationFrame(() => draw(gl, programData)); -} diff --git a/core/gl/vertices.ts b/core/gl/vertices.ts deleted file mode 100644 index 419257f..0000000 --- a/core/gl/vertices.ts +++ /dev/null @@ -1,22 +0,0 @@ -export const cubeVertices = [ - -0.5, -0.5, -0.5, 0.0, 0.0, 0.5, -0.5, -0.5, 1.0, 0.0, 0.5, 0.5, -0.5, 1.0, - 1.0, 0.5, 0.5, -0.5, 1.0, 1.0, -0.5, 0.5, -0.5, 0.0, 1.0, -0.5, -0.5, -0.5, - 0.0, 0.0, - - -0.5, -0.5, 0.5, 0.0, 0.0, 0.5, -0.5, 0.5, 1.0, 0.0, 0.5, 0.5, 0.5, 1.0, 1.0, - 0.5, 0.5, 0.5, 1.0, 1.0, -0.5, 0.5, 0.5, 0.0, 1.0, -0.5, -0.5, 0.5, 0.0, 0.0, - - -0.5, 0.5, 0.5, 1.0, 0.0, -0.5, 0.5, -0.5, 1.0, 1.0, -0.5, -0.5, -0.5, 0.0, - 1.0, -0.5, -0.5, -0.5, 0.0, 1.0, -0.5, -0.5, 0.5, 0.0, 0.0, -0.5, 0.5, 0.5, - 1.0, 0.0, - - 0.5, 0.5, 0.5, 1.0, 0.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5, -0.5, -0.5, 0.0, 1.0, - 0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, 0.5, 0.0, 0.0, 0.5, 0.5, 0.5, 1.0, 0.0, - - -0.5, -0.5, -0.5, 0.0, 1.0, 0.5, -0.5, -0.5, 1.0, 1.0, 0.5, -0.5, 0.5, 1.0, - 0.0, 0.5, -0.5, 0.5, 1.0, 0.0, -0.5, -0.5, 0.5, 0.0, 0.0, -0.5, -0.5, -0.5, - 0.0, 1.0, - - -0.5, 0.5, -0.5, 0.0, 1.0, 0.5, 0.5, -0.5, 1.0, 1.0, 0.5, 0.5, 0.5, 1.0, 0.0, - 0.5, 0.5, 0.5, 1.0, 0.0, -0.5, 0.5, 0.5, 0.0, 0.0, -0.5, 0.5, -0.5, 0.0, 1.0, -]; diff --git a/core/global.d.ts b/core/global.d.ts new file mode 100644 index 0000000..e47c9c6 --- /dev/null +++ b/core/global.d.ts @@ -0,0 +1 @@ +/// diff --git a/core/renderer/engine.ts b/core/renderer/engine.ts new file mode 100644 index 0000000..7ba1a5c --- /dev/null +++ b/core/renderer/engine.ts @@ -0,0 +1,31 @@ +import { Scene } from "./scene"; + +class Engine { + canvas: HTMLCanvasElement; + ctx: WebGL2RenderingContext; + scenes = [] as Scene[]; + + constructor(canvas: string | HTMLCanvasElement) { + /** get canvas by id */ + if (typeof canvas === "string") { + canvas = document.getElementById(canvas)! as HTMLCanvasElement; + } + + if (!canvas) { + throw new Error("canvas not found"); + } + this.canvas = canvas; + this.ctx = canvas.getContext("webgl2")!; + if (!this.ctx) { + throw new Error("can't get webgl2 context"); + } + } + + createScene() { + const scene = new Scene(this.canvas, this.ctx); + this.scenes.push(scene); + return scene; + } +} + +export { Engine }; diff --git a/core/renderer/gl.ts b/core/renderer/gl.ts new file mode 100644 index 0000000..4310e4e --- /dev/null +++ b/core/renderer/gl.ts @@ -0,0 +1,107 @@ +import { mat4 } from "gl-matrix"; + +export const compileShader = ( + gl: WebGL2RenderingContext, + type: number, + source: string, +) => { + const shader = gl.createShader(type); + if (!shader) { + throw new Error(`couldn't make the shader ${source}`); + } + + gl.shaderSource(shader, source); + gl.compileShader(shader); + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + throw new Error( + `Error in ${source}: ${gl.getShaderInfoLog(shader) ?? "no error returned"}`, + ); + } + + return shader; +}; + +export const createProgram = ( + gl: WebGL2RenderingContext, + vs: string, + fs: string, +): WebGLProgram => { + const program = gl.createProgram()!; + + const vShader = compileShader(gl, gl.VERTEX_SHADER, vs); + const fShader = compileShader(gl, gl.FRAGMENT_SHADER, fs); + + gl.attachShader(program, vShader); + gl.attachShader(program, fShader); + + gl.linkProgram(program); + + if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { + throw new Error(gl.getProgramInfoLog(program) || ""); + } + + return program; +}; + +export type AttributeCollection = { + name: string; + data: Float32Array; + size: number; +}; + +export const setupVAO = ( + gl: WebGL2RenderingContext, + program: WebGLProgram, + attributeCollections: AttributeCollection[], +) => { + const vao = gl.createVertexArray()!; + gl.bindVertexArray(vao); + + for (const attr of attributeCollections) { + const loc = gl.getAttribLocation(program, attr.name); + if (loc >= 0) { + const buf = gl.createBuffer()!; + gl.bindBuffer(gl.ARRAY_BUFFER, buf); + gl.bufferData(gl.ARRAY_BUFFER, attr.data, gl.STATIC_DRAW); + gl.enableVertexAttribArray(loc); + gl.vertexAttribPointer(loc, attr.size, gl.FLOAT, false, 0, 0); + } + } + + gl.bindVertexArray(null); + return vao; +}; + +export const updateVAO = ( + gl: WebGL2RenderingContext, + program: WebGLProgram, + vao: WebGLVertexArrayObject, + attributeCollections: AttributeCollection[], +) => { + gl.bindVertexArray(vao); + + for (const attr of attributeCollections) { + const loc = gl.getAttribLocation(program, attr.name); + if (loc >= 0) { + const buf = gl.createBuffer()!; + gl.bindBuffer(gl.ARRAY_BUFFER, buf); + gl.bufferData(gl.ARRAY_BUFFER, attr.data, gl.STATIC_DRAW); + gl.enableVertexAttribArray(loc); + gl.vertexAttribPointer(loc, attr.size, gl.FLOAT, false, 0, 0); + } + } + + gl.bindVertexArray(null); + return vao; +}; + +export const setMat4 = ( + gl: WebGL2RenderingContext, + program: WebGLProgram, + name: string, + mat: mat4, +) => { + const loc = gl.getUniformLocation(program, name); + if (loc) gl.uniformMatrix4fv(loc, false, mat); +}; diff --git a/core/renderer/scene.ts b/core/renderer/scene.ts new file mode 100644 index 0000000..d34b552 --- /dev/null +++ b/core/renderer/scene.ts @@ -0,0 +1,197 @@ +import { mat4, vec3 } from "gl-matrix"; +import { ECS } from "../ecs/ecs"; +import { createProgram, setMat4, setupVAO, updateVAO } from "./gl"; +import defaultVertexSrc from "../shaders/triangle/vertex.glsl"; +import defaultFragSrc from "../shaders/triangle/frag.glsl"; + +class Scene { + canvas: HTMLCanvasElement; + gl: WebGL2RenderingContext; + ecs: ECS>; + activeCamera: number; + + constructor(canvas: HTMLCanvasElement, ctx: WebGL2RenderingContext) { + this.canvas = canvas; + this.gl = ctx; + this.activeCamera = -1; + + /** make ecs */ + this.ecs = new ECS(); + this.initECS(); + } + + private initECS() { + const projection = mat4.create(); + mat4.perspective( + projection, + 45, + this.canvas.width / this.canvas.height, + 0.1, + 100.0, + ); + + this.ecs.addComponent("isMesh"); + this.ecs.addComponent("isCamera"); + this.ecs.addComponent("isMaterial"); + this.ecs.addComponent("program"); + this.ecs.addComponent("vao"); + this.ecs.addComponent("name", "deafult", "default"); + this.ecs.addComponent("attr_pos", [], []); + this.ecs.addComponent("attr_normals", [], []); + this.ecs.addComponent("u_model_matrix", mat4.create(), mat4.create()); + this.ecs.addComponent("u_projection_matrix", projection, projection); + + const defaultMaterial = this.addMaterial( + "default-material", + defaultVertexSrc, + defaultFragSrc, + ); + this.ecs.addComponent("applied_material", defaultMaterial, defaultMaterial); + + this.ecs.addSystem((data) => { + this.render(data); + + const model = mat4.create(); + const angle = Date.now() * 0.001; + mat4.translate(model, model, vec3.fromValues(0, 0, -5)); + mat4.rotate(model, model, angle, [0.5, 1, 0]); + + if (data["isMesh"]) { + return { + u_model_matrix: model, + }; + } + + return null; + }); + } + + runSystems() { + this.ecs.runSystems(); + } + + private render(data: any) { + if (this.activeCamera === -1) return; + const camera = this.ecs.getById(this.activeCamera); + + const view = mat4.create(); + mat4.invert(view, camera["u_model_matrix"] as mat4); + + const projection = camera["u_projection_matrix"] as mat4; + + const gl = this.gl; + gl.enable(gl.DEPTH_TEST); + + gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); + + gl.clearColor(0.0, 0.0, 0.0, 1.0); + // gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + if (data["isMesh"]) { + const { program, vao } = this.ecs.getById(data["applied_material"]); + + const attrCollection = [ + { + name: "attr_pos", + data: data["attr_pos"], + size: 3, + }, + { + name: "attr_normals", + data: data["attr_normals"], + size: 3, + }, + ]; + + updateVAO(gl, program as any, vao as any, attrCollection); + gl.useProgram(program!); + + const model = data["u_model_matrix"]; + setMat4(gl, program as any, "model", model); + setMat4(gl, program as any, "view", view); + setMat4(gl, program as any, "projection", projection); + + gl.bindVertexArray(vao as any); + const vertexCount = data["attr_pos"].length / 3; + gl.drawArrays(gl.TRIANGLES, 0, vertexCount); + console.log(vertexCount); + } + + gl.bindVertexArray(null); + gl.useProgram(null); + } + + addMaterial(name: string, vs: string, fs: string) { + const program = createProgram(this.gl, vs, fs); + const vao = setupVAO(this.gl, program, []); + return this.ecs.addEntity({ + name, + isMaterial: true, + program, + vao, + }); + } + + addCamera(name: string, setActive = true) { + const uid = this.ecs.addEntity({ + name, + }); + if (setActive) this.activeCamera = uid; + } + + addMesh(name: string, positions: number[], normals?: number[]) { + const numVerts = Math.floor(positions.length / 3); + const numTris = Math.floor(numVerts / 3); + positions.length = numTris * 9; + + if (!normals) { + normals = []; + const a = vec3.create(); + const b = vec3.create(); + const c = vec3.create(); + const e1 = vec3.create(); + const e2 = vec3.create(); + + for (let i = 0; i < numTris; i++) { + const base = i * 9; + + vec3.set( + a, + positions[base + 0], + positions[base + 1], + positions[base + 2], + ); + vec3.set( + b, + positions[base + 3], + positions[base + 4], + positions[base + 5], + ); + vec3.set( + c, + positions[base + 6], + positions[base + 7], + positions[base + 8], + ); + + vec3.subtract(e1, b, a); + vec3.subtract(e2, c, a); + vec3.cross(e1, e2, e1); + vec3.normalize(e1, e1); + + normals.push(e1[0], e1[1], e1[2]); + normals.push(e1[0], e1[1], e1[2]); + normals.push(e1[0], e1[1], e1[2]); + } + } + + this.ecs.addEntity({ + name, + attr_pos: new Float32Array(positions), + attr_normals: new Float32Array(normals), + isMesh: true, + }); + } +} + +export { Scene }; diff --git a/core/shaders/triangle/frag.glsl b/core/shaders/triangle/frag.glsl new file mode 100644 index 0000000..81b3114 --- /dev/null +++ b/core/shaders/triangle/frag.glsl @@ -0,0 +1,16 @@ +#version 300 es + +precision highp float; + +in vec3 vNormal; +out vec4 fragColor; + +void main() { + vec3 normal = normalize(vNormal); + vec3 lightDir = normalize(vec3(0.0, 0.0, 1.0)); + float diff = max(dot(normal, lightDir), 0.0); + + vec3 diffuseColor = vec3(1.0, 0.5, 0.3) * diff; + + fragColor = vec4(diffuseColor, 1.0); +} diff --git a/core/shaders/triangle/vertex.glsl b/core/shaders/triangle/vertex.glsl new file mode 100644 index 0000000..d8a6f3e --- /dev/null +++ b/core/shaders/triangle/vertex.glsl @@ -0,0 +1,20 @@ +#version 300 es + +precision highp float; + +in vec3 attr_pos; +in vec3 attr_normals; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +out vec3 vNormal; + +void main() { + mat3 normalMatrix = transpose(inverse(mat3(model))); + + vNormal = normalize(normalMatrix * attr_normals); + + gl_Position = projection * view * model * vec4(attr_pos, 1.0); +} diff --git a/package.json b/package.json index c01ef3e..567f776 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ }, "devDependencies": { "typescript": "^5.2.2", - "vite": "^5.3.4" + "vite": "^5.3.4", + "vite-plugin-glsl": "^1.4.1" }, "dependencies": { "gl-matrix": "^3.4.3", diff --git a/public/shaders/triangle/frag.glsl b/public/shaders/triangle/frag.glsl deleted file mode 100644 index 92d1c10..0000000 --- a/public/shaders/triangle/frag.glsl +++ /dev/null @@ -1,13 +0,0 @@ -#version 300 es - -// fragment shaders don't have a default precision so we need -// to pick one. highp is a good default. It means "high precision" -precision highp float; - -// we need to declare an output for the fragment shader -out vec4 outColor; - -void main() { - // Just set the output to a constant redish-purple - outColor = vec4(1, 0, 0.5, 1); -} \ No newline at end of file diff --git a/public/shaders/triangle/vertex.glsl b/public/shaders/triangle/vertex.glsl deleted file mode 100644 index 1f17f24..0000000 --- a/public/shaders/triangle/vertex.glsl +++ /dev/null @@ -1,18 +0,0 @@ -#version 300 es - -// an attribute is an input (in) to a vertex shader. -// It will receive data from a buffer -in vec3 position; - -// uniforms -uniform mat4 model; -uniform mat4 view; -uniform mat4 projection; - -// all shaders have a main function -void main() { - - // gl_Position is a special variable a vertex shader - // is responsible for setting - gl_Position = projection * view * model * vec4(position, 1.0); -} \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 457909d..2fc2a90 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,10 @@ import "./style.css"; import { attachCanvas, connectWorker } from "../core/connection/mainThread.ts"; import MainSceneWorker from "../examples/starterScene?worker"; +import { ECS } from "../core/ecs/ecs"; const mainSceneWorker = new MainSceneWorker(); connectWorker(mainSceneWorker); attachCanvas(mainSceneWorker, "rendering-canvas"); + +(window as any).ecs = new ECS(); diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..aba1f20 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "vite"; +import glsl from "vite-plugin-glsl"; + +export default defineConfig({ + plugins: [glsl({})], +}); diff --git a/yarn.lock b/yarn.lock index 9a40074..44781e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -117,6 +117,15 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== +"@rollup/pluginutils@^5.1.4": + version "5.1.4" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.1.4.tgz#bb94f1f9eaaac944da237767cdfee6c5b2262d4a" + integrity sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^4.0.2" + "@rollup/rollup-android-arm-eabi@4.19.2": version "4.19.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.19.2.tgz#6b991cb44bf69e50163528ea85bed545330ba821" @@ -202,6 +211,11 @@ resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz" integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== +"@types/estree@^1.0.0": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.7.tgz#4158d3105276773d5b7695cd4834b1722e4f37a8" + integrity sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ== + esbuild@^0.21.3: version "0.21.5" resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz" @@ -231,6 +245,11 @@ esbuild@^0.21.3: "@esbuild/win32-ia32" "0.21.5" "@esbuild/win32-x64" "0.21.5" +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + fsevents@~2.3.2, fsevents@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" @@ -251,6 +270,11 @@ picocolors@^1.0.1: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz" integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + postcss@^8.4.39: version "8.4.40" resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz" @@ -300,6 +324,13 @@ typescript@^5.2.2: resolved "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz" integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== +vite-plugin-glsl@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/vite-plugin-glsl/-/vite-plugin-glsl-1.4.1.tgz#9468538799c539cbd56016e3502c2c65ba06d344" + integrity sha512-LkfLZeHdyl0drA71GmCCfcTeLuXyn/DYwDfjzQrupvNYVwdFRvb7nkCnCm0o9LZRKxS4/8r7E3KNM7KQjWrWWQ== + dependencies: + "@rollup/pluginutils" "^5.1.4" + vite@^5.3.4: version "5.3.5" resolved "https://registry.npmjs.org/vite/-/vite-5.3.5.tgz"