forked from hackclub/sprig
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrender.js
213 lines (177 loc) · 6.9 KB
/
render.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
import { bitmapTextToImageData } from "./bitmap.js";
const spritesheetIndex = 0;
const texIndex = 1;
let backgroundTile = 0;
let gl, texLocation,
texResLocation,
spritesheetLocation,
backgroundTileLocation,
spritesheetTileCountLocation;
const SPRITESHEET_TILE_COUNT = 64;
let _bitmaps;
export function setBackground(bg) {
backgroundTile = 1+_bitmaps.findIndex(f => f[0] == bg);
}
export function setBitmaps(bitmaps) {
_bitmaps = bitmaps;
const sw = 16 * SPRITESHEET_TILE_COUNT;
const sh = 16 * SPRITESHEET_TILE_COUNT;
const spritesheet = new ImageData(sw, sh);
for (let i = 0; i < bitmaps.length; i++) {
const { data } = bitmapTextToImageData(bitmaps[i][1]);
for (let x = 0; x < 16; x++)
for (let y = 0; y < 16; y++) {
const sx = ( (i % SPRITESHEET_TILE_COUNT))*16 + x;
const sy = (Math.floor(i / SPRITESHEET_TILE_COUNT))*16 + y;
spritesheet.data[(sy*sw + sx)*4 + 0] = data[(y*16 + x)*4 + 0];
spritesheet.data[(sy*sw + sx)*4 + 1] = data[(y*16 + x)*4 + 1];
spritesheet.data[(sy*sw + sx)*4 + 2] = data[(y*16 + x)*4 + 2];
spritesheet.data[(sy*sw + sx)*4 + 3] = data[(y*16 + x)*4 + 3];
}
}
uploadImage(spritesheet, spritesheetIndex);
}
export function init(canvas) {
gl = canvas.getContext('webgl2');//, { alpha: false });
const program = createProgram(glsl['shader-vertex'], glsl['shader-fragment']);
gl.useProgram(program);
texLocation = gl.getUniformLocation(program, "u_tex");
texResLocation = gl.getUniformLocation(program, "u_texres");
spritesheetLocation = gl.getUniformLocation(program, "u_spritesheet");
backgroundTileLocation = gl.getUniformLocation(program, "u_background_tile");
spritesheetTileCountLocation = gl.getUniformLocation(program, "u_spritesheet_tile_count");
resize(canvas);
function createShader(source, type) {
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
throw new Error(gl.getShaderInfoLog(shader));
return shader;
}
function createProgram(vertex, fragment) {
var program = gl.createProgram();
gl.attachShader(program, createShader(vertex, gl.VERTEX_SHADER));
gl.attachShader(program, createShader(fragment, gl.FRAGMENT_SHADER));
gl.linkProgram(program);
program.createUniform = function (type, name) {
var location = gl.getUniformLocation(program, name);
return function (v1, v2, v3, v4) {
gl['uniform' + type](location, v1, v2, v3, v4);
}
};
const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = [
0, 0,
4, 0,
0, 4,
4, 4
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
const vao = gl.createVertexArray();
gl.bindVertexArray(vao);
gl.enableVertexAttribArray(positionAttributeLocation);
const size = 2; // 2 components per iteration
const type = gl.FLOAT; // the data is 32bit floats
const normalize = false; // don't normalize the data
const stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
const offset = 0; // start at the beginning of the buffer
gl.vertexAttribPointer(
positionAttributeLocation, size, type, normalize, stride, offset)
return program;
}
}
export function resize(canvas) {
gl.viewport(0, 0, canvas.width, canvas.height);
}
export function render(canvas) {
uploadImage(canvas, texIndex, gl.NEAREST);
gl.uniform1i(backgroundTileLocation, backgroundTile);
gl.uniform1i(spritesheetLocation, spritesheetIndex);
gl.uniform1i(texLocation, texIndex);
gl.uniform2f(texResLocation, canvas.width, canvas.height);
gl.uniform1i(spritesheetTileCountLocation, SPRITESHEET_TILE_COUNT);
gl.drawArrays(gl.TRIANGLE_FAN, 0, 3);
}
function uploadImage(image, i, sample=gl.NEAREST) {
// Create a texture.
var texture = gl.createTexture();
// make unit 0 the active texture unit
// (i.e, the unit all other texture commands will affect.)
gl.activeTexture(gl.TEXTURE0 + i);
// Bind texture to 'texture unit '0' 2D bind point
gl.bindTexture(gl.TEXTURE_2D, texture);
// Set the parameters so we don't need mips and so we're not filtering
// and we don't repeat
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, sample);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, sample);
// Upload the image into the texture.
var mipLevel = 0; // the largest mip
var internalFormat = gl.RGBA; // format we want in the texture
var srcFormat = gl.RGBA; // format of data we are supplying
var srcType = gl.UNSIGNED_BYTE // type of data we are supplying
gl.texImage2D(gl.TEXTURE_2D,
mipLevel,
internalFormat,
srcFormat,
srcType,
image);
}
const glsl = {
'shader-fragment': `#version 300 es
precision highp float;
uniform sampler2D u_tex;
uniform sampler2D u_spritesheet;
uniform int u_spritesheet_tile_count;
uniform int u_background_tile;
uniform vec2 u_texres;
in vec2 texCoord;
out vec4 frag;
vec4 sampleTile(vec2 coord, float index) {
// this index is sometimes wrong because of floating point math
// if it's low this should trigger
if (index - trunc(index) > 0.001) index = index + 0.0001;
int spriteIndex = int(index*255.0)-1;
vec2 fcoord = mod(coord*u_texres, 1.0);
fcoord += vec2(spriteIndex % u_spritesheet_tile_count,
spriteIndex / u_spritesheet_tile_count);
vec4 ret = texture(u_spritesheet, fcoord/float(u_spritesheet_tile_count));
ret.a *= min(1.0, index);
return ret;
}
void main(void) {
vec2 coord = vec2(texCoord.x, 1.0 - texCoord.y);
vec4 raw = texture(u_tex, coord);
frag = vec4(1);
vec4 sprite;
sprite = sampleTile(coord, float(u_background_tile)/255.0f);
if (sprite.a > 0.0) frag = vec4(sprite.xyz, 1);
sprite = sampleTile(coord, raw.a);
if (sprite.a > 0.0) frag = vec4(sprite.xyz, 1);
sprite = sampleTile(coord, raw.b);
if (sprite.a > 0.0) frag = vec4(sprite.xyz, 1);
sprite = sampleTile(coord, raw.g);
if (sprite.a > 0.0) frag = vec4(sprite.xyz, 1);
sprite = sampleTile(coord, raw.r);
if (sprite.a > 0.0) frag = vec4(sprite.xyz, 1);
}
`,
'shader-vertex': `#version 300 es
precision highp float;
in vec2 a_position;
out vec2 texCoord;
void main(void) {
// float x = float((gl_VertexID & 1) << 2);
// float y = float((gl_VertexID & 2) << 1);
float x = a_position.x;
float y = a_position.y;
texCoord.x = x * 0.5;
texCoord.y = y * 0.5;
gl_Position = vec4(x - 1.0, y - 1.0, 0, 1);
}
`,
};