]> git.r.bdr.sh - rbdr/flower/blob - lib/flower.js
69802d7ffee3f6638226b49a71978a78cfbe3c0e
[rbdr/flower] / lib / flower.js
1 /* globals window document mat4 */
2
3 const internals = {
4
5 // Constants
6
7 kEntrypointElementId: 'entrypoint', // The id of the canvas element where we will render
8 kWidthRatio: 2.76,
9 kHeightRatio: 1,
10 kTargetVerticalResolution: 32 + Math.round(Math.random() * 1024),
11 kFieldOfView: 45,
12 kNearLimit: 0.1,
13 kFarLimit: 100,
14 kBackgroundColor: [0.811, 0.73, 0.48, 1.0],
15 kRotationValues: [Math.random(), Math.random(), Math.random()],
16 kFPS: 30,
17
18 // Constants: Shaders
19
20 kVertexShader: `
21
22 attribute vec4 aVertexPosition;
23 attribute vec4 aColor;
24
25 varying vec4 vColor;
26
27 uniform mat4 uModelViewMatrix;
28 uniform mat4 uProjectionMatrix;
29
30 void main() {
31
32 gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;
33 vColor = aColor;
34 }
35 `,
36
37 kFragmentShader: `
38
39 precision mediump float;
40 varying vec4 vColor;
41
42 void main() {
43
44 gl_FragColor = vColor;
45 }
46 `,
47
48 // Properties: Animation
49
50 currentTime: 0,
51
52 // Runs on load, Initializes WebGL and starts the animation loop.
53
54 onLoad() {
55
56
57 const canvas = internals.initializeCanvas();
58 const { gl, programInfo, buffers } = internals.initializeWebGL(canvas);
59
60 window.requestAnimationFrame(internals.animate.bind(this, gl, programInfo, buffers));
61 },
62
63 // Gets a canvas element and sets up resizing events.
64
65 initializeCanvas() {
66
67 const canvas = document.getElementById(internals.kEntrypointElementId);
68 internals.resizeCanvas(canvas);
69 window.addEventListener('resize', () => internals.resizeCanvas(canvas));
70
71 return canvas;
72 },
73
74 // Given a canvas, it will initialize the webgl context and set up the shaders.
75
76 initializeWebGL(canvas) {
77
78 const gl = canvas.getContext('webgl', {
79 preserveDrawingBuffer: true
80 });
81 const shaderProgram = internals.initializeShaderProgram(gl, internals.kVertexShader, internals.kFragmentShader);
82
83 const programInfo = {
84 program: shaderProgram,
85 attribLocations: {
86 vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'),
87 vertexColor: gl.getAttribLocation(shaderProgram, 'aColor')
88 },
89 uniformLocations: {
90 projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'),
91 modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix')
92 }
93 };
94
95 const buffers = internals.initializeBuffers(gl);
96
97 return { gl, programInfo, buffers };
98 },
99
100 // Methods: Canvas
101
102 resizeCanvas(canvas) {
103
104 let width = window.innerWidth;
105 let height = Math.round(width * internals.kHeightRatio / internals.kWidthRatio);
106
107 if (window.innerHeight < height) {
108 height = window.innerHeight;
109 width = Math.round(height * internals.kWidthRatio / internals.kHeightRatio);
110 console.log(width, height);
111 }
112
113 canvas.style.width = `${width}px`;
114 canvas.style.height = `${height}px`;
115
116 canvas.width = internals.kTargetVerticalResolution * internals.kWidthRatio;
117 canvas.height = internals.kTargetVerticalResolution;
118 },
119
120 // Methods: Shader / GL Related
121
122 initializeShaderProgram(gl, vertexShaderSource, fragmentShaderSource) {
123
124 const vertexShader = internals.loadShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
125 const fragmentShader = internals.loadShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
126
127 const shaderProgram = gl.createProgram();
128 gl.attachShader(shaderProgram, vertexShader);
129 gl.attachShader(shaderProgram, fragmentShader);
130
131 gl.linkProgram(shaderProgram);
132
133 if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
134 console.error(`Unable to initialize shader program: ${gl.getProgramInfoLog(shaderProgram)}`);
135 return null;
136 }
137
138 return shaderProgram;
139 },
140
141 loadShader(gl, type, source) {
142
143 const shader = gl.createShader(type);
144 gl.shaderSource(shader, source);
145 gl.compileShader(shader);
146
147 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
148 console.error(`Unable to compile shader: ${gl.getShaderInfoLog(shader)}`);
149 gl.deleteShader(shader);
150 return null;
151 }
152
153 return shader;
154 },
155
156 initializeBuffers(gl) {
157
158 const positionBuffer = gl.createBuffer();
159
160 gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
161
162 const positions = [
163 -1.0, 1.0, 1.0, // Front-top-left
164 1.0, 1.0, 1.0, // Front-top-right
165 -1.0, -1.0, 1.0, // Front-bottom-left
166 1.0, -1.0, 1.0, // Front-bottom-right
167 1.0, -1.0, -1.0, // Back-bottom-right
168 1.0, 1.0, 1.0, // Front-top-right
169 1.0, 1.0, -1.0, // Back-top-right
170 -1.0, 1.0, 1.0, // Front-top-left
171 -1.0, 1.0, -1.0, // Back-top-left
172 -1.0, -1.0, 1.0, // Front-bottom-left
173 -1.0, -1.0, -1.0, // Back-bottom-left
174 1.0, -1.0, -1.0, // Back-bottom-right
175 -1.0, 1.0, -1.0, // Back-top-left
176 1.0, 1.0, -1.0 // Back-top-right
177 ];
178
179 gl.bufferData(gl.ARRAY_BUFFER,
180 new Float32Array(positions),
181 gl.STATIC_DRAW);
182
183 return {
184 position: positionBuffer
185 };
186 },
187
188 // Methods: Utility
189
190 createMatrix() {
191
192 const matrix = mat4.create();
193
194 mat4.translate(
195 matrix,
196 matrix,
197 [-0.0, 0.0, -6.0]
198 );
199
200 return matrix;
201 },
202
203 // Methods: Animation
204
205 rotate(matrix) {
206
207 mat4.rotate(internals.modelViewMatrix, internals.modelViewMatrix, internals.kRotationValues[0], [1, 0, 0]);
208 mat4.rotate(internals.modelViewMatrix, internals.modelViewMatrix, internals.kRotationValues[1], [0, 1, 0]);
209 mat4.rotate(internals.modelViewMatrix, internals.modelViewMatrix, internals.kRotationValues[2], [0, 0, 1]);
210 },
211
212 drawScene(gl, programInfo, buffers) {
213
214 gl.clearColor(...internals.kBackgroundColor);
215 gl.clearDepth(1.0);
216 gl.enable(gl.DEPTH_TEST);
217 gl.depthFunc(gl.LEQUAL);
218
219 const fieldOfView = internals.kFieldOfView * Math.PI / 180;
220 const aspectRatio = internals.kWidthRatio / internals.kHeightRatio;
221 const projectionMatrix = mat4.create();
222
223 mat4.perspective(
224 projectionMatrix,
225 fieldOfView,
226 aspectRatio,
227 internals.kNearLimit,
228 internals.kFarLimit
229 );
230
231 internals.modelViewMatrix = internals.modelViewMatrix || internals.createMatrix();
232
233 internals.rotate(internals.modelViewMatrix);
234
235 {
236 const numberOfComponents = 3;
237 const type = gl.FLOAT;
238 const normalize = false;
239 const stride = 0;
240 const offset = 0;
241
242 gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
243 gl.vertexAttribPointer(
244 programInfo.attribLocations.vertexPosition,
245 numberOfComponents,
246 type,
247 normalize,
248 stride,
249 offset
250 );
251 gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
252 }
253
254 {
255 // ATTEMPT TO SEND COLOR DATA
256
257 const colorBuffer = gl.createBuffer();
258
259 gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
260
261 const colors = [
262 1.0, 0.0, 0.5, 1.0, // Front-top-left
263 1.0, 0.3, 0.8, 1.0, // Front-top-right
264 1.0, 1.0, 0.7, 1.0, // Front-bottom-left
265 0.0, 0.3, 0.5, 1.0, // Front-bottom-right
266 0.0, 0.3, 0.5, 1.0, // Back-bottom-right
267 1.0, 0.3, 0.8, 1.0, // Front-top-right
268 1.0, 0.3, 0.8, 1.0, // Back-top-right
269 1.0, 0.0, 0.5, 1.0, // Front-top-left
270 1.0, 0.0, 0.5, 1.0, // Back-top-left
271 1.0, 1.0, 0.7, 1.0, // Front-bottom-left
272 1.0, 1.0, 0.7, 1.0, // Back-bottom-left
273 0.0, 0.3, 0.5, 1.0, // Back-bottom-right
274 1.0, 0.0, 0.5, 1.0, // Back-top-left
275 1.0, 0.3, 0.8, 1.0 // Back-top-right
276 ];
277
278 gl.bufferData(gl.ARRAY_BUFFER,
279 new Float32Array(colors),
280 gl.STATIC_DRAW);
281
282 const numberOfComponents = 4;
283 const type = gl.FLOAT;
284 const normalize = false;
285 const stride = 0;
286 const offset = 0;
287
288 gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
289 gl.vertexAttribPointer(
290 programInfo.attribLocations.vertexColor,
291 numberOfComponents,
292 type,
293 normalize,
294 stride,
295 offset
296 );
297 gl.enableVertexAttribArray(programInfo.attribLocations.vertexColor);
298
299 // END ATTEMPT
300 }
301
302 gl.useProgram(programInfo.program);
303
304 gl.uniformMatrix4fv(
305 programInfo.uniformLocations.projectionMatrix,
306 false,
307 projectionMatrix
308 );
309 gl.uniformMatrix4fv(
310 programInfo.uniformLocations.modelViewMatrix,
311 false,
312 internals.modelViewMatrix
313 );
314
315 {
316 const offset = 0;
317 const vertexCount = 14;
318 gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount);
319 }
320 },
321
322 animate(gl, programInfo, buffers, time) {
323
324 const delta = time - internals.currentTime;
325 const interval = 1000 / internals.kFPS;
326
327 if (delta >= interval) {
328 internals.drawScene(gl, programInfo, buffers, delta);
329 internals.currentTime = time;
330 }
331
332 window.requestAnimationFrame(internals.animate.bind(this, gl, programInfo, buffers));
333 }
334 };
335
336 window.addEventListener('load', internals.onLoad);