gridviz 3.0.29 → 3.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gridviz.js +295 -238
- package/dist/gridviz.min.js +1 -1
- package/package.json +1 -1
- package/src/style/ShadingStyle.js +15 -4
- package/src/style/SideTanakaStyle.js +13 -3
- package/src/style/SquareColorCategoryWebGLStyle.js +218 -30
- package/src/utils/WebGLSquareColoringAdvanced.js +46 -49
- package/src/utils/webGLUtils.js +5 -4
- package/src/utils/WebGLSquareColoringCatAdvanced.js +0 -133
package/package.json
CHANGED
|
@@ -42,14 +42,25 @@ export class ShadingStyle extends SideStyle {
|
|
|
42
42
|
// compute maximum side value for normalization
|
|
43
43
|
this.viewScale = sides => max(sides, s => sideValue(s))
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
// get colors
|
|
46
|
+
let colorTopLeft = opts.colorTopLeft || '255,255,255'
|
|
47
|
+
let colorBottomRight = opts.colorBottomRight || '0,0,0'
|
|
48
|
+
|
|
49
|
+
// revert colors (to revert the relief, show depressions as hills)
|
|
50
|
+
const revert = opts.revert == undefined? false : opts.revert
|
|
51
|
+
if(revert) {
|
|
52
|
+
let a = colorTopLeft
|
|
53
|
+
colorTopLeft = colorBottomRight
|
|
54
|
+
colorBottomRight = a
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
//
|
|
58
|
+
const scale = opts.scale
|
|
48
59
|
|
|
49
60
|
this.color = (side, resolution, z, max) => {
|
|
50
61
|
if (side.v == 0) return
|
|
51
62
|
let coeff = Math.abs(side.v / max)
|
|
52
|
-
coeff = scale(coeff)
|
|
63
|
+
if(scale) coeff = scale(coeff)
|
|
53
64
|
if ((side.v < 0 && side.or === 'h') || (side.v > 0 && side.or === 'v'))
|
|
54
65
|
return 'rgba(' + colorTopLeft + ',' + coeff + ')'
|
|
55
66
|
return 'rgba(' + colorBottomRight + ',' + coeff + ')'
|
|
@@ -35,9 +35,17 @@ export class SideTanakaStyle extends Style {
|
|
|
35
35
|
this.colorDark = opts.colorDark || '#111'
|
|
36
36
|
// the bright color: for side facing the light (coming from NW)
|
|
37
37
|
this.colorBright = opts.colorBright || '#ddd'
|
|
38
|
+
//
|
|
39
|
+
this.revert = opts.revert == undefined? false : opts.revert
|
|
38
40
|
|
|
39
41
|
/** Set to A or true so that the side is drawn as a diamond */
|
|
40
42
|
this.diamond = opts.diamond
|
|
43
|
+
|
|
44
|
+
/* Determines what to do for limit sides, between a cell with value and one with no value
|
|
45
|
+
* steep: the cell value absence is equivalent to 0. It shows potentially a steep limit then.
|
|
46
|
+
* skip: no side is drawn
|
|
47
|
+
* step: a side with a 1 step */
|
|
48
|
+
this.limit = opts.limit || "steep"
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
/**
|
|
@@ -61,8 +69,8 @@ export class SideTanakaStyle extends Style {
|
|
|
61
69
|
const cl1 = side.c1 ? classifier(side.c1) : undefined
|
|
62
70
|
const cl2 = side.c2 ? classifier(side.c2) : undefined
|
|
63
71
|
if (cl1 === undefined && cl2 === undefined) return undefined
|
|
64
|
-
if (cl1 === undefined) return cl2
|
|
65
|
-
if (cl2 === undefined) return -cl1
|
|
72
|
+
if (cl1 === undefined) return this.limit=="none"? undefined : this.limit=="steep"? cl2 : Math.sign(cl2)
|
|
73
|
+
if (cl2 === undefined) return this.limit=="none"? undefined : this.limit=="steep"? -cl1 : Math.sign(-cl1)
|
|
66
74
|
return cl2 - cl1
|
|
67
75
|
}
|
|
68
76
|
|
|
@@ -78,6 +86,8 @@ export class SideTanakaStyle extends Style {
|
|
|
78
86
|
//draw sides
|
|
79
87
|
ctx.lineCap = 'butt'
|
|
80
88
|
const r2 = resolution * 0.5
|
|
89
|
+
const cd = this.revert? this.colorBright : this.colorDark
|
|
90
|
+
const cb = this.revert? this.colorDark : this.colorBright
|
|
81
91
|
for (let side of sides) {
|
|
82
92
|
|
|
83
93
|
//get side value
|
|
@@ -86,7 +96,7 @@ export class SideTanakaStyle extends Style {
|
|
|
86
96
|
|
|
87
97
|
//color
|
|
88
98
|
/** @type {string|undefined} */
|
|
89
|
-
const col = ((v < 0 && side.or === 'h') || (v > 0 && side.or === 'v')) ?
|
|
99
|
+
const col = ((v < 0 && side.or === 'h') || (v > 0 && side.or === 'v')) ? cb : cd
|
|
90
100
|
if (!col || col == 'none') continue
|
|
91
101
|
|
|
92
102
|
if (this.diamond) {
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
'use strict'
|
|
3
3
|
|
|
4
4
|
import { Style } from '../core/Style.js'
|
|
5
|
-
import { makeWebGLCanvas } from '../utils/webGLUtils.js'
|
|
6
|
-
import {
|
|
5
|
+
import { initShaderProgram, createShader, makeWebGLCanvas } from '../utils/webGLUtils.js'
|
|
6
|
+
import { color } from 'd3-color'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Style based on webGL
|
|
@@ -21,8 +21,8 @@ export class SquareColorCategoryWebGLStyle extends Style {
|
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* A function returning the category code of the cell, for coloring.
|
|
24
|
-
* @type {function(import('../core/Dataset.js').Cell):string} */
|
|
25
|
-
this.code = opts.code
|
|
24
|
+
* @type {function(import('../core/Dataset.js').Cell, number, number, viewScale):string} */
|
|
25
|
+
this.code = opts.code // (c, resolution, z, viewScale) => "code1"
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* The dictionary (code -> color) which gives the color of each category code.
|
|
@@ -45,38 +45,105 @@ export class SquareColorCategoryWebGLStyle extends Style {
|
|
|
45
45
|
* @type {function(number,number):number} */
|
|
46
46
|
this.size = opts.size // (resolution, z) => ...
|
|
47
47
|
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
/** * @type {{canvas:HTMLCanvasElement, gl:WebGLRenderingContext, width:number, height:number }}*/
|
|
49
|
+
this.cvWGL = undefined
|
|
50
|
+
this.programm = undefined
|
|
51
|
+
|
|
52
|
+
this.x = undefined
|
|
53
|
+
this.y = undefined
|
|
54
|
+
this.z = undefined
|
|
55
|
+
this.cellsNb = undefined
|
|
52
56
|
}
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* @param {number} resolution
|
|
58
|
-
*/
|
|
59
|
-
draw(cells, geoCanvas, resolution) {
|
|
60
|
-
//filter
|
|
61
|
-
if (this.filter) cells = cells.filter(this.filter)
|
|
58
|
+
init(w, h) {
|
|
59
|
+
this.cvWGL = makeWebGLCanvas(w + '', h + '')
|
|
60
|
+
if (!this.cvWGL) { console.error('No webGL'); return }
|
|
62
61
|
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
const gl = this.cvWGL.gl
|
|
63
|
+
|
|
64
|
+
//draw
|
|
65
|
+
const vectorShader = `
|
|
66
|
+
attribute vec2 pos;
|
|
67
|
+
uniform float sizePix;
|
|
68
|
+
uniform mat3 mat;
|
|
69
|
+
attribute float i;
|
|
70
|
+
varying float vi;
|
|
71
|
+
void main() {
|
|
72
|
+
gl_Position = vec4(mat * vec3(pos, 1.0), 1.0);
|
|
73
|
+
gl_PointSize = sizePix;
|
|
74
|
+
vi = i;
|
|
75
|
+
}`
|
|
76
|
+
/** @type {WebGLShader} */
|
|
77
|
+
const vShader = createShader(gl, gl.VERTEX_SHADER, vectorShader)
|
|
78
|
+
|
|
79
|
+
const fragmentShader = `
|
|
80
|
+
precision highp float;
|
|
81
|
+
varying float vi;
|
|
82
|
+
uniform sampler2D colorLUT;
|
|
83
|
+
uniform float lutSize;
|
|
84
|
+
void main(void) {
|
|
85
|
+
float idx = floor(vi + 0.5);
|
|
86
|
+
float u = (idx + 0.5) / lutSize;
|
|
87
|
+
gl_FragColor = texture2D(colorLUT, vec2(u, 0.5));
|
|
88
|
+
}`
|
|
89
|
+
/** @type {WebGLShader} */
|
|
90
|
+
const fShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShader)
|
|
91
|
+
|
|
92
|
+
/** @type {WebGLProgram} */
|
|
93
|
+
this.program = initShaderProgram(gl, vShader, fShader)
|
|
94
|
+
gl.useProgram(this.program)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
bindColors() {
|
|
98
|
+
const gl = this.cvWGL.gl
|
|
99
|
+
const lutSize = this.colors.length;
|
|
100
|
+
const lutData = new Uint8Array(lutSize * 4); // RGBA for each entry
|
|
65
101
|
|
|
102
|
+
// Fill lutData with your color values (e.g., rainbow, grayscale, etc.)
|
|
103
|
+
for (let i = 0; i < lutSize; i++) {
|
|
104
|
+
const c = color(this.colors[i])
|
|
105
|
+
lutData[i * 4] = +c.r; // R
|
|
106
|
+
lutData[i * 4 + 1] = c.g; // G
|
|
107
|
+
lutData[i * 4 + 2] = c.b; // B
|
|
108
|
+
lutData[i * 4 + 3] = c?.opacity * 255; // A
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Create and bind texture
|
|
112
|
+
const lutTexture = gl.createTexture();
|
|
113
|
+
gl.bindTexture(gl.TEXTURE_2D, lutTexture);
|
|
114
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, lutSize, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, lutData);
|
|
115
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
116
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
117
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
118
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
119
|
+
|
|
120
|
+
// Get uniform locations
|
|
121
|
+
const uColorLUT = gl.getUniformLocation(this.program, 'colorLUT');
|
|
122
|
+
const uLutSize = gl.getUniformLocation(this.program, 'lutSize');
|
|
123
|
+
|
|
124
|
+
// Set uniform values
|
|
125
|
+
gl.uniform1i(uColorLUT, 0); // Texture unit 0
|
|
126
|
+
gl.uniform1f(uLutSize, lutSize);
|
|
127
|
+
|
|
128
|
+
// Bind the texture to texture unit 0
|
|
129
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
130
|
+
gl.bindTexture(gl.TEXTURE_2D, lutTexture);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
bindVertices(cells, resolution, z, viewScale) {
|
|
134
|
+
const gl = this.cvWGL.gl
|
|
66
135
|
//add vertice and fragment data
|
|
67
136
|
const r2 = resolution / 2
|
|
68
|
-
let c,
|
|
69
|
-
nb = cells.length
|
|
137
|
+
let c, nb = cells.length
|
|
70
138
|
const verticesBuffer = []
|
|
71
139
|
const iBuffer = []
|
|
72
140
|
for (let i = 0; i < nb; i++) {
|
|
73
141
|
c = cells[i]
|
|
74
|
-
const cat = this.code(c)
|
|
142
|
+
const cat = this.code(c, resolution, z, viewScale)
|
|
75
143
|
if (cat == undefined) {
|
|
76
144
|
console.log('Unexpected category: ' + cat)
|
|
77
145
|
continue
|
|
78
146
|
}
|
|
79
|
-
/** @type {number} */
|
|
80
147
|
const i_ = this.catToI[cat]
|
|
81
148
|
if (isNaN(+i_)) {
|
|
82
149
|
console.log('Unexpected category index: ' + cat + ' ' + i_)
|
|
@@ -86,22 +153,143 @@ export class SquareColorCategoryWebGLStyle extends Style {
|
|
|
86
153
|
iBuffer.push(+i_)
|
|
87
154
|
}
|
|
88
155
|
|
|
156
|
+
//bind vertice data
|
|
157
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer())
|
|
158
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verticesBuffer), gl.STATIC_DRAW)
|
|
159
|
+
const position = gl.getAttribLocation(this.program, 'pos')
|
|
160
|
+
gl.vertexAttribPointer(
|
|
161
|
+
position,
|
|
162
|
+
2, //numComponents
|
|
163
|
+
gl.FLOAT, //type
|
|
164
|
+
false, //normalise
|
|
165
|
+
0, //stride
|
|
166
|
+
0 //offset
|
|
167
|
+
)
|
|
168
|
+
gl.enableVertexAttribArray(position)
|
|
169
|
+
|
|
170
|
+
//i data
|
|
171
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer())
|
|
172
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(iBuffer), gl.STATIC_DRAW)
|
|
173
|
+
const i = gl.getAttribLocation(this.program, 'i')
|
|
174
|
+
gl.vertexAttribPointer(i, 1, gl.FLOAT, false, 0, 0)
|
|
175
|
+
gl.enableVertexAttribArray(i)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
// check if the vertices have to be bound again
|
|
181
|
+
mapContentChanged(v, cellsNb) {
|
|
182
|
+
if (v.x == this.x && v.y == this.y && v.z == this.z && this.cellsNb == cellsNb) return false
|
|
183
|
+
this.x = v.x
|
|
184
|
+
this.y = v.y
|
|
185
|
+
this.z = v.z
|
|
186
|
+
this.cellsNb = cellsNb
|
|
187
|
+
return true
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* @param {Array.<import("../core/Dataset.js").Cell>} cells
|
|
193
|
+
* @param {import("../core/GeoCanvas.js").GeoCanvas} geoCanvas
|
|
194
|
+
* @param {number} resolution
|
|
195
|
+
*/
|
|
196
|
+
draw(cells, geoCanvas, resolution) {
|
|
197
|
+
//filter
|
|
198
|
+
if (this.filter) cells = cells.filter(this.filter)
|
|
199
|
+
|
|
200
|
+
//
|
|
201
|
+
const z = geoCanvas.view.z
|
|
202
|
+
|
|
203
|
+
//get view scale
|
|
204
|
+
const viewScale = this.viewScale ? this.viewScale(cells, resolution, z) : undefined
|
|
205
|
+
|
|
89
206
|
//create canvas and webgl renderer
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return
|
|
207
|
+
if (!this.cvWGL || geoCanvas.w != this.cvWGL.width || geoCanvas.h != this.cvWGL.height) {
|
|
208
|
+
this.init(geoCanvas.w, geoCanvas.h)
|
|
209
|
+
this.bindColors()
|
|
94
210
|
}
|
|
211
|
+
const gl = this.cvWGL.gl
|
|
212
|
+
const canvas = this.cvWGL.canvas
|
|
95
213
|
|
|
96
|
-
//
|
|
97
|
-
const
|
|
98
|
-
|
|
214
|
+
//bind sizePix
|
|
215
|
+
const sizePix = this.size ? this.size(resolution, z) / z : resolution / z + 0.2
|
|
216
|
+
gl.uniform1f(gl.getUniformLocation(this.program, 'sizePix'), 1.0 * sizePix)
|
|
217
|
+
|
|
218
|
+
//
|
|
219
|
+
if (this.mapContentChanged(geoCanvas.view, cells.length))
|
|
220
|
+
//bind vertices
|
|
221
|
+
this.bindVertices(cells, resolution, z, viewScale)
|
|
222
|
+
//transformation
|
|
223
|
+
gl.uniformMatrix3fv(gl.getUniformLocation(this.program, 'mat'), false, new Float32Array(geoCanvas.getWebGLTransform()))
|
|
224
|
+
|
|
225
|
+
// Enable the depth test
|
|
226
|
+
//gl.enable(gl.DEPTH_TEST);
|
|
227
|
+
// Clear the color buffer bit
|
|
228
|
+
gl.clear(gl.COLOR_BUFFER_BIT)
|
|
229
|
+
// Set the view port
|
|
230
|
+
//gl.viewport(0, 0, cg.w, cg.h);
|
|
231
|
+
|
|
232
|
+
gl.drawArrays(gl.POINTS, 0, cells.length)
|
|
99
233
|
|
|
100
234
|
//draw in canvas geo
|
|
101
235
|
geoCanvas.initCanvasTransform()
|
|
102
|
-
geoCanvas.offscreenCtx.drawImage(
|
|
236
|
+
geoCanvas.offscreenCtx.drawImage(canvas, 0, 0)
|
|
103
237
|
|
|
104
238
|
//update legends
|
|
105
239
|
this.updateLegends({ style: this, resolution: resolution, z: z })
|
|
106
240
|
}
|
|
107
241
|
}
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
// early tests for webgl2 migration
|
|
246
|
+
|
|
247
|
+
/*
|
|
248
|
+
function getVectorShader2() {
|
|
249
|
+
return `
|
|
250
|
+
#version 300 es
|
|
251
|
+
precision highp float;
|
|
252
|
+
|
|
253
|
+
in vec2 pos;
|
|
254
|
+
in int i;
|
|
255
|
+
|
|
256
|
+
uniform float sizePix;
|
|
257
|
+
uniform mat3 mat;
|
|
258
|
+
|
|
259
|
+
flat out int vi;
|
|
260
|
+
|
|
261
|
+
void main() {
|
|
262
|
+
gl_Position = vec4(mat * vec3(pos, 1.0), 1.0);
|
|
263
|
+
gl_PointSize = sizePix;
|
|
264
|
+
vi = i;
|
|
265
|
+
}
|
|
266
|
+
`
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
function getFragmentShader2(colors) {
|
|
271
|
+
|
|
272
|
+
//prepare fragment shader code
|
|
273
|
+
//declare the uniform and other variables
|
|
274
|
+
const out = []
|
|
275
|
+
out.push('#version 300 es\nprecision highp float;\nflat in int vi;\n')
|
|
276
|
+
|
|
277
|
+
//add color uniforms
|
|
278
|
+
//uniform vec4 colors[12];
|
|
279
|
+
out.push('uniform vec4 colors[')
|
|
280
|
+
out.push(colors.length)
|
|
281
|
+
out.push('];\n')
|
|
282
|
+
|
|
283
|
+
out.push('out vec4 fragColor;\n')
|
|
284
|
+
|
|
285
|
+
//start the main function
|
|
286
|
+
//void main() { fragColor = colors[clamp(vi, 0, 11)]; }
|
|
287
|
+
out.push('void main() { fragColor = colors[vi]; }\n')
|
|
288
|
+
|
|
289
|
+
/** Fragment shader program
|
|
290
|
+
const fshString = out.join('')
|
|
291
|
+
console.log(fshString)
|
|
292
|
+
return fshString
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
*/
|
|
@@ -53,86 +53,85 @@ export class WebGLSquareColoringAdvanced {
|
|
|
53
53
|
|
|
54
54
|
//prepare fragment shader code
|
|
55
55
|
//declare the uniform and other variables
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
})() +
|
|
66
|
-
//start the main function, apply the stretching of t
|
|
67
|
-
'void main(void) {\n'
|
|
68
|
-
|
|
56
|
+
const fshBuff = []
|
|
57
|
+
fshBuff.push('precision mediump float;')
|
|
58
|
+
fshBuff.push('varying float vt;')
|
|
59
|
+
fshBuff.push('uniform float alpha;')
|
|
60
|
+
for (let i = 0; i < colors.length; i++) fshBuff.push('uniform vec4 c' + i + ';')
|
|
61
|
+
//start the main function
|
|
62
|
+
fshBuff.push('void main(void) {')
|
|
63
|
+
|
|
64
|
+
// apply the stretching of t
|
|
69
65
|
if (stretching) {
|
|
70
66
|
if (stretching.fun == 'pow')
|
|
71
67
|
//sPow = (t, alpha = 3) => Math.pow(t, alpha);
|
|
72
|
-
|
|
68
|
+
fshBuff.push(' float t = pow(vt, alpha);')
|
|
73
69
|
else if (stretching.fun == 'powInv')
|
|
74
70
|
//sPowRev = (t, alpha = 3) => 1 - Math.pow(1 - t, 1 / alpha);
|
|
75
|
-
|
|
71
|
+
fshBuff.push(' float t = 1.0-pow(1.0-vt, 1.0/alpha);')
|
|
76
72
|
else if (stretching.fun == 'exp')
|
|
77
73
|
//sExp = (t, alpha = 3) => alpha == 0 ? t : (Math.exp(t * alpha) - 1) / (Math.exp(alpha) - 1);
|
|
78
|
-
|
|
74
|
+
fshBuff.push(
|
|
79
75
|
stretching.alpha == 0
|
|
80
76
|
? `float t = vt;`
|
|
81
|
-
: ' float t = (exp(vt * alpha) - 1.0) / (exp(alpha) - 1.0)
|
|
77
|
+
: ' float t = (exp(vt * alpha) - 1.0) / (exp(alpha) - 1.0);')
|
|
82
78
|
else if (stretching.fun == 'log')
|
|
83
79
|
//sExpRev = (t, alpha = 3) => alpha == 0 ? t : 1 - (1 / alpha) * Math.log(Math.exp(alpha) * (1 - t) + t);
|
|
84
|
-
|
|
80
|
+
fshBuff.push(
|
|
85
81
|
stretching.alpha == 0
|
|
86
82
|
? `float t = vt;`
|
|
87
|
-
: ' float t = 1.0 - (1.0 / alpha) * log(exp(alpha) * (1.0 - vt) + vt)
|
|
83
|
+
: ' float t = 1.0 - (1.0 / alpha) * log(exp(alpha) * (1.0 - vt) + vt);')
|
|
88
84
|
else if (stretching.fun == 'circle') {
|
|
89
85
|
if (stretching.alpha == 0)
|
|
90
86
|
//if (alpha == 0) return t;
|
|
91
|
-
|
|
87
|
+
fshBuff.push(' float t = vt;')
|
|
92
88
|
else if (stretching.alpha == 1)
|
|
93
89
|
// if (alpha == 1) return Math.sqrt(2 * t - t * t);
|
|
94
|
-
|
|
90
|
+
fshBuff.push(' float t = sqrt(vt * (2.0 - vt));')
|
|
95
91
|
else {
|
|
96
92
|
//const a = alpha / (1 - alpha);
|
|
97
93
|
//return Math.sqrt(1 / (a * a) + t * (2 / a + 2 - t)) - 1 / a;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
' float t = sqrt(1.0 / (a * a) + vt * ( 2.0/a + 2.0 - vt )) - 1.0 / a;\n'
|
|
94
|
+
fshBuff.push(' float a = alpha / (1.0 - alpha);')
|
|
95
|
+
fshBuff.push(' float t = sqrt(1.0 / (a * a) + vt * ( 2.0/a + 2.0 - vt )) - 1.0 / a;')
|
|
101
96
|
}
|
|
102
97
|
} else if (stretching.fun == 'circleInv') {
|
|
103
98
|
// 1 - sCircleLow(1 - t, alpha)
|
|
104
99
|
if (stretching.alpha == 0)
|
|
105
100
|
//if (alpha == 0) return t;
|
|
106
|
-
|
|
101
|
+
fshBuff.push(' float t = vt;')
|
|
107
102
|
else if (stretching.alpha == 1)
|
|
108
103
|
// if (alpha == 1) return Math.sqrt(2 * t - t * t);
|
|
109
|
-
|
|
104
|
+
fshBuff.push(' float t = 1.0 - sqrt((1.0 - vt) * (1.0 + vt));')
|
|
110
105
|
else {
|
|
111
106
|
//const a = alpha / (1 - alpha);
|
|
112
107
|
//return Math.sqrt(1 / (a * a) + (2 * t) / a + 2 * t - t * t) - 1 / a;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
' float t = 1.0 - sqrt(1.0 / (a * a) + (1.0-vt) * ( 2.0/a + 1.0 + vt )) + 1.0 / a;\n'
|
|
108
|
+
fshBuff.push(' float a = alpha / (1.0 - alpha);')
|
|
109
|
+
fshBuff.push(' float t = 1.0 - sqrt(1.0 / (a * a) + (1.0-vt) * ( 2.0/a + 1.0 + vt )) + 1.0 / a;')
|
|
116
110
|
}
|
|
117
111
|
} else {
|
|
118
112
|
console.error('Unexpected stretching function code: ' + stretching.fun)
|
|
119
|
-
|
|
113
|
+
fshBuff.push(' float t = vt;')
|
|
120
114
|
}
|
|
121
115
|
} else {
|
|
122
|
-
|
|
116
|
+
fshBuff.push(' float t = vt;')
|
|
123
117
|
}
|
|
124
118
|
|
|
125
119
|
//choose initial and final colors, and adjust t value
|
|
126
|
-
if (colors.length == 1)
|
|
127
|
-
|
|
128
|
-
|
|
120
|
+
if (colors.length == 1) {
|
|
121
|
+
fshBuff.push(' vec4 cI=c0;')
|
|
122
|
+
fshBuff.push(' vec4 cF=c0;')
|
|
123
|
+
}
|
|
124
|
+
else if (colors.length == 2) {
|
|
125
|
+
fshBuff.push(' vec4 cI=c0;')
|
|
126
|
+
fshBuff.push(' vec4 cF=c1;')
|
|
127
|
+
} else {
|
|
129
128
|
const nb = colors.length - 1
|
|
130
129
|
const nbs = nb + '.0'
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
fshBuff.push(' vec4 cI;')
|
|
131
|
+
fshBuff.push(' vec4 cF;')
|
|
132
|
+
fshBuff.push(' if(t<1.0/' + nbs + ') { cI=c0; cF=c1; t=t*' + nbs + '; }')
|
|
134
133
|
for (let i = 2; i < nb; i++)
|
|
135
|
-
|
|
134
|
+
fshBuff.push(
|
|
136
135
|
' else if(t<' +
|
|
137
136
|
i +
|
|
138
137
|
'.0/' +
|
|
@@ -145,16 +144,17 @@ export class WebGLSquareColoringAdvanced {
|
|
|
145
144
|
nbs +
|
|
146
145
|
'*t-' +
|
|
147
146
|
(i - 1) +
|
|
148
|
-
'.0; }
|
|
149
|
-
|
|
150
|
-
' else { cI=c' + (nb - 1) + '; cF=c' + nb + '; t=' + nbs + '*t-' + (nb - 1) + '.0; }\n'
|
|
147
|
+
'.0; }')
|
|
148
|
+
fshBuff.push(' else { cI=c' + (nb - 1) + '; cF=c' + nb + '; t=' + nbs + '*t-' + (nb - 1) + '.0; }')
|
|
151
149
|
}
|
|
152
150
|
|
|
153
151
|
//one single color
|
|
154
|
-
if (colors.length == 1)
|
|
152
|
+
if (colors.length == 1) fshBuff.push(' gl_FragColor = vec4(c0[0], c0[1], c0[2], c0[3]);}')
|
|
155
153
|
//set interpolated color, between initial and final one
|
|
156
|
-
else
|
|
154
|
+
else fshBuff.push(' gl_FragColor = mix(cI, cF, t);}')
|
|
157
155
|
|
|
156
|
+
let fshString = fshBuff.join("")
|
|
157
|
+
//let fshString = fshBuff.join("\n")
|
|
158
158
|
//console.log(fshString)
|
|
159
159
|
|
|
160
160
|
/** @type {WebGLShader} */
|
|
@@ -180,12 +180,9 @@ export class WebGLSquareColoringAdvanced {
|
|
|
180
180
|
let opacity = c.opacity
|
|
181
181
|
if (c.opacity == 1 && globalOpacity != undefined) opacity = globalOpacity
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
+c.b / 255.0,
|
|
187
|
-
+opacity,
|
|
188
|
-
])
|
|
183
|
+
const colData = [+c.r / 255.0, +c.g / 255.0, +c.b / 255.0, +opacity]
|
|
184
|
+
//console.log(i, colors[i], c, colData)
|
|
185
|
+
gl.uniform4fv(gl.getUniformLocation(this.program, 'c' + i), colData)
|
|
189
186
|
}
|
|
190
187
|
}
|
|
191
188
|
|
package/src/utils/webGLUtils.js
CHANGED
|
@@ -5,18 +5,19 @@
|
|
|
5
5
|
* @param {string} width
|
|
6
6
|
* @param {string} height
|
|
7
7
|
* @param {object} opts
|
|
8
|
-
* @returns {{canvas:HTMLCanvasElement, gl:WebGLRenderingContext}}
|
|
8
|
+
* @returns {{canvas:HTMLCanvasElement, gl:WebGLRenderingContext, width:number, height:number }}
|
|
9
9
|
*/
|
|
10
10
|
export function makeWebGLCanvas(width, height, opts = {}) {
|
|
11
11
|
const canvas = document.createElement('canvas')
|
|
12
12
|
canvas.setAttribute('width', width)
|
|
13
13
|
canvas.setAttribute('height', height)
|
|
14
|
+
const version2 = (opts && +opts.version==2)? "2" : ""
|
|
14
15
|
/** @type {WebGLRenderingContext} */
|
|
15
|
-
const gl = canvas.getContext('webgl', opts)
|
|
16
|
+
const gl = canvas.getContext('webgl' + version2, opts)
|
|
16
17
|
if (!gl) {
|
|
17
|
-
throw new Error('Unable to initialize WebGL. Your browser or machine may not support it.')
|
|
18
|
+
throw new Error('Unable to initialize WebGL'+version2+'. Your browser or machine may not support it.')
|
|
18
19
|
}
|
|
19
|
-
return { canvas: canvas, gl: gl }
|
|
20
|
+
return { canvas: canvas, gl: gl, width: width, height: height }
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/**
|