Skip to content

Commit 483c318

Browse files
committed
[gldemo] move most code out of html into js module
Optionize and change world dimensions for example
1 parent 78bbdef commit 483c318

File tree

2 files changed

+135
-149
lines changed

2 files changed

+135
-149
lines changed

cube/gldemo.html

Lines changed: 9 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -11,95 +11,22 @@
1111
<body>
1212
<canvas id="world"></canvas>
1313
<script type="module">
14-
import {
15-
generateCurvedTiles,
16-
generateSimpleTiles,
17-
} from './tilegen.js';
18-
19-
import {
20-
default as demo,
21-
} from './gldemo.js';
22-
23-
function makeRandom(seed = 0xdead_beefn) {
24-
let randState = seed;
25-
const rand = () => (randState = randState * 6364136223846793005n + 1442695040888963407n) >> 17n & 0xffff_ffffn;
26-
const randn = n => rand() % n;
27-
const random = () => Number(rand()) / 0x1_0000_0000;
28-
return {rand, randn, random};
29-
}
14+
import demo from './gldemo.js';
3015

3116
const $world = document.querySelector('canvas#world');
32-
if ($world) demo({
17+
if (!$world) throw new Error('unable to find world canvas');
18+
19+
await demo({
3320
$world,
34-
cellSize: 130,
21+
cellSize: 100,
3522
tileSize: 256,
3623

37-
build(world) {
38-
const landCurveTiles = world.makeTileSheet(generateCurvedTiles({
39-
aFill: '#5c9e31', // land
40-
bFill: '#61b2e4', // water
41-
// gridLineStyle: 'red',
42-
}));
43-
44-
const foreTiles = world.makeTileSheet(generateSimpleTiles(
45-
{glyph: '🧚'},
46-
{glyph: '🍵'},
47-
{glyph: '🫖'},
48-
{glyph: '⛵'}
49-
));
50-
51-
const facet = world.makeFacet({x: 0, y: 0, width: 5, height: 5});
52-
53-
const bgSQ = facet.makeLayer(landCurveTiles);
54-
const bg = facet.makeLayer(landCurveTiles, {x: -0.5, y: -0.5});
55-
{
56-
const isWater = new Uint8Array(bg.width * bg.height);
57-
const {random} = makeRandom();
58-
for (let i = 0; i < isWater.length; i++)
59-
isWater[i] = random() > 0.5 ? 1 : 0;
60-
61-
const land = landCurveTiles.getLayerID(0b0000);
62-
const water = landCurveTiles.getLayerID(0b1111);
63-
for (let y = 0; y < bg.height; y++)
64-
for (let x = 0; x < bg.width; x++)
65-
bgSQ.set(x, y, {
66-
layerID: isWater[y * bg.width + x] ? water : land
67-
});
68-
69-
const stride = bg.width;
70-
for (let y = 0; y < bg.height; y++) {
71-
for (let x = 0; x < bg.width; x++) {
72-
const nw = isWater[(y + 0) * stride + x + 0];
73-
const ne = isWater[(y + 0) * stride + x + 1];
74-
const sw = isWater[(y + 1) * stride + x + 0];
75-
const se = isWater[(y + 1) * stride + x + 1];
76-
const tileID = ((nw << 1 | ne) << 1 | se) << 1 | sw;
77-
const layerID = landCurveTiles.getLayerID(tileID);
78-
bg.set(x, y, {layerID});
79-
}
80-
}
81-
82-
}
83-
bg.send();
84-
bgSQ.send();
85-
bgSQ.visible = false;
86-
87-
const fg = facet.makeLayer(foreTiles);
88-
{
89-
const {randn, random} = makeRandom();
90-
for (let y = 0; y < fg.height; y++) {
91-
for (let x = 0; x < fg.width; x++) {
92-
const tileID = Number(randn(2n * BigInt(foreTiles.size)));
93-
const layerID = foreTiles.getLayerID(tileID);
94-
const spin = random();
95-
fg.set(x, y, {layerID, spin});
96-
}
97-
}
98-
}
99-
fg.send();
100-
},
24+
worldWidth: 8,
25+
worldHeight: 8,
26+
showCurvyTiles: true,
10127

10228
});
29+
throw new Error('unexpected demo loop exit');
10330
</script>
10431
</body>
10532

cube/gldemo.js

Lines changed: 126 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -22,78 +22,128 @@ import {
2222
* @return TileSheet<T>
2323
*/
2424

25-
/** @typedef {object} TileWorld
26-
* @prop {tileMaker} makeTileSheet
27-
* @prop {(dims: FacetDims) => Facet} makeFacet
28-
*/
29-
30-
/** @typedef {object} FacetDims
31-
* @prop {number} x
32-
* @prop {number} y
33-
* @prop {number} width
34-
* @prop {number} height
35-
*/
36-
37-
/** @typedef {object} Facet
38-
* @prop {(sheet: TileSheet<unknown>, offset?: {x: number, y: number}) => Layer} makeLayer
39-
*/
25+
import {
26+
generateCurvedTiles,
27+
generateSimpleTiles,
28+
} from './tilegen.js';
4029

4130
/**
42-
* @param {object} param
43-
* @param {HTMLCanvasElement} param.$world
44-
* @param {number} [param.tileSize]
45-
* @param {number} [param.cellSize]
46-
* @param {(world: TileWorld) => void} param.build
31+
* @param {object} opts
32+
* @param {HTMLCanvasElement} opts.$world
33+
* @param {number} [opts.tileSize]
34+
* @param {number} [opts.cellSize]
35+
* @param {number} [opts.worldWidth]
36+
* @param {number} [opts.worldHeight]
37+
* @param {boolean} [opts.showCurvyTiles]
4738
*/
48-
export default async function demo({
49-
$world,
50-
tileSize = 256,
51-
cellSize = 64,
52-
build,
53-
}) {
39+
export default async function demo(opts) {
40+
const {
41+
$world,
42+
tileSize = 256,
43+
cellSize = 64,
44+
45+
// TODO fix curvy tile layer, needs to have dims N+1 but be scissored to cut outer ring in half
46+
worldWidth = 5,
47+
worldHeight = 5,
48+
showCurvyTiles = true,
49+
} = opts;
50+
5451
const gl = $world.getContext('webgl2');
5552
if (!gl) throw new Error('No GL For You!');
5653

5754
sizeToParent($world);
5855

56+
/** @type {Layer[]} */
57+
const layers = [];
58+
5959
const tileRend = makeTileRenderer(gl, await compileTileProgram(gl));
6060

61-
/** @type {TileSheet<unknown>[]} */
62-
const sheets = [];
63-
64-
/** @type {{dims: FacetDims, layers: Layer[]}[]} */
65-
const facets = [];
66-
67-
build({
68-
makeTileSheet(tiles) {
69-
const tileSheet = makeTileSheet(gl, tiles, { tileSize });
70-
sheets.push(tileSheet);
71-
return tileSheet;
72-
},
73-
74-
makeFacet(dims) {
75-
/** @type {Layer[]} */
76-
const layers = [];
77-
facets.push({ dims, layers });
78-
return {
79-
makeLayer({ texture }, offset = { x: 0, y: 0 }) {
80-
const { x, y, width, height } = dims;
81-
const layer = makeLayer(gl, {
82-
texture,
83-
cellSize,
84-
left: x + offset.x,
85-
top: y + offset.y,
86-
width, height
87-
});
88-
layers.push(layer);
89-
return layer;
90-
},
91-
};
92-
},
93-
});
94-
95-
/** @returns {Promise<number>} */
96-
const nextFrame = () => new Promise(resolve => requestAnimationFrame(t => resolve(t)))
61+
const landCurveTiles = makeTileSheet(gl, generateCurvedTiles({
62+
aFill: '#5c9e31', // land
63+
bFill: '#61b2e4', // water
64+
// gridLineStyle: 'red',
65+
}), { tileSize });
66+
67+
const foreTiles = makeTileSheet(gl, generateSimpleTiles(
68+
{ glyph: '🧚' },
69+
{ glyph: '🍵' },
70+
{ glyph: '🫖' },
71+
{ glyph: '⛵' }
72+
), { tileSize });
73+
74+
/**
75+
* @param {TileSheet<number>} sheet
76+
* @param {{x: number, y: number}} [offset]
77+
* @returns {Layer}
78+
*/
79+
const makeWorldLayer = ({ texture }, offset = { x: 0, y: 0 }) => {
80+
const x = 0, y = 0, width = worldWidth, height = worldHeight;
81+
const layer = makeLayer(gl, {
82+
texture,
83+
cellSize,
84+
left: x + offset.x,
85+
top: y + offset.y,
86+
width, height
87+
});
88+
layers.push(layer);
89+
return layer;
90+
};
91+
92+
const bgSQ = makeWorldLayer(landCurveTiles);
93+
const bg = makeWorldLayer(landCurveTiles, { x: -0.5, y: -0.5 });
94+
const fg = makeWorldLayer(foreTiles);
95+
96+
// generate terrain
97+
{
98+
const isWater = new Uint8Array(bg.width * bg.height);
99+
const { random } = makeRandom();
100+
for (let i = 0; i < isWater.length; i++)
101+
isWater[i] = random() > 0.5 ? 1 : 0;
102+
103+
const land = landCurveTiles.getLayerID(0b0000);
104+
const water = landCurveTiles.getLayerID(0b1111);
105+
for (let y = 0; y < bg.height; y++)
106+
for (let x = 0; x < bg.width; x++)
107+
bgSQ.set(x, y, {
108+
layerID: isWater[y * bg.width + x] ? water : land
109+
});
110+
111+
const stride = bg.width;
112+
for (let y = 0; y < bg.height; y++) {
113+
for (let x = 0; x < bg.width; x++) {
114+
const nw = isWater[(y + 0) * stride + x + 0];
115+
const ne = isWater[(y + 0) * stride + x + 1];
116+
const sw = isWater[(y + 1) * stride + x + 0];
117+
const se = isWater[(y + 1) * stride + x + 1];
118+
const tileID = ((nw << 1 | ne) << 1 | se) << 1 | sw;
119+
const layerID = landCurveTiles.getLayerID(tileID);
120+
bg.set(x, y, { layerID });
121+
}
122+
}
123+
}
124+
125+
// place fore objects
126+
{
127+
const { randn, random } = makeRandom();
128+
for (let y = 0; y < fg.height; y++) {
129+
for (let x = 0; x < fg.width; x++) {
130+
const tileID = Number(randn(2n * BigInt(foreTiles.size)));
131+
const layerID = foreTiles.getLayerID(tileID);
132+
const spin = random();
133+
fg.set(x, y, { layerID, spin });
134+
}
135+
}
136+
}
137+
138+
// send layer data to gpu; NOTE this needs to be called going forward after any update
139+
bg.send();
140+
bgSQ.send();
141+
fg.send();
142+
143+
bgSQ.visible = !showCurvyTiles; // boring non-curvy layer
144+
bg.visible = showCurvyTiles; // curvy new hotness
145+
146+
// forever draw loop
97147
for (
98148
let t = await nextFrame(), lastT = t; ;
99149
lastT = t, t = await nextFrame()
@@ -107,16 +157,25 @@ export default async function demo({
107157
gl.clear(gl.COLOR_BUFFER_BIT);
108158

109159
tileRend.draw(function*() {
110-
for (const { layers } of facets) {
111-
for (const layer of layers) {
112-
if (layer.visible) yield layer;
113-
}
114-
}
160+
for (const layer of layers)
161+
if (layer.visible) yield layer;
115162
}());
116163
}
117164

118165
}
119166

167+
function makeRandom(seed = 0xdead_beefn) {
168+
let randState = seed;
169+
const rand = () => (randState = randState * 6364136223846793005n + 1442695040888963407n) >> 17n & 0xffff_ffffn;
170+
/** @param {bigint} n */
171+
const randn = n => rand() % n;
172+
const random = () => Number(rand()) / 0x1_0000_0000;
173+
return { rand, randn, random };
174+
}
175+
176+
/** @returns {Promise<number>} */
177+
const nextFrame = () => new Promise(resolve => requestAnimationFrame(t => resolve(t)))
178+
120179
/** @param {HTMLCanvasElement} $canvas */
121180
function sizeToParent($canvas, update = () => { }) {
122181
const $cont = $canvas.parentElement;

0 commit comments

Comments
 (0)