figureone 1.7.1 → 1.9.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "figureone",
3
- "version": "1.7.1",
3
+ "version": "1.9.0",
4
4
  "description": "Draw, animate and interact with shapes, text, plots and equations in Javascript. Create interactive slide shows, and interactive videos.",
5
5
  "main": "index.js",
6
6
  "types": "types/index.d.ts",
@@ -42,6 +42,12 @@ declare class GLObject extends DrawingObject {
42
42
  loadColor: TypeColor;
43
43
  [key: string]: any;
44
44
  } | null;
45
+ maskTextures: Array<{
46
+ id: string;
47
+ src: string;
48
+ loadColor: TypeColor;
49
+ uniformName: string;
50
+ }>;
45
51
  attributes: {
46
52
  [attributeName: string]: {
47
53
  buffer: WebGLBuffer | null;
@@ -70,6 +76,7 @@ declare class GLObject extends DrawingObject {
70
76
  fragmentShader: TypeFragmentShader;
71
77
  selectorVertexShader: TypeVertexShader;
72
78
  selectorFragmentShader: TypeFragmentShader;
79
+ acquiredBaseTextureId: string | null;
73
80
  constructor(webgl: WebGLInstance, vertexShader?: TypeVertexShader, fragmentShader?: TypeFragmentShader, selectorVertexShader?: TypeVertexShader, selectorFragShader?: TypeFragmentShader);
74
81
  init(webgl: WebGLInstance): void;
75
82
  initProgram(): void;
@@ -85,8 +92,32 @@ declare class GLObject extends DrawingObject {
85
92
  * Buffer a texture for the shape to be painted with.
86
93
  */
87
94
  addTexture(location: string, mapFrom?: Rect, mapTo?: Rect, mapToBuffer?: string, points?: Array<number>, repeat?: boolean, onLoad?: null | (() => void), loadColor?: TypeColor): void;
95
+ /**
96
+ * Buffer a mask texture for the `textureMap` color mode. Each call appends a
97
+ * mask, bound to the next u_mask{i} sampler. Masks share the base texture's
98
+ * coordinates, so only a source and load color are needed. The default load
99
+ * color is fully transparent so that, until the mask loads, no region is
100
+ * recolored and the base texture shows through unchanged.
101
+ *
102
+ * An empty `location` registers a transparent placeholder, which keeps the
103
+ * u_mask{i} indexing aligned with the tint blocks when a caller supplies an
104
+ * invalid/missing mask in a positional list (the slot becomes a no-op).
105
+ */
106
+ addMaskTexture(location?: string, loadColor?: TypeColor): void;
88
107
  updateTexture(data: HTMLImageElement): void;
89
108
  initTexture(force?: boolean): void;
109
+ /**
110
+ * Adopt a base-texture reference to an already-registered texture (e.g. a
111
+ * shared font atlas uploaded by the Atlas, whose id this object renders with
112
+ * but does not upload itself).
113
+ *
114
+ * Releases any previously-held base reference first (so a font/atlas change
115
+ * rebalances correctly) and is idempotent when the id is unchanged. If the
116
+ * texture isn't registered yet, no reference is taken and acquiredBaseTextureId
117
+ * is cleared, so the later resetTextureBuffer release stays balanced (it only
118
+ * releases a reference that was actually acquired).
119
+ */
120
+ setBaseTextureRef(id: string): void;
90
121
  createTextureMap(xMinGL?: number, xMaxGL?: number, yMinGL?: number, yMaxGL?: number, xMinTex?: number, xMaxTex?: number, yMinTex?: number, yMaxTex?: number): void;
91
122
  addVertices(vertices: Array<number>, dimension?: 2 | 3, usage?: TypeGLBufferUsage): void;
92
123
  addVertices3(vertices: Array<number>, usage?: TypeGLBufferUsage): void;
@@ -224,6 +224,30 @@ export type OBJ_Texture = {
224
224
  repeat?: boolean;
225
225
  onLoad?: () => void;
226
226
  };
227
+ /**
228
+ * Mask texture used by the `gl` primitive to recolor regions of a base
229
+ * `texture`. A mask shares the base texture's coordinates, so it must be the
230
+ * same dimensions and aligned with the base image. Each of a mask's `r`, `g`,
231
+ * `b` and `a` channels selects a region recolored by an entry of the
232
+ * primitive's `tints` option.
233
+ *
234
+ * Supply a single mask with `mask`, or several with `masks` (an array). Mask `m`
235
+ * (0-based) uses `tints[4m]`, `tints[4m + 1]`, `tints[4m + 2]` and
236
+ * `tints[4m + 3]` for its r, g, b and a channels - so each mask adds four
237
+ * recolorable regions. A single mask costs one extra texture fetch and four
238
+ * mixes; each additional mask adds one fetch and four mixes.
239
+ *
240
+ * @property {string} [src] url of the mask image
241
+ * @property {TypeColor} [loadColor] color shown while the mask loads
242
+ * (`[0, 0, 0, 0]` - fully transparent, so nothing is recolored until the mask
243
+ * has loaded)
244
+ * @interface
245
+ * @group Shaders
246
+ */
247
+ export type OBJ_TextureMask = {
248
+ src?: string;
249
+ loadColor?: TypeColor;
250
+ };
227
251
  /**
228
252
  * Pulse options object
229
253
  *
@@ -443,6 +467,12 @@ export type TypeText = 'gl' | '2d';
443
467
  * {@link OBJ_FragmentShader} for names of attributes and uniforms used in the
444
468
  * shaders, and when they are used.
445
469
  *
470
+ * A texture can be recolored by region using one or more masks (see the mask
471
+ * examples below):
472
+ *
473
+ * ![](./apiassets/gl_mask.png)
474
+ * ![](./apiassets/gl_mask2.png)
475
+ *
446
476
  * @property {TypeGLPrimitive} [glPrimitive]
447
477
  * @property {TypeVertexShader} [vertexShader]
448
478
  * @property {TypeFragmentShader} [fragmentShader]
@@ -585,6 +615,46 @@ export type TypeText = 'gl' | '2d';
585
615
  * },
586
616
  * ],
587
617
  * });
618
+ *
619
+ * @example
620
+ * // Recolor regions of a texture with a mask. The mask image marks regions to
621
+ * // recolor in its red, green, blue and alpha channels, which map to tints 0,
622
+ * // 1, 2 and 3. Unmasked pixels keep the base texture's color.
623
+ * const p = figure.add({
624
+ * make: 'gl',
625
+ * vertices: [-0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5],
626
+ * numVertices: 6,
627
+ * texture: {
628
+ * src: './base.png',
629
+ * coords: [0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1],
630
+ * loadColor: [0, 0, 0, 0],
631
+ * },
632
+ * mask: { src: './mask.png' },
633
+ * tints: [[1, 0, 0, 1], [0, 0, 1, 1]],
634
+ * });
635
+ * // Change the first region's color at runtime
636
+ * p.custom.setTint(0, [0, 1, 0, 1]);
637
+ *
638
+ * @example
639
+ * // Recolor with two masks. Each mask adds four regions (its r, g, b, a
640
+ * // channels), so mask 0 uses tints 0-3 and mask 1 uses tints 4-7. Here mask 0
641
+ * // recolors three circles (tints 0, 1, 2) and mask 1 recolors a bar (tint 4).
642
+ * figure.add({
643
+ * make: 'gl',
644
+ * vertices: [-0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5],
645
+ * numVertices: 6,
646
+ * texture: {
647
+ * src: './base.png',
648
+ * coords: [0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1],
649
+ * loadColor: [0, 0, 0, 0],
650
+ * },
651
+ * masks: [{ src: './mask.png' }, { src: './mask1.png' }],
652
+ * tints: [
653
+ * [1, 0, 0, 1], [0, 0.6, 0, 1], [0, 0, 1, 1], null, // mask 0: circles
654
+ * [0.6, 0, 0.8, 1], // mask 1: bar
655
+ * ],
656
+ * });
657
+ *
588
658
  * @interface
589
659
  * @group Shaders
590
660
  */
@@ -595,6 +665,9 @@ export type OBJ_GenericGL = {
595
665
  attributes?: Array<OBJ_GLAttribute>;
596
666
  uniforms?: Array<OBJ_GLUniform>;
597
667
  texture?: OBJ_Texture;
668
+ mask?: OBJ_TextureMask;
669
+ masks?: Array<OBJ_TextureMask>;
670
+ tints?: Array<TypeColor | null>;
598
671
  dimension?: 2 | 3;
599
672
  light?: 'directional' | 'point' | null;
600
673
  vertices?: OBJ_GLVertexBuffer;
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Number of recolorable regions a single mask texture provides in the
3
+ * `textureMap` color mode - one per channel (r, g, b, a). N masks therefore
4
+ * define `CHANNELS_PER_MASK * N` tints.
5
+ * @group Shaders
6
+ */
7
+ export declare const CHANNELS_PER_MASK = 4;
1
8
  /**
2
9
  * Options used to compose vertex shader source code.
3
10
  *
@@ -53,14 +60,14 @@
53
60
  * to fragment shader used when `light = 'point'`
54
61
  *
55
62
  * @property {2 | 3} [dimension] (`2`)
56
- * @property {'vertex' | 'uniform' | 'texture'} [color] (`uniform`)
63
+ * @property {'vertex' | 'uniform' | 'texture' | 'textureMap'} [color] (`uniform`)
57
64
  * @property {'point' | 'directional' | null} [light] (`null`)
58
65
  * @interface
59
66
  * @group Shaders
60
67
  */
61
68
  export type OBJ_VertexShader = {
62
69
  light?: 'point' | 'directional' | null;
63
- color?: 'vertex' | 'uniform' | 'texture';
70
+ color?: 'vertex' | 'uniform' | 'texture' | 'textureMap';
64
71
  dimension?: 2 | 3;
65
72
  };
66
73
  /**
@@ -93,7 +100,16 @@ export type TypeVertexShader = string | {
93
100
  * - `vec4 u_color`: global color for all vertices used all times. When
94
101
  * `color = 'texture'` or `color = 'vertex'`, only the alpha channel of
95
102
  * `u_color` is used.
96
- * - `sampler2D u_texture`: texture used when `color = 'texture'`.
103
+ * - `sampler2D u_texture`: texture used when `color = 'texture'`,
104
+ * `color = 'textureAlpha'` or `color = 'textureMap'`.
105
+ * - `sampler2D u_mask0`, `u_mask1`, ...: mask textures used when
106
+ * `color = 'textureMap'` (one per mask, set by the `masks` count). Each mask's
107
+ * `r`, `g`, `b` and `a` channels select four regions of `u_texture` to
108
+ * recolor. Mask `m`'s four channels map to tints `u_tint{4m+0..3}`.
109
+ * - `vec4 u_tint0`, `u_tint1`, ...: region tint colors used when
110
+ * `color = 'textureMap'` (four per mask). The `rgb` channels are the tint
111
+ * color and the `a` channel is the tint strength (`0` leaves the base texture
112
+ * unchanged).
97
113
  * - `vec3 u_directionalLight`: world space position of directional light
98
114
  * source used when `light = 'directional'`
99
115
  * - `float u_ambientLight`: ambient light used when `light = 'directional'` or
@@ -113,14 +129,15 @@ export type TypeVertexShader = string | {
113
129
  * from vertex shader used when `light = 'point'`
114
130
  *
115
131
  * @property {2 | 3} [dimension] (`2`)
116
- * @property {'vertex' | 'uniform' | 'texture'} [color] (`uniform`)
132
+ * @property {'vertex' | 'uniform' | 'texture' | 'textureMap'} [color] (`uniform`)
117
133
  * @property {'point' | 'directional' | null} [light] (`null`)
118
134
  * @interface
119
135
  * @group Shaders
120
136
  */
121
137
  export type OBJ_FragmentShader = {
122
138
  light?: 'point' | 'directional' | null;
123
- color?: 'vertex' | 'uniform' | 'texture';
139
+ color?: 'vertex' | 'uniform' | 'texture' | 'textureMap';
140
+ masks?: number;
124
141
  };
125
142
  /**
126
143
  * A fragment shader can be defined with either:
@@ -12,11 +12,16 @@ declare class WebGLInstance {
12
12
  textures: {
13
13
  [name: string]: {
14
14
  glTexture: WebGLTexture;
15
- index: number;
15
+ handle: number;
16
+ refCount: number;
16
17
  state: 'loading' | 'loaded';
17
18
  onLoad: Array<((b: boolean, n: number) => void) | string>;
18
19
  };
19
20
  };
21
+ boundUnits: Array<string | null>;
22
+ nextTextureHandle: number;
23
+ maxTextureUnits: number;
24
+ warnedUnitOverflow: boolean;
20
25
  atlases: {
21
26
  [atlasId: string]: Atlas;
22
27
  };
@@ -39,8 +44,12 @@ declare class WebGLInstance {
39
44
  addTexture(id: string, data: string | HTMLImageElement | HTMLCanvasElement, loadColor?: TypeColor, repeat?: boolean, onLoad?: null | string | ((b: boolean, n: number) => void), force?: boolean): number;
40
45
  getAtlas(options: OBJ_Atlas): Atlas;
41
46
  recreateAtlases(): void;
47
+ acquireTexture(id: string): boolean;
42
48
  deleteTexture(id: string): void;
49
+ freeTexture(id: string): void;
43
50
  contextLost(): void;
51
+ clearBoundUnits(id: string): void;
52
+ bindTextureToUnit(id: string, unit: number): boolean;
44
53
  cleanup(): void;
45
54
  setTextureData(id: string, image: Record<string, any> | TypeColor, // image data
46
55
  repeat?: boolean): boolean;