205 lines
6 KiB
JavaScript
205 lines
6 KiB
JavaScript
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
|
|
}
|
|
|