import { addComponent, addEntity, createWorld, query } from '/src/ecs.js' import { Engine, Startup, Update, World } from '/src/core/engine.js' import { DefaultPlugins } from '/src/plugins/index.js' import { WebGLContext } from '/src/plugins/renderer/webgl-context.js' import { Camera, Mesh, Renderable, Transform } from '/src/components/index.js' import * as twgl from '/public/vendor/twgl/twgl-full.module.js' import { Assets, AssetType } from '/src/core/assets.js' import { Geometry, Material, Materials, Meshes } from '/src/plugins/renderer/index.js' /** @param {number} degrees */ const deg2rad = degrees => degrees * Math.PI / 180 // INFO: does a camera need a Transform, specifically // a scale?? /** @param {World} world */ const createCamera = world => { const entity = addEntity(world) addComponent(world, entity, [Camera, Transform]) const transform = twgl.m4.identity() twgl.m4.translate(transform, [0, 0, 10], transform) Transform.matrix[entity] = transform Camera.projectionMatrix[entity] = [] Camera.viewMatrix[entity] = [] Camera.up[entity] = new Float32Array([0, 1, 0]) Camera.fov[entity] = deg2rad(30) Camera.zNear[entity] = 0.1 Camera.zFar[entity] = 1000 return entity } const Cube = () => { const position = [ // Front face -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5, // Back face -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, // Top face -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, // Bottom face -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, // Right face 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, // Left face -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, ] const indices = [ // Front face 0, 1, 2, 0, 2, 3, // Back face 4, 5, 6, 4, 6, 7, // Top face 8, 9, 10, 8, 10, 11, // Bottom face 12, 13, 14, 12, 14, 15, // Right face 16, 17, 18, 16, 18, 19, // Left face 20, 21, 22, 20, 22, 23, ] const color = [ // Front face (red) 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // Back face (green) 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, // Top face (blue) 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, // Bottom face (yellow) 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, // Right face (magenta) 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, // Left face (cyan) 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, ] return { position, indices, color: { numComponents: 3, data: color } } } const Quad = () => { const position = [ -0.5, -0.5, 0, 0.5, -0.5, 0, 0.5, 0.5, 0, -0.5, 0.5, 0, ] const indices = [ 0, 1, 2, 2, 3, 0, ] const color = [ 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, ] return { position, indices, color: { numComponents: 3, data: color } } } const Triangle = () => { return { position: [-0.5, -0.5, 0, 0.5, -0.5, 0, 0, 0.5, 0], color: { numComponents: 3, data: [1, 0, 0, 0, 1, 0, 0, 0, 1] }, indices: [0, 1, 2] } } const createObject = (world, mesh, material, position) => { const entity = addEntity(world) addComponent(world, entity, [Renderable, Mesh, Transform]) const transform = twgl.m4.identity() twgl.m4.translate(transform, position, transform) Transform.matrix[entity] = transform Mesh.geometry[entity] = mesh Mesh.material[entity] = material return entity } /** @type {HTMLCanvasElement} */ const canvas = document.querySelector('main canvas') if (canvas.getContext) { const world = createWorld(new World()) let app = new Engine(world, canvas) .addResource(new WebGLContext(canvas)) .addResource(new Assets()) .addPlugin(DefaultPlugins) .addSystem(Startup, async world => { const gl = world.getResource(WebGLContext).context const meshes = world.getResource(Meshes) const materials = world.getResource(Materials) const assets = world.getResource(Assets) const camera = createCamera(world) let sources = ['simple-vert.wgsl', 'simple-frag.wgsl'] .map(url => `/public/shaders/${url}`) .map(import.meta.resolve) .map(url => assets.load(url, AssetType.Text)) sources = await Promise.all(sources) const mesh = Cube() const geometry = new Geometry(mesh.position, mesh.indices).createBuffers() const meshHandle = meshes.add(buffer) const materialHandle = materials.add(new Material( programInfo, { u_color: [1, 1, 1, 1] } )) const one = createObject(world, meshHandle, materialHandle, [0, -1.5, 0]) let transform = Transform.matrix[one] twgl.m4.rotateX(transform, deg2rad(45), transform) twgl.m4.rotateY(transform, deg2rad(45), transform) const two = createObject(world, meshHandle, materialHandle, [2, 1, 0]) transform = Transform.matrix[two] twgl.m4.rotateX(transform, deg2rad(135), transform) twgl.m4.rotateY(transform, deg2rad(135), transform) const three = createObject(world, meshHandle, materialHandle, [-2, 1, 0]) transform = Transform.matrix[three] twgl.m4.rotateX(transform, deg2rad(225), transform) twgl.m4.rotateY(transform, deg2rad(225), transform) }) .addSystem(Update, world => { const meshes = query(world, [Mesh, Transform]) for (const mesh of meshes) { const transform = Transform.matrix[mesh] twgl.m4.rotateZ(transform, 0.01, transform) } }) .run() } else { // canvas not supported }