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