p3nGu1nZz commited on
Commit
538ade1
1 Parent(s): ff401af

implement game ticks

Browse files
Files changed (2) hide show
  1. index.js +62 -33
  2. wgpu-config.js +2 -1
index.js CHANGED
@@ -17,16 +17,31 @@ async function main() {
17
  if (!device) return;
18
 
19
  state.device = device;
 
 
20
  const shaderCode = await fetchShaderCode('shaders.wgsl');
21
  const vertexSize = config.floatsPerVertex * 4;
22
 
 
23
  state.pipeline = await createPipeline(state.device, presentationFormat, vertexSize, shaderCode);
24
 
 
25
  const glyphCanvas = generateGlyphTextureAtlas(CANVAS, CTX, config);
26
  document.body.appendChild(glyphCanvas);
27
  glyphCanvas.style.backgroundColor = '#222';
28
 
29
- const vertexBufferSize = config.maxGlyphs * config.vertsPerGlyph * vertexSize;
 
 
 
 
 
 
 
 
 
 
 
30
  state.vertexBuffer = state.device.createBuffer({
31
  label: 'vertices',
32
  size: vertexBufferSize,
@@ -39,25 +54,31 @@ async function main() {
39
  usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
40
  });
41
 
42
- const indices = Array.from({ length: config.maxGlyphs * 6 }, (_, i) => {
 
 
 
 
 
43
  const ndx = Math.floor(i / 6) * 4;
44
  return (i % 6 < 3 ? [ndx, ndx + 1, ndx + 2] : [ndx + 2, ndx + 1, ndx + 3])[i % 3];
45
  });
46
- state.device.queue.writeBuffer(state.indexBuffer, 0, new Uint32Array(indices));
47
 
 
48
  const { vertexData, numGlyphs, width, height } = generateGlyphVerticesForText('Hello\nworld!\nText in\nWebGPU!', COLORS, config, glyphCanvas);
49
  state.device.queue.writeBuffer(state.vertexBuffer, 0, vertexData);
50
 
51
  state.texture = createTextureFromSource(state.device, glyphCanvas, { mips: true });
52
  state.sampler = state.device.createSampler({
53
  minFilter: 'linear',
54
- magFilter: 'linear'
55
  });
56
 
57
  state.uniformBuffer = state.device.createBuffer({
58
  label: 'uniforms for quad',
59
  size: config.uniformBufferSize,
60
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
61
  });
62
 
63
  state.matrix = state.uniformValues.subarray(0, 16);
@@ -74,42 +95,50 @@ async function main() {
74
  state.numGlyphs = numGlyphs;
75
  state.width = width;
76
  state.height = height;
77
-
78
- gameLoop(context);
79
  }
80
 
81
  function gameLoop(context) {
82
  let lastTime = performance.now();
 
83
 
84
- function update() {
85
  const currentTime = performance.now();
86
- const deltaTime = (currentTime - lastTime) / 1000; // Convert to seconds
87
- state.time += deltaTime;
88
-
89
- const fov = 60 * Math.PI / 180;
90
- const aspect = canvas.clientWidth / canvas.clientHeight;
91
- const projectionMatrix = mat4.perspective(fov, aspect, config.render.zNear, config.render.zFar);
92
- const viewMatrix = mat4.lookAt([0, 0, 5], [0, 0, 0], [0, 1, 0]);
93
- const viewProjectionMatrix = mat4.multiply(projectionMatrix, viewMatrix);
94
- RENDER_PASS_DESCRIPTOR.colorAttachments[0].view = context.getCurrentTexture().createView();
95
- const encoder = state.device.createCommandEncoder();
96
- const pass = encoder.beginRenderPass(RENDER_PASS_DESCRIPTOR);
97
- pass.setPipeline(state.pipeline);
98
- mat4.rotateY(viewProjectionMatrix, state.time, state.matrix);
99
- mat4.translate(state.matrix, [-state.width / 2, -state.height / 2, 0], state.matrix);
100
- state.device.queue.writeBuffer(state.uniformBuffer, 0, state.uniformValues);
101
- pass.setBindGroup(0, state.bindGroup);
102
- pass.setVertexBuffer(0, state.vertexBuffer);
103
- pass.setIndexBuffer(state.indexBuffer, 'uint32');
104
- pass.drawIndexed(state.numGlyphs * 6);
105
- pass.end();
106
- state.device.queue.submit([encoder.finish()]);
107
-
108
- lastTime = currentTime;
109
- setTimeout(update, 16); // Approximate 60 FPS
110
  }
111
 
112
- update();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  }
114
 
115
  main();
 
17
  if (!device) return;
18
 
19
  state.device = device;
20
+
21
+ // Load shader code
22
  const shaderCode = await fetchShaderCode('shaders.wgsl');
23
  const vertexSize = config.floatsPerVertex * 4;
24
 
25
+ // Create pipeline
26
  state.pipeline = await createPipeline(state.device, presentationFormat, vertexSize, shaderCode);
27
 
28
+ // Generate and display glyph texture atlas
29
  const glyphCanvas = generateGlyphTextureAtlas(CANVAS, CTX, config);
30
  document.body.appendChild(glyphCanvas);
31
  glyphCanvas.style.backgroundColor = '#222';
32
 
33
+ // Create vertex and index buffers
34
+ createBuffers();
35
+
36
+ // Generate vertex buffer data and texture
37
+ generateVertexDataAndTexture(glyphCanvas);
38
+
39
+ // Start the game loop
40
+ gameLoop(context);
41
+ }
42
+
43
+ function createBuffers() {
44
+ const vertexBufferSize = config.maxGlyphs * config.vertsPerGlyph * config.floatsPerVertex * 4;
45
  state.vertexBuffer = state.device.createBuffer({
46
  label: 'vertices',
47
  size: vertexBufferSize,
 
54
  usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
55
  });
56
 
57
+ const indices = generateIndices(config.maxGlyphs);
58
+ state.device.queue.writeBuffer(state.indexBuffer, 0, new Uint32Array(indices));
59
+ }
60
+
61
+ function generateIndices(maxGlyphs) {
62
+ return Array.from({ length: maxGlyphs * 6 }, (_, i) => {
63
  const ndx = Math.floor(i / 6) * 4;
64
  return (i % 6 < 3 ? [ndx, ndx + 1, ndx + 2] : [ndx + 2, ndx + 1, ndx + 3])[i % 3];
65
  });
66
+ }
67
 
68
+ function generateVertexDataAndTexture(glyphCanvas) {
69
  const { vertexData, numGlyphs, width, height } = generateGlyphVerticesForText('Hello\nworld!\nText in\nWebGPU!', COLORS, config, glyphCanvas);
70
  state.device.queue.writeBuffer(state.vertexBuffer, 0, vertexData);
71
 
72
  state.texture = createTextureFromSource(state.device, glyphCanvas, { mips: true });
73
  state.sampler = state.device.createSampler({
74
  minFilter: 'linear',
75
+ magFilter: 'linear',
76
  });
77
 
78
  state.uniformBuffer = state.device.createBuffer({
79
  label: 'uniforms for quad',
80
  size: config.uniformBufferSize,
81
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
82
  });
83
 
84
  state.matrix = state.uniformValues.subarray(0, 16);
 
95
  state.numGlyphs = numGlyphs;
96
  state.width = width;
97
  state.height = height;
 
 
98
  }
99
 
100
  function gameLoop(context) {
101
  let lastTime = performance.now();
102
+ const frameInterval = 1000 / config.maxFPS;
103
 
104
+ function tick() {
105
  const currentTime = performance.now();
106
+ const deltaTime = (currentTime - lastTime) / 1000;
107
+
108
+ if (currentTime - lastTime >= frameInterval) {
109
+ update(deltaTime, context);
110
+ lastTime = currentTime;
111
+ }
112
+
113
+ setTimeout(tick, 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  }
115
 
116
+ tick();
117
+ }
118
+
119
+ function update(deltaTime, context) {
120
+ state.time += deltaTime;
121
+
122
+ // Set up projection and view matrices
123
+ const fov = 60 * Math.PI / 180;
124
+ const aspect = canvas.clientWidth / canvas.clientHeight;
125
+ const projectionMatrix = mat4.perspective(fov, aspect, config.render.zNear, config.render.zFar);
126
+ const viewMatrix = mat4.lookAt([0, 0, 5], [0, 0, 0], [0, 1, 0]);
127
+ const viewProjectionMatrix = mat4.multiply(projectionMatrix, viewMatrix);
128
+ RENDER_PASS_DESCRIPTOR.colorAttachments[0].view = context.getCurrentTexture().createView();
129
+
130
+ const encoder = state.device.createCommandEncoder();
131
+ const pass = encoder.beginRenderPass(RENDER_PASS_DESCRIPTOR);
132
+ pass.setPipeline(state.pipeline);
133
+ mat4.rotateY(viewProjectionMatrix, state.time, state.matrix);
134
+ mat4.translate(state.matrix, [-state.width / 2, -state.height / 2, 0], state.matrix);
135
+ state.device.queue.writeBuffer(state.uniformBuffer, 0, state.uniformValues);
136
+ pass.setBindGroup(0, state.bindGroup);
137
+ pass.setVertexBuffer(0, state.vertexBuffer);
138
+ pass.setIndexBuffer(state.indexBuffer, 'uint32');
139
+ pass.drawIndexed(state.numGlyphs * 6);
140
+ pass.end();
141
+ state.device.queue.submit([encoder.finish()]);
142
  }
143
 
144
  main();
wgpu-config.js CHANGED
@@ -21,5 +21,6 @@ export const config = {
21
  render: {
22
  zNear: 0.001,
23
  zFar: 50
24
- }
 
25
  };
 
21
  render: {
22
  zNear: 0.001,
23
  zFar: 50
24
+ },
25
+ maxFPS: 60
26
  };