Gabriel commited on
Commit
bfd1654
·
verified ·
1 Parent(s): 8f90ae8

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +13 -0
  2. .python-version +1 -0
  3. README.md +384 -12
  4. app.py +266 -0
  5. backend/gradio_polygonannotator/__init__.py +4 -0
  6. backend/gradio_polygonannotator/polygonannotator.py +232 -0
  7. demo/__init__.py +0 -0
  8. demo/app.py +86 -0
  9. demo/css.css +157 -0
  10. demo/space.py +208 -0
  11. frontend/Example.svelte +70 -0
  12. frontend/Index.svelte +465 -0
  13. frontend/gradio.config.js +9 -0
  14. frontend/package-lock.json +0 -0
  15. frontend/package.json +52 -0
  16. frontend/shared/ClearImage.svelte +18 -0
  17. frontend/shared/ImagePreview.svelte +61 -0
  18. frontend/shared/ImageUploader.svelte +99 -0
  19. frontend/tsconfig.json +14 -0
  20. pyproject.toml +59 -0
  21. src/.gitignore +13 -0
  22. src/.python-version +1 -0
  23. src/README.md +384 -0
  24. src/app.py +266 -0
  25. src/backend/gradio_polygonannotator/__init__.py +4 -0
  26. src/backend/gradio_polygonannotator/polygonannotator.py +232 -0
  27. src/backend/gradio_polygonannotator/templates/component/CanvasPool-CO7699qB.js +47 -0
  28. src/backend/gradio_polygonannotator/templates/component/Index-Ct_1BCRd.js +0 -0
  29. src/backend/gradio_polygonannotator/templates/component/SharedSystems-DVDwWST4.js +2766 -0
  30. src/backend/gradio_polygonannotator/templates/component/WebGLRenderer-DDL2mbll.js +2643 -0
  31. src/backend/gradio_polygonannotator/templates/component/WebGPURenderer-scPngJ2c.js +1656 -0
  32. src/backend/gradio_polygonannotator/templates/component/browserAll-CBYXns0T.js +1869 -0
  33. src/backend/gradio_polygonannotator/templates/component/colorToUniform-zJcCVLeu.js +220 -0
  34. src/backend/gradio_polygonannotator/templates/component/index.js +4 -0
  35. src/backend/gradio_polygonannotator/templates/component/style.css +1 -0
  36. src/backend/gradio_polygonannotator/templates/component/webworkerAll-FY7_jo4S.js +0 -0
  37. src/backend/gradio_polygonannotator/templates/example/index.js +171 -0
  38. src/backend/gradio_polygonannotator/templates/example/style.css +1 -0
  39. src/demo/__init__.py +0 -0
  40. src/demo/app.py +86 -0
  41. src/demo/css.css +157 -0
  42. src/demo/space.py +208 -0
  43. src/frontend/Example.svelte +70 -0
  44. src/frontend/Index.svelte +465 -0
  45. src/frontend/gradio.config.js +9 -0
  46. src/frontend/package-lock.json +0 -0
  47. src/frontend/package.json +52 -0
  48. src/frontend/shared/ClearImage.svelte +18 -0
  49. src/frontend/shared/ImagePreview.svelte +61 -0
  50. src/frontend/shared/ImageUploader.svelte +99 -0
.gitignore ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .eggs/
2
+ dist/
3
+ *.pyc
4
+ __pycache__/
5
+ *.py[cod]
6
+ *$py.class
7
+ __tmp/*
8
+ *.pyi
9
+ .mypycache
10
+ .ruff_cache
11
+ node_modules
12
+ backend/**/templates/
13
+ .venv
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.12
README.md CHANGED
@@ -1,12 +1,384 @@
1
- ---
2
- title: Gradio Polygonannotator
3
- emoji: 🐠
4
- colorFrom: green
5
- colorTo: red
6
- sdk: gradio
7
- sdk_version: 5.46.1
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # `gradio_polygonannotator`
3
+ <img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.1.0%20-%20orange"> <a href="https://github.com/yourusername/gradio-polygonannotator/issues" target="_blank"><img alt="Static Badge" src="https://img.shields.io/badge/Issues-white?logo=github&logoColor=black"></a>
4
+
5
+ Interactive polygon annotation component for Gradio with multi-selection, hover effects, and customizable appearance
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install gradio_polygonannotator
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```python
16
+ import gradio as gr
17
+ from gradio_polygonannotator import PolygonAnnotator
18
+
19
+ # Example with document regions
20
+ example_data = {
21
+ "image": "https://images.unsplash.com/photo-1544816155-12df9643f363?w=800&h=1200",
22
+ "polygons": [
23
+ {
24
+ "id": "title",
25
+ "coordinates": [[180, 150], [580, 150], [580, 200], [180, 200]],
26
+ "color": "#FF6B6B",
27
+ "mask_opacity": 0.15,
28
+ "stroke_width": 1.0,
29
+ "stroke_opacity": 0.8,
30
+ },
31
+ {
32
+ "id": "paragraph_1",
33
+ "coordinates": [[100, 400], [750, 400], [750, 600], [100, 600]],
34
+ "color": "#4ECDC4",
35
+ "mask_opacity": 0.15,
36
+ "stroke_width": 0.7,
37
+ "stroke_opacity": 0.6,
38
+ },
39
+ {
40
+ "id": "paragraph_2",
41
+ "coordinates": [[100, 650], [750, 650], [750, 950], [100, 950]],
42
+ "color": "#4ECDC4",
43
+ "mask_opacity": 0.15,
44
+ "stroke_width": 0.7,
45
+ "stroke_opacity": 0.6,
46
+ },
47
+ {
48
+ "id": "signature",
49
+ "coordinates": [[400, 1020], [650, 1020], [650, 1080], [400, 1080]],
50
+ "color": "#FFE66D",
51
+ "mask_opacity": 0.2,
52
+ "stroke_width": 1.5,
53
+ "stroke_opacity": 0.8,
54
+ }
55
+ ]
56
+ }
57
+
58
+ def handle_selection(data, evt: gr.SelectData):
59
+ """Handle polygon selection and display info"""
60
+ if evt.value and data:
61
+ selected_ids = evt.value if isinstance(evt.value, list) else [evt.value]
62
+ info = f"Selected {len(selected_ids)} polygon(s):\n"
63
+ for poly_id in selected_ids:
64
+ polygon = next((p for p in data["polygons"] if p["id"] == poly_id), None)
65
+ if polygon:
66
+ info += f"• {poly_id}\n"
67
+ return info
68
+ return "Click on polygons to select them. Use Ctrl/Cmd+Click for multi-selection."
69
+
70
+ with gr.Blocks() as demo:
71
+ gr.Markdown("""
72
+ # PolygonAnnotator - Interactive Polygon Selection
73
+
74
+ Click on polygons to select them. Use **Ctrl/Cmd+Click** for multiple selections.
75
+ Click selected polygons to deselect.
76
+ """)
77
+
78
+ with gr.Row():
79
+ with gr.Column(scale=3):
80
+ annotator = PolygonAnnotator(
81
+ value=example_data,
82
+ label="Document with Region Annotations",
83
+ height=600,
84
+ )
85
+
86
+ with gr.Column(scale=1):
87
+ selected_info = gr.Textbox(
88
+ label="Selected Regions",
89
+ lines=6,
90
+ value="Click on polygons to select them. Use Ctrl/Cmd+Click for multi-selection."
91
+ )
92
+
93
+ # Handle selection events
94
+ annotator.select(
95
+ handle_selection,
96
+ inputs=[annotator],
97
+ outputs=[selected_info]
98
+ )
99
+
100
+ if __name__ == "__main__":
101
+ demo.launch()
102
+
103
+ ```
104
+
105
+ ## `PolygonAnnotator`
106
+
107
+ ### Initialization
108
+
109
+ <table>
110
+ <thead>
111
+ <tr>
112
+ <th align="left">name</th>
113
+ <th align="left" style="width: 25%;">type</th>
114
+ <th align="left">default</th>
115
+ <th align="left">description</th>
116
+ </tr>
117
+ </thead>
118
+ <tbody>
119
+ <tr>
120
+ <td align="left"><code>value</code></td>
121
+ <td align="left" style="width: 25%;">
122
+
123
+ ```python
124
+ dict | None
125
+ ```
126
+
127
+ </td>
128
+ <td align="left"><code>None</code></td>
129
+ <td align="left">Dictionary containing 'image' (FileData), 'polygons' (list with id, coordinates, color, opacities),</td>
130
+ </tr>
131
+
132
+ <tr>
133
+ <td align="left"><code>label</code></td>
134
+ <td align="left" style="width: 25%;">
135
+
136
+ ```python
137
+ str | I18nData | None
138
+ ```
139
+
140
+ </td>
141
+ <td align="left"><code>None</code></td>
142
+ <td align="left">Component label shown above the annotator.</td>
143
+ </tr>
144
+
145
+ <tr>
146
+ <td align="left"><code>every</code></td>
147
+ <td align="left" style="width: 25%;">
148
+
149
+ ```python
150
+ Timer | float | None
151
+ ```
152
+
153
+ </td>
154
+ <td align="left"><code>None</code></td>
155
+ <td align="left">Continuously calls `value` to recalculate it if `value` is a function.</td>
156
+ </tr>
157
+
158
+ <tr>
159
+ <td align="left"><code>inputs</code></td>
160
+ <td align="left" style="width: 25%;">
161
+
162
+ ```python
163
+ Component | Sequence[Component] | set[Component] | None
164
+ ```
165
+
166
+ </td>
167
+ <td align="left"><code>None</code></td>
168
+ <td align="left">Components used as inputs to calculate `value` if it's a function.</td>
169
+ </tr>
170
+
171
+ <tr>
172
+ <td align="left"><code>show_label</code></td>
173
+ <td align="left" style="width: 25%;">
174
+
175
+ ```python
176
+ bool | None
177
+ ```
178
+
179
+ </td>
180
+ <td align="left"><code>None</code></td>
181
+ <td align="left">Whether to display the label.</td>
182
+ </tr>
183
+
184
+ <tr>
185
+ <td align="left"><code>show_download_button</code></td>
186
+ <td align="left" style="width: 25%;">
187
+
188
+ ```python
189
+ bool
190
+ ```
191
+
192
+ </td>
193
+ <td align="left"><code>True</code></td>
194
+ <td align="left">Whether to show image download button.</td>
195
+ </tr>
196
+
197
+ <tr>
198
+ <td align="left"><code>height</code></td>
199
+ <td align="left" style="width: 25%;">
200
+
201
+ ```python
202
+ int | str | None
203
+ ```
204
+
205
+ </td>
206
+ <td align="left"><code>None</code></td>
207
+ <td align="left">Component height in pixels or CSS units.</td>
208
+ </tr>
209
+
210
+ <tr>
211
+ <td align="left"><code>width</code></td>
212
+ <td align="left" style="width: 25%;">
213
+
214
+ ```python
215
+ int | str | None
216
+ ```
217
+
218
+ </td>
219
+ <td align="left"><code>None</code></td>
220
+ <td align="left">Component width in pixels or CSS units.</td>
221
+ </tr>
222
+
223
+ <tr>
224
+ <td align="left"><code>container</code></td>
225
+ <td align="left" style="width: 25%;">
226
+
227
+ ```python
228
+ bool
229
+ ```
230
+
231
+ </td>
232
+ <td align="left"><code>True</code></td>
233
+ <td align="left">Whether to wrap component in a container with padding.</td>
234
+ </tr>
235
+
236
+ <tr>
237
+ <td align="left"><code>scale</code></td>
238
+ <td align="left" style="width: 25%;">
239
+
240
+ ```python
241
+ int | None
242
+ ```
243
+
244
+ </td>
245
+ <td align="left"><code>None</code></td>
246
+ <td align="left">Relative size compared to adjacent components.</td>
247
+ </tr>
248
+
249
+ <tr>
250
+ <td align="left"><code>min_width</code></td>
251
+ <td align="left" style="width: 25%;">
252
+
253
+ ```python
254
+ int
255
+ ```
256
+
257
+ </td>
258
+ <td align="left"><code>160</code></td>
259
+ <td align="left">Minimum pixel width before wrapping.</td>
260
+ </tr>
261
+
262
+ <tr>
263
+ <td align="left"><code>interactive</code></td>
264
+ <td align="left" style="width: 25%;">
265
+
266
+ ```python
267
+ bool | None
268
+ ```
269
+
270
+ </td>
271
+ <td align="left"><code>None</code></td>
272
+ <td align="left">Whether users can interact with polygons (selection/deselection).</td>
273
+ </tr>
274
+
275
+ <tr>
276
+ <td align="left"><code>visible</code></td>
277
+ <td align="left" style="width: 25%;">
278
+
279
+ ```python
280
+ bool | Literal["hidden"]
281
+ ```
282
+
283
+ </td>
284
+ <td align="left"><code>True</code></td>
285
+ <td align="left">Whether component is visible ("hidden" keeps it in DOM but invisible).</td>
286
+ </tr>
287
+
288
+ <tr>
289
+ <td align="left"><code>elem_id</code></td>
290
+ <td align="left" style="width: 25%;">
291
+
292
+ ```python
293
+ str | None
294
+ ```
295
+
296
+ </td>
297
+ <td align="left"><code>None</code></td>
298
+ <td align="left">HTML DOM id for CSS targeting.</td>
299
+ </tr>
300
+
301
+ <tr>
302
+ <td align="left"><code>elem_classes</code></td>
303
+ <td align="left" style="width: 25%;">
304
+
305
+ ```python
306
+ list[str] | str | None
307
+ ```
308
+
309
+ </td>
310
+ <td align="left"><code>None</code></td>
311
+ <td align="left">HTML DOM classes for CSS targeting.</td>
312
+ </tr>
313
+
314
+ <tr>
315
+ <td align="left"><code>render</code></td>
316
+ <td align="left" style="width: 25%;">
317
+
318
+ ```python
319
+ bool
320
+ ```
321
+
322
+ </td>
323
+ <td align="left"><code>True</code></td>
324
+ <td align="left">Whether to render the component immediately.</td>
325
+ </tr>
326
+
327
+ <tr>
328
+ <td align="left"><code>key</code></td>
329
+ <td align="left" style="width: 25%;">
330
+
331
+ ```python
332
+ int | str | tuple[int | str, ...] | None
333
+ ```
334
+
335
+ </td>
336
+ <td align="left"><code>None</code></td>
337
+ <td align="left">Key for maintaining component identity across re-renders.</td>
338
+ </tr>
339
+
340
+ <tr>
341
+ <td align="left"><code>preserved_by_key</code></td>
342
+ <td align="left" style="width: 25%;">
343
+
344
+ ```python
345
+ list[str] | str | None
346
+ ```
347
+
348
+ </td>
349
+ <td align="left"><code>"value"</code></td>
350
+ <td align="left">Parameters preserved across re-renders with same key.</td>
351
+ </tr>
352
+ </tbody></table>
353
+
354
+
355
+ ### Events
356
+
357
+ | name | description |
358
+ |:-----|:------------|
359
+ | `clear` | This listener is triggered when the user clears the PolygonAnnotator using the clear button for the component. |
360
+ | `change` | Triggered when the value of the PolygonAnnotator changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input. |
361
+ | `upload` | This listener is triggered when the user uploads a file into the PolygonAnnotator. |
362
+ | `select` | Event listener for when the user selects or deselects the PolygonAnnotator. Uses event data gradio.SelectData to carry `value` referring to the label of the PolygonAnnotator, and `selected` to refer to state of the PolygonAnnotator. See EventData documentation on how to use this event data |
363
+
364
+
365
+
366
+ ### User function
367
+
368
+ The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
369
+
370
+ - When used as an Input, the component only impacts the input signature of the user function.
371
+ - When used as an output, the component only impacts the return signature of the user function.
372
+
373
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
374
+
375
+ - **As output:** Is passed, dictionary with image path, polygon data including coordinates, colors, opacities,.
376
+ - **As input:** Should return, dictionary containing 'image' (file path or URL), 'polygons' (list of polygon dictionaries.
377
+
378
+ ```python
379
+ def predict(
380
+ value: dict | None
381
+ ) -> dict | None:
382
+ return value
383
+ ```
384
+
app.py ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from gradio_polygonannotator import PolygonAnnotator
3
+ from typing import Literal
4
+
5
+ example_data = {
6
+ "image": "https://images.unsplash.com/photo-1544816155-12df9643f363?w=800&h=1200",
7
+ "polygons": [
8
+ {
9
+ "id": "date_line",
10
+ "coordinates": [[180, 150], [580, 150], [580, 200], [180, 200]],
11
+ "color": "#FF0000",
12
+ "mask_opacity": 0.2,
13
+ "stroke_width": 0.7,
14
+ "stroke_opacity": 0.6,
15
+ "selected_mask_opacity": 0.5,
16
+ "selected_stroke_opacity": 1.0
17
+ },
18
+ {
19
+ "id": "salutation",
20
+ "coordinates": [[180, 280], [680, 280], [680, 340], [180, 340]],
21
+ "color": "#00FF00",
22
+ "mask_opacity": 0.2,
23
+ "stroke_width": 1.0,
24
+ "stroke_opacity": 0.6,
25
+ "selected_mask_opacity": 0.4,
26
+ "selected_stroke_opacity": 0.9
27
+ },
28
+ {
29
+ "id": "main_text_block",
30
+ "coordinates": [[100, 400], [750, 400], [750, 950], [100, 950]],
31
+ "color": "#0000FF",
32
+ "mask_opacity": 0.15,
33
+ "stroke_width": 0.5,
34
+ "stroke_opacity": 0.5,
35
+ "selected_mask_opacity": 0.4,
36
+ "selected_stroke_opacity": 0.8
37
+ },
38
+ {
39
+ "id": "closing_signature",
40
+ "coordinates": [[400, 1020], [650, 1020], [650, 1080], [400, 1080]],
41
+ "color": "#FFFF00",
42
+ "mask_opacity": 0.25,
43
+ "stroke_width": 1.5,
44
+ "stroke_opacity": 0.7,
45
+ "selected_mask_opacity": 0.6,
46
+ "selected_stroke_opacity": 1.0
47
+ }
48
+ ]
49
+ }
50
+
51
+ # Create dataframe data from polygon information
52
+ polygon_table = [
53
+ ["date_line", "Date Line", "#FF0000", 0.2, 0.7, 0.6],
54
+ ["salutation", "Salutation", "#00FF00", 0.2, 1.0, 0.6],
55
+ ["main_text_block", "Main Text Block", "#0000FF", 0.15, 0.5, 0.5],
56
+ ["closing_signature", "Closing/Signature", "#FFFF00", 0.25, 1.5, 0.7]
57
+ ]
58
+
59
+ def process_viewer_selection(data, evt: gr.SelectData):
60
+ """Handle polygon selection from viewer and update dataframe selection"""
61
+ if evt.value and data:
62
+ selected_ids = evt.value if isinstance(evt.value, list) else [evt.value]
63
+
64
+ # Create highlighted dataframe data
65
+ highlighted_table = []
66
+ for row in polygon_table:
67
+ if row[0] in selected_ids: # If this is a selected row
68
+ # Add highlighting markers to the selected row
69
+ highlighted_row = [f"→ {row[0]} ←", f"→ {row[1]} ←", f"→ {row[2]} ←", f"→ {row[3]} ←", f"→ {row[4]} ←", f"→ {row[5]} ←"]
70
+ highlighted_table.append(highlighted_row)
71
+ else:
72
+ highlighted_table.append(row)
73
+
74
+ # Create info text for all selected polygons
75
+ info_lines = [f"Selected {len(selected_ids)} polygon(s):"]
76
+ for selected_id in selected_ids:
77
+ selected_polygon = next((p for p in data["polygons"] if p["id"] == selected_id), None)
78
+ if selected_polygon:
79
+ info_lines.append(f"• {selected_id}: {selected_polygon['color']}, mask: {selected_polygon.get('mask_opacity', 0.2)}, stroke: {selected_polygon.get('stroke_width', 0.7)}px")
80
+
81
+ info_text = "\n".join(info_lines)
82
+ return info_text, highlighted_table
83
+
84
+ return "No polygons selected", polygon_table
85
+
86
+ def process_dataframe_selection(selected_data, evt: gr.SelectData):
87
+ """Handle row selection from dataframe and update viewer selection"""
88
+ if evt.index is not None and evt.index[0] < len(polygon_table):
89
+ selected_row = polygon_table[evt.index[0]]
90
+ polygon_id = selected_row[0]
91
+
92
+ # Update the viewer data with the selected polygon
93
+ updated_data = example_data.copy()
94
+ updated_data["selected_polygons"] = [polygon_id]
95
+
96
+ info_text = f"Selected polygon: {polygon_id}\nName: {selected_row[1]}\nColor: {selected_row[2]}\nMask Opacity: {selected_row[3]}\nStroke Width: {selected_row[4]}\nStroke Opacity: {selected_row[5]}"
97
+ return updated_data, info_text
98
+
99
+ # Deselection
100
+ updated_data = example_data.copy()
101
+ updated_data["selected_polygons"] = []
102
+ return updated_data, "No polygons selected"
103
+
104
+ def clear_selection():
105
+ """Clear polygon selection"""
106
+ updated_data = example_data.copy()
107
+ updated_data["selected_polygons"] = []
108
+ return updated_data, "No polygons selected", polygon_table
109
+
110
+ def select_polygon_by_id(polygon_id):
111
+ """Select polygon by ID from textbox input"""
112
+ if not polygon_id or polygon_id.strip() == "":
113
+ # Empty input - clear selection
114
+ updated_data = example_data.copy()
115
+ updated_data["selected_polygons"] = []
116
+ return updated_data, "No polygons selected", polygon_table
117
+
118
+ # Handle multiple IDs (comma-separated)
119
+ polygon_ids = [id.strip() for id in polygon_id.split(",") if id.strip()]
120
+ valid_ids = [p["id"] for p in example_data["polygons"]]
121
+
122
+ # Filter to only valid IDs
123
+ valid_selected_ids = [id for id in polygon_ids if id in valid_ids]
124
+ invalid_ids = [id for id in polygon_ids if id not in valid_ids]
125
+
126
+ if not valid_selected_ids:
127
+ # No valid IDs
128
+ updated_data = example_data.copy()
129
+ updated_data["selected_polygons"] = []
130
+ error_msg = f"Invalid polygon ID(s): {', '.join(invalid_ids)}. Valid IDs: {', '.join(valid_ids)}"
131
+ return updated_data, error_msg, polygon_table
132
+
133
+ # Valid IDs - select polygons
134
+ updated_data = example_data.copy()
135
+ updated_data["selected_polygons"] = valid_selected_ids
136
+
137
+ # Create highlighted dataframe data
138
+ highlighted_table = []
139
+ for row in polygon_table:
140
+ if row[0] in valid_selected_ids: # If this is a selected row
141
+ # Add highlighting markers to the selected row
142
+ highlighted_row = [f"→ {row[0]} ←", f"→ {row[1]} ←", f"→ {row[2]} ←", f"→ {row[3]} ←", f"→ {row[4]} ←", f"→ {row[5]} ←"]
143
+ highlighted_table.append(highlighted_row)
144
+ else:
145
+ highlighted_table.append(row)
146
+
147
+ # Create info text
148
+ info_lines = [f"Selected {len(valid_selected_ids)} polygon(s):"]
149
+ for selected_id in valid_selected_ids:
150
+ selected_polygon = next((p for p in example_data["polygons"] if p["id"] == selected_id), None)
151
+ if selected_polygon:
152
+ info_lines.append(f"• {selected_id}: {selected_polygon['color']}, mask: {selected_polygon.get('mask_opacity', 0.2)}, stroke: {selected_polygon.get('stroke_width', 0.7)}px")
153
+
154
+ if invalid_ids:
155
+ info_lines.append(f"\nInvalid IDs: {', '.join(invalid_ids)}")
156
+
157
+ info_text = "\n".join(info_lines)
158
+ return updated_data, info_text, highlighted_table
159
+
160
+ with gr.Blocks() as demo:
161
+ gr.Markdown("""
162
+ # PolygonAnnotator - Advanced Interactive Demo
163
+
164
+ This demo showcases all the features of the PolygonAnnotator component:
165
+ - **Click** on polygons to select/deselect them
166
+ - **Ctrl/Cmd+Click** for multiple selection
167
+ - **Click dataframe rows** to select polygons
168
+ - **Enter polygon IDs** manually in the textbox
169
+ - **Clear button** to deselect all
170
+ """)
171
+
172
+ with gr.Row():
173
+ with gr.Column(scale=2):
174
+ poly_annotator = PolygonAnnotator(
175
+ value=example_data,
176
+ label="Document with Interactive Polygon Annotations",
177
+ height=600,
178
+ )
179
+
180
+ with gr.Column(scale=1):
181
+ selected_info = gr.Textbox(
182
+ label="Selected Polygon Information",
183
+ lines=5,
184
+ value="Click on a polygon to see its information"
185
+ )
186
+
187
+ polygon_dataframe = gr.Dataframe(
188
+ value=polygon_table,
189
+ headers=["ID", "Name", "Color", "Mask", "Stroke W", "Stroke O"],
190
+ label="Polygon Data (Click rows to select)",
191
+ datatype=[Literal["str", "str", "str", "number", "number", "number"]],
192
+ interactive=True
193
+ )
194
+
195
+ clear_button = gr.Button("🗑️ Clear All Selections", variant="secondary")
196
+
197
+ with gr.Row():
198
+ polygon_id_input = gr.Textbox(
199
+ label="Select by Polygon ID(s)",
200
+ placeholder="Enter single ID or comma-separated IDs (e.g., 'date_line' or 'date_line, salutation')",
201
+ scale=3
202
+ )
203
+ select_button = gr.Button("Select", variant="primary", scale=1)
204
+
205
+ gr.Markdown("""
206
+ ### Features Demonstrated
207
+
208
+ #### 🎨 Visual Customization
209
+ - Different **mask opacity** for each polygon fill
210
+ - Variable **stroke width** (0.5px to 1.5px)
211
+ - Custom **stroke opacity** for borders
212
+ - Enhanced appearance when selected
213
+
214
+ #### 🖱️ Interaction Methods
215
+ 1. **Direct Click**: Click polygons in the viewer
216
+ 2. **Multi-Selection**: Ctrl/Cmd+Click for multiple
217
+ 3. **Dataframe**: Click table rows
218
+ 4. **Text Input**: Type polygon IDs
219
+ 5. **Clear All**: Reset selection
220
+
221
+ #### 📝 Polygon IDs
222
+ - `date_line` - Red header area
223
+ - `salutation` - Green greeting section
224
+ - `main_text_block` - Blue main content
225
+ - `closing_signature` - Yellow signature area
226
+
227
+ #### 💡 Tips
228
+ - Hover over polygons for visual feedback
229
+ - Selected polygons have increased opacity
230
+ - Use comma-separated IDs for batch selection
231
+ - Click selected polygons to deselect them
232
+ """)
233
+
234
+ # Handle selection events
235
+ poly_annotator.select(
236
+ process_viewer_selection,
237
+ inputs=[poly_annotator],
238
+ outputs=[selected_info, polygon_dataframe]
239
+ )
240
+
241
+ polygon_dataframe.select(
242
+ process_dataframe_selection,
243
+ inputs=[polygon_dataframe],
244
+ outputs=[poly_annotator, selected_info]
245
+ )
246
+
247
+ clear_button.click(
248
+ clear_selection,
249
+ outputs=[poly_annotator, selected_info, polygon_dataframe]
250
+ )
251
+
252
+ select_button.click(
253
+ select_polygon_by_id,
254
+ inputs=[polygon_id_input],
255
+ outputs=[poly_annotator, selected_info, polygon_dataframe]
256
+ )
257
+
258
+ # Also allow Enter key in textbox
259
+ polygon_id_input.submit(
260
+ select_polygon_by_id,
261
+ inputs=[polygon_id_input],
262
+ outputs=[poly_annotator, selected_info, polygon_dataframe]
263
+ )
264
+
265
+ if __name__ == "__main__":
266
+ demo.launch()
backend/gradio_polygonannotator/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+
2
+ from .polygonannotator import PolygonAnnotator
3
+
4
+ __all__ = ['PolygonAnnotator']
backend/gradio_polygonannotator/polygonannotator.py ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """gr.PolygonAnnotator() component for interactive polygon annotations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence
6
+ from typing import TYPE_CHECKING, Any, Literal, List, Optional
7
+
8
+ from gradio_client import handle_file
9
+
10
+ from gradio.components.base import Component
11
+ from gradio.data_classes import FileData, GradioModel
12
+ from gradio.events import Events
13
+ from gradio.i18n import I18nData
14
+
15
+ if TYPE_CHECKING:
16
+ from gradio.components import Timer
17
+
18
+
19
+ class Polygon(GradioModel):
20
+ id: str
21
+ coordinates: List[List[float]] # [[x1,y1], [x2,y2], ...]
22
+ color: str # hex color like "#FF0000"
23
+ mask_opacity: Optional[float] = 0.2 # fill opacity from 0.0 to 1.0, default 0.2
24
+ stroke_width: Optional[float] = 0.7 # stroke width in pixels, default 0.7
25
+ stroke_opacity: Optional[float] = 0.6 # stroke opacity from 0.0 to 1.0, default 0.6
26
+ selected_mask_opacity: Optional[float] = 0.5 # mask opacity when selected, default 0.5
27
+ selected_stroke_opacity: Optional[float] = 1.0 # stroke opacity when selected, default 1.0
28
+
29
+
30
+ class PolygonAnnotatorData(GradioModel):
31
+ image: FileData
32
+ polygons: List[Polygon]
33
+ selected_polygons: Optional[List[str]] = None # List of IDs of the currently selected polygons
34
+
35
+
36
+ class PolygonAnnotator(Component):
37
+ """
38
+ Interactive polygon annotation component for visualizing and selecting polygon regions on images.
39
+
40
+ The PolygonAnnotator displays an image with customizable polygon overlays that users can interact with.
41
+ Features include multi-selection with Ctrl/Cmd+click, hover effects, and customizable appearance including
42
+ stroke width, opacity settings for both fill and stroke, with separate settings for selected states.
43
+
44
+ Perfect for:
45
+ - Document layout analysis and region selection
46
+ - Image segmentation visualization
47
+ - Interactive annotation review and editing
48
+ - Object detection result visualization
49
+ """
50
+
51
+ EVENTS = [
52
+ Events.clear,
53
+ Events.change,
54
+ Events.upload,
55
+ Events.select,
56
+ ]
57
+
58
+ data_model = PolygonAnnotatorData
59
+
60
+ def __init__(
61
+ self,
62
+ value: dict | None = None,
63
+ *,
64
+ label: str | I18nData | None = None,
65
+ every: Timer | float | None = None,
66
+ inputs: Component | Sequence[Component] | set[Component] | None = None,
67
+ show_label: bool | None = None,
68
+ show_download_button: bool = True,
69
+ height: int | str | None = None,
70
+ width: int | str | None = None,
71
+ container: bool = True,
72
+ scale: int | None = None,
73
+ min_width: int = 160,
74
+ interactive: bool | None = None,
75
+ visible: bool | Literal["hidden"] = True,
76
+ elem_id: str | None = None,
77
+ elem_classes: list[str] | str | None = None,
78
+ render: bool = True,
79
+ key: int | str | tuple[int | str, ...] | None = None,
80
+ preserved_by_key: list[str] | str | None = "value",
81
+ ):
82
+ """
83
+ Parameters:
84
+ value: Dictionary containing 'image' (FileData), 'polygons' (list with id, coordinates, color, opacities),
85
+ and optionally 'selected_polygons' (list of selected IDs).
86
+ label: Component label shown above the annotator.
87
+ every: Continuously calls `value` to recalculate it if `value` is a function.
88
+ inputs: Components used as inputs to calculate `value` if it's a function.
89
+ show_label: Whether to display the label.
90
+ show_download_button: Whether to show image download button.
91
+ height: Component height in pixels or CSS units.
92
+ width: Component width in pixels or CSS units.
93
+ container: Whether to wrap component in a container with padding.
94
+ scale: Relative size compared to adjacent components.
95
+ min_width: Minimum pixel width before wrapping.
96
+ interactive: Whether users can interact with polygons (selection/deselection).
97
+ visible: Whether component is visible ("hidden" keeps it in DOM but invisible).
98
+ elem_id: HTML DOM id for CSS targeting.
99
+ elem_classes: HTML DOM classes for CSS targeting.
100
+ render: Whether to render the component immediately.
101
+ key: Key for maintaining component identity across re-renders.
102
+ preserved_by_key: Parameters preserved across re-renders with same key.
103
+ """
104
+ self.show_download_button = show_download_button
105
+ self.height = height
106
+ self.width = width
107
+ super().__init__(
108
+ label=label,
109
+ every=every,
110
+ inputs=inputs,
111
+ show_label=show_label,
112
+ container=container,
113
+ scale=scale,
114
+ min_width=min_width,
115
+ interactive=interactive,
116
+ visible=visible,
117
+ elem_id=elem_id,
118
+ elem_classes=elem_classes,
119
+ render=render,
120
+ key=key,
121
+ preserved_by_key=preserved_by_key,
122
+ value=value,
123
+ )
124
+
125
+ def preprocess(self, payload: PolygonAnnotatorData | None) -> dict | None:
126
+ """
127
+ Parameters:
128
+ payload: The component data containing image and polygon annotations.
129
+ Returns:
130
+ Dictionary with image path, polygon data including coordinates, colors, opacities,
131
+ and the list of currently selected polygon IDs.
132
+ """
133
+ if payload is None:
134
+ return None
135
+ return {
136
+ "image": payload.image.path,
137
+ "polygons": [
138
+ {
139
+ "id": p.id,
140
+ "coordinates": p.coordinates,
141
+ "color": p.color,
142
+ "mask_opacity": p.mask_opacity,
143
+ "stroke_width": p.stroke_width,
144
+ "stroke_opacity": p.stroke_opacity,
145
+ "selected_mask_opacity": p.selected_mask_opacity,
146
+ "selected_stroke_opacity": p.selected_stroke_opacity
147
+ }
148
+ for p in payload.polygons
149
+ ],
150
+ "selected_polygons": payload.selected_polygons
151
+ }
152
+
153
+ def postprocess(self, value: dict | None) -> PolygonAnnotatorData | None:
154
+ """
155
+ Parameters:
156
+ value: Dictionary containing 'image' (file path or URL), 'polygons' (list of polygon dictionaries
157
+ with id, coordinates, color, mask_opacity, stroke_width, stroke_opacity, and selection opacity settings),
158
+ and optionally 'selected_polygons' (list of selected polygon IDs).
159
+ Returns:
160
+ Processed component data ready for display.
161
+ """
162
+ if value is None:
163
+ return None
164
+
165
+ # Handle the image path
166
+ image_path = value.get("image")
167
+ if isinstance(image_path, str):
168
+ image_data = FileData(path=image_path)
169
+ else:
170
+ return None
171
+
172
+ # Handle polygons
173
+ polygons = []
174
+ for poly in value.get("polygons", []):
175
+ polygons.append(
176
+ Polygon(
177
+ id=poly["id"],
178
+ coordinates=poly["coordinates"],
179
+ color=poly.get("color", "#FF0000"),
180
+ mask_opacity=poly.get("mask_opacity", poly.get("opacity", 0.2)), # Support old 'opacity' key for backwards compatibility
181
+ stroke_width=poly.get("stroke_width", 0.7),
182
+ stroke_opacity=poly.get("stroke_opacity", 0.6),
183
+ selected_mask_opacity=poly.get("selected_mask_opacity", 0.5),
184
+ selected_stroke_opacity=poly.get("selected_stroke_opacity", 1.0)
185
+ )
186
+ )
187
+
188
+ return PolygonAnnotatorData(
189
+ image=image_data,
190
+ polygons=polygons,
191
+ selected_polygons=value.get("selected_polygons")
192
+ )
193
+
194
+ def example_payload(self) -> Any:
195
+ return {
196
+ "image": handle_file(
197
+ "https://raw.githubusercontent.com/gradio-app/gradio/main/test/test_files/bus.png"
198
+ ),
199
+ "polygons": [
200
+ {
201
+ "id": "polygon1",
202
+ "coordinates": [[50, 50], [150, 50], [150, 150], [50, 150]],
203
+ "color": "#FF0000",
204
+ "mask_opacity": 0.2,
205
+ "stroke_width": 0.7,
206
+ "stroke_opacity": 0.6
207
+ }
208
+ ]
209
+ }
210
+
211
+ def example_value(self) -> Any:
212
+ return {
213
+ "image": "https://raw.githubusercontent.com/gradio-app/gradio/main/test/test_files/bus.png",
214
+ "polygons": [
215
+ {
216
+ "id": "polygon1",
217
+ "coordinates": [[50, 50], [150, 50], [150, 150], [50, 150]],
218
+ "color": "#FF0000",
219
+ "mask_opacity": 0.2,
220
+ "stroke_width": 0.7,
221
+ "stroke_opacity": 0.6
222
+ },
223
+ {
224
+ "id": "polygon2",
225
+ "coordinates": [[200, 100], [300, 100], [250, 200]],
226
+ "color": "#00FF00",
227
+ "mask_opacity": 0.2,
228
+ "stroke_width": 1,
229
+ "stroke_opacity": 0.8
230
+ }
231
+ ]
232
+ }
demo/__init__.py ADDED
File without changes
demo/app.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from gradio_polygonannotator import PolygonAnnotator
3
+
4
+ # Example with document regions
5
+ example_data = {
6
+ "image": "https://images.unsplash.com/photo-1544816155-12df9643f363?w=800&h=1200",
7
+ "polygons": [
8
+ {
9
+ "id": "title",
10
+ "coordinates": [[180, 150], [580, 150], [580, 200], [180, 200]],
11
+ "color": "#FF6B6B",
12
+ "mask_opacity": 0.15,
13
+ "stroke_width": 1.0,
14
+ "stroke_opacity": 0.8,
15
+ },
16
+ {
17
+ "id": "paragraph_1",
18
+ "coordinates": [[100, 400], [750, 400], [750, 600], [100, 600]],
19
+ "color": "#4ECDC4",
20
+ "mask_opacity": 0.15,
21
+ "stroke_width": 0.7,
22
+ "stroke_opacity": 0.6,
23
+ },
24
+ {
25
+ "id": "paragraph_2",
26
+ "coordinates": [[100, 650], [750, 650], [750, 950], [100, 950]],
27
+ "color": "#4ECDC4",
28
+ "mask_opacity": 0.15,
29
+ "stroke_width": 0.7,
30
+ "stroke_opacity": 0.6,
31
+ },
32
+ {
33
+ "id": "signature",
34
+ "coordinates": [[400, 1020], [650, 1020], [650, 1080], [400, 1080]],
35
+ "color": "#FFE66D",
36
+ "mask_opacity": 0.2,
37
+ "stroke_width": 1.5,
38
+ "stroke_opacity": 0.8,
39
+ }
40
+ ]
41
+ }
42
+
43
+ def handle_selection(data, evt: gr.SelectData):
44
+ """Handle polygon selection and display info"""
45
+ if evt.value and data:
46
+ selected_ids = evt.value if isinstance(evt.value, list) else [evt.value]
47
+ info = f"Selected {len(selected_ids)} polygon(s):\n"
48
+ for poly_id in selected_ids:
49
+ polygon = next((p for p in data["polygons"] if p["id"] == poly_id), None)
50
+ if polygon:
51
+ info += f"• {poly_id}\n"
52
+ return info
53
+ return "Click on polygons to select them. Use Ctrl/Cmd+Click for multi-selection."
54
+
55
+ with gr.Blocks() as demo:
56
+ gr.Markdown("""
57
+ # PolygonAnnotator - Interactive Polygon Selection
58
+
59
+ Click on polygons to select them. Use **Ctrl/Cmd+Click** for multiple selections.
60
+ Click selected polygons to deselect.
61
+ """)
62
+
63
+ with gr.Row():
64
+ with gr.Column(scale=3):
65
+ annotator = PolygonAnnotator(
66
+ value=example_data,
67
+ label="Document with Region Annotations",
68
+ height=600,
69
+ )
70
+
71
+ with gr.Column(scale=1):
72
+ selected_info = gr.Textbox(
73
+ label="Selected Regions",
74
+ lines=6,
75
+ value="Click on polygons to select them. Use Ctrl/Cmd+Click for multi-selection."
76
+ )
77
+
78
+ # Handle selection events
79
+ annotator.select(
80
+ handle_selection,
81
+ inputs=[annotator],
82
+ outputs=[selected_info]
83
+ )
84
+
85
+ if __name__ == "__main__":
86
+ demo.launch()
demo/css.css ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ html {
2
+ font-family: Inter;
3
+ font-size: 16px;
4
+ font-weight: 400;
5
+ line-height: 1.5;
6
+ -webkit-text-size-adjust: 100%;
7
+ background: #fff;
8
+ color: #323232;
9
+ -webkit-font-smoothing: antialiased;
10
+ -moz-osx-font-smoothing: grayscale;
11
+ text-rendering: optimizeLegibility;
12
+ }
13
+
14
+ :root {
15
+ --space: 1;
16
+ --vspace: calc(var(--space) * 1rem);
17
+ --vspace-0: calc(3 * var(--space) * 1rem);
18
+ --vspace-1: calc(2 * var(--space) * 1rem);
19
+ --vspace-2: calc(1.5 * var(--space) * 1rem);
20
+ --vspace-3: calc(0.5 * var(--space) * 1rem);
21
+ }
22
+
23
+ .app {
24
+ max-width: 748px !important;
25
+ }
26
+
27
+ .prose p {
28
+ margin: var(--vspace) 0;
29
+ line-height: var(--vspace * 2);
30
+ font-size: 1rem;
31
+ }
32
+
33
+ code {
34
+ font-family: "Inconsolata", sans-serif;
35
+ font-size: 16px;
36
+ }
37
+
38
+ h1,
39
+ h1 code {
40
+ font-weight: 400;
41
+ line-height: calc(2.5 / var(--space) * var(--vspace));
42
+ }
43
+
44
+ h1 code {
45
+ background: none;
46
+ border: none;
47
+ letter-spacing: 0.05em;
48
+ padding-bottom: 5px;
49
+ position: relative;
50
+ padding: 0;
51
+ }
52
+
53
+ h2 {
54
+ margin: var(--vspace-1) 0 var(--vspace-2) 0;
55
+ line-height: 1em;
56
+ }
57
+
58
+ h3,
59
+ h3 code {
60
+ margin: var(--vspace-1) 0 var(--vspace-2) 0;
61
+ line-height: 1em;
62
+ }
63
+
64
+ h4,
65
+ h5,
66
+ h6 {
67
+ margin: var(--vspace-3) 0 var(--vspace-3) 0;
68
+ line-height: var(--vspace);
69
+ }
70
+
71
+ .bigtitle,
72
+ h1,
73
+ h1 code {
74
+ font-size: calc(8px * 4.5);
75
+ word-break: break-word;
76
+ }
77
+
78
+ .title,
79
+ h2,
80
+ h2 code {
81
+ font-size: calc(8px * 3.375);
82
+ font-weight: lighter;
83
+ word-break: break-word;
84
+ border: none;
85
+ background: none;
86
+ }
87
+
88
+ .subheading1,
89
+ h3,
90
+ h3 code {
91
+ font-size: calc(8px * 1.8);
92
+ font-weight: 600;
93
+ border: none;
94
+ background: none;
95
+ letter-spacing: 0.1em;
96
+ text-transform: uppercase;
97
+ }
98
+
99
+ h2 code {
100
+ padding: 0;
101
+ position: relative;
102
+ letter-spacing: 0.05em;
103
+ }
104
+
105
+ blockquote {
106
+ font-size: calc(8px * 1.1667);
107
+ font-style: italic;
108
+ line-height: calc(1.1667 * var(--vspace));
109
+ margin: var(--vspace-2) var(--vspace-2);
110
+ }
111
+
112
+ .subheading2,
113
+ h4 {
114
+ font-size: calc(8px * 1.4292);
115
+ text-transform: uppercase;
116
+ font-weight: 600;
117
+ }
118
+
119
+ .subheading3,
120
+ h5 {
121
+ font-size: calc(8px * 1.2917);
122
+ line-height: calc(1.2917 * var(--vspace));
123
+
124
+ font-weight: lighter;
125
+ text-transform: uppercase;
126
+ letter-spacing: 0.15em;
127
+ }
128
+
129
+ h6 {
130
+ font-size: calc(8px * 1.1667);
131
+ font-size: 1.1667em;
132
+ font-weight: normal;
133
+ font-style: italic;
134
+ font-family: "le-monde-livre-classic-byol", serif !important;
135
+ letter-spacing: 0px !important;
136
+ }
137
+
138
+ #start .md > *:first-child {
139
+ margin-top: 0;
140
+ }
141
+
142
+ h2 + h3 {
143
+ margin-top: 0;
144
+ }
145
+
146
+ .md hr {
147
+ border: none;
148
+ border-top: 1px solid var(--block-border-color);
149
+ margin: var(--vspace-2) 0 var(--vspace-2) 0;
150
+ }
151
+ .prose ul {
152
+ margin: var(--vspace-2) 0 var(--vspace-1) 0;
153
+ }
154
+
155
+ .gap {
156
+ gap: 0;
157
+ }
demo/space.py ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from app import demo as app
4
+ import os
5
+
6
+ _docs = {'PolygonAnnotator': {'description': 'Interactive polygon annotation component for visualizing and selecting polygon regions on images.\n\nThe PolygonAnnotator displays an image with customizable polygon overlays that users can interact with.\nFeatures include multi-selection with Ctrl/Cmd+click, hover effects, and customizable appearance including\nstroke width, opacity settings for both fill and stroke, with separate settings for selected states.\n\nPerfect for:\n- Document layout analysis and region selection\n- Image segmentation visualization\n- Interactive annotation review and editing\n- Object detection result visualization', 'members': {'__init__': {'value': {'type': 'dict | None', 'default': 'None', 'description': "Dictionary containing 'image' (FileData), 'polygons' (list with id, coordinates, color, opacities),"}, 'label': {'type': 'str | I18nData | None', 'default': 'None', 'description': 'Component label shown above the annotator.'}, 'every': {'type': 'Timer | float | None', 'default': 'None', 'description': 'Continuously calls `value` to recalculate it if `value` is a function.'}, 'inputs': {'type': 'Component | Sequence[Component] | set[Component] | None', 'default': 'None', 'description': "Components used as inputs to calculate `value` if it's a function."}, 'show_label': {'type': 'bool | None', 'default': 'None', 'description': 'Whether to display the label.'}, 'show_download_button': {'type': 'bool', 'default': 'True', 'description': 'Whether to show image download button.'}, 'height': {'type': 'int | str | None', 'default': 'None', 'description': 'Component height in pixels or CSS units.'}, 'width': {'type': 'int | str | None', 'default': 'None', 'description': 'Component width in pixels or CSS units.'}, 'container': {'type': 'bool', 'default': 'True', 'description': 'Whether to wrap component in a container with padding.'}, 'scale': {'type': 'int | None', 'default': 'None', 'description': 'Relative size compared to adjacent components.'}, 'min_width': {'type': 'int', 'default': '160', 'description': 'Minimum pixel width before wrapping.'}, 'interactive': {'type': 'bool | None', 'default': 'None', 'description': 'Whether users can interact with polygons (selection/deselection).'}, 'visible': {'type': 'bool | Literal["hidden"]', 'default': 'True', 'description': 'Whether component is visible ("hidden" keeps it in DOM but invisible).'}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': 'HTML DOM id for CSS targeting.'}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': 'HTML DOM classes for CSS targeting.'}, 'render': {'type': 'bool', 'default': 'True', 'description': 'Whether to render the component immediately.'}, 'key': {'type': 'int | str | tuple[int | str, ...] | None', 'default': 'None', 'description': 'Key for maintaining component identity across re-renders.'}, 'preserved_by_key': {'type': 'list[str] | str | None', 'default': '"value"', 'description': 'Parameters preserved across re-renders with same key.'}}, 'postprocess': {'value': {'type': 'dict | None', 'description': "Dictionary containing 'image' (file path or URL), 'polygons' (list of polygon dictionaries"}}, 'preprocess': {'return': {'type': 'dict | None', 'description': 'Dictionary with image path, polygon data including coordinates, colors, opacities,'}, 'value': None}}, 'events': {'clear': {'type': None, 'default': None, 'description': 'This listener is triggered when the user clears the PolygonAnnotator using the clear button for the component.'}, 'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the PolygonAnnotator changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}, 'upload': {'type': None, 'default': None, 'description': 'This listener is triggered when the user uploads a file into the PolygonAnnotator.'}, 'select': {'type': None, 'default': None, 'description': 'Event listener for when the user selects or deselects the PolygonAnnotator. Uses event data gradio.SelectData to carry `value` referring to the label of the PolygonAnnotator, and `selected` to refer to state of the PolygonAnnotator. See EventData documentation on how to use this event data'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'PolygonAnnotator': []}}}
7
+
8
+ abs_path = os.path.join(os.path.dirname(__file__), "css.css")
9
+
10
+ with gr.Blocks(
11
+ css=abs_path,
12
+ theme=gr.themes.Default(
13
+ font_mono=[
14
+ gr.themes.GoogleFont("Inconsolata"),
15
+ "monospace",
16
+ ],
17
+ ),
18
+ ) as demo:
19
+ gr.Markdown(
20
+ """
21
+ # `gradio_polygonannotator`
22
+
23
+ <div style="display: flex; gap: 7px;">
24
+ <img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.1.0%20-%20orange"> <a href="https://github.com/yourusername/gradio-polygonannotator/issues" target="_blank"><img alt="Static Badge" src="https://img.shields.io/badge/Issues-white?logo=github&logoColor=black"></a>
25
+ </div>
26
+
27
+ Interactive polygon annotation component for Gradio with multi-selection, hover effects, and customizable appearance
28
+ """, elem_classes=["md-custom"], header_links=True)
29
+ app.render()
30
+ gr.Markdown(
31
+ """
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install gradio_polygonannotator
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```python
41
+ import gradio as gr
42
+ from gradio_polygonannotator import PolygonAnnotator
43
+
44
+ # Example with document regions
45
+ example_data = {
46
+ "image": "https://images.unsplash.com/photo-1544816155-12df9643f363?w=800&h=1200",
47
+ "polygons": [
48
+ {
49
+ "id": "title",
50
+ "coordinates": [[180, 150], [580, 150], [580, 200], [180, 200]],
51
+ "color": "#FF6B6B",
52
+ "mask_opacity": 0.15,
53
+ "stroke_width": 1.0,
54
+ "stroke_opacity": 0.8,
55
+ },
56
+ {
57
+ "id": "paragraph_1",
58
+ "coordinates": [[100, 400], [750, 400], [750, 600], [100, 600]],
59
+ "color": "#4ECDC4",
60
+ "mask_opacity": 0.15,
61
+ "stroke_width": 0.7,
62
+ "stroke_opacity": 0.6,
63
+ },
64
+ {
65
+ "id": "paragraph_2",
66
+ "coordinates": [[100, 650], [750, 650], [750, 950], [100, 950]],
67
+ "color": "#4ECDC4",
68
+ "mask_opacity": 0.15,
69
+ "stroke_width": 0.7,
70
+ "stroke_opacity": 0.6,
71
+ },
72
+ {
73
+ "id": "signature",
74
+ "coordinates": [[400, 1020], [650, 1020], [650, 1080], [400, 1080]],
75
+ "color": "#FFE66D",
76
+ "mask_opacity": 0.2,
77
+ "stroke_width": 1.5,
78
+ "stroke_opacity": 0.8,
79
+ }
80
+ ]
81
+ }
82
+
83
+ def handle_selection(data, evt: gr.SelectData):
84
+ \"\"\"Handle polygon selection and display info\"\"\"
85
+ if evt.value and data:
86
+ selected_ids = evt.value if isinstance(evt.value, list) else [evt.value]
87
+ info = f"Selected {len(selected_ids)} polygon(s):\n"
88
+ for poly_id in selected_ids:
89
+ polygon = next((p for p in data["polygons"] if p["id"] == poly_id), None)
90
+ if polygon:
91
+ info += f"• {poly_id}\n"
92
+ return info
93
+ return "Click on polygons to select them. Use Ctrl/Cmd+Click for multi-selection."
94
+
95
+ with gr.Blocks() as demo:
96
+ gr.Markdown(\"\"\"
97
+ # PolygonAnnotator - Interactive Polygon Selection
98
+
99
+ Click on polygons to select them. Use **Ctrl/Cmd+Click** for multiple selections.
100
+ Click selected polygons to deselect.
101
+ \"\"\")
102
+
103
+ with gr.Row():
104
+ with gr.Column(scale=3):
105
+ annotator = PolygonAnnotator(
106
+ value=example_data,
107
+ label="Document with Region Annotations",
108
+ height=600,
109
+ )
110
+
111
+ with gr.Column(scale=1):
112
+ selected_info = gr.Textbox(
113
+ label="Selected Regions",
114
+ lines=6,
115
+ value="Click on polygons to select them. Use Ctrl/Cmd+Click for multi-selection."
116
+ )
117
+
118
+ # Handle selection events
119
+ annotator.select(
120
+ handle_selection,
121
+ inputs=[annotator],
122
+ outputs=[selected_info]
123
+ )
124
+
125
+ if __name__ == "__main__":
126
+ demo.launch()
127
+
128
+ ```
129
+ """, elem_classes=["md-custom"], header_links=True)
130
+
131
+
132
+ gr.Markdown("""
133
+ ## `PolygonAnnotator`
134
+
135
+ ### Initialization
136
+ """, elem_classes=["md-custom"], header_links=True)
137
+
138
+ gr.ParamViewer(value=_docs["PolygonAnnotator"]["members"]["__init__"], linkify=[])
139
+
140
+
141
+ gr.Markdown("### Events")
142
+ gr.ParamViewer(value=_docs["PolygonAnnotator"]["events"], linkify=['Event'])
143
+
144
+
145
+
146
+
147
+ gr.Markdown("""
148
+
149
+ ### User function
150
+
151
+ The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
152
+
153
+ - When used as an Input, the component only impacts the input signature of the user function.
154
+ - When used as an output, the component only impacts the return signature of the user function.
155
+
156
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
157
+
158
+ - **As input:** Is passed, dictionary with image path, polygon data including coordinates, colors, opacities,.
159
+ - **As output:** Should return, dictionary containing 'image' (file path or URL), 'polygons' (list of polygon dictionaries.
160
+
161
+ ```python
162
+ def predict(
163
+ value: dict | None
164
+ ) -> dict | None:
165
+ return value
166
+ ```
167
+ """, elem_classes=["md-custom", "PolygonAnnotator-user-fn"], header_links=True)
168
+
169
+
170
+
171
+
172
+ demo.load(None, js=r"""function() {
173
+ const refs = {};
174
+ const user_fn_refs = {
175
+ PolygonAnnotator: [], };
176
+ requestAnimationFrame(() => {
177
+
178
+ Object.entries(user_fn_refs).forEach(([key, refs]) => {
179
+ if (refs.length > 0) {
180
+ const el = document.querySelector(`.${key}-user-fn`);
181
+ if (!el) return;
182
+ refs.forEach(ref => {
183
+ el.innerHTML = el.innerHTML.replace(
184
+ new RegExp("\\b"+ref+"\\b", "g"),
185
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
186
+ );
187
+ })
188
+ }
189
+ })
190
+
191
+ Object.entries(refs).forEach(([key, refs]) => {
192
+ if (refs.length > 0) {
193
+ const el = document.querySelector(`.${key}`);
194
+ if (!el) return;
195
+ refs.forEach(ref => {
196
+ el.innerHTML = el.innerHTML.replace(
197
+ new RegExp("\\b"+ref+"\\b", "g"),
198
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
199
+ );
200
+ })
201
+ }
202
+ })
203
+ })
204
+ }
205
+
206
+ """)
207
+
208
+ demo.launch()
frontend/Example.svelte ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { FileData } from "@gradio/client";
3
+
4
+ export let value: null | { image: FileData; polygons: Array<{id: string, coordinates: number[][], color: string}> };
5
+ export let type: "gallery" | "table";
6
+ export let selected = false;
7
+ export const index: number = 0;
8
+ </script>
9
+
10
+ {#if value?.image}
11
+ <div
12
+ class="container"
13
+ class:table={type === "table"}
14
+ class:gallery={type === "gallery"}
15
+ class:selected
16
+ >
17
+ <img src={value.image.url || value.image.path} alt="" />
18
+ {#if value.polygons && value.polygons.length > 0}
19
+ <div class="polygon-count">
20
+ {value.polygons.length} polygon{value.polygons.length !== 1 ? 's' : ''}
21
+ </div>
22
+ {/if}
23
+ </div>
24
+ {/if}
25
+
26
+ <style>
27
+ .container :global(img) {
28
+ width: 100%;
29
+ height: 100%;
30
+ }
31
+
32
+ .container.selected {
33
+ border-color: var(--border-color-accent);
34
+ }
35
+
36
+ .container.table {
37
+ margin: 0 auto;
38
+ border: 2px solid var(--border-color-primary);
39
+ border-radius: var(--radius-lg);
40
+ overflow: hidden;
41
+ width: var(--size-20);
42
+ height: var(--size-20);
43
+ object-fit: cover;
44
+ }
45
+
46
+ .container.gallery {
47
+ height: var(--size-20);
48
+ max-height: var(--size-20);
49
+ object-fit: cover;
50
+ }
51
+ .container img {
52
+ object-fit: cover;
53
+ }
54
+
55
+ .polygon-count {
56
+ position: absolute;
57
+ bottom: 4px;
58
+ right: 4px;
59
+ background: rgba(0, 0, 0, 0.7);
60
+ color: white;
61
+ padding: 2px 6px;
62
+ border-radius: 3px;
63
+ font-size: 11px;
64
+ font-weight: 500;
65
+ }
66
+
67
+ .container {
68
+ position: relative;
69
+ }
70
+ </style>
frontend/Index.svelte ADDED
@@ -0,0 +1,465 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <svelte:options accessors={true} />
2
+
3
+ <script lang="ts">
4
+ import { onMount, onDestroy, tick } from "svelte";
5
+ import * as PIXI from "pixi.js";
6
+ import type { Gradio } from "@gradio/utils";
7
+ import { Block, BlockLabel } from "@gradio/atoms";
8
+ import { Image as ImageIcon } from "@gradio/icons";
9
+ import { StatusTracker } from "@gradio/statustracker";
10
+ import type { LoadingStatus } from "@gradio/statustracker";
11
+ import type { FileData } from "@gradio/client";
12
+
13
+ export let elem_id = "";
14
+ export let elem_classes: string[] = [];
15
+ export let visible: boolean | "hidden" = true;
16
+ export let value: {
17
+ image: FileData;
18
+ polygons: Array<{
19
+ id: string;
20
+ coordinates: number[][];
21
+ color: string;
22
+ mask_opacity?: number;
23
+ stroke_width?: number;
24
+ stroke_opacity?: number;
25
+ selected_mask_opacity?: number;
26
+ selected_stroke_opacity?: number;
27
+ }>;
28
+ selected_polygons?: string[] | null;
29
+ } | null = null;
30
+ export let label: string;
31
+ export let show_label: boolean;
32
+ export let height: number | string | undefined = undefined;
33
+ export let width: number | string | undefined = undefined;
34
+ export let container = true;
35
+ export let scale: number | null = null;
36
+ export let min_width: number | undefined = undefined;
37
+ export let loading_status: LoadingStatus;
38
+ export let root: string;
39
+
40
+ export let gradio: Gradio<{
41
+ change: never;
42
+ upload: never;
43
+ clear: never;
44
+ select: { index: number | null; value: any };
45
+ clear_status: LoadingStatus;
46
+ }>;
47
+
48
+ let canvasContainer: HTMLDivElement;
49
+ let app: PIXI.Application;
50
+ let imageSprite: PIXI.Sprite | null = null;
51
+ let polygonGraphics: Map<string, PIXI.Graphics> = new Map();
52
+ let selectedPolygonIds: string[] = [];
53
+ type ImageRect = {
54
+ left: number;
55
+ top: number;
56
+ right: number;
57
+ bottom: number;
58
+ width: number;
59
+ height: number;
60
+ naturalWidth: number;
61
+ naturalHeight: number;
62
+ };
63
+ let imageRect: ImageRect = {
64
+ left: 0,
65
+ top: 0,
66
+ right: 1,
67
+ bottom: 1,
68
+ width: 1,
69
+ height: 1,
70
+ naturalWidth: 2,
71
+ naturalHeight: 2,
72
+ };
73
+
74
+ $: (value, handleValueChange());
75
+
76
+ async function handleValueChange() {
77
+ if (!app || !value) return;
78
+ selectedPolygonIds = value.selected_polygons || [];
79
+ await renderAnnotations();
80
+ }
81
+
82
+ function updateSelection(newSelectedIds: string[]) {
83
+ if (!value || !imageSprite) return;
84
+
85
+ polygonGraphics.forEach((graphics, polygonId) => {
86
+ const polygon = value.polygons.find((p) => p.id === polygonId);
87
+ if (!polygon) return;
88
+
89
+ const originalMaskAlpha = polygon.mask_opacity ?? 0.2;
90
+ const selectedMaskAlpha = polygon.selected_mask_opacity ?? 0.5;
91
+ const originalStrokeAlpha = polygon.stroke_opacity ?? 0.6;
92
+ const selectedStrokeAlpha = polygon.selected_stroke_opacity ?? 1.0;
93
+ const strokeWidth = polygon.stroke_width ?? 0.7;
94
+
95
+ graphics.clear();
96
+ if (newSelectedIds.includes(polygonId)) {
97
+ drawPolygonPath(graphics, polygon, imageSprite!, selectedMaskAlpha, strokeWidth, selectedStrokeAlpha);
98
+ } else {
99
+ drawPolygonPath(graphics, polygon, imageSprite!, originalMaskAlpha, strokeWidth, originalStrokeAlpha);
100
+ }
101
+ });
102
+ }
103
+
104
+ async function initPixiApp() {
105
+ if (!canvasContainer) return;
106
+
107
+ const containerWidth = canvasContainer.clientWidth || 800;
108
+ const containerHeight = canvasContainer.clientHeight || 600;
109
+
110
+ app = new PIXI.Application();
111
+ await app.init({
112
+ width: containerWidth,
113
+ height: containerHeight,
114
+ backgroundColor: 0xf0f0f0,
115
+ antialias: true,
116
+ resolution: window.devicePixelRatio || 1,
117
+ autoDensity: true,
118
+ });
119
+
120
+ canvasContainer.appendChild(app.canvas as HTMLCanvasElement);
121
+
122
+ app.stage.eventMode = "static";
123
+ app.stage.hitArea = app.screen;
124
+ }
125
+
126
+ async function renderAnnotations() {
127
+ if (!app || !value) return;
128
+
129
+ app.stage.removeChildren();
130
+ polygonGraphics.clear();
131
+ if (value.image) {
132
+ let imageUrl = "";
133
+
134
+ if (typeof value.image === "string") {
135
+ imageUrl = value.image;
136
+ } else if (value.image.url) {
137
+ imageUrl = value.image.url;
138
+ } else if (value.image.path) {
139
+ if (root && !value.image.path.startsWith("http")) {
140
+ imageUrl = `${root}/file=${value.image.path}`;
141
+ } else {
142
+ imageUrl = value.image.path;
143
+ }
144
+ }
145
+
146
+ if (imageUrl) {
147
+ try {
148
+ const img = new Image();
149
+ img.crossOrigin = "anonymous";
150
+
151
+ const imageLoadPromise = new Promise<HTMLImageElement>(
152
+ (resolve, reject) => {
153
+ img.onload = () => resolve(img);
154
+ img.onerror = reject;
155
+ img.src = imageUrl;
156
+ },
157
+ );
158
+
159
+ const loadedImage = await imageLoadPromise;
160
+ const texture = PIXI.Texture.from(loadedImage);
161
+ imageSprite = new PIXI.Sprite(texture);
162
+
163
+ const scaleX = app.screen.width / texture.width;
164
+ const scaleY = app.screen.height / texture.height;
165
+ const scale = Math.min(scaleX, scaleY);
166
+
167
+ imageSprite.scale.set(scale);
168
+
169
+ const displayWidth = texture.width * scale;
170
+ const displayHeight = texture.height * scale;
171
+
172
+ imageSprite.x = (app.screen.width - displayWidth) / 2;
173
+ imageSprite.y = (app.screen.height - displayHeight) / 2;
174
+
175
+ imageRect = {
176
+ left: imageSprite.x,
177
+ top: imageSprite.y,
178
+ right: imageSprite.x + displayWidth,
179
+ bottom: imageSprite.y + displayHeight,
180
+ width: displayWidth,
181
+ height: displayHeight,
182
+ naturalWidth: texture.width,
183
+ naturalHeight: texture.height,
184
+ };
185
+
186
+ app.stage.addChild(imageSprite);
187
+ } catch (error) {
188
+ console.error("Failed to load image:", error);
189
+ return;
190
+ }
191
+ }
192
+ }
193
+
194
+ if (value.polygons && value.polygons.length > 0 && imageSprite) {
195
+ value.polygons.forEach((polygon) => {
196
+ const graphics = new PIXI.Graphics();
197
+
198
+ let color = 0xff0000;
199
+ try {
200
+ if (polygon.color) {
201
+ const colorStr = polygon.color.replace("#", "");
202
+ color = parseInt(colorStr, 16);
203
+ }
204
+ } catch (e) {
205
+ console.error("Error parsing color:", e);
206
+ }
207
+
208
+ const polygonMaskOpacity = polygon.mask_opacity ?? 0.2;
209
+ const selectedMaskAlpha = polygon.selected_mask_opacity ?? 0.5;
210
+ const polygonStrokeOpacity = polygon.stroke_opacity ?? 0.6;
211
+ const selectedStrokeAlpha = polygon.selected_stroke_opacity ?? 1.0;
212
+ const strokeWidth = polygon.stroke_width ?? 0.7;
213
+ const initialMaskAlpha = selectedPolygonIds.includes(polygon.id)
214
+ ? selectedMaskAlpha
215
+ : polygonMaskOpacity;
216
+ const initialStrokeAlpha = selectedPolygonIds.includes(polygon.id)
217
+ ? selectedStrokeAlpha
218
+ : polygonStrokeOpacity;
219
+
220
+ if (polygon.coordinates && polygon.coordinates.length > 0) {
221
+ const displayCoords = polygon.coordinates.map((coord) => {
222
+ return [
223
+ (coord[0] / (imageRect.naturalWidth - 1)) *
224
+ imageRect.width +
225
+ imageRect.left,
226
+ (coord[1] / (imageRect.naturalHeight - 1)) *
227
+ imageRect.height +
228
+ imageRect.top,
229
+ ];
230
+ });
231
+
232
+ graphics.poly(displayCoords.flat());
233
+ graphics.fill({ color: color, alpha: initialMaskAlpha });
234
+ graphics.stroke({ width: strokeWidth, color: color, alpha: initialStrokeAlpha });
235
+ }
236
+
237
+ graphics.eventMode = "static";
238
+ graphics.cursor = "pointer";
239
+
240
+ const originalMaskAlpha = polygonMaskOpacity;
241
+ const hoverMaskAlpha = Math.min(polygonMaskOpacity + 0.1, 1.0);
242
+ const hoverStrokeAlpha = Math.min(polygonStrokeOpacity + 0.2, 1.0);
243
+
244
+ graphics.on("pointerover", () => {
245
+ if (!selectedPolygonIds.includes(polygon.id)) {
246
+ graphics.clear();
247
+ drawPolygonPath(
248
+ graphics,
249
+ polygon,
250
+ imageSprite!,
251
+ hoverMaskAlpha,
252
+ strokeWidth,
253
+ hoverStrokeAlpha,
254
+ );
255
+ }
256
+ });
257
+
258
+ graphics.on("pointerout", () => {
259
+ if (!selectedPolygonIds.includes(polygon.id)) {
260
+ graphics.clear();
261
+ drawPolygonPath(
262
+ graphics,
263
+ polygon,
264
+ imageSprite!,
265
+ originalMaskAlpha,
266
+ strokeWidth,
267
+ polygonStrokeOpacity,
268
+ );
269
+ }
270
+ });
271
+
272
+ graphics.on("pointerdown", (event) => {
273
+ // Check if Ctrl/Cmd key is held for multi-selection
274
+ const isMultiSelect = event.ctrlKey || event.metaKey;
275
+
276
+ if (selectedPolygonIds.includes(polygon.id)) {
277
+ // Deselect this polygon
278
+ const newSelectedIds = selectedPolygonIds.filter(
279
+ (id) => id !== polygon.id,
280
+ );
281
+ updateSelection(newSelectedIds);
282
+ selectedPolygonIds = newSelectedIds;
283
+
284
+ // Dispatch deselection event to Gradio
285
+ gradio.dispatch("select", {
286
+ index:
287
+ newSelectedIds.length > 0
288
+ ? value.polygons.findIndex(
289
+ (p) =>
290
+ p.id ===
291
+ newSelectedIds[
292
+ newSelectedIds.length - 1
293
+ ],
294
+ )
295
+ : null,
296
+ value:
297
+ newSelectedIds.length > 0
298
+ ? newSelectedIds
299
+ : null,
300
+ });
301
+ return;
302
+ }
303
+
304
+ // Select polygon
305
+ let newSelectedIds: string[];
306
+ if (isMultiSelect) {
307
+ // Add to existing selection
308
+ newSelectedIds = [...selectedPolygonIds, polygon.id];
309
+ } else {
310
+ // Replace selection
311
+ newSelectedIds = [polygon.id];
312
+ }
313
+
314
+ updateSelection(newSelectedIds);
315
+ selectedPolygonIds = newSelectedIds;
316
+
317
+ // Dispatch select event to Gradio
318
+ gradio.dispatch("select", {
319
+ index: value.polygons.findIndex(
320
+ (p) => p.id === polygon.id,
321
+ ),
322
+ value: newSelectedIds,
323
+ });
324
+ });
325
+
326
+ app.stage.addChild(graphics);
327
+ polygonGraphics.set(polygon.id, graphics);
328
+ });
329
+ }
330
+ }
331
+
332
+ function drawPolygonPath(
333
+ graphics: PIXI.Graphics,
334
+ polygon: any,
335
+ imageSprite: PIXI.Sprite,
336
+ maskAlpha: number = 0.2,
337
+ strokeWidth: number = 0.7,
338
+ strokeAlpha: number = 0.6,
339
+ ) {
340
+ if (polygon.coordinates && polygon.coordinates.length > 0) {
341
+ // Transform coordinates from natural image space to display space
342
+ const displayCoords = polygon.coordinates.map((coord: number[]) => {
343
+ return [
344
+ (coord[0] / (imageRect.naturalWidth - 1)) *
345
+ imageRect.width +
346
+ imageRect.left,
347
+ (coord[1] / (imageRect.naturalHeight - 1)) *
348
+ imageRect.height +
349
+ imageRect.top,
350
+ ];
351
+ });
352
+
353
+ let color = 0xff0000;
354
+ try {
355
+ if (polygon.color) {
356
+ const colorStr = polygon.color.replace("#", "");
357
+ color = parseInt(colorStr, 16);
358
+ }
359
+ } catch (e) {
360
+ console.error("Error parsing color in drawPolygonPath:", e);
361
+ }
362
+
363
+ // Use Pixi.js 8 drawing API
364
+ graphics.poly(displayCoords.flat());
365
+ graphics.fill({ color: color, alpha: maskAlpha });
366
+ graphics.stroke({ width: strokeWidth, color: color, alpha: strokeAlpha });
367
+ }
368
+ }
369
+
370
+ onMount(async () => {
371
+ await tick();
372
+ await initPixiApp();
373
+ if (value) {
374
+ await renderAnnotations();
375
+ }
376
+ });
377
+
378
+ onDestroy(() => {
379
+ if (app) {
380
+ app.destroy(true, { children: true, texture: true });
381
+ }
382
+ });
383
+
384
+ // Handle canvas resize
385
+ async function handleResize() {
386
+ if (!canvasContainer || !app) return;
387
+
388
+ const newWidth = canvasContainer.clientWidth;
389
+ const newHeight = canvasContainer.clientHeight;
390
+
391
+ if (newWidth !== app.screen.width || newHeight !== app.screen.height) {
392
+ app.renderer.resize(newWidth, newHeight);
393
+ // Re-render annotations with updated canvas dimensions
394
+ await renderAnnotations();
395
+ }
396
+ }
397
+
398
+ $: if (canvasContainer) {
399
+ handleResize();
400
+ }
401
+
402
+ $: (value, gradio.dispatch("change"));
403
+ </script>
404
+
405
+ <Block
406
+ {visible}
407
+ variant={"solid"}
408
+ padding={false}
409
+ {elem_id}
410
+ {elem_classes}
411
+ allow_overflow={false}
412
+ {container}
413
+ {scale}
414
+ {min_width}
415
+ {height}
416
+ {width}
417
+ >
418
+ <StatusTracker
419
+ autoscroll={gradio.autoscroll}
420
+ i18n={gradio.i18n}
421
+ {...loading_status}
422
+ on:clear_status={() => gradio.dispatch("clear_status", loading_status)}
423
+ />
424
+
425
+ <BlockLabel
426
+ {show_label}
427
+ Icon={ImageIcon}
428
+ label={label || "Image Annotations"}
429
+ />
430
+
431
+ <div class="container">
432
+ <div class="canvas-container" bind:this={canvasContainer} />
433
+ </div>
434
+ </Block>
435
+
436
+ <style>
437
+ .container {
438
+ display: flex;
439
+ position: relative;
440
+ flex-direction: column;
441
+ justify-content: center;
442
+ align-items: center;
443
+ width: 100%;
444
+ height: 100%;
445
+ }
446
+
447
+ .canvas-container {
448
+ position: relative;
449
+ width: 100%;
450
+ height: 100%;
451
+ min-height: 400px;
452
+ overflow: hidden;
453
+ display: flex;
454
+ justify-content: center;
455
+ align-items: center;
456
+ background-color: #f0f0f0;
457
+ }
458
+
459
+ :global(.canvas-container canvas) {
460
+ display: block;
461
+ width: 100%;
462
+ height: 100%;
463
+ object-fit: contain;
464
+ }
465
+ </style>
frontend/gradio.config.js ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ export default {
2
+ plugins: [],
3
+ svelte: {
4
+ preprocess: [],
5
+ },
6
+ build: {
7
+ target: "modules",
8
+ },
9
+ };
frontend/package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
frontend/package.json ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "gradio_annoviewer",
3
+ "version": "0.9.0",
4
+ "description": "Gradio UI packages",
5
+ "type": "module",
6
+ "author": "",
7
+ "license": "ISC",
8
+ "private": false,
9
+ "dependencies": {
10
+ "@gradio/atoms": "0.18.0",
11
+ "@gradio/client": "1.19.0",
12
+ "@gradio/icons": "0.14.0",
13
+ "@gradio/statustracker": "0.11.1",
14
+ "@gradio/upload": "0.17.0",
15
+ "@gradio/utils": "0.10.2",
16
+ "cropperjs": "^1.5.12",
17
+ "lazy-brush": "^1.0.1",
18
+ "pixi.js": "^8.0.0",
19
+ "resize-observer-polyfill": "^1.5.1"
20
+ },
21
+ "devDependencies": {
22
+ "@gradio/preview": "0.14.0"
23
+ },
24
+ "main_changeset": true,
25
+ "main": "./Index.svelte",
26
+ "exports": {
27
+ "./package.json": "./package.json",
28
+ ".": {
29
+ "gradio": "./Index.svelte",
30
+ "svelte": "./dist/Index.svelte",
31
+ "types": "./dist/Index.svelte.d.ts"
32
+ },
33
+ "./example": {
34
+ "gradio": "./Example.svelte",
35
+ "svelte": "./dist/Example.svelte",
36
+ "types": "./dist/Example.svelte.d.ts"
37
+ },
38
+ "./base": {
39
+ "gradio": "./shared/ImagePreview.svelte",
40
+ "svelte": "./dist/shared/ImagePreview.svelte",
41
+ "types": "./dist/shared/ImagePreview.svelte.d.ts"
42
+ }
43
+ },
44
+ "peerDependencies": {
45
+ "svelte": "^4.0.0"
46
+ },
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git+https://github.com/gradio-app/gradio.git",
50
+ "directory": "js/simpleimage"
51
+ }
52
+ }
frontend/shared/ClearImage.svelte ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { createEventDispatcher } from "svelte";
3
+ import { IconButton, IconButtonWrapper } from "@gradio/atoms";
4
+ import { Clear } from "@gradio/icons";
5
+
6
+ const dispatch = createEventDispatcher();
7
+ </script>
8
+
9
+ <IconButtonWrapper>
10
+ <IconButton
11
+ Icon={Clear}
12
+ label="Remove Image"
13
+ on:click={(event) => {
14
+ dispatch("remove_image");
15
+ event.stopPropagation();
16
+ }}
17
+ />
18
+ </IconButtonWrapper>
frontend/shared/ImagePreview.svelte ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import {
3
+ BlockLabel,
4
+ Empty,
5
+ IconButton,
6
+ IconButtonWrapper,
7
+ DownloadLink
8
+ } from "@gradio/atoms";
9
+ import { Download } from "@gradio/icons";
10
+
11
+ import { Image as ImageIcon } from "@gradio/icons";
12
+ import { type FileData } from "@gradio/client";
13
+ import type { I18nFormatter } from "@gradio/utils";
14
+
15
+ export let value: null | FileData;
16
+ export let label: string | undefined = undefined;
17
+ export let show_label: boolean;
18
+ export let show_download_button = true;
19
+ export let selectable = false;
20
+ export let i18n: I18nFormatter;
21
+ </script>
22
+
23
+ <BlockLabel
24
+ {show_label}
25
+ Icon={ImageIcon}
26
+ label={label || i18n("image.image")}
27
+ />
28
+ {#if value === null || !value.url}
29
+ <Empty unpadded_box={true} size="large"><ImageIcon /></Empty>
30
+ {:else}
31
+ <IconButtonWrapper>
32
+ {#if show_download_button}
33
+ <DownloadLink href={value.url} download={value.orig_name || "image"}>
34
+ <IconButton Icon={Download} label={i18n("common.download")} />
35
+ </DownloadLink>
36
+ {/if}
37
+ </IconButtonWrapper>
38
+ <button>
39
+ <div class:selectable class="image-container">
40
+ <img src={value.url} alt="" loading="lazy" />
41
+ </div>
42
+ </button>
43
+ {/if}
44
+
45
+ <style>
46
+ .image-container {
47
+ height: 100%;
48
+ }
49
+ .image-container :global(img),
50
+ button {
51
+ width: var(--size-full);
52
+ height: var(--size-full);
53
+ object-fit: scale-down;
54
+ display: block;
55
+ border-radius: var(--radius-lg);
56
+ }
57
+
58
+ .selectable {
59
+ cursor: crosshair;
60
+ }
61
+ </style>
frontend/shared/ImageUploader.svelte ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { createEventDispatcher } from "svelte";
3
+ import { BlockLabel } from "@gradio/atoms";
4
+ import { Image as ImageIcon } from "@gradio/icons";
5
+
6
+ import { Upload } from "@gradio/upload";
7
+ import type { FileData, Client } from "@gradio/client";
8
+ import ClearImage from "./ClearImage.svelte";
9
+
10
+ export let value: null | FileData;
11
+ export let label: string | undefined = undefined;
12
+ export let show_label: boolean;
13
+ export let root: string;
14
+ export let upload: Client["upload"];
15
+ export let stream_handler: Client["stream"];
16
+
17
+ let upload_component: Upload;
18
+ let uploading = false;
19
+
20
+ function handle_upload({ detail }: CustomEvent<FileData>): void {
21
+ value = detail;
22
+ dispatch("upload");
23
+ }
24
+ $: if (uploading) value = null;
25
+
26
+ const dispatch = createEventDispatcher<{
27
+ change?: never;
28
+ clear?: never;
29
+ drag: boolean;
30
+ upload?: never;
31
+ }>();
32
+
33
+ let dragging = false;
34
+ $: dispatch("drag", dragging);
35
+ </script>
36
+
37
+ <BlockLabel {show_label} Icon={ImageIcon} label={label || "Image"} />
38
+
39
+ <div data-testid="image" class="image-container">
40
+ {#if value?.url}
41
+ <ClearImage
42
+ on:remove_image={() => {
43
+ value = null;
44
+ dispatch("clear");
45
+ }}
46
+ />
47
+ {/if}
48
+ <div class="upload-container">
49
+ <Upload
50
+ {upload}
51
+ {stream_handler}
52
+ hidden={value !== null}
53
+ bind:this={upload_component}
54
+ bind:uploading
55
+ bind:dragging
56
+ filetype="image/*"
57
+ on:load={handle_upload}
58
+ on:error
59
+ {root}
60
+ >
61
+ {#if value === null}
62
+ <slot />
63
+ {/if}
64
+ </Upload>
65
+ {#if value !== null}
66
+ <div class="image-frame">
67
+ <img src={value.url} alt={value.alt_text} />
68
+ </div>
69
+ {/if}
70
+ </div>
71
+ </div>
72
+
73
+ <style>
74
+ .image-frame :global(img) {
75
+ width: var(--size-full);
76
+ height: var(--size-full);
77
+ object-fit: scale-down;
78
+ }
79
+
80
+ .image-frame {
81
+ width: 100%;
82
+ height: 100%;
83
+ }
84
+
85
+ .upload-container {
86
+ height: 100%;
87
+ flex-shrink: 1;
88
+ max-height: 100%;
89
+ }
90
+
91
+ .image-container {
92
+ display: flex;
93
+ height: 100%;
94
+ flex-direction: column;
95
+ justify-content: center;
96
+ align-items: center;
97
+ max-height: 100%;
98
+ }
99
+ </style>
frontend/tsconfig.json ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "compilerOptions": {
3
+ "allowJs": true,
4
+ "checkJs": true,
5
+ "esModuleInterop": true,
6
+ "forceConsistentCasingInFileNames": true,
7
+ "resolveJsonModule": true,
8
+ "skipLibCheck": true,
9
+ "sourceMap": true,
10
+ "strict": true,
11
+ "verbatimModuleSyntax": true
12
+ },
13
+ "exclude": ["node_modules", "dist", "./gradio.config.js"]
14
+ }
pyproject.toml ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [build-system]
2
+ requires = [
3
+ "hatchling",
4
+ "hatch-requirements-txt",
5
+ "hatch-fancy-pypi-readme>=22.5.0",
6
+ ]
7
+ build-backend = "hatchling.build"
8
+
9
+ [project]
10
+ name = "gradio_polygonannotator"
11
+ version = "0.1.0"
12
+ description = "Interactive polygon annotation component for Gradio with multi-selection, hover effects, and customizable appearance"
13
+ readme = "README.md"
14
+ license = "Apache-2.0"
15
+ requires-python = ">=3.8"
16
+ authors = [{ name = "Borg93", email = "[email protected]" }]
17
+ keywords = [
18
+ "gradio-custom-component",
19
+ "polygon-annotation",
20
+ "image-annotation",
21
+ "interactive-visualization",
22
+ "document-analysis"
23
+ ]
24
+ # Add dependencies here
25
+ dependencies = [
26
+ "gradio>=4.0,<6.0",
27
+ ]
28
+ classifiers = [
29
+ 'Development Status :: 3 - Alpha',
30
+ 'Operating System :: OS Independent',
31
+ 'Programming Language :: Python :: 3',
32
+ 'Programming Language :: Python :: 3 :: Only',
33
+ 'Programming Language :: Python :: 3.8',
34
+ 'Programming Language :: Python :: 3.9',
35
+ 'Programming Language :: Python :: 3.10',
36
+ 'Programming Language :: Python :: 3.11',
37
+ 'Topic :: Scientific/Engineering',
38
+ 'Topic :: Scientific/Engineering :: Artificial Intelligence',
39
+ 'Topic :: Scientific/Engineering :: Visualization',
40
+ ]
41
+
42
+ # The repository and space URLs are optional, but recommended.
43
+ # Adding a repository URL will create a badge in the auto-generated README that links to the repository.
44
+ # Adding a space URL will create a badge in the auto-generated README that links to the space.
45
+ # This will make it easy for people to find your deployed demo or source code when they
46
+ # encounter your project in the wild.
47
+
48
+ [project.urls]
49
+ repository = "https://github.com/yourusername/gradio-polygonannotator"
50
+ # space = "https://huggingface.co/spaces/yourusername/polygonannotator-demo"
51
+
52
+ [project.optional-dependencies]
53
+ dev = ["build", "twine"]
54
+
55
+ [tool.hatch.build]
56
+ artifacts = ["/backend/gradio_polygonannotator/templates", "*.pyi"]
57
+
58
+ [tool.hatch.build.targets.wheel]
59
+ packages = ["/backend/gradio_polygonannotator"]
src/.gitignore ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .eggs/
2
+ dist/
3
+ *.pyc
4
+ __pycache__/
5
+ *.py[cod]
6
+ *$py.class
7
+ __tmp/*
8
+ *.pyi
9
+ .mypycache
10
+ .ruff_cache
11
+ node_modules
12
+ backend/**/templates/
13
+ .venv
src/.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.12
src/README.md ADDED
@@ -0,0 +1,384 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ # `gradio_polygonannotator`
3
+ <img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.1.0%20-%20orange"> <a href="https://github.com/yourusername/gradio-polygonannotator/issues" target="_blank"><img alt="Static Badge" src="https://img.shields.io/badge/Issues-white?logo=github&logoColor=black"></a>
4
+
5
+ Interactive polygon annotation component for Gradio with multi-selection, hover effects, and customizable appearance
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install gradio_polygonannotator
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```python
16
+ import gradio as gr
17
+ from gradio_polygonannotator import PolygonAnnotator
18
+
19
+ # Example with document regions
20
+ example_data = {
21
+ "image": "https://images.unsplash.com/photo-1544816155-12df9643f363?w=800&h=1200",
22
+ "polygons": [
23
+ {
24
+ "id": "title",
25
+ "coordinates": [[180, 150], [580, 150], [580, 200], [180, 200]],
26
+ "color": "#FF6B6B",
27
+ "mask_opacity": 0.15,
28
+ "stroke_width": 1.0,
29
+ "stroke_opacity": 0.8,
30
+ },
31
+ {
32
+ "id": "paragraph_1",
33
+ "coordinates": [[100, 400], [750, 400], [750, 600], [100, 600]],
34
+ "color": "#4ECDC4",
35
+ "mask_opacity": 0.15,
36
+ "stroke_width": 0.7,
37
+ "stroke_opacity": 0.6,
38
+ },
39
+ {
40
+ "id": "paragraph_2",
41
+ "coordinates": [[100, 650], [750, 650], [750, 950], [100, 950]],
42
+ "color": "#4ECDC4",
43
+ "mask_opacity": 0.15,
44
+ "stroke_width": 0.7,
45
+ "stroke_opacity": 0.6,
46
+ },
47
+ {
48
+ "id": "signature",
49
+ "coordinates": [[400, 1020], [650, 1020], [650, 1080], [400, 1080]],
50
+ "color": "#FFE66D",
51
+ "mask_opacity": 0.2,
52
+ "stroke_width": 1.5,
53
+ "stroke_opacity": 0.8,
54
+ }
55
+ ]
56
+ }
57
+
58
+ def handle_selection(data, evt: gr.SelectData):
59
+ """Handle polygon selection and display info"""
60
+ if evt.value and data:
61
+ selected_ids = evt.value if isinstance(evt.value, list) else [evt.value]
62
+ info = f"Selected {len(selected_ids)} polygon(s):\n"
63
+ for poly_id in selected_ids:
64
+ polygon = next((p for p in data["polygons"] if p["id"] == poly_id), None)
65
+ if polygon:
66
+ info += f"• {poly_id}\n"
67
+ return info
68
+ return "Click on polygons to select them. Use Ctrl/Cmd+Click for multi-selection."
69
+
70
+ with gr.Blocks() as demo:
71
+ gr.Markdown("""
72
+ # PolygonAnnotator - Interactive Polygon Selection
73
+
74
+ Click on polygons to select them. Use **Ctrl/Cmd+Click** for multiple selections.
75
+ Click selected polygons to deselect.
76
+ """)
77
+
78
+ with gr.Row():
79
+ with gr.Column(scale=3):
80
+ annotator = PolygonAnnotator(
81
+ value=example_data,
82
+ label="Document with Region Annotations",
83
+ height=600,
84
+ )
85
+
86
+ with gr.Column(scale=1):
87
+ selected_info = gr.Textbox(
88
+ label="Selected Regions",
89
+ lines=6,
90
+ value="Click on polygons to select them. Use Ctrl/Cmd+Click for multi-selection."
91
+ )
92
+
93
+ # Handle selection events
94
+ annotator.select(
95
+ handle_selection,
96
+ inputs=[annotator],
97
+ outputs=[selected_info]
98
+ )
99
+
100
+ if __name__ == "__main__":
101
+ demo.launch()
102
+
103
+ ```
104
+
105
+ ## `PolygonAnnotator`
106
+
107
+ ### Initialization
108
+
109
+ <table>
110
+ <thead>
111
+ <tr>
112
+ <th align="left">name</th>
113
+ <th align="left" style="width: 25%;">type</th>
114
+ <th align="left">default</th>
115
+ <th align="left">description</th>
116
+ </tr>
117
+ </thead>
118
+ <tbody>
119
+ <tr>
120
+ <td align="left"><code>value</code></td>
121
+ <td align="left" style="width: 25%;">
122
+
123
+ ```python
124
+ dict | None
125
+ ```
126
+
127
+ </td>
128
+ <td align="left"><code>None</code></td>
129
+ <td align="left">Dictionary containing 'image' (FileData), 'polygons' (list with id, coordinates, color, opacities),</td>
130
+ </tr>
131
+
132
+ <tr>
133
+ <td align="left"><code>label</code></td>
134
+ <td align="left" style="width: 25%;">
135
+
136
+ ```python
137
+ str | I18nData | None
138
+ ```
139
+
140
+ </td>
141
+ <td align="left"><code>None</code></td>
142
+ <td align="left">Component label shown above the annotator.</td>
143
+ </tr>
144
+
145
+ <tr>
146
+ <td align="left"><code>every</code></td>
147
+ <td align="left" style="width: 25%;">
148
+
149
+ ```python
150
+ Timer | float | None
151
+ ```
152
+
153
+ </td>
154
+ <td align="left"><code>None</code></td>
155
+ <td align="left">Continuously calls `value` to recalculate it if `value` is a function.</td>
156
+ </tr>
157
+
158
+ <tr>
159
+ <td align="left"><code>inputs</code></td>
160
+ <td align="left" style="width: 25%;">
161
+
162
+ ```python
163
+ Component | Sequence[Component] | set[Component] | None
164
+ ```
165
+
166
+ </td>
167
+ <td align="left"><code>None</code></td>
168
+ <td align="left">Components used as inputs to calculate `value` if it's a function.</td>
169
+ </tr>
170
+
171
+ <tr>
172
+ <td align="left"><code>show_label</code></td>
173
+ <td align="left" style="width: 25%;">
174
+
175
+ ```python
176
+ bool | None
177
+ ```
178
+
179
+ </td>
180
+ <td align="left"><code>None</code></td>
181
+ <td align="left">Whether to display the label.</td>
182
+ </tr>
183
+
184
+ <tr>
185
+ <td align="left"><code>show_download_button</code></td>
186
+ <td align="left" style="width: 25%;">
187
+
188
+ ```python
189
+ bool
190
+ ```
191
+
192
+ </td>
193
+ <td align="left"><code>True</code></td>
194
+ <td align="left">Whether to show image download button.</td>
195
+ </tr>
196
+
197
+ <tr>
198
+ <td align="left"><code>height</code></td>
199
+ <td align="left" style="width: 25%;">
200
+
201
+ ```python
202
+ int | str | None
203
+ ```
204
+
205
+ </td>
206
+ <td align="left"><code>None</code></td>
207
+ <td align="left">Component height in pixels or CSS units.</td>
208
+ </tr>
209
+
210
+ <tr>
211
+ <td align="left"><code>width</code></td>
212
+ <td align="left" style="width: 25%;">
213
+
214
+ ```python
215
+ int | str | None
216
+ ```
217
+
218
+ </td>
219
+ <td align="left"><code>None</code></td>
220
+ <td align="left">Component width in pixels or CSS units.</td>
221
+ </tr>
222
+
223
+ <tr>
224
+ <td align="left"><code>container</code></td>
225
+ <td align="left" style="width: 25%;">
226
+
227
+ ```python
228
+ bool
229
+ ```
230
+
231
+ </td>
232
+ <td align="left"><code>True</code></td>
233
+ <td align="left">Whether to wrap component in a container with padding.</td>
234
+ </tr>
235
+
236
+ <tr>
237
+ <td align="left"><code>scale</code></td>
238
+ <td align="left" style="width: 25%;">
239
+
240
+ ```python
241
+ int | None
242
+ ```
243
+
244
+ </td>
245
+ <td align="left"><code>None</code></td>
246
+ <td align="left">Relative size compared to adjacent components.</td>
247
+ </tr>
248
+
249
+ <tr>
250
+ <td align="left"><code>min_width</code></td>
251
+ <td align="left" style="width: 25%;">
252
+
253
+ ```python
254
+ int
255
+ ```
256
+
257
+ </td>
258
+ <td align="left"><code>160</code></td>
259
+ <td align="left">Minimum pixel width before wrapping.</td>
260
+ </tr>
261
+
262
+ <tr>
263
+ <td align="left"><code>interactive</code></td>
264
+ <td align="left" style="width: 25%;">
265
+
266
+ ```python
267
+ bool | None
268
+ ```
269
+
270
+ </td>
271
+ <td align="left"><code>None</code></td>
272
+ <td align="left">Whether users can interact with polygons (selection/deselection).</td>
273
+ </tr>
274
+
275
+ <tr>
276
+ <td align="left"><code>visible</code></td>
277
+ <td align="left" style="width: 25%;">
278
+
279
+ ```python
280
+ bool | Literal["hidden"]
281
+ ```
282
+
283
+ </td>
284
+ <td align="left"><code>True</code></td>
285
+ <td align="left">Whether component is visible ("hidden" keeps it in DOM but invisible).</td>
286
+ </tr>
287
+
288
+ <tr>
289
+ <td align="left"><code>elem_id</code></td>
290
+ <td align="left" style="width: 25%;">
291
+
292
+ ```python
293
+ str | None
294
+ ```
295
+
296
+ </td>
297
+ <td align="left"><code>None</code></td>
298
+ <td align="left">HTML DOM id for CSS targeting.</td>
299
+ </tr>
300
+
301
+ <tr>
302
+ <td align="left"><code>elem_classes</code></td>
303
+ <td align="left" style="width: 25%;">
304
+
305
+ ```python
306
+ list[str] | str | None
307
+ ```
308
+
309
+ </td>
310
+ <td align="left"><code>None</code></td>
311
+ <td align="left">HTML DOM classes for CSS targeting.</td>
312
+ </tr>
313
+
314
+ <tr>
315
+ <td align="left"><code>render</code></td>
316
+ <td align="left" style="width: 25%;">
317
+
318
+ ```python
319
+ bool
320
+ ```
321
+
322
+ </td>
323
+ <td align="left"><code>True</code></td>
324
+ <td align="left">Whether to render the component immediately.</td>
325
+ </tr>
326
+
327
+ <tr>
328
+ <td align="left"><code>key</code></td>
329
+ <td align="left" style="width: 25%;">
330
+
331
+ ```python
332
+ int | str | tuple[int | str, ...] | None
333
+ ```
334
+
335
+ </td>
336
+ <td align="left"><code>None</code></td>
337
+ <td align="left">Key for maintaining component identity across re-renders.</td>
338
+ </tr>
339
+
340
+ <tr>
341
+ <td align="left"><code>preserved_by_key</code></td>
342
+ <td align="left" style="width: 25%;">
343
+
344
+ ```python
345
+ list[str] | str | None
346
+ ```
347
+
348
+ </td>
349
+ <td align="left"><code>"value"</code></td>
350
+ <td align="left">Parameters preserved across re-renders with same key.</td>
351
+ </tr>
352
+ </tbody></table>
353
+
354
+
355
+ ### Events
356
+
357
+ | name | description |
358
+ |:-----|:------------|
359
+ | `clear` | This listener is triggered when the user clears the PolygonAnnotator using the clear button for the component. |
360
+ | `change` | Triggered when the value of the PolygonAnnotator changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input. |
361
+ | `upload` | This listener is triggered when the user uploads a file into the PolygonAnnotator. |
362
+ | `select` | Event listener for when the user selects or deselects the PolygonAnnotator. Uses event data gradio.SelectData to carry `value` referring to the label of the PolygonAnnotator, and `selected` to refer to state of the PolygonAnnotator. See EventData documentation on how to use this event data |
363
+
364
+
365
+
366
+ ### User function
367
+
368
+ The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
369
+
370
+ - When used as an Input, the component only impacts the input signature of the user function.
371
+ - When used as an output, the component only impacts the return signature of the user function.
372
+
373
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
374
+
375
+ - **As output:** Is passed, dictionary with image path, polygon data including coordinates, colors, opacities,.
376
+ - **As input:** Should return, dictionary containing 'image' (file path or URL), 'polygons' (list of polygon dictionaries.
377
+
378
+ ```python
379
+ def predict(
380
+ value: dict | None
381
+ ) -> dict | None:
382
+ return value
383
+ ```
384
+
src/app.py ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from gradio_polygonannotator import PolygonAnnotator
3
+ from typing import Literal
4
+
5
+ example_data = {
6
+ "image": "https://images.unsplash.com/photo-1544816155-12df9643f363?w=800&h=1200",
7
+ "polygons": [
8
+ {
9
+ "id": "date_line",
10
+ "coordinates": [[180, 150], [580, 150], [580, 200], [180, 200]],
11
+ "color": "#FF0000",
12
+ "mask_opacity": 0.2,
13
+ "stroke_width": 0.7,
14
+ "stroke_opacity": 0.6,
15
+ "selected_mask_opacity": 0.5,
16
+ "selected_stroke_opacity": 1.0
17
+ },
18
+ {
19
+ "id": "salutation",
20
+ "coordinates": [[180, 280], [680, 280], [680, 340], [180, 340]],
21
+ "color": "#00FF00",
22
+ "mask_opacity": 0.2,
23
+ "stroke_width": 1.0,
24
+ "stroke_opacity": 0.6,
25
+ "selected_mask_opacity": 0.4,
26
+ "selected_stroke_opacity": 0.9
27
+ },
28
+ {
29
+ "id": "main_text_block",
30
+ "coordinates": [[100, 400], [750, 400], [750, 950], [100, 950]],
31
+ "color": "#0000FF",
32
+ "mask_opacity": 0.15,
33
+ "stroke_width": 0.5,
34
+ "stroke_opacity": 0.5,
35
+ "selected_mask_opacity": 0.4,
36
+ "selected_stroke_opacity": 0.8
37
+ },
38
+ {
39
+ "id": "closing_signature",
40
+ "coordinates": [[400, 1020], [650, 1020], [650, 1080], [400, 1080]],
41
+ "color": "#FFFF00",
42
+ "mask_opacity": 0.25,
43
+ "stroke_width": 1.5,
44
+ "stroke_opacity": 0.7,
45
+ "selected_mask_opacity": 0.6,
46
+ "selected_stroke_opacity": 1.0
47
+ }
48
+ ]
49
+ }
50
+
51
+ # Create dataframe data from polygon information
52
+ polygon_table = [
53
+ ["date_line", "Date Line", "#FF0000", 0.2, 0.7, 0.6],
54
+ ["salutation", "Salutation", "#00FF00", 0.2, 1.0, 0.6],
55
+ ["main_text_block", "Main Text Block", "#0000FF", 0.15, 0.5, 0.5],
56
+ ["closing_signature", "Closing/Signature", "#FFFF00", 0.25, 1.5, 0.7]
57
+ ]
58
+
59
+ def process_viewer_selection(data, evt: gr.SelectData):
60
+ """Handle polygon selection from viewer and update dataframe selection"""
61
+ if evt.value and data:
62
+ selected_ids = evt.value if isinstance(evt.value, list) else [evt.value]
63
+
64
+ # Create highlighted dataframe data
65
+ highlighted_table = []
66
+ for row in polygon_table:
67
+ if row[0] in selected_ids: # If this is a selected row
68
+ # Add highlighting markers to the selected row
69
+ highlighted_row = [f"→ {row[0]} ←", f"→ {row[1]} ←", f"→ {row[2]} ←", f"→ {row[3]} ←", f"→ {row[4]} ←", f"→ {row[5]} ←"]
70
+ highlighted_table.append(highlighted_row)
71
+ else:
72
+ highlighted_table.append(row)
73
+
74
+ # Create info text for all selected polygons
75
+ info_lines = [f"Selected {len(selected_ids)} polygon(s):"]
76
+ for selected_id in selected_ids:
77
+ selected_polygon = next((p for p in data["polygons"] if p["id"] == selected_id), None)
78
+ if selected_polygon:
79
+ info_lines.append(f"• {selected_id}: {selected_polygon['color']}, mask: {selected_polygon.get('mask_opacity', 0.2)}, stroke: {selected_polygon.get('stroke_width', 0.7)}px")
80
+
81
+ info_text = "\n".join(info_lines)
82
+ return info_text, highlighted_table
83
+
84
+ return "No polygons selected", polygon_table
85
+
86
+ def process_dataframe_selection(selected_data, evt: gr.SelectData):
87
+ """Handle row selection from dataframe and update viewer selection"""
88
+ if evt.index is not None and evt.index[0] < len(polygon_table):
89
+ selected_row = polygon_table[evt.index[0]]
90
+ polygon_id = selected_row[0]
91
+
92
+ # Update the viewer data with the selected polygon
93
+ updated_data = example_data.copy()
94
+ updated_data["selected_polygons"] = [polygon_id]
95
+
96
+ info_text = f"Selected polygon: {polygon_id}\nName: {selected_row[1]}\nColor: {selected_row[2]}\nMask Opacity: {selected_row[3]}\nStroke Width: {selected_row[4]}\nStroke Opacity: {selected_row[5]}"
97
+ return updated_data, info_text
98
+
99
+ # Deselection
100
+ updated_data = example_data.copy()
101
+ updated_data["selected_polygons"] = []
102
+ return updated_data, "No polygons selected"
103
+
104
+ def clear_selection():
105
+ """Clear polygon selection"""
106
+ updated_data = example_data.copy()
107
+ updated_data["selected_polygons"] = []
108
+ return updated_data, "No polygons selected", polygon_table
109
+
110
+ def select_polygon_by_id(polygon_id):
111
+ """Select polygon by ID from textbox input"""
112
+ if not polygon_id or polygon_id.strip() == "":
113
+ # Empty input - clear selection
114
+ updated_data = example_data.copy()
115
+ updated_data["selected_polygons"] = []
116
+ return updated_data, "No polygons selected", polygon_table
117
+
118
+ # Handle multiple IDs (comma-separated)
119
+ polygon_ids = [id.strip() for id in polygon_id.split(",") if id.strip()]
120
+ valid_ids = [p["id"] for p in example_data["polygons"]]
121
+
122
+ # Filter to only valid IDs
123
+ valid_selected_ids = [id for id in polygon_ids if id in valid_ids]
124
+ invalid_ids = [id for id in polygon_ids if id not in valid_ids]
125
+
126
+ if not valid_selected_ids:
127
+ # No valid IDs
128
+ updated_data = example_data.copy()
129
+ updated_data["selected_polygons"] = []
130
+ error_msg = f"Invalid polygon ID(s): {', '.join(invalid_ids)}. Valid IDs: {', '.join(valid_ids)}"
131
+ return updated_data, error_msg, polygon_table
132
+
133
+ # Valid IDs - select polygons
134
+ updated_data = example_data.copy()
135
+ updated_data["selected_polygons"] = valid_selected_ids
136
+
137
+ # Create highlighted dataframe data
138
+ highlighted_table = []
139
+ for row in polygon_table:
140
+ if row[0] in valid_selected_ids: # If this is a selected row
141
+ # Add highlighting markers to the selected row
142
+ highlighted_row = [f"→ {row[0]} ←", f"→ {row[1]} ←", f"→ {row[2]} ←", f"→ {row[3]} ←", f"→ {row[4]} ←", f"→ {row[5]} ←"]
143
+ highlighted_table.append(highlighted_row)
144
+ else:
145
+ highlighted_table.append(row)
146
+
147
+ # Create info text
148
+ info_lines = [f"Selected {len(valid_selected_ids)} polygon(s):"]
149
+ for selected_id in valid_selected_ids:
150
+ selected_polygon = next((p for p in example_data["polygons"] if p["id"] == selected_id), None)
151
+ if selected_polygon:
152
+ info_lines.append(f"• {selected_id}: {selected_polygon['color']}, mask: {selected_polygon.get('mask_opacity', 0.2)}, stroke: {selected_polygon.get('stroke_width', 0.7)}px")
153
+
154
+ if invalid_ids:
155
+ info_lines.append(f"\nInvalid IDs: {', '.join(invalid_ids)}")
156
+
157
+ info_text = "\n".join(info_lines)
158
+ return updated_data, info_text, highlighted_table
159
+
160
+ with gr.Blocks() as demo:
161
+ gr.Markdown("""
162
+ # PolygonAnnotator - Advanced Interactive Demo
163
+
164
+ This demo showcases all the features of the PolygonAnnotator component:
165
+ - **Click** on polygons to select/deselect them
166
+ - **Ctrl/Cmd+Click** for multiple selection
167
+ - **Click dataframe rows** to select polygons
168
+ - **Enter polygon IDs** manually in the textbox
169
+ - **Clear button** to deselect all
170
+ """)
171
+
172
+ with gr.Row():
173
+ with gr.Column(scale=2):
174
+ poly_annotator = PolygonAnnotator(
175
+ value=example_data,
176
+ label="Document with Interactive Polygon Annotations",
177
+ height=600,
178
+ )
179
+
180
+ with gr.Column(scale=1):
181
+ selected_info = gr.Textbox(
182
+ label="Selected Polygon Information",
183
+ lines=5,
184
+ value="Click on a polygon to see its information"
185
+ )
186
+
187
+ polygon_dataframe = gr.Dataframe(
188
+ value=polygon_table,
189
+ headers=["ID", "Name", "Color", "Mask", "Stroke W", "Stroke O"],
190
+ label="Polygon Data (Click rows to select)",
191
+ datatype=[Literal["str", "str", "str", "number", "number", "number"]],
192
+ interactive=True
193
+ )
194
+
195
+ clear_button = gr.Button("🗑️ Clear All Selections", variant="secondary")
196
+
197
+ with gr.Row():
198
+ polygon_id_input = gr.Textbox(
199
+ label="Select by Polygon ID(s)",
200
+ placeholder="Enter single ID or comma-separated IDs (e.g., 'date_line' or 'date_line, salutation')",
201
+ scale=3
202
+ )
203
+ select_button = gr.Button("Select", variant="primary", scale=1)
204
+
205
+ gr.Markdown("""
206
+ ### Features Demonstrated
207
+
208
+ #### 🎨 Visual Customization
209
+ - Different **mask opacity** for each polygon fill
210
+ - Variable **stroke width** (0.5px to 1.5px)
211
+ - Custom **stroke opacity** for borders
212
+ - Enhanced appearance when selected
213
+
214
+ #### 🖱️ Interaction Methods
215
+ 1. **Direct Click**: Click polygons in the viewer
216
+ 2. **Multi-Selection**: Ctrl/Cmd+Click for multiple
217
+ 3. **Dataframe**: Click table rows
218
+ 4. **Text Input**: Type polygon IDs
219
+ 5. **Clear All**: Reset selection
220
+
221
+ #### 📝 Polygon IDs
222
+ - `date_line` - Red header area
223
+ - `salutation` - Green greeting section
224
+ - `main_text_block` - Blue main content
225
+ - `closing_signature` - Yellow signature area
226
+
227
+ #### 💡 Tips
228
+ - Hover over polygons for visual feedback
229
+ - Selected polygons have increased opacity
230
+ - Use comma-separated IDs for batch selection
231
+ - Click selected polygons to deselect them
232
+ """)
233
+
234
+ # Handle selection events
235
+ poly_annotator.select(
236
+ process_viewer_selection,
237
+ inputs=[poly_annotator],
238
+ outputs=[selected_info, polygon_dataframe]
239
+ )
240
+
241
+ polygon_dataframe.select(
242
+ process_dataframe_selection,
243
+ inputs=[polygon_dataframe],
244
+ outputs=[poly_annotator, selected_info]
245
+ )
246
+
247
+ clear_button.click(
248
+ clear_selection,
249
+ outputs=[poly_annotator, selected_info, polygon_dataframe]
250
+ )
251
+
252
+ select_button.click(
253
+ select_polygon_by_id,
254
+ inputs=[polygon_id_input],
255
+ outputs=[poly_annotator, selected_info, polygon_dataframe]
256
+ )
257
+
258
+ # Also allow Enter key in textbox
259
+ polygon_id_input.submit(
260
+ select_polygon_by_id,
261
+ inputs=[polygon_id_input],
262
+ outputs=[poly_annotator, selected_info, polygon_dataframe]
263
+ )
264
+
265
+ if __name__ == "__main__":
266
+ demo.launch()
src/backend/gradio_polygonannotator/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+
2
+ from .polygonannotator import PolygonAnnotator
3
+
4
+ __all__ = ['PolygonAnnotator']
src/backend/gradio_polygonannotator/polygonannotator.py ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """gr.PolygonAnnotator() component for interactive polygon annotations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence
6
+ from typing import TYPE_CHECKING, Any, Literal, List, Optional
7
+
8
+ from gradio_client import handle_file
9
+
10
+ from gradio.components.base import Component
11
+ from gradio.data_classes import FileData, GradioModel
12
+ from gradio.events import Events
13
+ from gradio.i18n import I18nData
14
+
15
+ if TYPE_CHECKING:
16
+ from gradio.components import Timer
17
+
18
+
19
+ class Polygon(GradioModel):
20
+ id: str
21
+ coordinates: List[List[float]] # [[x1,y1], [x2,y2], ...]
22
+ color: str # hex color like "#FF0000"
23
+ mask_opacity: Optional[float] = 0.2 # fill opacity from 0.0 to 1.0, default 0.2
24
+ stroke_width: Optional[float] = 0.7 # stroke width in pixels, default 0.7
25
+ stroke_opacity: Optional[float] = 0.6 # stroke opacity from 0.0 to 1.0, default 0.6
26
+ selected_mask_opacity: Optional[float] = 0.5 # mask opacity when selected, default 0.5
27
+ selected_stroke_opacity: Optional[float] = 1.0 # stroke opacity when selected, default 1.0
28
+
29
+
30
+ class PolygonAnnotatorData(GradioModel):
31
+ image: FileData
32
+ polygons: List[Polygon]
33
+ selected_polygons: Optional[List[str]] = None # List of IDs of the currently selected polygons
34
+
35
+
36
+ class PolygonAnnotator(Component):
37
+ """
38
+ Interactive polygon annotation component for visualizing and selecting polygon regions on images.
39
+
40
+ The PolygonAnnotator displays an image with customizable polygon overlays that users can interact with.
41
+ Features include multi-selection with Ctrl/Cmd+click, hover effects, and customizable appearance including
42
+ stroke width, opacity settings for both fill and stroke, with separate settings for selected states.
43
+
44
+ Perfect for:
45
+ - Document layout analysis and region selection
46
+ - Image segmentation visualization
47
+ - Interactive annotation review and editing
48
+ - Object detection result visualization
49
+ """
50
+
51
+ EVENTS = [
52
+ Events.clear,
53
+ Events.change,
54
+ Events.upload,
55
+ Events.select,
56
+ ]
57
+
58
+ data_model = PolygonAnnotatorData
59
+
60
+ def __init__(
61
+ self,
62
+ value: dict | None = None,
63
+ *,
64
+ label: str | I18nData | None = None,
65
+ every: Timer | float | None = None,
66
+ inputs: Component | Sequence[Component] | set[Component] | None = None,
67
+ show_label: bool | None = None,
68
+ show_download_button: bool = True,
69
+ height: int | str | None = None,
70
+ width: int | str | None = None,
71
+ container: bool = True,
72
+ scale: int | None = None,
73
+ min_width: int = 160,
74
+ interactive: bool | None = None,
75
+ visible: bool | Literal["hidden"] = True,
76
+ elem_id: str | None = None,
77
+ elem_classes: list[str] | str | None = None,
78
+ render: bool = True,
79
+ key: int | str | tuple[int | str, ...] | None = None,
80
+ preserved_by_key: list[str] | str | None = "value",
81
+ ):
82
+ """
83
+ Parameters:
84
+ value: Dictionary containing 'image' (FileData), 'polygons' (list with id, coordinates, color, opacities),
85
+ and optionally 'selected_polygons' (list of selected IDs).
86
+ label: Component label shown above the annotator.
87
+ every: Continuously calls `value` to recalculate it if `value` is a function.
88
+ inputs: Components used as inputs to calculate `value` if it's a function.
89
+ show_label: Whether to display the label.
90
+ show_download_button: Whether to show image download button.
91
+ height: Component height in pixels or CSS units.
92
+ width: Component width in pixels or CSS units.
93
+ container: Whether to wrap component in a container with padding.
94
+ scale: Relative size compared to adjacent components.
95
+ min_width: Minimum pixel width before wrapping.
96
+ interactive: Whether users can interact with polygons (selection/deselection).
97
+ visible: Whether component is visible ("hidden" keeps it in DOM but invisible).
98
+ elem_id: HTML DOM id for CSS targeting.
99
+ elem_classes: HTML DOM classes for CSS targeting.
100
+ render: Whether to render the component immediately.
101
+ key: Key for maintaining component identity across re-renders.
102
+ preserved_by_key: Parameters preserved across re-renders with same key.
103
+ """
104
+ self.show_download_button = show_download_button
105
+ self.height = height
106
+ self.width = width
107
+ super().__init__(
108
+ label=label,
109
+ every=every,
110
+ inputs=inputs,
111
+ show_label=show_label,
112
+ container=container,
113
+ scale=scale,
114
+ min_width=min_width,
115
+ interactive=interactive,
116
+ visible=visible,
117
+ elem_id=elem_id,
118
+ elem_classes=elem_classes,
119
+ render=render,
120
+ key=key,
121
+ preserved_by_key=preserved_by_key,
122
+ value=value,
123
+ )
124
+
125
+ def preprocess(self, payload: PolygonAnnotatorData | None) -> dict | None:
126
+ """
127
+ Parameters:
128
+ payload: The component data containing image and polygon annotations.
129
+ Returns:
130
+ Dictionary with image path, polygon data including coordinates, colors, opacities,
131
+ and the list of currently selected polygon IDs.
132
+ """
133
+ if payload is None:
134
+ return None
135
+ return {
136
+ "image": payload.image.path,
137
+ "polygons": [
138
+ {
139
+ "id": p.id,
140
+ "coordinates": p.coordinates,
141
+ "color": p.color,
142
+ "mask_opacity": p.mask_opacity,
143
+ "stroke_width": p.stroke_width,
144
+ "stroke_opacity": p.stroke_opacity,
145
+ "selected_mask_opacity": p.selected_mask_opacity,
146
+ "selected_stroke_opacity": p.selected_stroke_opacity
147
+ }
148
+ for p in payload.polygons
149
+ ],
150
+ "selected_polygons": payload.selected_polygons
151
+ }
152
+
153
+ def postprocess(self, value: dict | None) -> PolygonAnnotatorData | None:
154
+ """
155
+ Parameters:
156
+ value: Dictionary containing 'image' (file path or URL), 'polygons' (list of polygon dictionaries
157
+ with id, coordinates, color, mask_opacity, stroke_width, stroke_opacity, and selection opacity settings),
158
+ and optionally 'selected_polygons' (list of selected polygon IDs).
159
+ Returns:
160
+ Processed component data ready for display.
161
+ """
162
+ if value is None:
163
+ return None
164
+
165
+ # Handle the image path
166
+ image_path = value.get("image")
167
+ if isinstance(image_path, str):
168
+ image_data = FileData(path=image_path)
169
+ else:
170
+ return None
171
+
172
+ # Handle polygons
173
+ polygons = []
174
+ for poly in value.get("polygons", []):
175
+ polygons.append(
176
+ Polygon(
177
+ id=poly["id"],
178
+ coordinates=poly["coordinates"],
179
+ color=poly.get("color", "#FF0000"),
180
+ mask_opacity=poly.get("mask_opacity", poly.get("opacity", 0.2)), # Support old 'opacity' key for backwards compatibility
181
+ stroke_width=poly.get("stroke_width", 0.7),
182
+ stroke_opacity=poly.get("stroke_opacity", 0.6),
183
+ selected_mask_opacity=poly.get("selected_mask_opacity", 0.5),
184
+ selected_stroke_opacity=poly.get("selected_stroke_opacity", 1.0)
185
+ )
186
+ )
187
+
188
+ return PolygonAnnotatorData(
189
+ image=image_data,
190
+ polygons=polygons,
191
+ selected_polygons=value.get("selected_polygons")
192
+ )
193
+
194
+ def example_payload(self) -> Any:
195
+ return {
196
+ "image": handle_file(
197
+ "https://raw.githubusercontent.com/gradio-app/gradio/main/test/test_files/bus.png"
198
+ ),
199
+ "polygons": [
200
+ {
201
+ "id": "polygon1",
202
+ "coordinates": [[50, 50], [150, 50], [150, 150], [50, 150]],
203
+ "color": "#FF0000",
204
+ "mask_opacity": 0.2,
205
+ "stroke_width": 0.7,
206
+ "stroke_opacity": 0.6
207
+ }
208
+ ]
209
+ }
210
+
211
+ def example_value(self) -> Any:
212
+ return {
213
+ "image": "https://raw.githubusercontent.com/gradio-app/gradio/main/test/test_files/bus.png",
214
+ "polygons": [
215
+ {
216
+ "id": "polygon1",
217
+ "coordinates": [[50, 50], [150, 50], [150, 150], [50, 150]],
218
+ "color": "#FF0000",
219
+ "mask_opacity": 0.2,
220
+ "stroke_width": 0.7,
221
+ "stroke_opacity": 0.6
222
+ },
223
+ {
224
+ "id": "polygon2",
225
+ "coordinates": [[200, 100], [300, 100], [250, 200]],
226
+ "color": "#00FF00",
227
+ "mask_opacity": 0.2,
228
+ "stroke_width": 1,
229
+ "stroke_opacity": 0.8
230
+ }
231
+ ]
232
+ }
src/backend/gradio_polygonannotator/templates/component/CanvasPool-CO7699qB.js ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { D as n, n as c, G as r } from "./Index-Ct_1BCRd.js";
2
+ class l {
3
+ constructor(a) {
4
+ this._canvasPool = /* @__PURE__ */ Object.create(null), this.canvasOptions = a || {}, this.enableFullScreen = !1;
5
+ }
6
+ /**
7
+ * Creates texture with params that were specified in pool constructor.
8
+ * @param pixelWidth - Width of texture in pixels.
9
+ * @param pixelHeight - Height of texture in pixels.
10
+ */
11
+ _createCanvasAndContext(a, s) {
12
+ const t = n.get().createCanvas();
13
+ t.width = a, t.height = s;
14
+ const e = t.getContext("2d");
15
+ return { canvas: t, context: e };
16
+ }
17
+ /**
18
+ * Gets a Power-of-Two render texture or fullScreen texture
19
+ * @param minWidth - The minimum width of the render texture.
20
+ * @param minHeight - The minimum height of the render texture.
21
+ * @param resolution - The resolution of the render texture.
22
+ * @returns The new render texture.
23
+ */
24
+ getOptimalCanvasAndContext(a, s, t = 1) {
25
+ a = Math.ceil(a * t - 1e-6), s = Math.ceil(s * t - 1e-6), a = c(a), s = c(s);
26
+ const e = (a << 17) + (s << 1);
27
+ this._canvasPool[e] || (this._canvasPool[e] = []);
28
+ let o = this._canvasPool[e].pop();
29
+ return o || (o = this._createCanvasAndContext(a, s)), o;
30
+ }
31
+ /**
32
+ * Place a render texture back into the pool.
33
+ * @param canvasAndContext
34
+ */
35
+ returnCanvasAndContext(a) {
36
+ const s = a.canvas, { width: t, height: e } = s, o = (t << 17) + (e << 1);
37
+ a.context.resetTransform(), a.context.clearRect(0, 0, t, e), this._canvasPool[o].push(a);
38
+ }
39
+ clear() {
40
+ this._canvasPool = {};
41
+ }
42
+ }
43
+ const v = new l();
44
+ r.register(v);
45
+ export {
46
+ v as C
47
+ };
src/backend/gradio_polygonannotator/templates/component/Index-Ct_1BCRd.js ADDED
The diff for this file is too large to render. See raw diff
 
src/backend/gradio_polygonannotator/templates/component/SharedSystems-DVDwWST4.js ADDED
@@ -0,0 +1,2766 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { q as He, t as ne, u as ie, v as ze, k as oe, M as v, x as le, E as u, e as O, y as S, z as We, F, H as b, R as L, I as ue, J as Ve, s as m, S as f, h as B, w as H, K as J, L as Ne, b as X, B as k, i as U, G as je, N as M, j as T, O as w, Q as $e, a as qe, V as de, W as ce, X as he, Y as fe, C as P, Z as Ke, _ as A, $ as Q, D as z, a0 as Ye, P as Je, c as Xe, T as Z, a1 as ee, a2 as Qe, a3 as Ze, a4 as et } from "./Index-Ct_1BCRd.js";
2
+ import { S as pe, B as me, c as tt } from "./colorToUniform-zJcCVLeu.js";
3
+ const ve = class I extends He {
4
+ /**
5
+ * @param options - The optional parameters of this filter.
6
+ */
7
+ constructor(e) {
8
+ e = { ...I.defaultOptions, ...e }, super(e), this.enabled = !0, this._state = pe.for2d(), this.blendMode = e.blendMode, this.padding = e.padding, typeof e.antialias == "boolean" ? this.antialias = e.antialias ? "on" : "off" : this.antialias = e.antialias, this.resolution = e.resolution, this.blendRequired = e.blendRequired, this.clipToViewport = e.clipToViewport, this.addResource("uTexture", 0, 1);
9
+ }
10
+ /**
11
+ * Applies the filter
12
+ * @param filterManager - The renderer to retrieve the filter from
13
+ * @param input - The input render target.
14
+ * @param output - The target to output to.
15
+ * @param clearMode - Should the output be cleared before rendering to it
16
+ */
17
+ apply(e, t, r, s) {
18
+ e.applyFilter(this, t, r, s);
19
+ }
20
+ /**
21
+ * Get the blend mode of the filter.
22
+ * @default "normal"
23
+ */
24
+ get blendMode() {
25
+ return this._state.blendMode;
26
+ }
27
+ /** Sets the blend mode of the filter. */
28
+ set blendMode(e) {
29
+ this._state.blendMode = e;
30
+ }
31
+ /**
32
+ * A short hand function to create a filter based of a vertex and fragment shader src.
33
+ * @param options
34
+ * @returns A shiny new PixiJS filter!
35
+ */
36
+ static from(e) {
37
+ const { gpu: t, gl: r, ...s } = e;
38
+ let a, i;
39
+ return t && (a = ne.from(t)), r && (i = ie.from(r)), new I({
40
+ gpuProgram: a,
41
+ glProgram: i,
42
+ ...s
43
+ });
44
+ }
45
+ };
46
+ ve.defaultOptions = {
47
+ blendMode: "normal",
48
+ resolution: 1,
49
+ padding: 0,
50
+ antialias: "off",
51
+ blendRequired: !1,
52
+ clipToViewport: !0
53
+ };
54
+ let rt = ve;
55
+ var st = `in vec2 vMaskCoord;
56
+ in vec2 vTextureCoord;
57
+
58
+ uniform sampler2D uTexture;
59
+ uniform sampler2D uMaskTexture;
60
+
61
+ uniform float uAlpha;
62
+ uniform vec4 uMaskClamp;
63
+ uniform float uInverse;
64
+
65
+ out vec4 finalColor;
66
+
67
+ void main(void)
68
+ {
69
+ float clip = step(3.5,
70
+ step(uMaskClamp.x, vMaskCoord.x) +
71
+ step(uMaskClamp.y, vMaskCoord.y) +
72
+ step(vMaskCoord.x, uMaskClamp.z) +
73
+ step(vMaskCoord.y, uMaskClamp.w));
74
+
75
+ // TODO look into why this is needed
76
+ float npmAlpha = uAlpha;
77
+ vec4 original = texture(uTexture, vTextureCoord);
78
+ vec4 masky = texture(uMaskTexture, vMaskCoord);
79
+ float alphaMul = 1.0 - npmAlpha * (1.0 - masky.a);
80
+
81
+ float a = alphaMul * masky.r * npmAlpha * clip;
82
+
83
+ if (uInverse == 1.0) {
84
+ a = 1.0 - a;
85
+ }
86
+
87
+ finalColor = original * a;
88
+ }
89
+ `, at = `in vec2 aPosition;
90
+
91
+ out vec2 vTextureCoord;
92
+ out vec2 vMaskCoord;
93
+
94
+
95
+ uniform vec4 uInputSize;
96
+ uniform vec4 uOutputFrame;
97
+ uniform vec4 uOutputTexture;
98
+ uniform mat3 uFilterMatrix;
99
+
100
+ vec4 filterVertexPosition( vec2 aPosition )
101
+ {
102
+ vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;
103
+
104
+ position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;
105
+ position.y = position.y * (2.0*uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;
106
+
107
+ return vec4(position, 0.0, 1.0);
108
+ }
109
+
110
+ vec2 filterTextureCoord( vec2 aPosition )
111
+ {
112
+ return aPosition * (uOutputFrame.zw * uInputSize.zw);
113
+ }
114
+
115
+ vec2 getFilterCoord( vec2 aPosition )
116
+ {
117
+ return ( uFilterMatrix * vec3( filterTextureCoord(aPosition), 1.0) ).xy;
118
+ }
119
+
120
+ void main(void)
121
+ {
122
+ gl_Position = filterVertexPosition(aPosition);
123
+ vTextureCoord = filterTextureCoord(aPosition);
124
+ vMaskCoord = getFilterCoord(aPosition);
125
+ }
126
+ `, te = `struct GlobalFilterUniforms {
127
+ uInputSize:vec4<f32>,
128
+ uInputPixel:vec4<f32>,
129
+ uInputClamp:vec4<f32>,
130
+ uOutputFrame:vec4<f32>,
131
+ uGlobalFrame:vec4<f32>,
132
+ uOutputTexture:vec4<f32>,
133
+ };
134
+
135
+ struct MaskUniforms {
136
+ uFilterMatrix:mat3x3<f32>,
137
+ uMaskClamp:vec4<f32>,
138
+ uAlpha:f32,
139
+ uInverse:f32,
140
+ };
141
+
142
+ @group(0) @binding(0) var<uniform> gfu: GlobalFilterUniforms;
143
+ @group(0) @binding(1) var uTexture: texture_2d<f32>;
144
+ @group(0) @binding(2) var uSampler : sampler;
145
+
146
+ @group(1) @binding(0) var<uniform> filterUniforms : MaskUniforms;
147
+ @group(1) @binding(1) var uMaskTexture: texture_2d<f32>;
148
+
149
+ struct VSOutput {
150
+ @builtin(position) position: vec4<f32>,
151
+ @location(0) uv : vec2<f32>,
152
+ @location(1) filterUv : vec2<f32>,
153
+ };
154
+
155
+ fn filterVertexPosition(aPosition:vec2<f32>) -> vec4<f32>
156
+ {
157
+ var position = aPosition * gfu.uOutputFrame.zw + gfu.uOutputFrame.xy;
158
+
159
+ position.x = position.x * (2.0 / gfu.uOutputTexture.x) - 1.0;
160
+ position.y = position.y * (2.0*gfu.uOutputTexture.z / gfu.uOutputTexture.y) - gfu.uOutputTexture.z;
161
+
162
+ return vec4(position, 0.0, 1.0);
163
+ }
164
+
165
+ fn filterTextureCoord( aPosition:vec2<f32> ) -> vec2<f32>
166
+ {
167
+ return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);
168
+ }
169
+
170
+ fn globalTextureCoord( aPosition:vec2<f32> ) -> vec2<f32>
171
+ {
172
+ return (aPosition.xy / gfu.uGlobalFrame.zw) + (gfu.uGlobalFrame.xy / gfu.uGlobalFrame.zw);
173
+ }
174
+
175
+ fn getFilterCoord(aPosition:vec2<f32> ) -> vec2<f32>
176
+ {
177
+ return ( filterUniforms.uFilterMatrix * vec3( filterTextureCoord(aPosition), 1.0) ).xy;
178
+ }
179
+
180
+ fn getSize() -> vec2<f32>
181
+ {
182
+ return gfu.uGlobalFrame.zw;
183
+ }
184
+
185
+ @vertex
186
+ fn mainVertex(
187
+ @location(0) aPosition : vec2<f32>,
188
+ ) -> VSOutput {
189
+ return VSOutput(
190
+ filterVertexPosition(aPosition),
191
+ filterTextureCoord(aPosition),
192
+ getFilterCoord(aPosition)
193
+ );
194
+ }
195
+
196
+ @fragment
197
+ fn mainFragment(
198
+ @location(0) uv: vec2<f32>,
199
+ @location(1) filterUv: vec2<f32>,
200
+ @builtin(position) position: vec4<f32>
201
+ ) -> @location(0) vec4<f32> {
202
+
203
+ var maskClamp = filterUniforms.uMaskClamp;
204
+ var uAlpha = filterUniforms.uAlpha;
205
+
206
+ var clip = step(3.5,
207
+ step(maskClamp.x, filterUv.x) +
208
+ step(maskClamp.y, filterUv.y) +
209
+ step(filterUv.x, maskClamp.z) +
210
+ step(filterUv.y, maskClamp.w));
211
+
212
+ var mask = textureSample(uMaskTexture, uSampler, filterUv);
213
+ var source = textureSample(uTexture, uSampler, uv);
214
+ var alphaMul = 1.0 - uAlpha * (1.0 - mask.a);
215
+
216
+ var a: f32 = alphaMul * mask.r * uAlpha * clip;
217
+
218
+ if (filterUniforms.uInverse == 1.0) {
219
+ a = 1.0 - a;
220
+ }
221
+
222
+ return source * a;
223
+ }
224
+ `;
225
+ class nt extends rt {
226
+ constructor(e) {
227
+ const { sprite: t, ...r } = e, s = new ze(t.texture), a = new oe({
228
+ uFilterMatrix: { value: new v(), type: "mat3x3<f32>" },
229
+ uMaskClamp: { value: s.uClampFrame, type: "vec4<f32>" },
230
+ uAlpha: { value: 1, type: "f32" },
231
+ uInverse: { value: e.inverse ? 1 : 0, type: "f32" }
232
+ }), i = ne.from({
233
+ vertex: {
234
+ source: te,
235
+ entryPoint: "mainVertex"
236
+ },
237
+ fragment: {
238
+ source: te,
239
+ entryPoint: "mainFragment"
240
+ }
241
+ }), o = ie.from({
242
+ vertex: at,
243
+ fragment: st,
244
+ name: "mask-filter"
245
+ });
246
+ super({
247
+ ...r,
248
+ gpuProgram: i,
249
+ glProgram: o,
250
+ clipToViewport: !1,
251
+ resources: {
252
+ filterUniforms: a,
253
+ uMaskTexture: t.texture.source
254
+ }
255
+ }), this.sprite = t, this._textureMatrix = s;
256
+ }
257
+ set inverse(e) {
258
+ this.resources.filterUniforms.uniforms.uInverse = e ? 1 : 0;
259
+ }
260
+ get inverse() {
261
+ return this.resources.filterUniforms.uniforms.uInverse === 1;
262
+ }
263
+ apply(e, t, r, s) {
264
+ this._textureMatrix.texture = this.sprite.texture, e.calculateSpriteMatrix(
265
+ this.resources.filterUniforms.uniforms.uFilterMatrix,
266
+ this.sprite
267
+ ).prepend(this._textureMatrix.mapCoord), this.resources.uMaskTexture = this.sprite.texture.source, e.applyFilter(this, t, r, s);
268
+ }
269
+ }
270
+ const W = class ge {
271
+ constructor(e, t) {
272
+ var r, s;
273
+ this.state = pe.for2d(), this._batchersByInstructionSet = /* @__PURE__ */ Object.create(null), this._activeBatches = /* @__PURE__ */ Object.create(null), this.renderer = e, this._adaptor = t, (s = (r = this._adaptor).init) == null || s.call(r, this);
274
+ }
275
+ static getBatcher(e) {
276
+ return new this._availableBatchers[e]();
277
+ }
278
+ buildStart(e) {
279
+ let t = this._batchersByInstructionSet[e.uid];
280
+ t || (t = this._batchersByInstructionSet[e.uid] = /* @__PURE__ */ Object.create(null), t.default || (t.default = new le({
281
+ maxTextures: this.renderer.limits.maxBatchableTextures
282
+ }))), this._activeBatches = t, this._activeBatch = this._activeBatches.default;
283
+ for (const r in this._activeBatches)
284
+ this._activeBatches[r].begin();
285
+ }
286
+ addToBatch(e, t) {
287
+ if (this._activeBatch.name !== e.batcherName) {
288
+ this._activeBatch.break(t);
289
+ let r = this._activeBatches[e.batcherName];
290
+ r || (r = this._activeBatches[e.batcherName] = ge.getBatcher(e.batcherName), r.begin()), this._activeBatch = r;
291
+ }
292
+ this._activeBatch.add(e);
293
+ }
294
+ break(e) {
295
+ this._activeBatch.break(e);
296
+ }
297
+ buildEnd(e) {
298
+ this._activeBatch.break(e);
299
+ const t = this._activeBatches;
300
+ for (const r in t) {
301
+ const s = t[r], a = s.geometry;
302
+ a.indexBuffer.setDataWithSize(s.indexBuffer, s.indexSize, !0), a.buffers[0].setDataWithSize(s.attributeBuffer.float32View, s.attributeSize, !1);
303
+ }
304
+ }
305
+ upload(e) {
306
+ const t = this._batchersByInstructionSet[e.uid];
307
+ for (const r in t) {
308
+ const s = t[r], a = s.geometry;
309
+ s.dirty && (s.dirty = !1, a.buffers[0].update(s.attributeSize * 4));
310
+ }
311
+ }
312
+ execute(e) {
313
+ if (e.action === "startBatch") {
314
+ const t = e.batcher, r = t.geometry, s = t.shader;
315
+ this._adaptor.start(this, r, s);
316
+ }
317
+ this._adaptor.execute(this, e);
318
+ }
319
+ destroy() {
320
+ this.state = null, this.renderer = null, this._adaptor = null;
321
+ for (const e in this._activeBatches)
322
+ this._activeBatches[e].destroy();
323
+ this._activeBatches = null;
324
+ }
325
+ };
326
+ W.extension = {
327
+ type: [
328
+ u.WebGLPipes,
329
+ u.WebGPUPipes,
330
+ u.CanvasPipes
331
+ ],
332
+ name: "batch"
333
+ };
334
+ W._availableBatchers = /* @__PURE__ */ Object.create(null);
335
+ let xe = W;
336
+ O.handleByMap(u.Batcher, xe._availableBatchers);
337
+ O.add(le);
338
+ const It = {
339
+ name: "texture-bit",
340
+ vertex: {
341
+ header: (
342
+ /* wgsl */
343
+ `
344
+
345
+ struct TextureUniforms {
346
+ uTextureMatrix:mat3x3<f32>,
347
+ }
348
+
349
+ @group(2) @binding(2) var<uniform> textureUniforms : TextureUniforms;
350
+ `
351
+ ),
352
+ main: (
353
+ /* wgsl */
354
+ `
355
+ uv = (textureUniforms.uTextureMatrix * vec3(uv, 1.0)).xy;
356
+ `
357
+ )
358
+ },
359
+ fragment: {
360
+ header: (
361
+ /* wgsl */
362
+ `
363
+ @group(2) @binding(0) var uTexture: texture_2d<f32>;
364
+ @group(2) @binding(1) var uSampler: sampler;
365
+
366
+
367
+ `
368
+ ),
369
+ main: (
370
+ /* wgsl */
371
+ `
372
+ outColor = textureSample(uTexture, uSampler, vUV);
373
+ `
374
+ )
375
+ }
376
+ }, Gt = {
377
+ name: "texture-bit",
378
+ vertex: {
379
+ header: (
380
+ /* glsl */
381
+ `
382
+ uniform mat3 uTextureMatrix;
383
+ `
384
+ ),
385
+ main: (
386
+ /* glsl */
387
+ `
388
+ uv = (uTextureMatrix * vec3(uv, 1.0)).xy;
389
+ `
390
+ )
391
+ },
392
+ fragment: {
393
+ header: (
394
+ /* glsl */
395
+ `
396
+ uniform sampler2D uTexture;
397
+
398
+
399
+ `
400
+ ),
401
+ main: (
402
+ /* glsl */
403
+ `
404
+ outColor = texture(uTexture, vUV);
405
+ `
406
+ )
407
+ }
408
+ }, it = new F();
409
+ class ot extends ue {
410
+ constructor() {
411
+ super(), this.filters = [new nt({
412
+ sprite: new Ve(m.EMPTY),
413
+ inverse: !1,
414
+ resolution: "inherit",
415
+ antialias: "inherit"
416
+ })];
417
+ }
418
+ get sprite() {
419
+ return this.filters[0].sprite;
420
+ }
421
+ set sprite(e) {
422
+ this.filters[0].sprite = e;
423
+ }
424
+ get inverse() {
425
+ return this.filters[0].inverse;
426
+ }
427
+ set inverse(e) {
428
+ this.filters[0].inverse = e;
429
+ }
430
+ }
431
+ class _e {
432
+ constructor(e) {
433
+ this._activeMaskStage = [], this._renderer = e;
434
+ }
435
+ push(e, t, r) {
436
+ const s = this._renderer;
437
+ if (s.renderPipes.batch.break(r), r.add({
438
+ renderPipeId: "alphaMask",
439
+ action: "pushMaskBegin",
440
+ mask: e,
441
+ inverse: t._maskOptions.inverse,
442
+ canBundle: !1,
443
+ maskedContainer: t
444
+ }), e.inverse = t._maskOptions.inverse, e.renderMaskToTexture) {
445
+ const a = e.mask;
446
+ a.includeInBuild = !0, a.collectRenderables(
447
+ r,
448
+ s,
449
+ null
450
+ ), a.includeInBuild = !1;
451
+ }
452
+ s.renderPipes.batch.break(r), r.add({
453
+ renderPipeId: "alphaMask",
454
+ action: "pushMaskEnd",
455
+ mask: e,
456
+ maskedContainer: t,
457
+ inverse: t._maskOptions.inverse,
458
+ canBundle: !1
459
+ });
460
+ }
461
+ pop(e, t, r) {
462
+ this._renderer.renderPipes.batch.break(r), r.add({
463
+ renderPipeId: "alphaMask",
464
+ action: "popMaskEnd",
465
+ mask: e,
466
+ inverse: t._maskOptions.inverse,
467
+ canBundle: !1
468
+ });
469
+ }
470
+ execute(e) {
471
+ const t = this._renderer, r = e.mask.renderMaskToTexture;
472
+ if (e.action === "pushMaskBegin") {
473
+ const s = S.get(ot);
474
+ if (s.inverse = e.inverse, r) {
475
+ e.mask.mask.measurable = !0;
476
+ const a = We(e.mask.mask, !0, it);
477
+ e.mask.mask.measurable = !1, a.ceil();
478
+ const i = t.renderTarget.renderTarget.colorTexture.source, o = b.getOptimalTexture(
479
+ a.width,
480
+ a.height,
481
+ i._resolution,
482
+ i.antialias
483
+ );
484
+ t.renderTarget.push(o, !0), t.globalUniforms.push({
485
+ offset: a,
486
+ worldColor: 4294967295
487
+ });
488
+ const l = s.sprite;
489
+ l.texture = o, l.worldTransform.tx = a.minX, l.worldTransform.ty = a.minY, this._activeMaskStage.push({
490
+ filterEffect: s,
491
+ maskedContainer: e.maskedContainer,
492
+ filterTexture: o
493
+ });
494
+ } else
495
+ s.sprite = e.mask.mask, this._activeMaskStage.push({
496
+ filterEffect: s,
497
+ maskedContainer: e.maskedContainer
498
+ });
499
+ } else if (e.action === "pushMaskEnd") {
500
+ const s = this._activeMaskStage[this._activeMaskStage.length - 1];
501
+ r && (t.type === L.WEBGL && t.renderTarget.finishRenderPass(), t.renderTarget.pop(), t.globalUniforms.pop()), t.filter.push({
502
+ renderPipeId: "filter",
503
+ action: "pushFilter",
504
+ container: s.maskedContainer,
505
+ filterEffect: s.filterEffect,
506
+ canBundle: !1
507
+ });
508
+ } else if (e.action === "popMaskEnd") {
509
+ t.filter.pop();
510
+ const s = this._activeMaskStage.pop();
511
+ r && b.returnTexture(s.filterTexture), S.return(s.filterEffect);
512
+ }
513
+ }
514
+ destroy() {
515
+ this._renderer = null, this._activeMaskStage = null;
516
+ }
517
+ }
518
+ _e.extension = {
519
+ type: [
520
+ u.WebGLPipes,
521
+ u.WebGPUPipes,
522
+ u.CanvasPipes
523
+ ],
524
+ name: "alphaMask"
525
+ };
526
+ class be {
527
+ constructor(e) {
528
+ this._colorStack = [], this._colorStackIndex = 0, this._currentColor = 0, this._renderer = e;
529
+ }
530
+ buildStart() {
531
+ this._colorStack[0] = 15, this._colorStackIndex = 1, this._currentColor = 15;
532
+ }
533
+ push(e, t, r) {
534
+ this._renderer.renderPipes.batch.break(r);
535
+ const a = this._colorStack;
536
+ a[this._colorStackIndex] = a[this._colorStackIndex - 1] & e.mask;
537
+ const i = this._colorStack[this._colorStackIndex];
538
+ i !== this._currentColor && (this._currentColor = i, r.add({
539
+ renderPipeId: "colorMask",
540
+ colorMask: i,
541
+ canBundle: !1
542
+ })), this._colorStackIndex++;
543
+ }
544
+ pop(e, t, r) {
545
+ this._renderer.renderPipes.batch.break(r);
546
+ const a = this._colorStack;
547
+ this._colorStackIndex--;
548
+ const i = a[this._colorStackIndex - 1];
549
+ i !== this._currentColor && (this._currentColor = i, r.add({
550
+ renderPipeId: "colorMask",
551
+ colorMask: i,
552
+ canBundle: !1
553
+ }));
554
+ }
555
+ execute(e) {
556
+ this._renderer.colorMask.setMask(e.colorMask);
557
+ }
558
+ destroy() {
559
+ this._renderer = null, this._colorStack = null;
560
+ }
561
+ }
562
+ be.extension = {
563
+ type: [
564
+ u.WebGLPipes,
565
+ u.WebGPUPipes,
566
+ u.CanvasPipes
567
+ ],
568
+ name: "colorMask"
569
+ };
570
+ class Te {
571
+ constructor(e) {
572
+ this._maskStackHash = {}, this._maskHash = /* @__PURE__ */ new WeakMap(), this._renderer = e;
573
+ }
574
+ push(e, t, r) {
575
+ var s;
576
+ const a = e, i = this._renderer;
577
+ i.renderPipes.batch.break(r), i.renderPipes.blendMode.setBlendMode(a.mask, "none", r), r.add({
578
+ renderPipeId: "stencilMask",
579
+ action: "pushMaskBegin",
580
+ mask: e,
581
+ inverse: t._maskOptions.inverse,
582
+ canBundle: !1
583
+ });
584
+ const o = a.mask;
585
+ o.includeInBuild = !0, this._maskHash.has(a) || this._maskHash.set(a, {
586
+ instructionsStart: 0,
587
+ instructionsLength: 0
588
+ });
589
+ const l = this._maskHash.get(a);
590
+ l.instructionsStart = r.instructionSize, o.collectRenderables(
591
+ r,
592
+ i,
593
+ null
594
+ ), o.includeInBuild = !1, i.renderPipes.batch.break(r), r.add({
595
+ renderPipeId: "stencilMask",
596
+ action: "pushMaskEnd",
597
+ mask: e,
598
+ inverse: t._maskOptions.inverse,
599
+ canBundle: !1
600
+ });
601
+ const d = r.instructionSize - l.instructionsStart - 1;
602
+ l.instructionsLength = d;
603
+ const c = i.renderTarget.renderTarget.uid;
604
+ (s = this._maskStackHash)[c] ?? (s[c] = 0);
605
+ }
606
+ pop(e, t, r) {
607
+ const s = e, a = this._renderer;
608
+ a.renderPipes.batch.break(r), a.renderPipes.blendMode.setBlendMode(s.mask, "none", r), r.add({
609
+ renderPipeId: "stencilMask",
610
+ action: "popMaskBegin",
611
+ inverse: t._maskOptions.inverse,
612
+ canBundle: !1
613
+ });
614
+ const i = this._maskHash.get(e);
615
+ for (let o = 0; o < i.instructionsLength; o++)
616
+ r.instructions[r.instructionSize++] = r.instructions[i.instructionsStart++];
617
+ r.add({
618
+ renderPipeId: "stencilMask",
619
+ action: "popMaskEnd",
620
+ canBundle: !1
621
+ });
622
+ }
623
+ execute(e) {
624
+ var t;
625
+ const r = this._renderer, s = r.renderTarget.renderTarget.uid;
626
+ let a = (t = this._maskStackHash)[s] ?? (t[s] = 0);
627
+ e.action === "pushMaskBegin" ? (r.renderTarget.ensureDepthStencil(), r.stencil.setStencilMode(f.RENDERING_MASK_ADD, a), a++, r.colorMask.setMask(0)) : e.action === "pushMaskEnd" ? (e.inverse ? r.stencil.setStencilMode(f.INVERSE_MASK_ACTIVE, a) : r.stencil.setStencilMode(f.MASK_ACTIVE, a), r.colorMask.setMask(15)) : e.action === "popMaskBegin" ? (r.colorMask.setMask(0), a !== 0 ? r.stencil.setStencilMode(f.RENDERING_MASK_REMOVE, a) : (r.renderTarget.clear(null, B.STENCIL), r.stencil.setStencilMode(f.DISABLED, a)), a--) : e.action === "popMaskEnd" && (e.inverse ? r.stencil.setStencilMode(f.INVERSE_MASK_ACTIVE, a) : r.stencil.setStencilMode(f.MASK_ACTIVE, a), r.colorMask.setMask(15)), this._maskStackHash[s] = a;
628
+ }
629
+ destroy() {
630
+ this._renderer = null, this._maskStackHash = null, this._maskHash = null;
631
+ }
632
+ }
633
+ Te.extension = {
634
+ type: [
635
+ u.WebGLPipes,
636
+ u.WebGPUPipes,
637
+ u.CanvasPipes
638
+ ],
639
+ name: "stencilMask"
640
+ };
641
+ function Et(n, e) {
642
+ for (const t in n.attributes) {
643
+ const r = n.attributes[t], s = e[t];
644
+ s ? (r.format ?? (r.format = s.format), r.offset ?? (r.offset = s.offset), r.instance ?? (r.instance = s.instance)) : H(`Attribute ${t} is not present in the shader, but is present in the geometry. Unable to infer attribute details.`);
645
+ }
646
+ lt(n);
647
+ }
648
+ function lt(n) {
649
+ const { buffers: e, attributes: t } = n, r = {}, s = {};
650
+ for (const a in e) {
651
+ const i = e[a];
652
+ r[i.uid] = 0, s[i.uid] = 0;
653
+ }
654
+ for (const a in t) {
655
+ const i = t[a];
656
+ r[i.buffer.uid] += J(i.format).stride;
657
+ }
658
+ for (const a in t) {
659
+ const i = t[a];
660
+ i.stride ?? (i.stride = r[i.buffer.uid]), i.start ?? (i.start = s[i.buffer.uid]), s[i.buffer.uid] += J(i.format).stride;
661
+ }
662
+ }
663
+ const _ = [];
664
+ _[f.NONE] = void 0;
665
+ _[f.DISABLED] = {
666
+ stencilWriteMask: 0,
667
+ stencilReadMask: 0
668
+ };
669
+ _[f.RENDERING_MASK_ADD] = {
670
+ stencilFront: {
671
+ compare: "equal",
672
+ passOp: "increment-clamp"
673
+ },
674
+ stencilBack: {
675
+ compare: "equal",
676
+ passOp: "increment-clamp"
677
+ }
678
+ };
679
+ _[f.RENDERING_MASK_REMOVE] = {
680
+ stencilFront: {
681
+ compare: "equal",
682
+ passOp: "decrement-clamp"
683
+ },
684
+ stencilBack: {
685
+ compare: "equal",
686
+ passOp: "decrement-clamp"
687
+ }
688
+ };
689
+ _[f.MASK_ACTIVE] = {
690
+ stencilWriteMask: 0,
691
+ stencilFront: {
692
+ compare: "equal",
693
+ passOp: "keep"
694
+ },
695
+ stencilBack: {
696
+ compare: "equal",
697
+ passOp: "keep"
698
+ }
699
+ };
700
+ _[f.INVERSE_MASK_ACTIVE] = {
701
+ stencilWriteMask: 0,
702
+ stencilFront: {
703
+ compare: "not-equal",
704
+ passOp: "keep"
705
+ },
706
+ stencilBack: {
707
+ compare: "not-equal",
708
+ passOp: "keep"
709
+ }
710
+ };
711
+ class Dt {
712
+ constructor(e) {
713
+ this._syncFunctionHash = /* @__PURE__ */ Object.create(null), this._adaptor = e, this._systemCheck();
714
+ }
715
+ /**
716
+ * Overridable function by `pixi.js/unsafe-eval` to silence
717
+ * throwing an error if platform doesn't support unsafe-evals.
718
+ * @private
719
+ */
720
+ _systemCheck() {
721
+ if (!Ne())
722
+ throw new Error("Current environment does not allow unsafe-eval, please use pixi.js/unsafe-eval module to enable support.");
723
+ }
724
+ ensureUniformGroup(e) {
725
+ const t = this.getUniformGroupData(e);
726
+ e.buffer || (e.buffer = new X({
727
+ data: new Float32Array(t.layout.size / 4),
728
+ usage: k.UNIFORM | k.COPY_DST
729
+ }));
730
+ }
731
+ getUniformGroupData(e) {
732
+ return this._syncFunctionHash[e._signature] || this._initUniformGroup(e);
733
+ }
734
+ _initUniformGroup(e) {
735
+ const t = e._signature;
736
+ let r = this._syncFunctionHash[t];
737
+ if (!r) {
738
+ const s = Object.keys(e.uniformStructures).map((o) => e.uniformStructures[o]), a = this._adaptor.createUboElements(s), i = this._generateUboSync(a.uboElements);
739
+ r = this._syncFunctionHash[t] = {
740
+ layout: a,
741
+ syncFunction: i
742
+ };
743
+ }
744
+ return this._syncFunctionHash[t];
745
+ }
746
+ _generateUboSync(e) {
747
+ return this._adaptor.generateUboSync(e);
748
+ }
749
+ syncUniformGroup(e, t, r) {
750
+ const s = this.getUniformGroupData(e);
751
+ e.buffer || (e.buffer = new X({
752
+ data: new Float32Array(s.layout.size / 4),
753
+ usage: k.UNIFORM | k.COPY_DST
754
+ }));
755
+ let a = null;
756
+ return t || (t = e.buffer.data, a = e.buffer.dataInt32), r || (r = 0), s.syncFunction(e.uniforms, t, a, r), !0;
757
+ }
758
+ updateUniformGroup(e) {
759
+ if (e.isStatic && !e._dirtyId)
760
+ return !1;
761
+ e._dirtyId = 0;
762
+ const t = this.syncUniformGroup(e);
763
+ return e.buffer.update(), t;
764
+ }
765
+ destroy() {
766
+ this._syncFunctionHash = null;
767
+ }
768
+ }
769
+ const C = [
770
+ // uploading pixi matrix object to mat3
771
+ {
772
+ type: "mat3x3<f32>",
773
+ test: (n) => n.value.a !== void 0,
774
+ ubo: `
775
+ var matrix = uv[name].toArray(true);
776
+ data[offset] = matrix[0];
777
+ data[offset + 1] = matrix[1];
778
+ data[offset + 2] = matrix[2];
779
+ data[offset + 4] = matrix[3];
780
+ data[offset + 5] = matrix[4];
781
+ data[offset + 6] = matrix[5];
782
+ data[offset + 8] = matrix[6];
783
+ data[offset + 9] = matrix[7];
784
+ data[offset + 10] = matrix[8];
785
+ `,
786
+ uniform: `
787
+ gl.uniformMatrix3fv(ud[name].location, false, uv[name].toArray(true));
788
+ `
789
+ },
790
+ // uploading a pixi rectangle as a vec4
791
+ {
792
+ type: "vec4<f32>",
793
+ test: (n) => n.type === "vec4<f32>" && n.size === 1 && n.value.width !== void 0,
794
+ ubo: `
795
+ v = uv[name];
796
+ data[offset] = v.x;
797
+ data[offset + 1] = v.y;
798
+ data[offset + 2] = v.width;
799
+ data[offset + 3] = v.height;
800
+ `,
801
+ uniform: `
802
+ cv = ud[name].value;
803
+ v = uv[name];
804
+ if (cv[0] !== v.x || cv[1] !== v.y || cv[2] !== v.width || cv[3] !== v.height) {
805
+ cv[0] = v.x;
806
+ cv[1] = v.y;
807
+ cv[2] = v.width;
808
+ cv[3] = v.height;
809
+ gl.uniform4f(ud[name].location, v.x, v.y, v.width, v.height);
810
+ }
811
+ `
812
+ },
813
+ // uploading a pixi point as a vec2
814
+ {
815
+ type: "vec2<f32>",
816
+ test: (n) => n.type === "vec2<f32>" && n.size === 1 && n.value.x !== void 0,
817
+ ubo: `
818
+ v = uv[name];
819
+ data[offset] = v.x;
820
+ data[offset + 1] = v.y;
821
+ `,
822
+ uniform: `
823
+ cv = ud[name].value;
824
+ v = uv[name];
825
+ if (cv[0] !== v.x || cv[1] !== v.y) {
826
+ cv[0] = v.x;
827
+ cv[1] = v.y;
828
+ gl.uniform2f(ud[name].location, v.x, v.y);
829
+ }
830
+ `
831
+ },
832
+ // uploading a pixi color as a vec4
833
+ {
834
+ type: "vec4<f32>",
835
+ test: (n) => n.type === "vec4<f32>" && n.size === 1 && n.value.red !== void 0,
836
+ ubo: `
837
+ v = uv[name];
838
+ data[offset] = v.red;
839
+ data[offset + 1] = v.green;
840
+ data[offset + 2] = v.blue;
841
+ data[offset + 3] = v.alpha;
842
+ `,
843
+ uniform: `
844
+ cv = ud[name].value;
845
+ v = uv[name];
846
+ if (cv[0] !== v.red || cv[1] !== v.green || cv[2] !== v.blue || cv[3] !== v.alpha) {
847
+ cv[0] = v.red;
848
+ cv[1] = v.green;
849
+ cv[2] = v.blue;
850
+ cv[3] = v.alpha;
851
+ gl.uniform4f(ud[name].location, v.red, v.green, v.blue, v.alpha);
852
+ }
853
+ `
854
+ },
855
+ // uploading a pixi color as a vec3
856
+ {
857
+ type: "vec3<f32>",
858
+ test: (n) => n.type === "vec3<f32>" && n.size === 1 && n.value.red !== void 0,
859
+ ubo: `
860
+ v = uv[name];
861
+ data[offset] = v.red;
862
+ data[offset + 1] = v.green;
863
+ data[offset + 2] = v.blue;
864
+ `,
865
+ uniform: `
866
+ cv = ud[name].value;
867
+ v = uv[name];
868
+ if (cv[0] !== v.red || cv[1] !== v.green || cv[2] !== v.blue) {
869
+ cv[0] = v.red;
870
+ cv[1] = v.green;
871
+ cv[2] = v.blue;
872
+ gl.uniform3f(ud[name].location, v.red, v.green, v.blue);
873
+ }
874
+ `
875
+ }
876
+ ];
877
+ function Ot(n, e, t, r) {
878
+ const s = [`
879
+ var v = null;
880
+ var v2 = null;
881
+ var t = 0;
882
+ var index = 0;
883
+ var name = null;
884
+ var arrayOffset = null;
885
+ `];
886
+ let a = 0;
887
+ for (let o = 0; o < n.length; o++) {
888
+ const l = n[o], d = l.data.name;
889
+ let c = !1, h = 0;
890
+ for (let p = 0; p < C.length; p++)
891
+ if (C[p].test(l.data)) {
892
+ h = l.offset / 4, s.push(
893
+ `name = "${d}";`,
894
+ `offset += ${h - a};`,
895
+ C[p][e] || C[p].ubo
896
+ ), c = !0;
897
+ break;
898
+ }
899
+ if (!c)
900
+ if (l.data.size > 1)
901
+ h = l.offset / 4, s.push(t(l, h - a));
902
+ else {
903
+ const p = r[l.data.type];
904
+ h = l.offset / 4, s.push(
905
+ /* wgsl */
906
+ `
907
+ v = uv.${d};
908
+ offset += ${h - a};
909
+ ${p};
910
+ `
911
+ );
912
+ }
913
+ a = h;
914
+ }
915
+ const i = s.join(`
916
+ `);
917
+ return new Function(
918
+ "uv",
919
+ "data",
920
+ "dataInt32",
921
+ "offset",
922
+ i
923
+ );
924
+ }
925
+ function g(n, e) {
926
+ return `
927
+ for (let i = 0; i < ${n * e}; i++) {
928
+ data[offset + (((i / ${n})|0) * 4) + (i % ${n})] = v[i];
929
+ }
930
+ `;
931
+ }
932
+ const ut = {
933
+ f32: `
934
+ data[offset] = v;`,
935
+ i32: `
936
+ dataInt32[offset] = v;`,
937
+ "vec2<f32>": `
938
+ data[offset] = v[0];
939
+ data[offset + 1] = v[1];`,
940
+ "vec3<f32>": `
941
+ data[offset] = v[0];
942
+ data[offset + 1] = v[1];
943
+ data[offset + 2] = v[2];`,
944
+ "vec4<f32>": `
945
+ data[offset] = v[0];
946
+ data[offset + 1] = v[1];
947
+ data[offset + 2] = v[2];
948
+ data[offset + 3] = v[3];`,
949
+ "vec2<i32>": `
950
+ dataInt32[offset] = v[0];
951
+ dataInt32[offset + 1] = v[1];`,
952
+ "vec3<i32>": `
953
+ dataInt32[offset] = v[0];
954
+ dataInt32[offset + 1] = v[1];
955
+ dataInt32[offset + 2] = v[2];`,
956
+ "vec4<i32>": `
957
+ dataInt32[offset] = v[0];
958
+ dataInt32[offset + 1] = v[1];
959
+ dataInt32[offset + 2] = v[2];
960
+ dataInt32[offset + 3] = v[3];`,
961
+ "mat2x2<f32>": `
962
+ data[offset] = v[0];
963
+ data[offset + 1] = v[1];
964
+ data[offset + 4] = v[2];
965
+ data[offset + 5] = v[3];`,
966
+ "mat3x3<f32>": `
967
+ data[offset] = v[0];
968
+ data[offset + 1] = v[1];
969
+ data[offset + 2] = v[2];
970
+ data[offset + 4] = v[3];
971
+ data[offset + 5] = v[4];
972
+ data[offset + 6] = v[5];
973
+ data[offset + 8] = v[6];
974
+ data[offset + 9] = v[7];
975
+ data[offset + 10] = v[8];`,
976
+ "mat4x4<f32>": `
977
+ for (let i = 0; i < 16; i++) {
978
+ data[offset + i] = v[i];
979
+ }`,
980
+ "mat3x2<f32>": g(3, 2),
981
+ "mat4x2<f32>": g(4, 2),
982
+ "mat2x3<f32>": g(2, 3),
983
+ "mat4x3<f32>": g(4, 3),
984
+ "mat2x4<f32>": g(2, 4),
985
+ "mat3x4<f32>": g(3, 4)
986
+ }, Ft = {
987
+ ...ut,
988
+ "mat2x2<f32>": `
989
+ data[offset] = v[0];
990
+ data[offset + 1] = v[1];
991
+ data[offset + 2] = v[2];
992
+ data[offset + 3] = v[3];
993
+ `
994
+ };
995
+ function dt(n, e, t, r, s, a) {
996
+ const i = a ? 1 : -1;
997
+ return n.identity(), n.a = 1 / r * 2, n.d = i * (1 / s * 2), n.tx = -1 - e * n.a, n.ty = -i - t * n.d, n;
998
+ }
999
+ const x = /* @__PURE__ */ new Map();
1000
+ je.register(x);
1001
+ function ye(n, e) {
1002
+ if (!x.has(n)) {
1003
+ const t = new m({
1004
+ source: new U({
1005
+ resource: n,
1006
+ ...e
1007
+ })
1008
+ }), r = () => {
1009
+ x.get(n) === t && x.delete(n);
1010
+ };
1011
+ t.once("destroy", r), t.source.once("destroy", r), x.set(n, t);
1012
+ }
1013
+ return x.get(n);
1014
+ }
1015
+ function ct(n) {
1016
+ const e = n.colorTexture.source.resource;
1017
+ return globalThis.HTMLCanvasElement && e instanceof HTMLCanvasElement && document.body.contains(e);
1018
+ }
1019
+ const ke = class Ce {
1020
+ /**
1021
+ * @param [descriptor] - Options for creating a render target.
1022
+ */
1023
+ constructor(e = {}) {
1024
+ if (this.uid = M("renderTarget"), this.colorTextures = [], this.dirtyId = 0, this.isRoot = !1, this._size = new Float32Array(2), this._managedColorTextures = !1, e = { ...Ce.defaultOptions, ...e }, this.stencil = e.stencil, this.depth = e.depth, this.isRoot = e.isRoot, typeof e.colorTextures == "number") {
1025
+ this._managedColorTextures = !0;
1026
+ for (let t = 0; t < e.colorTextures; t++)
1027
+ this.colorTextures.push(
1028
+ new T({
1029
+ width: e.width,
1030
+ height: e.height,
1031
+ resolution: e.resolution,
1032
+ antialias: e.antialias
1033
+ })
1034
+ );
1035
+ } else {
1036
+ this.colorTextures = [...e.colorTextures.map((r) => r.source)];
1037
+ const t = this.colorTexture.source;
1038
+ this.resize(t.width, t.height, t._resolution);
1039
+ }
1040
+ this.colorTexture.source.on("resize", this.onSourceResize, this), (e.depthStencilTexture || this.stencil) && (e.depthStencilTexture instanceof m || e.depthStencilTexture instanceof T ? this.depthStencilTexture = e.depthStencilTexture.source : this.ensureDepthStencilTexture());
1041
+ }
1042
+ get size() {
1043
+ const e = this._size;
1044
+ return e[0] = this.pixelWidth, e[1] = this.pixelHeight, e;
1045
+ }
1046
+ get width() {
1047
+ return this.colorTexture.source.width;
1048
+ }
1049
+ get height() {
1050
+ return this.colorTexture.source.height;
1051
+ }
1052
+ get pixelWidth() {
1053
+ return this.colorTexture.source.pixelWidth;
1054
+ }
1055
+ get pixelHeight() {
1056
+ return this.colorTexture.source.pixelHeight;
1057
+ }
1058
+ get resolution() {
1059
+ return this.colorTexture.source._resolution;
1060
+ }
1061
+ get colorTexture() {
1062
+ return this.colorTextures[0];
1063
+ }
1064
+ onSourceResize(e) {
1065
+ this.resize(e.width, e.height, e._resolution, !0);
1066
+ }
1067
+ /**
1068
+ * This will ensure a depthStencil texture is created for this render target.
1069
+ * Most likely called by the mask system to make sure we have stencil buffer added.
1070
+ * @internal
1071
+ */
1072
+ ensureDepthStencilTexture() {
1073
+ this.depthStencilTexture || (this.depthStencilTexture = new T({
1074
+ width: this.width,
1075
+ height: this.height,
1076
+ resolution: this.resolution,
1077
+ format: "depth24plus-stencil8",
1078
+ autoGenerateMipmaps: !1,
1079
+ antialias: !1,
1080
+ mipLevelCount: 1
1081
+ // sampleCount: handled by the render target system..
1082
+ }));
1083
+ }
1084
+ resize(e, t, r = this.resolution, s = !1) {
1085
+ this.dirtyId++, this.colorTextures.forEach((a, i) => {
1086
+ s && i === 0 || a.source.resize(e, t, r);
1087
+ }), this.depthStencilTexture && this.depthStencilTexture.source.resize(e, t, r);
1088
+ }
1089
+ destroy() {
1090
+ this.colorTexture.source.off("resize", this.onSourceResize, this), this._managedColorTextures && this.colorTextures.forEach((e) => {
1091
+ e.destroy();
1092
+ }), this.depthStencilTexture && (this.depthStencilTexture.destroy(), delete this.depthStencilTexture);
1093
+ }
1094
+ };
1095
+ ke.defaultOptions = {
1096
+ /** the width of the RenderTarget */
1097
+ width: 0,
1098
+ /** the height of the RenderTarget */
1099
+ height: 0,
1100
+ /** the resolution of the RenderTarget */
1101
+ resolution: 1,
1102
+ /** an array of textures, or a number indicating how many color textures there should be */
1103
+ colorTextures: 1,
1104
+ /** should this render target have a stencil buffer? */
1105
+ stencil: !1,
1106
+ /** should this render target have a depth buffer? */
1107
+ depth: !1,
1108
+ /** should this render target be antialiased? */
1109
+ antialias: !1,
1110
+ // save on perf by default!
1111
+ /** is this a root element, true if this is gl context owners render target */
1112
+ isRoot: !1
1113
+ };
1114
+ let G = ke;
1115
+ class Lt {
1116
+ constructor(e) {
1117
+ this.rootViewPort = new w(), this.viewport = new w(), this.onRenderTargetChange = new $e("onRenderTargetChange"), this.projectionMatrix = new v(), this.defaultClearColor = [0, 0, 0, 0], this._renderSurfaceToRenderTargetHash = /* @__PURE__ */ new Map(), this._gpuRenderTargetHash = /* @__PURE__ */ Object.create(null), this._renderTargetStack = [], this._renderer = e, e.renderableGC.addManagedHash(this, "_gpuRenderTargetHash");
1118
+ }
1119
+ /** called when dev wants to finish a render pass */
1120
+ finishRenderPass() {
1121
+ this.adaptor.finishRenderPass(this.renderTarget);
1122
+ }
1123
+ /**
1124
+ * called when the renderer starts to render a scene.
1125
+ * @param options
1126
+ * @param options.target - the render target to render to
1127
+ * @param options.clear - the clear mode to use. Can be true or a CLEAR number 'COLOR | DEPTH | STENCIL' 0b111
1128
+ * @param options.clearColor - the color to clear to
1129
+ * @param options.frame - the frame to render to
1130
+ */
1131
+ renderStart({
1132
+ target: e,
1133
+ clear: t,
1134
+ clearColor: r,
1135
+ frame: s
1136
+ }) {
1137
+ var a, i;
1138
+ this._renderTargetStack.length = 0, this.push(
1139
+ e,
1140
+ t,
1141
+ r,
1142
+ s
1143
+ ), this.rootViewPort.copyFrom(this.viewport), this.rootRenderTarget = this.renderTarget, this.renderingToScreen = ct(this.rootRenderTarget), (i = (a = this.adaptor).prerender) == null || i.call(a, this.rootRenderTarget);
1144
+ }
1145
+ postrender() {
1146
+ var e, t;
1147
+ (t = (e = this.adaptor).postrender) == null || t.call(e, this.rootRenderTarget);
1148
+ }
1149
+ /**
1150
+ * Binding a render surface! This is the main function of the render target system.
1151
+ * It will take the RenderSurface (which can be a texture, canvas, or render target) and bind it to the renderer.
1152
+ * Once bound all draw calls will be rendered to the render surface.
1153
+ *
1154
+ * If a frame is not provide and the render surface is a texture, the frame of the texture will be used.
1155
+ * @param renderSurface - the render surface to bind
1156
+ * @param clear - the clear mode to use. Can be true or a CLEAR number 'COLOR | DEPTH | STENCIL' 0b111
1157
+ * @param clearColor - the color to clear to
1158
+ * @param frame - the frame to render to
1159
+ * @returns the render target that was bound
1160
+ */
1161
+ bind(e, t = !0, r, s) {
1162
+ const a = this.getRenderTarget(e), i = this.renderTarget !== a;
1163
+ this.renderTarget = a, this.renderSurface = e;
1164
+ const o = this.getGpuRenderTarget(a);
1165
+ (a.pixelWidth !== o.width || a.pixelHeight !== o.height) && (this.adaptor.resizeGpuRenderTarget(a), o.width = a.pixelWidth, o.height = a.pixelHeight);
1166
+ const l = a.colorTexture, d = this.viewport, c = l.pixelWidth, h = l.pixelHeight;
1167
+ if (!s && e instanceof m && (s = e.frame), s) {
1168
+ const p = l._resolution;
1169
+ d.x = s.x * p + 0.5 | 0, d.y = s.y * p + 0.5 | 0, d.width = s.width * p + 0.5 | 0, d.height = s.height * p + 0.5 | 0;
1170
+ } else
1171
+ d.x = 0, d.y = 0, d.width = c, d.height = h;
1172
+ return dt(
1173
+ this.projectionMatrix,
1174
+ 0,
1175
+ 0,
1176
+ d.width / l.resolution,
1177
+ d.height / l.resolution,
1178
+ !a.isRoot
1179
+ ), this.adaptor.startRenderPass(a, t, r, d), i && this.onRenderTargetChange.emit(a), a;
1180
+ }
1181
+ clear(e, t = B.ALL, r) {
1182
+ t && (e && (e = this.getRenderTarget(e)), this.adaptor.clear(
1183
+ e || this.renderTarget,
1184
+ t,
1185
+ r,
1186
+ this.viewport
1187
+ ));
1188
+ }
1189
+ contextChange() {
1190
+ this._gpuRenderTargetHash = /* @__PURE__ */ Object.create(null);
1191
+ }
1192
+ /**
1193
+ * Push a render surface to the renderer. This will bind the render surface to the renderer,
1194
+ * @param renderSurface - the render surface to push
1195
+ * @param clear - the clear mode to use. Can be true or a CLEAR number 'COLOR | DEPTH | STENCIL' 0b111
1196
+ * @param clearColor - the color to clear to
1197
+ * @param frame - the frame to use when rendering to the render surface
1198
+ */
1199
+ push(e, t = B.ALL, r, s) {
1200
+ const a = this.bind(e, t, r, s);
1201
+ return this._renderTargetStack.push({
1202
+ renderTarget: a,
1203
+ frame: s
1204
+ }), a;
1205
+ }
1206
+ /** Pops the current render target from the renderer and restores the previous render target. */
1207
+ pop() {
1208
+ this._renderTargetStack.pop();
1209
+ const e = this._renderTargetStack[this._renderTargetStack.length - 1];
1210
+ this.bind(e.renderTarget, !1, null, e.frame);
1211
+ }
1212
+ /**
1213
+ * Gets the render target from the provide render surface. Eg if its a texture,
1214
+ * it will return the render target for the texture.
1215
+ * If its a render target, it will return the same render target.
1216
+ * @param renderSurface - the render surface to get the render target for
1217
+ * @returns the render target for the render surface
1218
+ */
1219
+ getRenderTarget(e) {
1220
+ return e.isTexture && (e = e.source), this._renderSurfaceToRenderTargetHash.get(e) ?? this._initRenderTarget(e);
1221
+ }
1222
+ /**
1223
+ * Copies a render surface to another texture.
1224
+ *
1225
+ * NOTE:
1226
+ * for sourceRenderSurfaceTexture, The render target must be something that is written too by the renderer
1227
+ *
1228
+ * The following is not valid:
1229
+ * @example
1230
+ * const canvas = document.createElement('canvas')
1231
+ * canvas.width = 200;
1232
+ * canvas.height = 200;
1233
+ *
1234
+ * const ctx = canvas2.getContext('2d')!
1235
+ * ctx.fillStyle = 'red'
1236
+ * ctx.fillRect(0, 0, 200, 200);
1237
+ *
1238
+ * const texture = RenderTexture.create({
1239
+ * width: 200,
1240
+ * height: 200,
1241
+ * })
1242
+ * const renderTarget = renderer.renderTarget.getRenderTarget(canvas2);
1243
+ *
1244
+ * renderer.renderTarget.copyToTexture(renderTarget,texture, {x:0,y:0},{width:200,height:200},{x:0,y:0});
1245
+ *
1246
+ * The best way to copy a canvas is to create a texture from it. Then render with that.
1247
+ *
1248
+ * Parsing in a RenderTarget canvas context (with a 2d context)
1249
+ * @param sourceRenderSurfaceTexture - the render surface to copy from
1250
+ * @param destinationTexture - the texture to copy to
1251
+ * @param originSrc - the origin of the copy
1252
+ * @param originSrc.x - the x origin of the copy
1253
+ * @param originSrc.y - the y origin of the copy
1254
+ * @param size - the size of the copy
1255
+ * @param size.width - the width of the copy
1256
+ * @param size.height - the height of the copy
1257
+ * @param originDest - the destination origin (top left to paste from!)
1258
+ * @param originDest.x - the x origin of the paste
1259
+ * @param originDest.y - the y origin of the paste
1260
+ */
1261
+ copyToTexture(e, t, r, s, a) {
1262
+ r.x < 0 && (s.width += r.x, a.x -= r.x, r.x = 0), r.y < 0 && (s.height += r.y, a.y -= r.y, r.y = 0);
1263
+ const { pixelWidth: i, pixelHeight: o } = e;
1264
+ return s.width = Math.min(s.width, i - r.x), s.height = Math.min(s.height, o - r.y), this.adaptor.copyToTexture(
1265
+ e,
1266
+ t,
1267
+ r,
1268
+ s,
1269
+ a
1270
+ );
1271
+ }
1272
+ /**
1273
+ * ensures that we have a depth stencil buffer available to render to
1274
+ * This is used by the mask system to make sure we have a stencil buffer.
1275
+ */
1276
+ ensureDepthStencil() {
1277
+ this.renderTarget.stencil || (this.renderTarget.stencil = !0, this.adaptor.startRenderPass(this.renderTarget, !1, null, this.viewport));
1278
+ }
1279
+ /** nukes the render target system */
1280
+ destroy() {
1281
+ this._renderer = null, this._renderSurfaceToRenderTargetHash.forEach((e, t) => {
1282
+ e !== t && e.destroy();
1283
+ }), this._renderSurfaceToRenderTargetHash.clear(), this._gpuRenderTargetHash = /* @__PURE__ */ Object.create(null);
1284
+ }
1285
+ _initRenderTarget(e) {
1286
+ let t = null;
1287
+ return U.test(e) && (e = ye(e).source), e instanceof G ? t = e : e instanceof T && (t = new G({
1288
+ colorTextures: [e]
1289
+ }), e.source instanceof U && (t.isRoot = !0), e.once("destroy", () => {
1290
+ t.destroy(), this._renderSurfaceToRenderTargetHash.delete(e);
1291
+ const r = this._gpuRenderTargetHash[t.uid];
1292
+ r && (this._gpuRenderTargetHash[t.uid] = null, this.adaptor.destroyGpuRenderTarget(r));
1293
+ })), this._renderSurfaceToRenderTargetHash.set(e, t), t;
1294
+ }
1295
+ getGpuRenderTarget(e) {
1296
+ return this._gpuRenderTargetHash[e.uid] || (this._gpuRenderTargetHash[e.uid] = this.adaptor.initGpuRenderTarget(e));
1297
+ }
1298
+ resetState() {
1299
+ this.renderTarget = null, this.renderSurface = null;
1300
+ }
1301
+ }
1302
+ class Ht extends qe {
1303
+ /**
1304
+ * Create a new Buffer Resource.
1305
+ * @param options - The options for the buffer resource
1306
+ * @param options.buffer - The underlying buffer that this resource is using
1307
+ * @param options.offset - The offset of the buffer this resource is using.
1308
+ * If not provided, then it will use the offset of the buffer.
1309
+ * @param options.size - The size of the buffer this resource is using.
1310
+ * If not provided, then it will use the size of the buffer.
1311
+ */
1312
+ constructor({ buffer: e, offset: t, size: r }) {
1313
+ super(), this.uid = M("buffer"), this._resourceType = "bufferResource", this._touched = 0, this._resourceId = M("resource"), this._bufferResource = !0, this.destroyed = !1, this.buffer = e, this.offset = t | 0, this.size = r, this.buffer.on("change", this.onBufferChange, this);
1314
+ }
1315
+ onBufferChange() {
1316
+ this._resourceId = M("resource"), this.emit("change", this);
1317
+ }
1318
+ /**
1319
+ * Destroys this resource. Make sure the underlying buffer is not used anywhere else
1320
+ * if you want to destroy it as well, or code will explode
1321
+ * @param destroyBuffer - Should the underlying buffer be destroyed as well?
1322
+ */
1323
+ destroy(e = !1) {
1324
+ this.destroyed = !0, e && this.buffer.destroy(), this.emit("change", this), this.buffer = null;
1325
+ }
1326
+ }
1327
+ class Me {
1328
+ constructor(e) {
1329
+ this._renderer = e;
1330
+ }
1331
+ updateRenderable() {
1332
+ }
1333
+ destroyRenderable() {
1334
+ }
1335
+ validateRenderable() {
1336
+ return !1;
1337
+ }
1338
+ addRenderable(e, t) {
1339
+ this._renderer.renderPipes.batch.break(t), t.add(e);
1340
+ }
1341
+ execute(e) {
1342
+ e.isRenderable && e.render(this._renderer);
1343
+ }
1344
+ destroy() {
1345
+ this._renderer = null;
1346
+ }
1347
+ }
1348
+ Me.extension = {
1349
+ type: [
1350
+ u.WebGLPipes,
1351
+ u.WebGPUPipes,
1352
+ u.CanvasPipes
1353
+ ],
1354
+ name: "customRender"
1355
+ };
1356
+ function E(n, e) {
1357
+ const t = n.instructionSet, r = t.instructions;
1358
+ for (let s = 0; s < t.instructionSize; s++) {
1359
+ const a = r[s];
1360
+ e[a.renderPipeId].execute(a);
1361
+ }
1362
+ }
1363
+ const ht = new v();
1364
+ class Se {
1365
+ constructor(e) {
1366
+ this._renderer = e;
1367
+ }
1368
+ addRenderGroup(e, t) {
1369
+ e.isCachedAsTexture ? this._addRenderableCacheAsTexture(e, t) : this._addRenderableDirect(e, t);
1370
+ }
1371
+ execute(e) {
1372
+ e.isRenderable && (e.isCachedAsTexture ? this._executeCacheAsTexture(e) : this._executeDirect(e));
1373
+ }
1374
+ destroy() {
1375
+ this._renderer = null;
1376
+ }
1377
+ _addRenderableDirect(e, t) {
1378
+ this._renderer.renderPipes.batch.break(t), e._batchableRenderGroup && (S.return(e._batchableRenderGroup), e._batchableRenderGroup = null), t.add(e);
1379
+ }
1380
+ _addRenderableCacheAsTexture(e, t) {
1381
+ const r = e._batchableRenderGroup ?? (e._batchableRenderGroup = S.get(me));
1382
+ r.renderable = e.root, r.transform = e.root.relativeGroupTransform, r.texture = e.texture, r.bounds = e._textureBounds, t.add(e), this._renderer.renderPipes.blendMode.pushBlendMode(e, e.root.groupBlendMode, t), this._renderer.renderPipes.batch.addToBatch(r, t), this._renderer.renderPipes.blendMode.popBlendMode(t);
1383
+ }
1384
+ _executeCacheAsTexture(e) {
1385
+ if (e.textureNeedsUpdate) {
1386
+ e.textureNeedsUpdate = !1;
1387
+ const t = ht.identity().translate(
1388
+ -e._textureBounds.x,
1389
+ -e._textureBounds.y
1390
+ );
1391
+ this._renderer.renderTarget.push(e.texture, !0, null, e.texture.frame), this._renderer.globalUniforms.push({
1392
+ worldTransformMatrix: t,
1393
+ worldColor: 4294967295,
1394
+ offset: { x: 0, y: 0 }
1395
+ }), E(e, this._renderer.renderPipes), this._renderer.renderTarget.finishRenderPass(), this._renderer.renderTarget.pop(), this._renderer.globalUniforms.pop();
1396
+ }
1397
+ e._batchableRenderGroup._batcher.updateElement(e._batchableRenderGroup), e._batchableRenderGroup._batcher.geometry.buffers[0].update();
1398
+ }
1399
+ _executeDirect(e) {
1400
+ this._renderer.globalUniforms.push({
1401
+ worldTransformMatrix: e.inverseParentTextureTransform,
1402
+ worldColor: e.worldColorAlpha
1403
+ }), E(e, this._renderer.renderPipes), this._renderer.globalUniforms.pop();
1404
+ }
1405
+ }
1406
+ Se.extension = {
1407
+ type: [
1408
+ u.WebGLPipes,
1409
+ u.WebGPUPipes,
1410
+ u.CanvasPipes
1411
+ ],
1412
+ name: "renderGroup"
1413
+ };
1414
+ function D(n, e) {
1415
+ e || (e = 0);
1416
+ for (let t = e; t < n.length && n[t]; t++)
1417
+ n[t] = null;
1418
+ }
1419
+ const ft = new P(), re = ce | he | fe;
1420
+ function we(n, e = !1) {
1421
+ pt(n);
1422
+ const t = n.childrenToUpdate, r = n.updateTick++;
1423
+ for (const s in t) {
1424
+ const a = Number(s), i = t[s], o = i.list, l = i.index;
1425
+ for (let d = 0; d < l; d++) {
1426
+ const c = o[d];
1427
+ c.parentRenderGroup === n && c.relativeRenderGroupDepth === a && Pe(c, r, 0);
1428
+ }
1429
+ D(o, l), i.index = 0;
1430
+ }
1431
+ if (e)
1432
+ for (let s = 0; s < n.renderGroupChildren.length; s++)
1433
+ we(n.renderGroupChildren[s], e);
1434
+ }
1435
+ function pt(n) {
1436
+ const e = n.root;
1437
+ let t;
1438
+ if (n.renderGroupParent) {
1439
+ const r = n.renderGroupParent;
1440
+ n.worldTransform.appendFrom(
1441
+ e.relativeGroupTransform,
1442
+ r.worldTransform
1443
+ ), n.worldColor = de(
1444
+ e.groupColor,
1445
+ r.worldColor
1446
+ ), t = e.groupAlpha * r.worldAlpha;
1447
+ } else
1448
+ n.worldTransform.copyFrom(e.localTransform), n.worldColor = e.localColor, t = e.localAlpha;
1449
+ t = t < 0 ? 0 : t > 1 ? 1 : t, n.worldAlpha = t, n.worldColorAlpha = n.worldColor + ((t * 255 | 0) << 24);
1450
+ }
1451
+ function Pe(n, e, t) {
1452
+ if (e === n.updateTick)
1453
+ return;
1454
+ n.updateTick = e, n.didChange = !1;
1455
+ const r = n.localTransform;
1456
+ n.updateLocalTransform();
1457
+ const s = n.parent;
1458
+ if (s && !s.renderGroup ? (t |= n._updateFlags, n.relativeGroupTransform.appendFrom(
1459
+ r,
1460
+ s.relativeGroupTransform
1461
+ ), t & re && se(n, s, t)) : (t = n._updateFlags, n.relativeGroupTransform.copyFrom(r), t & re && se(n, ft, t)), !n.renderGroup) {
1462
+ const a = n.children, i = a.length;
1463
+ for (let d = 0; d < i; d++)
1464
+ Pe(a[d], e, t);
1465
+ const o = n.parentRenderGroup, l = n;
1466
+ l.renderPipeId && !o.structureDidChange && o.updateRenderable(l);
1467
+ }
1468
+ }
1469
+ function se(n, e, t) {
1470
+ if (t & he) {
1471
+ n.groupColor = de(
1472
+ n.localColor,
1473
+ e.groupColor
1474
+ );
1475
+ let r = n.localAlpha * e.groupAlpha;
1476
+ r = r < 0 ? 0 : r > 1 ? 1 : r, n.groupAlpha = r, n.groupColorAlpha = n.groupColor + ((r * 255 | 0) << 24);
1477
+ }
1478
+ t & fe && (n.groupBlendMode = n.localBlendMode === "inherit" ? e.groupBlendMode : n.localBlendMode), t & ce && (n.globalDisplayStatus = n.localDisplayStatus & e.globalDisplayStatus), n._updateFlags = 0;
1479
+ }
1480
+ function mt(n, e) {
1481
+ const { list: t, index: r } = n.childrenRenderablesToUpdate;
1482
+ let s = !1;
1483
+ for (let a = 0; a < r; a++) {
1484
+ const i = t[a];
1485
+ if (s = e[i.renderPipeId].validateRenderable(i), s)
1486
+ break;
1487
+ }
1488
+ return n.structureDidChange = s, s;
1489
+ }
1490
+ const vt = new v();
1491
+ class Re {
1492
+ constructor(e) {
1493
+ this._renderer = e;
1494
+ }
1495
+ render({ container: e, transform: t }) {
1496
+ const r = e.parent, s = e.renderGroup.renderGroupParent;
1497
+ e.parent = null, e.renderGroup.renderGroupParent = null;
1498
+ const a = this._renderer, i = vt;
1499
+ t && (i.copyFrom(e.renderGroup.localTransform), e.renderGroup.localTransform.copyFrom(t));
1500
+ const o = a.renderPipes;
1501
+ this._updateCachedRenderGroups(e.renderGroup, null), this._updateRenderGroups(e.renderGroup), a.globalUniforms.start({
1502
+ worldTransformMatrix: t ? e.renderGroup.localTransform : e.renderGroup.worldTransform,
1503
+ worldColor: e.renderGroup.worldColorAlpha
1504
+ }), E(e.renderGroup, o), o.uniformBatch && o.uniformBatch.renderEnd(), t && e.renderGroup.localTransform.copyFrom(i), e.parent = r, e.renderGroup.renderGroupParent = s;
1505
+ }
1506
+ destroy() {
1507
+ this._renderer = null;
1508
+ }
1509
+ _updateCachedRenderGroups(e, t) {
1510
+ if (e._parentCacheAsTextureRenderGroup = t, e.isCachedAsTexture) {
1511
+ if (!e.textureNeedsUpdate)
1512
+ return;
1513
+ t = e;
1514
+ }
1515
+ for (let r = e.renderGroupChildren.length - 1; r >= 0; r--)
1516
+ this._updateCachedRenderGroups(e.renderGroupChildren[r], t);
1517
+ if (e.invalidateMatrices(), e.isCachedAsTexture) {
1518
+ if (e.textureNeedsUpdate) {
1519
+ const r = e.root.getLocalBounds();
1520
+ r.ceil();
1521
+ const s = e.texture;
1522
+ e.texture && b.returnTexture(e.texture, !0);
1523
+ const a = this._renderer, i = e.textureOptions.resolution || a.view.resolution, o = e.textureOptions.antialias ?? a.view.antialias, l = e.textureOptions.scaleMode ?? "linear", d = b.getOptimalTexture(
1524
+ r.width,
1525
+ r.height,
1526
+ i,
1527
+ o
1528
+ );
1529
+ d._source.style = new Ke({ scaleMode: l }), e.texture = d, e._textureBounds || (e._textureBounds = new F()), e._textureBounds.copyFrom(r), s !== e.texture && e.renderGroupParent && (e.renderGroupParent.structureDidChange = !0);
1530
+ }
1531
+ } else e.texture && (b.returnTexture(e.texture, !0), e.texture = null);
1532
+ }
1533
+ _updateRenderGroups(e) {
1534
+ const t = this._renderer, r = t.renderPipes;
1535
+ if (e.runOnRender(t), e.instructionSet.renderPipes = r, e.structureDidChange ? D(e.childrenRenderablesToUpdate.list, 0) : mt(e, r), we(e), e.structureDidChange ? (e.structureDidChange = !1, this._buildInstructions(e, t)) : this._updateRenderables(e), e.childrenRenderablesToUpdate.index = 0, t.renderPipes.batch.upload(e.instructionSet), !(e.isCachedAsTexture && !e.textureNeedsUpdate))
1536
+ for (let s = 0; s < e.renderGroupChildren.length; s++)
1537
+ this._updateRenderGroups(e.renderGroupChildren[s]);
1538
+ }
1539
+ _updateRenderables(e) {
1540
+ const { list: t, index: r } = e.childrenRenderablesToUpdate;
1541
+ for (let s = 0; s < r; s++) {
1542
+ const a = t[s];
1543
+ a.didViewUpdate && e.updateRenderable(a);
1544
+ }
1545
+ D(t, r);
1546
+ }
1547
+ _buildInstructions(e, t) {
1548
+ const r = e.root, s = e.instructionSet;
1549
+ s.reset();
1550
+ const a = t.renderPipes ? t : t.batch.renderer, i = a.renderPipes;
1551
+ i.batch.buildStart(s), i.blendMode.buildStart(), i.colorMask.buildStart(), r.sortableChildren && r.sortChildren(), r.collectRenderablesWithEffects(s, a, null), i.batch.buildEnd(s), i.blendMode.buildEnd(s);
1552
+ }
1553
+ }
1554
+ Re.extension = {
1555
+ type: [
1556
+ u.WebGLSystem,
1557
+ u.WebGPUSystem,
1558
+ u.CanvasSystem
1559
+ ],
1560
+ name: "renderGroup"
1561
+ };
1562
+ class Be {
1563
+ constructor(e) {
1564
+ this._renderer = e;
1565
+ }
1566
+ addRenderable(e, t) {
1567
+ const r = this._getGpuSprite(e);
1568
+ e.didViewUpdate && this._updateBatchableSprite(e, r), this._renderer.renderPipes.batch.addToBatch(r, t);
1569
+ }
1570
+ updateRenderable(e) {
1571
+ const t = this._getGpuSprite(e);
1572
+ e.didViewUpdate && this._updateBatchableSprite(e, t), t._batcher.updateElement(t);
1573
+ }
1574
+ validateRenderable(e) {
1575
+ const t = this._getGpuSprite(e);
1576
+ return !t._batcher.checkAndUpdateTexture(
1577
+ t,
1578
+ e._texture
1579
+ );
1580
+ }
1581
+ _updateBatchableSprite(e, t) {
1582
+ t.bounds = e.visualBounds, t.texture = e._texture;
1583
+ }
1584
+ _getGpuSprite(e) {
1585
+ return e._gpuData[this._renderer.uid] || this._initGPUSprite(e);
1586
+ }
1587
+ _initGPUSprite(e) {
1588
+ const t = new me();
1589
+ return t.renderable = e, t.transform = e.groupTransform, t.texture = e._texture, t.bounds = e.visualBounds, t.roundPixels = this._renderer._roundPixels | e._roundPixels, e._gpuData[this._renderer.uid] = t, t;
1590
+ }
1591
+ destroy() {
1592
+ this._renderer = null;
1593
+ }
1594
+ }
1595
+ Be.extension = {
1596
+ type: [
1597
+ u.WebGLPipes,
1598
+ u.WebGPUPipes,
1599
+ u.CanvasPipes
1600
+ ],
1601
+ name: "sprite"
1602
+ };
1603
+ const V = class Ue {
1604
+ constructor() {
1605
+ this.clearBeforeRender = !0, this._backgroundColor = new A(0), this.color = this._backgroundColor, this.alpha = 1;
1606
+ }
1607
+ /**
1608
+ * initiates the background system
1609
+ * @param options - the options for the background colors
1610
+ */
1611
+ init(e) {
1612
+ e = { ...Ue.defaultOptions, ...e }, this.clearBeforeRender = e.clearBeforeRender, this.color = e.background || e.backgroundColor || this._backgroundColor, this.alpha = e.backgroundAlpha, this._backgroundColor.setAlpha(e.backgroundAlpha);
1613
+ }
1614
+ /** The background color to fill if not transparent */
1615
+ get color() {
1616
+ return this._backgroundColor;
1617
+ }
1618
+ set color(e) {
1619
+ A.shared.setValue(e).alpha < 1 && this._backgroundColor.alpha === 1 && H(
1620
+ "Cannot set a transparent background on an opaque canvas. To enable transparency, set backgroundAlpha < 1 when initializing your Application."
1621
+ ), this._backgroundColor.setValue(e);
1622
+ }
1623
+ /** The background color alpha. Setting this to 0 will make the canvas transparent. */
1624
+ get alpha() {
1625
+ return this._backgroundColor.alpha;
1626
+ }
1627
+ set alpha(e) {
1628
+ this._backgroundColor.setAlpha(e);
1629
+ }
1630
+ /** The background color as an [R, G, B, A] array. */
1631
+ get colorRgba() {
1632
+ return this._backgroundColor.toArray();
1633
+ }
1634
+ /**
1635
+ * destroys the background system
1636
+ * @internal
1637
+ */
1638
+ destroy() {
1639
+ }
1640
+ };
1641
+ V.extension = {
1642
+ type: [
1643
+ u.WebGLSystem,
1644
+ u.WebGPUSystem,
1645
+ u.CanvasSystem
1646
+ ],
1647
+ name: "background",
1648
+ priority: 0
1649
+ };
1650
+ V.defaultOptions = {
1651
+ /**
1652
+ * {@link WebGLOptions.backgroundAlpha}
1653
+ * @default 1
1654
+ */
1655
+ backgroundAlpha: 1,
1656
+ /**
1657
+ * {@link WebGLOptions.backgroundColor}
1658
+ * @default 0x000000
1659
+ */
1660
+ backgroundColor: 0,
1661
+ /**
1662
+ * {@link WebGLOptions.clearBeforeRender}
1663
+ * @default true
1664
+ */
1665
+ clearBeforeRender: !0
1666
+ };
1667
+ let gt = V;
1668
+ const y = {};
1669
+ O.handle(u.BlendMode, (n) => {
1670
+ if (!n.name)
1671
+ throw new Error("BlendMode extension must have a name property");
1672
+ y[n.name] = n.ref;
1673
+ }, (n) => {
1674
+ delete y[n.name];
1675
+ });
1676
+ class Ae {
1677
+ constructor(e) {
1678
+ this._blendModeStack = [], this._isAdvanced = !1, this._filterHash = /* @__PURE__ */ Object.create(null), this._renderer = e, this._renderer.runners.prerender.add(this);
1679
+ }
1680
+ prerender() {
1681
+ this._activeBlendMode = "normal", this._isAdvanced = !1;
1682
+ }
1683
+ /**
1684
+ * Push a blend mode onto the internal stack and apply it to the instruction set if needed.
1685
+ * @param renderable - The renderable or {@link RenderGroup} associated with the change.
1686
+ * @param blendMode - The blend mode to activate.
1687
+ * @param instructionSet - The instruction set being built.
1688
+ */
1689
+ pushBlendMode(e, t, r) {
1690
+ this._blendModeStack.push(t), this.setBlendMode(e, t, r);
1691
+ }
1692
+ /**
1693
+ * Pop the last blend mode from the stack and apply the new top-of-stack mode.
1694
+ * @param instructionSet - The instruction set being built.
1695
+ */
1696
+ popBlendMode(e) {
1697
+ this._blendModeStack.pop();
1698
+ const t = this._blendModeStack[this._activeBlendMode.length - 1] ?? "normal";
1699
+ this.setBlendMode(null, t, e);
1700
+ }
1701
+ /**
1702
+ * Ensure a blend mode switch is added to the instruction set when the mode changes.
1703
+ * If an advanced blend mode is active, subsequent renderables will be collected so they can be
1704
+ * rendered within a single filter pass.
1705
+ * @param renderable - The renderable or {@link RenderGroup} to associate with the change, or null when unwinding.
1706
+ * @param blendMode - The target blend mode.
1707
+ * @param instructionSet - The instruction set being built.
1708
+ */
1709
+ setBlendMode(e, t, r) {
1710
+ var a;
1711
+ const s = e instanceof Q;
1712
+ if (this._activeBlendMode === t) {
1713
+ this._isAdvanced && e && !s && ((a = this._renderableList) == null || a.push(e));
1714
+ return;
1715
+ }
1716
+ this._isAdvanced && this._endAdvancedBlendMode(r), this._activeBlendMode = t, e && (this._isAdvanced = !!y[t], this._isAdvanced && this._beginAdvancedBlendMode(e, r));
1717
+ }
1718
+ _beginAdvancedBlendMode(e, t) {
1719
+ this._renderer.renderPipes.batch.break(t);
1720
+ const r = this._activeBlendMode;
1721
+ if (!y[r]) {
1722
+ H(`Unable to assign BlendMode: '${r}'. You may want to include: import 'pixi.js/advanced-blend-modes'`);
1723
+ return;
1724
+ }
1725
+ const s = this._ensureFilterEffect(r), a = e instanceof Q, i = {
1726
+ renderPipeId: "filter",
1727
+ action: "pushFilter",
1728
+ filterEffect: s,
1729
+ renderables: a ? null : [e],
1730
+ container: a ? e.root : null,
1731
+ canBundle: !1
1732
+ };
1733
+ this._renderableList = i.renderables, t.add(i);
1734
+ }
1735
+ _ensureFilterEffect(e) {
1736
+ let t = this._filterHash[e];
1737
+ return t || (t = this._filterHash[e] = new ue(), t.filters = [new y[e]()]), t;
1738
+ }
1739
+ _endAdvancedBlendMode(e) {
1740
+ this._isAdvanced = !1, this._renderableList = null, this._renderer.renderPipes.batch.break(e), e.add({
1741
+ renderPipeId: "filter",
1742
+ action: "popFilter",
1743
+ canBundle: !1
1744
+ });
1745
+ }
1746
+ /**
1747
+ * called when the instruction build process is starting this will reset internally to the default blend mode
1748
+ * @internal
1749
+ */
1750
+ buildStart() {
1751
+ this._isAdvanced = !1;
1752
+ }
1753
+ /**
1754
+ * called when the instruction build process is finished, ensuring that if there is an advanced blend mode
1755
+ * active, we add the final render instructions added to the instruction set
1756
+ * @param instructionSet - The instruction set we are adding to
1757
+ * @internal
1758
+ */
1759
+ buildEnd(e) {
1760
+ this._isAdvanced && this._endAdvancedBlendMode(e);
1761
+ }
1762
+ /** @internal */
1763
+ destroy() {
1764
+ this._renderer = null, this._renderableList = null;
1765
+ for (const e in this._filterHash)
1766
+ this._filterHash[e].destroy();
1767
+ this._filterHash = null;
1768
+ }
1769
+ }
1770
+ Ae.extension = {
1771
+ type: [
1772
+ u.WebGLPipes,
1773
+ u.WebGPUPipes,
1774
+ u.CanvasPipes
1775
+ ],
1776
+ name: "blendMode"
1777
+ };
1778
+ const R = {
1779
+ png: "image/png",
1780
+ jpg: "image/jpeg",
1781
+ webp: "image/webp"
1782
+ }, N = class Ie {
1783
+ /** @param renderer - The renderer this System works for. */
1784
+ constructor(e) {
1785
+ this._renderer = e;
1786
+ }
1787
+ _normalizeOptions(e, t = {}) {
1788
+ return e instanceof P || e instanceof m ? {
1789
+ target: e,
1790
+ ...t
1791
+ } : {
1792
+ ...t,
1793
+ ...e
1794
+ };
1795
+ }
1796
+ /**
1797
+ * Creates an IImage from a display object or texture.
1798
+ * @param options - Options for creating the image, or the target to extract
1799
+ * @returns Promise that resolves with the generated IImage
1800
+ * @example
1801
+ * ```ts
1802
+ * // Basic usage with a sprite
1803
+ * const sprite = new Sprite(texture);
1804
+ * const image = await renderer.extract.image(sprite);
1805
+ * document.body.appendChild(image);
1806
+ *
1807
+ * // Advanced usage with options
1808
+ * const image = await renderer.extract.image({
1809
+ * target: container,
1810
+ * format: 'webp',
1811
+ * quality: 0.8,
1812
+ * frame: new Rectangle(0, 0, 100, 100),
1813
+ * resolution: 2,
1814
+ * clearColor: '#ff0000',
1815
+ * antialias: true
1816
+ * });
1817
+ *
1818
+ * // Extract directly from a texture
1819
+ * const texture = Texture.from('myTexture.png');
1820
+ * const image = await renderer.extract.image(texture);
1821
+ * ```
1822
+ * @see {@link ExtractImageOptions} For detailed options
1823
+ * @see {@link ExtractSystem.base64} For base64 string output
1824
+ * @see {@link ExtractSystem.canvas} For canvas output
1825
+ * @see {@link ImageLike} For the image interface
1826
+ * @category rendering
1827
+ */
1828
+ async image(e) {
1829
+ const t = z.get().createImage();
1830
+ return t.src = await this.base64(e), t;
1831
+ }
1832
+ /**
1833
+ * Converts the target into a base64 encoded string.
1834
+ *
1835
+ * This method works by first creating
1836
+ * a canvas using `Extract.canvas` and then converting it to a base64 string.
1837
+ * @param options - The options for creating the base64 string, or the target to extract
1838
+ * @returns Promise that resolves with the base64 encoded string
1839
+ * @example
1840
+ * ```ts
1841
+ * // Basic usage with a sprite
1842
+ * const sprite = new Sprite(texture);
1843
+ * const base64 = await renderer.extract.base64(sprite);
1844
+ * console.log(base64); // data:image/png;base64,...
1845
+ *
1846
+ * // Advanced usage with options
1847
+ * const base64 = await renderer.extract.base64({
1848
+ * target: container,
1849
+ * format: 'webp',
1850
+ * quality: 0.8,
1851
+ * frame: new Rectangle(0, 0, 100, 100),
1852
+ * resolution: 2
1853
+ * });
1854
+ * ```
1855
+ * @throws Will throw an error if the platform doesn't support any of:
1856
+ * - ICanvas.toDataURL
1857
+ * - ICanvas.toBlob
1858
+ * - ICanvas.convertToBlob
1859
+ * @see {@link ExtractImageOptions} For detailed options
1860
+ * @see {@link ExtractSystem.canvas} For canvas output
1861
+ * @see {@link ExtractSystem.image} For HTMLImage output
1862
+ * @category rendering
1863
+ */
1864
+ async base64(e) {
1865
+ e = this._normalizeOptions(
1866
+ e,
1867
+ Ie.defaultImageOptions
1868
+ );
1869
+ const { format: t, quality: r } = e, s = this.canvas(e);
1870
+ if (s.toBlob !== void 0)
1871
+ return new Promise((a, i) => {
1872
+ s.toBlob((o) => {
1873
+ if (!o) {
1874
+ i(new Error("ICanvas.toBlob failed!"));
1875
+ return;
1876
+ }
1877
+ const l = new FileReader();
1878
+ l.onload = () => a(l.result), l.onerror = i, l.readAsDataURL(o);
1879
+ }, R[t], r);
1880
+ });
1881
+ if (s.toDataURL !== void 0)
1882
+ return s.toDataURL(R[t], r);
1883
+ if (s.convertToBlob !== void 0) {
1884
+ const a = await s.convertToBlob({ type: R[t], quality: r });
1885
+ return new Promise((i, o) => {
1886
+ const l = new FileReader();
1887
+ l.onload = () => i(l.result), l.onerror = o, l.readAsDataURL(a);
1888
+ });
1889
+ }
1890
+ throw new Error("Extract.base64() requires ICanvas.toDataURL, ICanvas.toBlob, or ICanvas.convertToBlob to be implemented");
1891
+ }
1892
+ /**
1893
+ * Creates a Canvas element, renders the target to it and returns it.
1894
+ * This method is useful for creating static images or when you need direct canvas access.
1895
+ * @param options - The options for creating the canvas, or the target to extract
1896
+ * @returns A Canvas element with the texture rendered on
1897
+ * @example
1898
+ * ```ts
1899
+ * // Basic canvas extraction from a sprite
1900
+ * const sprite = new Sprite(texture);
1901
+ * const canvas = renderer.extract.canvas(sprite);
1902
+ * document.body.appendChild(canvas);
1903
+ *
1904
+ * // Extract with custom region
1905
+ * const canvas = renderer.extract.canvas({
1906
+ * target: container,
1907
+ * frame: new Rectangle(0, 0, 100, 100)
1908
+ * });
1909
+ *
1910
+ * // Extract with high resolution
1911
+ * const canvas = renderer.extract.canvas({
1912
+ * target: sprite,
1913
+ * resolution: 2,
1914
+ * clearColor: '#ff0000'
1915
+ * });
1916
+ *
1917
+ * // Extract directly from a texture
1918
+ * const texture = Texture.from('myTexture.png');
1919
+ * const canvas = renderer.extract.canvas(texture);
1920
+ *
1921
+ * // Extract with anti-aliasing
1922
+ * const canvas = renderer.extract.canvas({
1923
+ * target: graphics,
1924
+ * antialias: true
1925
+ * });
1926
+ * ```
1927
+ * @see {@link ExtractOptions} For detailed options
1928
+ * @see {@link ExtractSystem.image} For HTMLImage output
1929
+ * @see {@link ExtractSystem.pixels} For raw pixel data
1930
+ * @category rendering
1931
+ */
1932
+ canvas(e) {
1933
+ e = this._normalizeOptions(e);
1934
+ const t = e.target, r = this._renderer;
1935
+ if (t instanceof m)
1936
+ return r.texture.generateCanvas(t);
1937
+ const s = r.textureGenerator.generateTexture(e), a = r.texture.generateCanvas(s);
1938
+ return s.destroy(!0), a;
1939
+ }
1940
+ /**
1941
+ * Returns a one-dimensional array containing the pixel data of the entire texture in RGBA order,
1942
+ * with integer values between 0 and 255 (inclusive).
1943
+ * > [!NOE] The returned array is a flat Uint8Array where every 4 values represent RGBA
1944
+ * @param options - The options for extracting the image, or the target to extract
1945
+ * @returns One-dimensional Uint8Array containing the pixel data in RGBA format
1946
+ * @example
1947
+ * ```ts
1948
+ * // Basic pixel extraction
1949
+ * const sprite = new Sprite(texture);
1950
+ * const pixels = renderer.extract.pixels(sprite);
1951
+ * console.log(pixels[0], pixels[1], pixels[2], pixels[3]); // R,G,B,A values
1952
+ *
1953
+ * // Extract with custom region
1954
+ * const pixels = renderer.extract.pixels({
1955
+ * target: sprite,
1956
+ * frame: new Rectangle(0, 0, 100, 100)
1957
+ * });
1958
+ *
1959
+ * // Extract with high resolution
1960
+ * const pixels = renderer.extract.pixels({
1961
+ * target: sprite,
1962
+ * resolution: 2
1963
+ * });
1964
+ * ```
1965
+ * @see {@link ExtractOptions} For detailed options
1966
+ * @see {@link ExtractSystem.canvas} For canvas output
1967
+ * @see {@link ExtractSystem.image} For image output
1968
+ * @category rendering
1969
+ */
1970
+ pixels(e) {
1971
+ e = this._normalizeOptions(e);
1972
+ const t = e.target, r = this._renderer, s = t instanceof m ? t : r.textureGenerator.generateTexture(e), a = r.texture.getPixels(s);
1973
+ return t instanceof P && s.destroy(!0), a;
1974
+ }
1975
+ /**
1976
+ * Creates a texture from a display object or existing texture.
1977
+ *
1978
+ * This is useful for creating
1979
+ * reusable textures from rendered content or making copies of existing textures.
1980
+ * > [!NOTE] The returned texture should be destroyed when no longer needed
1981
+ * @param options - The options for creating the texture, or the target to extract
1982
+ * @returns A new texture containing the extracted content
1983
+ * @example
1984
+ * ```ts
1985
+ * // Basic texture extraction from a sprite
1986
+ * const sprite = new Sprite(texture);
1987
+ * const extractedTexture = renderer.extract.texture(sprite);
1988
+ *
1989
+ * // Extract with custom region
1990
+ * const regionTexture = renderer.extract.texture({
1991
+ * target: container,
1992
+ * frame: new Rectangle(0, 0, 100, 100)
1993
+ * });
1994
+ *
1995
+ * // Extract with high resolution
1996
+ * const hiResTexture = renderer.extract.texture({
1997
+ * target: sprite,
1998
+ * resolution: 2,
1999
+ * clearColor: '#ff0000'
2000
+ * });
2001
+ *
2002
+ * // Create a new sprite from extracted texture
2003
+ * const newSprite = new Sprite(
2004
+ * renderer.extract.texture({
2005
+ * target: graphics,
2006
+ * antialias: true
2007
+ * })
2008
+ * );
2009
+ *
2010
+ * // Clean up when done
2011
+ * extractedTexture.destroy(true);
2012
+ * ```
2013
+ * @see {@link ExtractOptions} For detailed options
2014
+ * @see {@link Texture} For texture management
2015
+ * @see {@link GenerateTextureSystem} For texture generation
2016
+ * @category rendering
2017
+ */
2018
+ texture(e) {
2019
+ return e = this._normalizeOptions(e), e.target instanceof m ? e.target : this._renderer.textureGenerator.generateTexture(e);
2020
+ }
2021
+ /**
2022
+ * Extracts and downloads content from the renderer as an image file.
2023
+ * This is a convenient way to save screenshots or export rendered content.
2024
+ * > [!NOTE] The download will use PNG format regardless of the filename extension
2025
+ * @param options - The options for downloading and extracting the image, or the target to extract
2026
+ * @example
2027
+ * ```ts
2028
+ * // Basic download with default filename
2029
+ * const sprite = new Sprite(texture);
2030
+ * renderer.extract.download(sprite); // Downloads as 'image.png'
2031
+ *
2032
+ * // Download with custom filename
2033
+ * renderer.extract.download({
2034
+ * target: sprite,
2035
+ * filename: 'screenshot.png'
2036
+ * });
2037
+ *
2038
+ * // Download with custom region
2039
+ * renderer.extract.download({
2040
+ * target: container,
2041
+ * filename: 'region.png',
2042
+ * frame: new Rectangle(0, 0, 100, 100)
2043
+ * });
2044
+ *
2045
+ * // Download with high resolution and background
2046
+ * renderer.extract.download({
2047
+ * target: stage,
2048
+ * filename: 'hd-screenshot.png',
2049
+ * resolution: 2,
2050
+ * clearColor: '#ff0000'
2051
+ * });
2052
+ *
2053
+ * // Download with anti-aliasing
2054
+ * renderer.extract.download({
2055
+ * target: graphics,
2056
+ * filename: 'smooth.png',
2057
+ * antialias: true
2058
+ * });
2059
+ * ```
2060
+ * @see {@link ExtractDownloadOptions} For detailed options
2061
+ * @see {@link ExtractSystem.image} For creating images without download
2062
+ * @see {@link ExtractSystem.canvas} For canvas output
2063
+ * @category rendering
2064
+ */
2065
+ download(e) {
2066
+ e = this._normalizeOptions(e);
2067
+ const t = this.canvas(e), r = document.createElement("a");
2068
+ r.download = e.filename ?? "image.png", r.href = t.toDataURL("image/png"), document.body.appendChild(r), r.click(), document.body.removeChild(r);
2069
+ }
2070
+ /**
2071
+ * Logs the target to the console as an image. This is a useful way to debug what's happening in the renderer.
2072
+ * The image will be displayed in the browser's console using CSS background images.
2073
+ * @param options - The options for logging the image, or the target to log
2074
+ * @param options.width - The width of the logged image preview in the console (in pixels)
2075
+ * @example
2076
+ * ```ts
2077
+ * // Basic usage
2078
+ * const sprite = new Sprite(texture);
2079
+ * renderer.extract.log(sprite);
2080
+ * ```
2081
+ * @see {@link ExtractSystem.canvas} For getting raw canvas output
2082
+ * @see {@link ExtractSystem.pixels} For raw pixel data
2083
+ * @category rendering
2084
+ * @advanced
2085
+ */
2086
+ log(e) {
2087
+ const t = e.width ?? 200;
2088
+ e = this._normalizeOptions(e);
2089
+ const r = this.canvas(e), s = r.toDataURL();
2090
+ console.log(`[Pixi Texture] ${r.width}px ${r.height}px`);
2091
+ const a = [
2092
+ "font-size: 1px;",
2093
+ `padding: ${t}px 300px;`,
2094
+ `background: url(${s}) no-repeat;`,
2095
+ "background-size: contain;"
2096
+ ].join(" ");
2097
+ console.log("%c ", a);
2098
+ }
2099
+ destroy() {
2100
+ this._renderer = null;
2101
+ }
2102
+ };
2103
+ N.extension = {
2104
+ type: [
2105
+ u.WebGLSystem,
2106
+ u.WebGPUSystem
2107
+ ],
2108
+ name: "extract"
2109
+ };
2110
+ N.defaultImageOptions = {
2111
+ format: "png",
2112
+ quality: 1
2113
+ };
2114
+ let xt = N;
2115
+ class j extends m {
2116
+ static create(e) {
2117
+ return new j({
2118
+ source: new T(e)
2119
+ });
2120
+ }
2121
+ /**
2122
+ * Resizes the render texture.
2123
+ * @param width - The new width of the render texture.
2124
+ * @param height - The new height of the render texture.
2125
+ * @param resolution - The new resolution of the render texture.
2126
+ * @returns This texture.
2127
+ */
2128
+ resize(e, t, r) {
2129
+ return this.source.resize(e, t, r), this;
2130
+ }
2131
+ }
2132
+ const _t = new w(), bt = new F(), Tt = [0, 0, 0, 0];
2133
+ class Ge {
2134
+ constructor(e) {
2135
+ this._renderer = e;
2136
+ }
2137
+ /**
2138
+ * Creates a texture from a display object that can be used for creating sprites and other textures.
2139
+ * This is particularly useful for optimizing performance when a complex container needs to be reused.
2140
+ * @param options - Generate texture options or a container to convert to texture
2141
+ * @returns A new RenderTexture containing the rendered display object
2142
+ * @example
2143
+ * ```ts
2144
+ * // Basic usage with a container
2145
+ * const container = new Container();
2146
+ * container.addChild(
2147
+ * new Graphics()
2148
+ * .circle(0, 0, 50)
2149
+ * .fill('red')
2150
+ * );
2151
+ *
2152
+ * const texture = renderer.textureGenerator.generateTexture(container);
2153
+ *
2154
+ * // Advanced usage with options
2155
+ * const texture = renderer.textureGenerator.generateTexture({
2156
+ * target: container,
2157
+ * frame: new Rectangle(0, 0, 100, 100), // Specific region
2158
+ * resolution: 2, // High DPI
2159
+ * clearColor: '#ff0000', // Red background
2160
+ * antialias: true // Smooth edges
2161
+ * });
2162
+ *
2163
+ * // Create a sprite from the generated texture
2164
+ * const sprite = new Sprite(texture);
2165
+ *
2166
+ * // Clean up when done
2167
+ * texture.destroy(true);
2168
+ * ```
2169
+ * @see {@link GenerateTextureOptions} For detailed texture generation options
2170
+ * @see {@link RenderTexture} For the type of texture created
2171
+ * @category rendering
2172
+ */
2173
+ generateTexture(e) {
2174
+ var d;
2175
+ e instanceof P && (e = {
2176
+ target: e,
2177
+ frame: void 0,
2178
+ textureSourceOptions: {},
2179
+ resolution: void 0
2180
+ });
2181
+ const t = e.resolution || this._renderer.resolution, r = e.antialias || this._renderer.view.antialias, s = e.target;
2182
+ let a = e.clearColor;
2183
+ a ? a = Array.isArray(a) && a.length === 4 ? a : A.shared.setValue(a).toArray() : a = Tt;
2184
+ const i = ((d = e.frame) == null ? void 0 : d.copyTo(_t)) || Ye(s, bt).rectangle;
2185
+ i.width = Math.max(i.width, 1 / t) | 0, i.height = Math.max(i.height, 1 / t) | 0;
2186
+ const o = j.create({
2187
+ ...e.textureSourceOptions,
2188
+ width: i.width,
2189
+ height: i.height,
2190
+ resolution: t,
2191
+ antialias: r
2192
+ }), l = v.shared.translate(-i.x, -i.y);
2193
+ return this._renderer.render({
2194
+ container: s,
2195
+ transform: l,
2196
+ target: o,
2197
+ clearColor: a
2198
+ }), o.source.updateMipmaps(), o;
2199
+ }
2200
+ destroy() {
2201
+ this._renderer = null;
2202
+ }
2203
+ }
2204
+ Ge.extension = {
2205
+ type: [
2206
+ u.WebGLSystem,
2207
+ u.WebGPUSystem
2208
+ ],
2209
+ name: "textureGenerator"
2210
+ };
2211
+ class Ee {
2212
+ constructor(e) {
2213
+ this._stackIndex = 0, this._globalUniformDataStack = [], this._uniformsPool = [], this._activeUniforms = [], this._bindGroupPool = [], this._activeBindGroups = [], this._renderer = e;
2214
+ }
2215
+ reset() {
2216
+ this._stackIndex = 0;
2217
+ for (let e = 0; e < this._activeUniforms.length; e++)
2218
+ this._uniformsPool.push(this._activeUniforms[e]);
2219
+ for (let e = 0; e < this._activeBindGroups.length; e++)
2220
+ this._bindGroupPool.push(this._activeBindGroups[e]);
2221
+ this._activeUniforms.length = 0, this._activeBindGroups.length = 0;
2222
+ }
2223
+ start(e) {
2224
+ this.reset(), this.push(e);
2225
+ }
2226
+ bind({
2227
+ size: e,
2228
+ projectionMatrix: t,
2229
+ worldTransformMatrix: r,
2230
+ worldColor: s,
2231
+ offset: a
2232
+ }) {
2233
+ const i = this._renderer.renderTarget.renderTarget, o = this._stackIndex ? this._globalUniformDataStack[this._stackIndex - 1] : {
2234
+ worldTransformMatrix: new v(),
2235
+ worldColor: 4294967295,
2236
+ offset: new Je()
2237
+ }, l = {
2238
+ projectionMatrix: t || this._renderer.renderTarget.projectionMatrix,
2239
+ resolution: e || i.size,
2240
+ worldTransformMatrix: r || o.worldTransformMatrix,
2241
+ worldColor: s || o.worldColor,
2242
+ offset: a || o.offset,
2243
+ bindGroup: null
2244
+ }, d = this._uniformsPool.pop() || this._createUniforms();
2245
+ this._activeUniforms.push(d);
2246
+ const c = d.uniforms;
2247
+ c.uProjectionMatrix = l.projectionMatrix, c.uResolution = l.resolution, c.uWorldTransformMatrix.copyFrom(l.worldTransformMatrix), c.uWorldTransformMatrix.tx -= l.offset.x, c.uWorldTransformMatrix.ty -= l.offset.y, tt(
2248
+ l.worldColor,
2249
+ c.uWorldColorAlpha,
2250
+ 0
2251
+ ), d.update();
2252
+ let h;
2253
+ this._renderer.renderPipes.uniformBatch ? h = this._renderer.renderPipes.uniformBatch.getUniformBindGroup(d, !1) : (h = this._bindGroupPool.pop() || new Xe(), this._activeBindGroups.push(h), h.setResource(d, 0)), l.bindGroup = h, this._currentGlobalUniformData = l;
2254
+ }
2255
+ push(e) {
2256
+ this.bind(e), this._globalUniformDataStack[this._stackIndex++] = this._currentGlobalUniformData;
2257
+ }
2258
+ pop() {
2259
+ this._currentGlobalUniformData = this._globalUniformDataStack[--this._stackIndex - 1], this._renderer.type === L.WEBGL && this._currentGlobalUniformData.bindGroup.resources[0].update();
2260
+ }
2261
+ get bindGroup() {
2262
+ return this._currentGlobalUniformData.bindGroup;
2263
+ }
2264
+ get globalUniformData() {
2265
+ return this._currentGlobalUniformData;
2266
+ }
2267
+ get uniformGroup() {
2268
+ return this._currentGlobalUniformData.bindGroup.resources[0];
2269
+ }
2270
+ _createUniforms() {
2271
+ return new oe({
2272
+ uProjectionMatrix: { value: new v(), type: "mat3x3<f32>" },
2273
+ uWorldTransformMatrix: { value: new v(), type: "mat3x3<f32>" },
2274
+ // TODO - someone smart - set this to be a unorm8x4 rather than a vec4<f32>
2275
+ uWorldColorAlpha: { value: new Float32Array(4), type: "vec4<f32>" },
2276
+ uResolution: { value: [0, 0], type: "vec2<f32>" }
2277
+ }, {
2278
+ isStatic: !0
2279
+ });
2280
+ }
2281
+ destroy() {
2282
+ this._renderer = null, this._globalUniformDataStack.length = 0, this._uniformsPool.length = 0, this._activeUniforms.length = 0, this._bindGroupPool.length = 0, this._activeBindGroups.length = 0, this._currentGlobalUniformData = null;
2283
+ }
2284
+ }
2285
+ Ee.extension = {
2286
+ type: [
2287
+ u.WebGLSystem,
2288
+ u.WebGPUSystem,
2289
+ u.CanvasSystem
2290
+ ],
2291
+ name: "globalUniforms"
2292
+ };
2293
+ let yt = 1;
2294
+ class De {
2295
+ constructor() {
2296
+ this._tasks = [], this._offset = 0;
2297
+ }
2298
+ /** Initializes the scheduler system and starts the ticker. */
2299
+ init() {
2300
+ Z.system.add(this._update, this);
2301
+ }
2302
+ /**
2303
+ * Schedules a repeating task.
2304
+ * @param func - The function to execute.
2305
+ * @param duration - The interval duration in milliseconds.
2306
+ * @param useOffset - this will spread out tasks so that they do not all run at the same time
2307
+ * @returns The unique identifier for the scheduled task.
2308
+ */
2309
+ repeat(e, t, r = !0) {
2310
+ const s = yt++;
2311
+ let a = 0;
2312
+ return r && (this._offset += 1e3, a = this._offset), this._tasks.push({
2313
+ func: e,
2314
+ duration: t,
2315
+ start: performance.now(),
2316
+ offset: a,
2317
+ last: performance.now(),
2318
+ repeat: !0,
2319
+ id: s
2320
+ }), s;
2321
+ }
2322
+ /**
2323
+ * Cancels a scheduled task.
2324
+ * @param id - The unique identifier of the task to cancel.
2325
+ */
2326
+ cancel(e) {
2327
+ for (let t = 0; t < this._tasks.length; t++)
2328
+ if (this._tasks[t].id === e) {
2329
+ this._tasks.splice(t, 1);
2330
+ return;
2331
+ }
2332
+ }
2333
+ /**
2334
+ * Updates and executes the scheduled tasks.
2335
+ * @private
2336
+ */
2337
+ _update() {
2338
+ const e = performance.now();
2339
+ for (let t = 0; t < this._tasks.length; t++) {
2340
+ const r = this._tasks[t];
2341
+ if (e - r.offset - r.last >= r.duration) {
2342
+ const s = e - r.start;
2343
+ r.func(s), r.last = e;
2344
+ }
2345
+ }
2346
+ }
2347
+ /**
2348
+ * Destroys the scheduler system and removes all tasks.
2349
+ * @internal
2350
+ */
2351
+ destroy() {
2352
+ Z.system.remove(this._update, this), this._tasks.length = 0;
2353
+ }
2354
+ }
2355
+ De.extension = {
2356
+ type: [
2357
+ u.WebGLSystem,
2358
+ u.WebGPUSystem,
2359
+ u.CanvasSystem
2360
+ ],
2361
+ name: "scheduler",
2362
+ priority: 0
2363
+ };
2364
+ let ae = !1;
2365
+ function kt(n) {
2366
+ if (!ae) {
2367
+ if (z.get().getNavigator().userAgent.toLowerCase().indexOf("chrome") > -1) {
2368
+ const e = [
2369
+ `%c %c %c %c %c PixiJS %c v${ee} (${n}) http://www.pixijs.com/
2370
+
2371
+ `,
2372
+ "background: #E72264; padding:5px 0;",
2373
+ "background: #6CA2EA; padding:5px 0;",
2374
+ "background: #B5D33D; padding:5px 0;",
2375
+ "background: #FED23F; padding:5px 0;",
2376
+ "color: #FFFFFF; background: #E72264; padding:5px 0;",
2377
+ "color: #E72264; background: #FFFFFF; padding:5px 0;"
2378
+ ];
2379
+ globalThis.console.log(...e);
2380
+ } else globalThis.console && globalThis.console.log(`PixiJS ${ee} - ${n} - http://www.pixijs.com/`);
2381
+ ae = !0;
2382
+ }
2383
+ }
2384
+ class $ {
2385
+ constructor(e) {
2386
+ this._renderer = e;
2387
+ }
2388
+ /**
2389
+ * It all starts here! This initiates every system, passing in the options for any system by name.
2390
+ * @param options - the config for the renderer and all its systems
2391
+ */
2392
+ init(e) {
2393
+ if (e.hello) {
2394
+ let t = this._renderer.name;
2395
+ this._renderer.type === L.WEBGL && (t += ` ${this._renderer.context.webGLVersion}`), kt(t);
2396
+ }
2397
+ }
2398
+ }
2399
+ $.extension = {
2400
+ type: [
2401
+ u.WebGLSystem,
2402
+ u.WebGPUSystem,
2403
+ u.CanvasSystem
2404
+ ],
2405
+ name: "hello",
2406
+ priority: -2
2407
+ };
2408
+ $.defaultOptions = {
2409
+ /** {@link WebGLOptions.hello} */
2410
+ hello: !1
2411
+ };
2412
+ function Ct(n) {
2413
+ let e = !1;
2414
+ for (const r in n)
2415
+ if (n[r] == null) {
2416
+ e = !0;
2417
+ break;
2418
+ }
2419
+ if (!e)
2420
+ return n;
2421
+ const t = /* @__PURE__ */ Object.create(null);
2422
+ for (const r in n) {
2423
+ const s = n[r];
2424
+ s && (t[r] = s);
2425
+ }
2426
+ return t;
2427
+ }
2428
+ function Mt(n) {
2429
+ let e = 0;
2430
+ for (let t = 0; t < n.length; t++)
2431
+ n[t] == null ? e++ : n[t - e] = n[t];
2432
+ return n.length -= e, n;
2433
+ }
2434
+ let St = 0;
2435
+ const q = class Oe {
2436
+ /**
2437
+ * Creates a new RenderableGCSystem instance.
2438
+ * @param renderer - The renderer this garbage collection system works for
2439
+ */
2440
+ constructor(e) {
2441
+ this._managedRenderables = [], this._managedHashes = [], this._managedArrays = [], this._renderer = e;
2442
+ }
2443
+ /**
2444
+ * Initializes the garbage collection system with the provided options.
2445
+ * @param options - Configuration options for the renderer
2446
+ */
2447
+ init(e) {
2448
+ e = { ...Oe.defaultOptions, ...e }, this.maxUnusedTime = e.renderableGCMaxUnusedTime, this._frequency = e.renderableGCFrequency, this.enabled = e.renderableGCActive;
2449
+ }
2450
+ /**
2451
+ * Gets whether the garbage collection system is currently enabled.
2452
+ * @returns True if GC is enabled, false otherwise
2453
+ */
2454
+ get enabled() {
2455
+ return !!this._handler;
2456
+ }
2457
+ /**
2458
+ * Enables or disables the garbage collection system.
2459
+ * When enabled, schedules periodic cleanup of resources.
2460
+ * When disabled, cancels all scheduled cleanups.
2461
+ */
2462
+ set enabled(e) {
2463
+ this.enabled !== e && (e ? (this._handler = this._renderer.scheduler.repeat(
2464
+ () => this.run(),
2465
+ this._frequency,
2466
+ !1
2467
+ ), this._hashHandler = this._renderer.scheduler.repeat(
2468
+ () => {
2469
+ for (const t of this._managedHashes)
2470
+ t.context[t.hash] = Ct(t.context[t.hash]);
2471
+ },
2472
+ this._frequency
2473
+ ), this._arrayHandler = this._renderer.scheduler.repeat(
2474
+ () => {
2475
+ for (const t of this._managedArrays)
2476
+ Mt(t.context[t.hash]);
2477
+ },
2478
+ this._frequency
2479
+ )) : (this._renderer.scheduler.cancel(this._handler), this._renderer.scheduler.cancel(this._hashHandler), this._renderer.scheduler.cancel(this._arrayHandler)));
2480
+ }
2481
+ /**
2482
+ * Adds a hash table to be managed by the garbage collector.
2483
+ * @param context - The object containing the hash table
2484
+ * @param hash - The property name of the hash table
2485
+ */
2486
+ addManagedHash(e, t) {
2487
+ this._managedHashes.push({ context: e, hash: t });
2488
+ }
2489
+ /**
2490
+ * Adds an array to be managed by the garbage collector.
2491
+ * @param context - The object containing the array
2492
+ * @param hash - The property name of the array
2493
+ */
2494
+ addManagedArray(e, t) {
2495
+ this._managedArrays.push({ context: e, hash: t });
2496
+ }
2497
+ /**
2498
+ * Updates the GC timestamp and tracking before rendering.
2499
+ * @param options - The render options
2500
+ * @param options.container - The container to render
2501
+ */
2502
+ prerender({
2503
+ container: e
2504
+ }) {
2505
+ this._now = performance.now(), e.renderGroup.gcTick = St++, this._updateInstructionGCTick(e.renderGroup, e.renderGroup.gcTick);
2506
+ }
2507
+ /**
2508
+ * Starts tracking a renderable for garbage collection.
2509
+ * @param renderable - The renderable to track
2510
+ */
2511
+ addRenderable(e) {
2512
+ this.enabled && (e._lastUsed === -1 && (this._managedRenderables.push(e), e.once("destroyed", this._removeRenderable, this)), e._lastUsed = this._now);
2513
+ }
2514
+ /**
2515
+ * Performs garbage collection by cleaning up unused renderables.
2516
+ * Removes renderables that haven't been used for longer than maxUnusedTime.
2517
+ */
2518
+ run() {
2519
+ var a;
2520
+ const e = this._now, t = this._managedRenderables, r = this._renderer.renderPipes;
2521
+ let s = 0;
2522
+ for (let i = 0; i < t.length; i++) {
2523
+ const o = t[i];
2524
+ if (o === null) {
2525
+ s++;
2526
+ continue;
2527
+ }
2528
+ const l = o.renderGroup ?? o.parentRenderGroup, d = ((a = l == null ? void 0 : l.instructionSet) == null ? void 0 : a.gcTick) ?? -1;
2529
+ if (((l == null ? void 0 : l.gcTick) ?? 0) === d && (o._lastUsed = e), e - o._lastUsed > this.maxUnusedTime) {
2530
+ if (!o.destroyed) {
2531
+ const c = r;
2532
+ l && (l.structureDidChange = !0), c[o.renderPipeId].destroyRenderable(o);
2533
+ }
2534
+ o._lastUsed = -1, s++, o.off("destroyed", this._removeRenderable, this);
2535
+ } else
2536
+ t[i - s] = o;
2537
+ }
2538
+ t.length -= s;
2539
+ }
2540
+ /** Cleans up the garbage collection system. Disables GC and removes all tracked resources. */
2541
+ destroy() {
2542
+ this.enabled = !1, this._renderer = null, this._managedRenderables.length = 0, this._managedHashes.length = 0, this._managedArrays.length = 0;
2543
+ }
2544
+ /**
2545
+ * Removes a renderable from being tracked when it's destroyed.
2546
+ * @param renderable - The renderable to stop tracking
2547
+ */
2548
+ _removeRenderable(e) {
2549
+ const t = this._managedRenderables.indexOf(e);
2550
+ t >= 0 && (e.off("destroyed", this._removeRenderable, this), this._managedRenderables[t] = null);
2551
+ }
2552
+ /**
2553
+ * Updates the GC tick counter for a render group and its children.
2554
+ * @param renderGroup - The render group to update
2555
+ * @param gcTick - The new tick value
2556
+ */
2557
+ _updateInstructionGCTick(e, t) {
2558
+ e.instructionSet.gcTick = t;
2559
+ for (const r of e.renderGroupChildren)
2560
+ this._updateInstructionGCTick(r, t);
2561
+ }
2562
+ };
2563
+ q.extension = {
2564
+ type: [
2565
+ u.WebGLSystem,
2566
+ u.WebGPUSystem
2567
+ ],
2568
+ name: "renderableGC",
2569
+ priority: 0
2570
+ };
2571
+ q.defaultOptions = {
2572
+ /** Enable/disable the garbage collector */
2573
+ renderableGCActive: !0,
2574
+ /** Time in ms before an unused resource is collected (default 1 minute) */
2575
+ renderableGCMaxUnusedTime: 6e4,
2576
+ /** How often to run garbage collection in ms (default 30 seconds) */
2577
+ renderableGCFrequency: 3e4
2578
+ };
2579
+ let wt = q;
2580
+ const K = class Fe {
2581
+ /** @param renderer - The renderer this System works for. */
2582
+ constructor(e) {
2583
+ this._renderer = e, this.count = 0, this.checkCount = 0;
2584
+ }
2585
+ init(e) {
2586
+ e = { ...Fe.defaultOptions, ...e }, this.checkCountMax = e.textureGCCheckCountMax, this.maxIdle = e.textureGCAMaxIdle ?? e.textureGCMaxIdle, this.active = e.textureGCActive;
2587
+ }
2588
+ /**
2589
+ * Checks to see when the last time a texture was used.
2590
+ * If the texture has not been used for a specified amount of time, it will be removed from the GPU.
2591
+ */
2592
+ postrender() {
2593
+ this._renderer.renderingToScreen && (this.count++, this.active && (this.checkCount++, this.checkCount > this.checkCountMax && (this.checkCount = 0, this.run())));
2594
+ }
2595
+ /**
2596
+ * Checks to see when the last time a texture was used.
2597
+ * If the texture has not been used for a specified amount of time, it will be removed from the GPU.
2598
+ */
2599
+ run() {
2600
+ const e = this._renderer.texture.managedTextures;
2601
+ for (let t = 0; t < e.length; t++) {
2602
+ const r = e[t];
2603
+ r.autoGarbageCollect && r.resource && r._touched > -1 && this.count - r._touched > this.maxIdle && (r._touched = -1, r.unload());
2604
+ }
2605
+ }
2606
+ destroy() {
2607
+ this._renderer = null;
2608
+ }
2609
+ };
2610
+ K.extension = {
2611
+ type: [
2612
+ u.WebGLSystem,
2613
+ u.WebGPUSystem
2614
+ ],
2615
+ name: "textureGC"
2616
+ };
2617
+ K.defaultOptions = {
2618
+ /**
2619
+ * If set to true, this will enable the garbage collector on the GPU.
2620
+ * @default true
2621
+ */
2622
+ textureGCActive: !0,
2623
+ /**
2624
+ * @deprecated since 8.3.0
2625
+ * @see {@link TextureGCSystemOptions.textureGCMaxIdle}
2626
+ */
2627
+ textureGCAMaxIdle: null,
2628
+ /**
2629
+ * The maximum idle frames before a texture is destroyed by garbage collection.
2630
+ * @default 60 * 60
2631
+ */
2632
+ textureGCMaxIdle: 60 * 60,
2633
+ /**
2634
+ * Frames between two garbage collections.
2635
+ * @default 600
2636
+ */
2637
+ textureGCCheckCountMax: 600
2638
+ };
2639
+ let Pt = K;
2640
+ const Y = class Le {
2641
+ /**
2642
+ * Whether CSS dimensions of canvas view should be resized to screen dimensions automatically.
2643
+ * This is only supported for HTMLCanvasElement and will be ignored if the canvas is an OffscreenCanvas.
2644
+ * @type {boolean}
2645
+ */
2646
+ get autoDensity() {
2647
+ return this.texture.source.autoDensity;
2648
+ }
2649
+ set autoDensity(e) {
2650
+ this.texture.source.autoDensity = e;
2651
+ }
2652
+ /** The resolution / device pixel ratio of the renderer. */
2653
+ get resolution() {
2654
+ return this.texture.source._resolution;
2655
+ }
2656
+ set resolution(e) {
2657
+ this.texture.source.resize(
2658
+ this.texture.source.width,
2659
+ this.texture.source.height,
2660
+ e
2661
+ );
2662
+ }
2663
+ /**
2664
+ * initiates the view system
2665
+ * @param options - the options for the view
2666
+ */
2667
+ init(e) {
2668
+ e = {
2669
+ ...Le.defaultOptions,
2670
+ ...e
2671
+ }, e.view && (Qe(Ze, "ViewSystem.view has been renamed to ViewSystem.canvas"), e.canvas = e.view), this.screen = new w(0, 0, e.width, e.height), this.canvas = e.canvas || z.get().createCanvas(), this.antialias = !!e.antialias, this.texture = ye(this.canvas, e), this.renderTarget = new G({
2672
+ colorTextures: [this.texture],
2673
+ depth: !!e.depth,
2674
+ isRoot: !0
2675
+ }), this.texture.source.transparent = e.backgroundAlpha < 1, this.resolution = e.resolution;
2676
+ }
2677
+ /**
2678
+ * Resizes the screen and canvas to the specified dimensions.
2679
+ * @param desiredScreenWidth - The new width of the screen.
2680
+ * @param desiredScreenHeight - The new height of the screen.
2681
+ * @param resolution
2682
+ */
2683
+ resize(e, t, r) {
2684
+ this.texture.source.resize(e, t, r), this.screen.width = this.texture.frame.width, this.screen.height = this.texture.frame.height;
2685
+ }
2686
+ /**
2687
+ * Destroys this System and optionally removes the canvas from the dom.
2688
+ * @param {options | false} options - The options for destroying the view, or "false".
2689
+ * @example
2690
+ * viewSystem.destroy();
2691
+ * viewSystem.destroy(true);
2692
+ * viewSystem.destroy({ removeView: true });
2693
+ */
2694
+ destroy(e = !1) {
2695
+ (typeof e == "boolean" ? e : !!(e != null && e.removeView)) && this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas), this.texture.destroy();
2696
+ }
2697
+ };
2698
+ Y.extension = {
2699
+ type: [
2700
+ u.WebGLSystem,
2701
+ u.WebGPUSystem,
2702
+ u.CanvasSystem
2703
+ ],
2704
+ name: "view",
2705
+ priority: 0
2706
+ };
2707
+ Y.defaultOptions = {
2708
+ /**
2709
+ * {@link WebGLOptions.width}
2710
+ * @default 800
2711
+ */
2712
+ width: 800,
2713
+ /**
2714
+ * {@link WebGLOptions.height}
2715
+ * @default 600
2716
+ */
2717
+ height: 600,
2718
+ /**
2719
+ * {@link WebGLOptions.autoDensity}
2720
+ * @default false
2721
+ */
2722
+ autoDensity: !1,
2723
+ /**
2724
+ * {@link WebGLOptions.antialias}
2725
+ * @default false
2726
+ */
2727
+ antialias: !1
2728
+ };
2729
+ let Rt = Y;
2730
+ const zt = [
2731
+ gt,
2732
+ Ee,
2733
+ $,
2734
+ Rt,
2735
+ Re,
2736
+ Pt,
2737
+ Ge,
2738
+ xt,
2739
+ et,
2740
+ wt,
2741
+ De
2742
+ ], Wt = [
2743
+ Ae,
2744
+ xe,
2745
+ Be,
2746
+ Se,
2747
+ _e,
2748
+ Te,
2749
+ be,
2750
+ Me
2751
+ ];
2752
+ export {
2753
+ Ht as B,
2754
+ _ as G,
2755
+ Lt as R,
2756
+ zt as S,
2757
+ Dt as U,
2758
+ Wt as a,
2759
+ ut as b,
2760
+ Ot as c,
2761
+ C as d,
2762
+ Et as e,
2763
+ Gt as f,
2764
+ It as t,
2765
+ Ft as u
2766
+ };
src/backend/gradio_polygonannotator/templates/component/WebGLRenderer-DDL2mbll.js ADDED
@@ -0,0 +1,2643 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { E as d, B, w as m, D as S, K, u as Be, q as U, s as b, a5 as Ae, j as $, a6 as Ne, S as p, O as H, i as A, h as N, k as F, M as z, a7 as Y, a8 as ye, a9 as Ce, aa as q, ab as Ie, A as De, R as Ge, e as T } from "./Index-Ct_1BCRd.js";
2
+ import { S as O, b as Z } from "./colorToUniform-zJcCVLeu.js";
3
+ import { e as Ue, G as Fe, c as Oe, b as Pe, U as Me, R as Le, B as Q, d as y, f as He, S as we, a as Ve } from "./SharedSystems-DVDwWST4.js";
4
+ class J {
5
+ constructor() {
6
+ this._tempState = O.for2d(), this._didUploadHash = {};
7
+ }
8
+ init(e) {
9
+ e.renderer.runners.contextChange.add(this);
10
+ }
11
+ contextChange() {
12
+ this._didUploadHash = {};
13
+ }
14
+ start(e, r, s) {
15
+ const n = e.renderer, i = this._didUploadHash[s.uid];
16
+ n.shader.bind(s, i), i || (this._didUploadHash[s.uid] = !0), n.shader.updateUniformGroup(n.globalUniforms.uniformGroup), n.geometry.bind(r, s.glProgram);
17
+ }
18
+ execute(e, r) {
19
+ const s = e.renderer;
20
+ this._tempState.blendMode = r.blendMode, s.state.set(this._tempState);
21
+ const n = r.textures.textures;
22
+ for (let i = 0; i < r.textures.count; i++)
23
+ s.texture.bind(n[i], i);
24
+ s.geometry.draw(r.topology, r.size, r.start);
25
+ }
26
+ }
27
+ J.extension = {
28
+ type: [
29
+ d.WebGLPipesAdaptor
30
+ ],
31
+ name: "batch"
32
+ };
33
+ var x = /* @__PURE__ */ ((t) => (t[t.ELEMENT_ARRAY_BUFFER = 34963] = "ELEMENT_ARRAY_BUFFER", t[t.ARRAY_BUFFER = 34962] = "ARRAY_BUFFER", t[t.UNIFORM_BUFFER = 35345] = "UNIFORM_BUFFER", t))(x || {});
34
+ class ke {
35
+ constructor(e, r) {
36
+ this._lastBindBaseLocation = -1, this._lastBindCallId = -1, this.buffer = e || null, this.updateID = -1, this.byteLength = -1, this.type = r;
37
+ }
38
+ }
39
+ class ee {
40
+ /**
41
+ * @param {Renderer} renderer - The renderer this System works for.
42
+ */
43
+ constructor(e) {
44
+ this._gpuBuffers = /* @__PURE__ */ Object.create(null), this._boundBufferBases = /* @__PURE__ */ Object.create(null), this._minBaseLocation = 0, this._nextBindBaseIndex = this._minBaseLocation, this._bindCallId = 0, this._renderer = e, this._renderer.renderableGC.addManagedHash(this, "_gpuBuffers");
45
+ }
46
+ /** @ignore */
47
+ destroy() {
48
+ this._renderer = null, this._gl = null, this._gpuBuffers = null, this._boundBufferBases = null;
49
+ }
50
+ /** Sets up the renderer context and necessary buffers. */
51
+ contextChange() {
52
+ this._gl = this._renderer.gl, this._gpuBuffers = /* @__PURE__ */ Object.create(null), this._maxBindings = this._renderer.limits.maxUniformBindings;
53
+ }
54
+ getGlBuffer(e) {
55
+ return this._gpuBuffers[e.uid] || this.createGLBuffer(e);
56
+ }
57
+ /**
58
+ * This binds specified buffer. On first run, it will create the webGL buffers for the context too
59
+ * @param buffer - the buffer to bind to the renderer
60
+ */
61
+ bind(e) {
62
+ const { _gl: r } = this, s = this.getGlBuffer(e);
63
+ r.bindBuffer(s.type, s.buffer);
64
+ }
65
+ /**
66
+ * Binds an uniform buffer to at the given index.
67
+ *
68
+ * A cache is used so a buffer will not be bound again if already bound.
69
+ * @param glBuffer - the buffer to bind
70
+ * @param index - the base index to bind it to.
71
+ */
72
+ bindBufferBase(e, r) {
73
+ const { _gl: s } = this;
74
+ this._boundBufferBases[r] !== e && (this._boundBufferBases[r] = e, e._lastBindBaseLocation = r, s.bindBufferBase(s.UNIFORM_BUFFER, r, e.buffer));
75
+ }
76
+ nextBindBase(e) {
77
+ this._bindCallId++, this._minBaseLocation = 0, e && (this._boundBufferBases[0] = null, this._minBaseLocation = 1, this._nextBindBaseIndex < 1 && (this._nextBindBaseIndex = 1));
78
+ }
79
+ freeLocationForBufferBase(e) {
80
+ let r = this.getLastBindBaseLocation(e);
81
+ if (r >= this._minBaseLocation)
82
+ return e._lastBindCallId = this._bindCallId, r;
83
+ let s = 0, n = this._nextBindBaseIndex;
84
+ for (; s < 2; ) {
85
+ n >= this._maxBindings && (n = this._minBaseLocation, s++);
86
+ const i = this._boundBufferBases[n];
87
+ if (i && i._lastBindCallId === this._bindCallId) {
88
+ n++;
89
+ continue;
90
+ }
91
+ break;
92
+ }
93
+ return r = n, this._nextBindBaseIndex = n + 1, s >= 2 ? -1 : (e._lastBindCallId = this._bindCallId, this._boundBufferBases[r] = null, r);
94
+ }
95
+ getLastBindBaseLocation(e) {
96
+ const r = e._lastBindBaseLocation;
97
+ return this._boundBufferBases[r] === e ? r : -1;
98
+ }
99
+ /**
100
+ * Binds a buffer whilst also binding its range.
101
+ * This will make the buffer start from the offset supplied rather than 0 when it is read.
102
+ * @param glBuffer - the buffer to bind
103
+ * @param index - the base index to bind at, defaults to 0
104
+ * @param offset - the offset to bind at (this is blocks of 256). 0 = 0, 1 = 256, 2 = 512 etc
105
+ * @param size - the size to bind at (this is blocks of 256).
106
+ */
107
+ bindBufferRange(e, r, s, n) {
108
+ const { _gl: i } = this;
109
+ s || (s = 0), r || (r = 0), this._boundBufferBases[r] = null, i.bindBufferRange(i.UNIFORM_BUFFER, r || 0, e.buffer, s * 256, n || 256);
110
+ }
111
+ /**
112
+ * Will ensure the data in the buffer is uploaded to the GPU.
113
+ * @param {Buffer} buffer - the buffer to update
114
+ */
115
+ updateBuffer(e) {
116
+ const { _gl: r } = this, s = this.getGlBuffer(e);
117
+ if (e._updateID === s.updateID)
118
+ return s;
119
+ s.updateID = e._updateID, r.bindBuffer(s.type, s.buffer);
120
+ const n = e.data, i = e.descriptor.usage & B.STATIC ? r.STATIC_DRAW : r.DYNAMIC_DRAW;
121
+ return n ? s.byteLength >= n.byteLength ? r.bufferSubData(s.type, 0, n, 0, e._updateSize / n.BYTES_PER_ELEMENT) : (s.byteLength = n.byteLength, r.bufferData(s.type, n, i)) : (s.byteLength = e.descriptor.size, r.bufferData(s.type, s.byteLength, i)), s;
122
+ }
123
+ /** dispose all WebGL resources of all managed buffers */
124
+ destroyAll() {
125
+ const e = this._gl;
126
+ for (const r in this._gpuBuffers)
127
+ e.deleteBuffer(this._gpuBuffers[r].buffer);
128
+ this._gpuBuffers = /* @__PURE__ */ Object.create(null);
129
+ }
130
+ /**
131
+ * Disposes buffer
132
+ * @param {Buffer} buffer - buffer with data
133
+ * @param {boolean} [contextLost=false] - If context was lost, we suppress deleteVertexArray
134
+ */
135
+ onBufferDestroy(e, r) {
136
+ const s = this._gpuBuffers[e.uid], n = this._gl;
137
+ r || n.deleteBuffer(s.buffer), this._gpuBuffers[e.uid] = null;
138
+ }
139
+ /**
140
+ * creates and attaches a GLBuffer object tied to the current context.
141
+ * @param buffer
142
+ * @protected
143
+ */
144
+ createGLBuffer(e) {
145
+ const { _gl: r } = this;
146
+ let s = x.ARRAY_BUFFER;
147
+ e.descriptor.usage & B.INDEX ? s = x.ELEMENT_ARRAY_BUFFER : e.descriptor.usage & B.UNIFORM && (s = x.UNIFORM_BUFFER);
148
+ const n = new ke(r.createBuffer(), s);
149
+ return this._gpuBuffers[e.uid] = n, e.on("destroy", this.onBufferDestroy, this), n;
150
+ }
151
+ resetState() {
152
+ this._boundBufferBases = /* @__PURE__ */ Object.create(null);
153
+ }
154
+ }
155
+ ee.extension = {
156
+ type: [
157
+ d.WebGLSystem
158
+ ],
159
+ name: "buffer"
160
+ };
161
+ const P = class te {
162
+ /** @param renderer - The renderer this System works for. */
163
+ constructor(e) {
164
+ this.supports = {
165
+ /** Support for 32-bit indices buffer. */
166
+ uint32Indices: !0,
167
+ /** Support for UniformBufferObjects */
168
+ uniformBufferObject: !0,
169
+ /** Support for VertexArrayObjects */
170
+ vertexArrayObject: !0,
171
+ /** Support for SRGB texture format */
172
+ srgbTextures: !0,
173
+ /** Support for wrapping modes if a texture is non-power of two */
174
+ nonPowOf2wrapping: !0,
175
+ /** Support for MSAA (antialiasing of dynamic textures) */
176
+ msaa: !0,
177
+ /** Support for mipmaps if a texture is non-power of two */
178
+ nonPowOf2mipmaps: !0
179
+ }, this._renderer = e, this.extensions = /* @__PURE__ */ Object.create(null), this.handleContextLost = this.handleContextLost.bind(this), this.handleContextRestored = this.handleContextRestored.bind(this);
180
+ }
181
+ /**
182
+ * `true` if the context is lost
183
+ * @readonly
184
+ */
185
+ get isLost() {
186
+ return !this.gl || this.gl.isContextLost();
187
+ }
188
+ /**
189
+ * Handles the context change event.
190
+ * @param {WebGLRenderingContext} gl - New WebGL context.
191
+ */
192
+ contextChange(e) {
193
+ this.gl = e, this._renderer.gl = e;
194
+ }
195
+ init(e) {
196
+ e = { ...te.defaultOptions, ...e };
197
+ let r = this.multiView = e.multiView;
198
+ if (e.context && r && (m("Renderer created with both a context and multiview enabled. Disabling multiView as both cannot work together."), r = !1), r ? this.canvas = S.get().createCanvas(this._renderer.canvas.width, this._renderer.canvas.height) : this.canvas = this._renderer.view.canvas, e.context)
199
+ this.initFromContext(e.context);
200
+ else {
201
+ const s = this._renderer.background.alpha < 1, n = e.premultipliedAlpha ?? !0, i = e.antialias && !this._renderer.backBuffer.useBackBuffer;
202
+ this.createContext(e.preferWebGLVersion, {
203
+ alpha: s,
204
+ premultipliedAlpha: n,
205
+ antialias: i,
206
+ stencil: !0,
207
+ preserveDrawingBuffer: e.preserveDrawingBuffer,
208
+ powerPreference: e.powerPreference ?? "default"
209
+ });
210
+ }
211
+ }
212
+ ensureCanvasSize(e) {
213
+ if (!this.multiView) {
214
+ e !== this.canvas && m("multiView is disabled, but targetCanvas is not the main canvas");
215
+ return;
216
+ }
217
+ const { canvas: r } = this;
218
+ (r.width < e.width || r.height < e.height) && (r.width = Math.max(e.width, e.width), r.height = Math.max(e.height, e.height));
219
+ }
220
+ /**
221
+ * Initializes the context.
222
+ * @protected
223
+ * @param {WebGLRenderingContext} gl - WebGL context
224
+ */
225
+ initFromContext(e) {
226
+ this.gl = e, this.webGLVersion = e instanceof S.get().getWebGLRenderingContext() ? 1 : 2, this.getExtensions(), this.validateContext(e), this._renderer.runners.contextChange.emit(e);
227
+ const r = this._renderer.view.canvas;
228
+ r.addEventListener("webglcontextlost", this.handleContextLost, !1), r.addEventListener("webglcontextrestored", this.handleContextRestored, !1);
229
+ }
230
+ /**
231
+ * Initialize from context options
232
+ * @protected
233
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext
234
+ * @param preferWebGLVersion
235
+ * @param {object} options - context attributes
236
+ */
237
+ createContext(e, r) {
238
+ let s;
239
+ const n = this.canvas;
240
+ if (e === 2 && (s = n.getContext("webgl2", r)), !s && (s = n.getContext("webgl", r), !s))
241
+ throw new Error("This browser does not support WebGL. Try using the canvas renderer");
242
+ this.gl = s, this.initFromContext(this.gl);
243
+ }
244
+ /** Auto-populate the {@link GlContextSystem.extensions extensions}. */
245
+ getExtensions() {
246
+ const { gl: e } = this, r = {
247
+ anisotropicFiltering: e.getExtension("EXT_texture_filter_anisotropic"),
248
+ floatTextureLinear: e.getExtension("OES_texture_float_linear"),
249
+ s3tc: e.getExtension("WEBGL_compressed_texture_s3tc"),
250
+ s3tc_sRGB: e.getExtension("WEBGL_compressed_texture_s3tc_srgb"),
251
+ // eslint-disable-line camelcase
252
+ etc: e.getExtension("WEBGL_compressed_texture_etc"),
253
+ etc1: e.getExtension("WEBGL_compressed_texture_etc1"),
254
+ pvrtc: e.getExtension("WEBGL_compressed_texture_pvrtc") || e.getExtension("WEBKIT_WEBGL_compressed_texture_pvrtc"),
255
+ atc: e.getExtension("WEBGL_compressed_texture_atc"),
256
+ astc: e.getExtension("WEBGL_compressed_texture_astc"),
257
+ bptc: e.getExtension("EXT_texture_compression_bptc"),
258
+ rgtc: e.getExtension("EXT_texture_compression_rgtc"),
259
+ loseContext: e.getExtension("WEBGL_lose_context")
260
+ };
261
+ if (this.webGLVersion === 1)
262
+ this.extensions = {
263
+ ...r,
264
+ drawBuffers: e.getExtension("WEBGL_draw_buffers"),
265
+ depthTexture: e.getExtension("WEBGL_depth_texture"),
266
+ vertexArrayObject: e.getExtension("OES_vertex_array_object") || e.getExtension("MOZ_OES_vertex_array_object") || e.getExtension("WEBKIT_OES_vertex_array_object"),
267
+ uint32ElementIndex: e.getExtension("OES_element_index_uint"),
268
+ // Floats and half-floats
269
+ floatTexture: e.getExtension("OES_texture_float"),
270
+ floatTextureLinear: e.getExtension("OES_texture_float_linear"),
271
+ textureHalfFloat: e.getExtension("OES_texture_half_float"),
272
+ textureHalfFloatLinear: e.getExtension("OES_texture_half_float_linear"),
273
+ vertexAttribDivisorANGLE: e.getExtension("ANGLE_instanced_arrays"),
274
+ srgb: e.getExtension("EXT_sRGB")
275
+ };
276
+ else {
277
+ this.extensions = {
278
+ ...r,
279
+ colorBufferFloat: e.getExtension("EXT_color_buffer_float")
280
+ };
281
+ const s = e.getExtension("WEBGL_provoking_vertex");
282
+ s && s.provokingVertexWEBGL(s.FIRST_VERTEX_CONVENTION_WEBGL);
283
+ }
284
+ }
285
+ /**
286
+ * Handles a lost webgl context
287
+ * @param {WebGLContextEvent} event - The context lost event.
288
+ */
289
+ handleContextLost(e) {
290
+ e.preventDefault(), this._contextLossForced && (this._contextLossForced = !1, setTimeout(() => {
291
+ var r;
292
+ this.gl.isContextLost() && ((r = this.extensions.loseContext) == null || r.restoreContext());
293
+ }, 0));
294
+ }
295
+ /** Handles a restored webgl context. */
296
+ handleContextRestored() {
297
+ this.getExtensions(), this._renderer.runners.contextChange.emit(this.gl);
298
+ }
299
+ destroy() {
300
+ var r;
301
+ const e = this._renderer.view.canvas;
302
+ this._renderer = null, e.removeEventListener("webglcontextlost", this.handleContextLost), e.removeEventListener("webglcontextrestored", this.handleContextRestored), this.gl.useProgram(null), (r = this.extensions.loseContext) == null || r.loseContext();
303
+ }
304
+ /**
305
+ * this function can be called to force a webGL context loss
306
+ * this will release all resources on the GPU.
307
+ * Useful if you need to put Pixi to sleep, and save some GPU memory
308
+ *
309
+ * As soon as render is called - all resources will be created again.
310
+ */
311
+ forceContextLoss() {
312
+ var e;
313
+ (e = this.extensions.loseContext) == null || e.loseContext(), this._contextLossForced = !0;
314
+ }
315
+ /**
316
+ * Validate context.
317
+ * @param {WebGLRenderingContext} gl - Render context.
318
+ */
319
+ validateContext(e) {
320
+ const r = e.getContextAttributes();
321
+ r && !r.stencil && m("Provided WebGL context does not have a stencil buffer, masks may not render correctly");
322
+ const s = this.supports, n = this.webGLVersion === 2, i = this.extensions;
323
+ s.uint32Indices = n || !!i.uint32ElementIndex, s.uniformBufferObject = n, s.vertexArrayObject = n || !!i.vertexArrayObject, s.srgbTextures = n || !!i.srgb, s.nonPowOf2wrapping = n, s.nonPowOf2mipmaps = n, s.msaa = n, s.uint32Indices || m("Provided WebGL context does not support 32 index buffer, large scenes may not render correctly");
324
+ }
325
+ };
326
+ P.extension = {
327
+ type: [
328
+ d.WebGLSystem
329
+ ],
330
+ name: "context"
331
+ };
332
+ P.defaultOptions = {
333
+ /**
334
+ * {@link WebGLOptions.context}
335
+ * @default null
336
+ */
337
+ context: null,
338
+ /**
339
+ * {@link WebGLOptions.premultipliedAlpha}
340
+ * @default true
341
+ */
342
+ premultipliedAlpha: !0,
343
+ /**
344
+ * {@link WebGLOptions.preserveDrawingBuffer}
345
+ * @default false
346
+ */
347
+ preserveDrawingBuffer: !1,
348
+ /**
349
+ * {@link WebGLOptions.powerPreference}
350
+ * @default default
351
+ */
352
+ powerPreference: void 0,
353
+ /**
354
+ * {@link WebGLOptions.webGLVersion}
355
+ * @default 2
356
+ */
357
+ preferWebGLVersion: 2,
358
+ /**
359
+ * {@link WebGLOptions.multiView}
360
+ * @default false
361
+ */
362
+ multiView: !1
363
+ };
364
+ let Xe = P;
365
+ var D = /* @__PURE__ */ ((t) => (t[t.RGBA = 6408] = "RGBA", t[t.RGB = 6407] = "RGB", t[t.RG = 33319] = "RG", t[t.RED = 6403] = "RED", t[t.RGBA_INTEGER = 36249] = "RGBA_INTEGER", t[t.RGB_INTEGER = 36248] = "RGB_INTEGER", t[t.RG_INTEGER = 33320] = "RG_INTEGER", t[t.RED_INTEGER = 36244] = "RED_INTEGER", t[t.ALPHA = 6406] = "ALPHA", t[t.LUMINANCE = 6409] = "LUMINANCE", t[t.LUMINANCE_ALPHA = 6410] = "LUMINANCE_ALPHA", t[t.DEPTH_COMPONENT = 6402] = "DEPTH_COMPONENT", t[t.DEPTH_STENCIL = 34041] = "DEPTH_STENCIL", t))(D || {}), re = /* @__PURE__ */ ((t) => (t[t.TEXTURE_2D = 3553] = "TEXTURE_2D", t[t.TEXTURE_CUBE_MAP = 34067] = "TEXTURE_CUBE_MAP", t[t.TEXTURE_2D_ARRAY = 35866] = "TEXTURE_2D_ARRAY", t[t.TEXTURE_CUBE_MAP_POSITIVE_X = 34069] = "TEXTURE_CUBE_MAP_POSITIVE_X", t[t.TEXTURE_CUBE_MAP_NEGATIVE_X = 34070] = "TEXTURE_CUBE_MAP_NEGATIVE_X", t[t.TEXTURE_CUBE_MAP_POSITIVE_Y = 34071] = "TEXTURE_CUBE_MAP_POSITIVE_Y", t[t.TEXTURE_CUBE_MAP_NEGATIVE_Y = 34072] = "TEXTURE_CUBE_MAP_NEGATIVE_Y", t[t.TEXTURE_CUBE_MAP_POSITIVE_Z = 34073] = "TEXTURE_CUBE_MAP_POSITIVE_Z", t[t.TEXTURE_CUBE_MAP_NEGATIVE_Z = 34074] = "TEXTURE_CUBE_MAP_NEGATIVE_Z", t))(re || {}), h = /* @__PURE__ */ ((t) => (t[t.UNSIGNED_BYTE = 5121] = "UNSIGNED_BYTE", t[t.UNSIGNED_SHORT = 5123] = "UNSIGNED_SHORT", t[t.UNSIGNED_SHORT_5_6_5 = 33635] = "UNSIGNED_SHORT_5_6_5", t[t.UNSIGNED_SHORT_4_4_4_4 = 32819] = "UNSIGNED_SHORT_4_4_4_4", t[t.UNSIGNED_SHORT_5_5_5_1 = 32820] = "UNSIGNED_SHORT_5_5_5_1", t[t.UNSIGNED_INT = 5125] = "UNSIGNED_INT", t[t.UNSIGNED_INT_10F_11F_11F_REV = 35899] = "UNSIGNED_INT_10F_11F_11F_REV", t[t.UNSIGNED_INT_2_10_10_10_REV = 33640] = "UNSIGNED_INT_2_10_10_10_REV", t[t.UNSIGNED_INT_24_8 = 34042] = "UNSIGNED_INT_24_8", t[t.UNSIGNED_INT_5_9_9_9_REV = 35902] = "UNSIGNED_INT_5_9_9_9_REV", t[t.BYTE = 5120] = "BYTE", t[t.SHORT = 5122] = "SHORT", t[t.INT = 5124] = "INT", t[t.FLOAT = 5126] = "FLOAT", t[t.FLOAT_32_UNSIGNED_INT_24_8_REV = 36269] = "FLOAT_32_UNSIGNED_INT_24_8_REV", t[t.HALF_FLOAT = 36193] = "HALF_FLOAT", t))(h || {});
366
+ const w = {
367
+ uint8x2: h.UNSIGNED_BYTE,
368
+ uint8x4: h.UNSIGNED_BYTE,
369
+ sint8x2: h.BYTE,
370
+ sint8x4: h.BYTE,
371
+ unorm8x2: h.UNSIGNED_BYTE,
372
+ unorm8x4: h.UNSIGNED_BYTE,
373
+ snorm8x2: h.BYTE,
374
+ snorm8x4: h.BYTE,
375
+ uint16x2: h.UNSIGNED_SHORT,
376
+ uint16x4: h.UNSIGNED_SHORT,
377
+ sint16x2: h.SHORT,
378
+ sint16x4: h.SHORT,
379
+ unorm16x2: h.UNSIGNED_SHORT,
380
+ unorm16x4: h.UNSIGNED_SHORT,
381
+ snorm16x2: h.SHORT,
382
+ snorm16x4: h.SHORT,
383
+ float16x2: h.HALF_FLOAT,
384
+ float16x4: h.HALF_FLOAT,
385
+ float32: h.FLOAT,
386
+ float32x2: h.FLOAT,
387
+ float32x3: h.FLOAT,
388
+ float32x4: h.FLOAT,
389
+ uint32: h.UNSIGNED_INT,
390
+ uint32x2: h.UNSIGNED_INT,
391
+ uint32x3: h.UNSIGNED_INT,
392
+ uint32x4: h.UNSIGNED_INT,
393
+ sint32: h.INT,
394
+ sint32x2: h.INT,
395
+ sint32x3: h.INT,
396
+ sint32x4: h.INT
397
+ };
398
+ function We(t) {
399
+ return w[t] ?? w.float32;
400
+ }
401
+ const je = {
402
+ "point-list": 0,
403
+ "line-list": 1,
404
+ "line-strip": 3,
405
+ "triangle-list": 4,
406
+ "triangle-strip": 5
407
+ };
408
+ class se {
409
+ /** @param renderer - The renderer this System works for. */
410
+ constructor(e) {
411
+ this._geometryVaoHash = /* @__PURE__ */ Object.create(null), this._renderer = e, this._activeGeometry = null, this._activeVao = null, this.hasVao = !0, this.hasInstance = !0, this._renderer.renderableGC.addManagedHash(this, "_geometryVaoHash");
412
+ }
413
+ /** Sets up the renderer context and necessary buffers. */
414
+ contextChange() {
415
+ const e = this.gl = this._renderer.gl;
416
+ if (!this._renderer.context.supports.vertexArrayObject)
417
+ throw new Error("[PixiJS] Vertex Array Objects are not supported on this device");
418
+ const r = this._renderer.context.extensions.vertexArrayObject;
419
+ r && (e.createVertexArray = () => r.createVertexArrayOES(), e.bindVertexArray = (n) => r.bindVertexArrayOES(n), e.deleteVertexArray = (n) => r.deleteVertexArrayOES(n));
420
+ const s = this._renderer.context.extensions.vertexAttribDivisorANGLE;
421
+ s && (e.drawArraysInstanced = (n, i, a, o) => {
422
+ s.drawArraysInstancedANGLE(n, i, a, o);
423
+ }, e.drawElementsInstanced = (n, i, a, o, c) => {
424
+ s.drawElementsInstancedANGLE(n, i, a, o, c);
425
+ }, e.vertexAttribDivisor = (n, i) => s.vertexAttribDivisorANGLE(n, i)), this._activeGeometry = null, this._activeVao = null, this._geometryVaoHash = /* @__PURE__ */ Object.create(null);
426
+ }
427
+ /**
428
+ * Binds geometry so that is can be drawn. Creating a Vao if required
429
+ * @param geometry - Instance of geometry to bind.
430
+ * @param program - Instance of program to use vao for.
431
+ */
432
+ bind(e, r) {
433
+ const s = this.gl;
434
+ this._activeGeometry = e;
435
+ const n = this.getVao(e, r);
436
+ this._activeVao !== n && (this._activeVao = n, s.bindVertexArray(n)), this.updateBuffers();
437
+ }
438
+ /** Reset and unbind any active VAO and geometry. */
439
+ resetState() {
440
+ this.unbind();
441
+ }
442
+ /** Update buffers of the currently bound geometry. */
443
+ updateBuffers() {
444
+ const e = this._activeGeometry, r = this._renderer.buffer;
445
+ for (let s = 0; s < e.buffers.length; s++) {
446
+ const n = e.buffers[s];
447
+ r.updateBuffer(n);
448
+ }
449
+ }
450
+ /**
451
+ * Check compatibility between a geometry and a program
452
+ * @param geometry - Geometry instance.
453
+ * @param program - Program instance.
454
+ */
455
+ checkCompatibility(e, r) {
456
+ const s = e.attributes, n = r._attributeData;
457
+ for (const i in n)
458
+ if (!s[i])
459
+ throw new Error(`shader and geometry incompatible, geometry missing the "${i}" attribute`);
460
+ }
461
+ /**
462
+ * Takes a geometry and program and generates a unique signature for them.
463
+ * @param geometry - To get signature from.
464
+ * @param program - To test geometry against.
465
+ * @returns - Unique signature of the geometry and program
466
+ */
467
+ getSignature(e, r) {
468
+ const s = e.attributes, n = r._attributeData, i = ["g", e.uid];
469
+ for (const a in s)
470
+ n[a] && i.push(a, n[a].location);
471
+ return i.join("-");
472
+ }
473
+ getVao(e, r) {
474
+ var s;
475
+ return ((s = this._geometryVaoHash[e.uid]) == null ? void 0 : s[r._key]) || this.initGeometryVao(e, r);
476
+ }
477
+ /**
478
+ * Creates or gets Vao with the same structure as the geometry and stores it on the geometry.
479
+ * If vao is created, it is bound automatically. We use a shader to infer what and how to set up the
480
+ * attribute locations.
481
+ * @param geometry - Instance of geometry to to generate Vao for.
482
+ * @param program
483
+ * @param _incRefCount - Increment refCount of all geometry buffers.
484
+ */
485
+ initGeometryVao(e, r, s = !0) {
486
+ const n = this._renderer.gl, i = this._renderer.buffer;
487
+ this._renderer.shader._getProgramData(r), this.checkCompatibility(e, r);
488
+ const a = this.getSignature(e, r);
489
+ this._geometryVaoHash[e.uid] || (this._geometryVaoHash[e.uid] = /* @__PURE__ */ Object.create(null), e.on("destroy", this.onGeometryDestroy, this));
490
+ const o = this._geometryVaoHash[e.uid];
491
+ let c = o[a];
492
+ if (c)
493
+ return o[r._key] = c, c;
494
+ Ue(e, r._attributeData);
495
+ const u = e.buffers;
496
+ c = n.createVertexArray(), n.bindVertexArray(c);
497
+ for (let _ = 0; _ < u.length; _++) {
498
+ const f = u[_];
499
+ i.bind(f);
500
+ }
501
+ return this.activateVao(e, r), o[r._key] = c, o[a] = c, n.bindVertexArray(null), c;
502
+ }
503
+ /**
504
+ * Disposes geometry.
505
+ * @param geometry - Geometry with buffers. Only VAO will be disposed
506
+ * @param [contextLost=false] - If context was lost, we suppress deleteVertexArray
507
+ */
508
+ onGeometryDestroy(e, r) {
509
+ const s = this._geometryVaoHash[e.uid], n = this.gl;
510
+ if (s) {
511
+ if (r)
512
+ for (const i in s)
513
+ this._activeVao !== s[i] && this.unbind(), n.deleteVertexArray(s[i]);
514
+ this._geometryVaoHash[e.uid] = null;
515
+ }
516
+ }
517
+ /**
518
+ * Dispose all WebGL resources of all managed geometries.
519
+ * @param [contextLost=false] - If context was lost, we suppress `gl.delete` calls
520
+ */
521
+ destroyAll(e = !1) {
522
+ const r = this.gl;
523
+ for (const s in this._geometryVaoHash) {
524
+ if (e)
525
+ for (const n in this._geometryVaoHash[s]) {
526
+ const i = this._geometryVaoHash[s];
527
+ this._activeVao !== i && this.unbind(), r.deleteVertexArray(i[n]);
528
+ }
529
+ this._geometryVaoHash[s] = null;
530
+ }
531
+ }
532
+ /**
533
+ * Activate vertex array object.
534
+ * @param geometry - Geometry instance.
535
+ * @param program - Shader program instance.
536
+ */
537
+ activateVao(e, r) {
538
+ var o;
539
+ const s = this._renderer.gl, n = this._renderer.buffer, i = e.attributes;
540
+ e.indexBuffer && n.bind(e.indexBuffer);
541
+ let a = null;
542
+ for (const c in i) {
543
+ const u = i[c], _ = u.buffer, f = n.getGlBuffer(_), l = r._attributeData[c];
544
+ if (l) {
545
+ a !== f && (n.bind(_), a = f);
546
+ const E = l.location;
547
+ s.enableVertexAttribArray(E);
548
+ const v = K(u.format), L = We(u.format);
549
+ if (((o = l.format) == null ? void 0 : o.substring(1, 4)) === "int" ? s.vertexAttribIPointer(
550
+ E,
551
+ v.size,
552
+ L,
553
+ u.stride,
554
+ u.offset
555
+ ) : s.vertexAttribPointer(
556
+ E,
557
+ v.size,
558
+ L,
559
+ v.normalised,
560
+ u.stride,
561
+ u.offset
562
+ ), u.instance)
563
+ if (this.hasInstance) {
564
+ const ve = u.divisor ?? 1;
565
+ s.vertexAttribDivisor(E, ve);
566
+ } else
567
+ throw new Error("geometry error, GPU Instancing is not supported on this device");
568
+ }
569
+ }
570
+ }
571
+ /**
572
+ * Draws the currently bound geometry.
573
+ * @param topology - The type primitive to render.
574
+ * @param size - The number of elements to be rendered. If not specified, all vertices after the
575
+ * starting vertex will be drawn.
576
+ * @param start - The starting vertex in the geometry to start drawing from. If not specified,
577
+ * drawing will start from the first vertex.
578
+ * @param instanceCount - The number of instances of the set of elements to execute. If not specified,
579
+ * all instances will be drawn.
580
+ * @returns This instance of the geometry system.
581
+ */
582
+ draw(e, r, s, n) {
583
+ const { gl: i } = this._renderer, a = this._activeGeometry, o = je[e || a.topology];
584
+ if (n ?? (n = a.instanceCount), a.indexBuffer) {
585
+ const c = a.indexBuffer.data.BYTES_PER_ELEMENT, u = c === 2 ? i.UNSIGNED_SHORT : i.UNSIGNED_INT;
586
+ n > 1 ? i.drawElementsInstanced(o, r || a.indexBuffer.data.length, u, (s || 0) * c, n) : i.drawElements(o, r || a.indexBuffer.data.length, u, (s || 0) * c);
587
+ } else n > 1 ? i.drawArraysInstanced(o, s || 0, r || a.getSize(), n) : i.drawArrays(o, s || 0, r || a.getSize());
588
+ return this;
589
+ }
590
+ /** Unbind/reset everything. */
591
+ unbind() {
592
+ this.gl.bindVertexArray(null), this._activeVao = null, this._activeGeometry = null;
593
+ }
594
+ destroy() {
595
+ this._renderer = null, this.gl = null, this._activeVao = null, this._activeGeometry = null, this._geometryVaoHash = null;
596
+ }
597
+ }
598
+ se.extension = {
599
+ type: [
600
+ d.WebGLSystem
601
+ ],
602
+ name: "geometry"
603
+ };
604
+ const Ke = new Ae({
605
+ attributes: {
606
+ aPosition: [
607
+ -1,
608
+ -1,
609
+ // Bottom left corner
610
+ 3,
611
+ -1,
612
+ // Bottom right corner, extending beyond right edge
613
+ -1,
614
+ 3
615
+ // Top left corner, extending beyond top edge
616
+ ]
617
+ }
618
+ }), M = class ne {
619
+ constructor(e) {
620
+ this.useBackBuffer = !1, this._useBackBufferThisRender = !1, this._renderer = e;
621
+ }
622
+ init(e = {}) {
623
+ const { useBackBuffer: r, antialias: s } = { ...ne.defaultOptions, ...e };
624
+ this.useBackBuffer = r, this._antialias = s, this._renderer.context.supports.msaa || (m("antialiasing, is not supported on when using the back buffer"), this._antialias = !1), this._state = O.for2d();
625
+ const n = new Be({
626
+ vertex: `
627
+ attribute vec2 aPosition;
628
+ out vec2 vUv;
629
+
630
+ void main() {
631
+ gl_Position = vec4(aPosition, 0.0, 1.0);
632
+
633
+ vUv = (aPosition + 1.0) / 2.0;
634
+
635
+ // flip dem UVs
636
+ vUv.y = 1.0 - vUv.y;
637
+ }`,
638
+ fragment: `
639
+ in vec2 vUv;
640
+ out vec4 finalColor;
641
+
642
+ uniform sampler2D uTexture;
643
+
644
+ void main() {
645
+ finalColor = texture(uTexture, vUv);
646
+ }`,
647
+ name: "big-triangle"
648
+ });
649
+ this._bigTriangleShader = new U({
650
+ glProgram: n,
651
+ resources: {
652
+ uTexture: b.WHITE.source
653
+ }
654
+ });
655
+ }
656
+ /**
657
+ * This is called before the RenderTargetSystem is started. This is where
658
+ * we replace the target with the back buffer if required.
659
+ * @param options - The options for this render.
660
+ */
661
+ renderStart(e) {
662
+ const r = this._renderer.renderTarget.getRenderTarget(e.target);
663
+ if (this._useBackBufferThisRender = this.useBackBuffer && !!r.isRoot, this._useBackBufferThisRender) {
664
+ const s = this._renderer.renderTarget.getRenderTarget(e.target);
665
+ this._targetTexture = s.colorTexture, e.target = this._getBackBufferTexture(s.colorTexture);
666
+ }
667
+ }
668
+ renderEnd() {
669
+ this._presentBackBuffer();
670
+ }
671
+ _presentBackBuffer() {
672
+ const e = this._renderer;
673
+ e.renderTarget.finishRenderPass(), this._useBackBufferThisRender && (e.renderTarget.bind(this._targetTexture, !1), this._bigTriangleShader.resources.uTexture = this._backBufferTexture.source, e.encoder.draw({
674
+ geometry: Ke,
675
+ shader: this._bigTriangleShader,
676
+ state: this._state
677
+ }));
678
+ }
679
+ _getBackBufferTexture(e) {
680
+ return this._backBufferTexture = this._backBufferTexture || new b({
681
+ source: new $({
682
+ width: e.width,
683
+ height: e.height,
684
+ resolution: e._resolution,
685
+ antialias: this._antialias
686
+ })
687
+ }), this._backBufferTexture.source.resize(
688
+ e.width,
689
+ e.height,
690
+ e._resolution
691
+ ), this._backBufferTexture;
692
+ }
693
+ /** destroys the back buffer */
694
+ destroy() {
695
+ this._backBufferTexture && (this._backBufferTexture.destroy(), this._backBufferTexture = null);
696
+ }
697
+ };
698
+ M.extension = {
699
+ type: [
700
+ d.WebGLSystem
701
+ ],
702
+ name: "backBuffer",
703
+ priority: 1
704
+ };
705
+ M.defaultOptions = {
706
+ /** if true will use the back buffer where required */
707
+ useBackBuffer: !1
708
+ };
709
+ let $e = M;
710
+ class ie {
711
+ constructor(e) {
712
+ this._colorMaskCache = 15, this._renderer = e;
713
+ }
714
+ setMask(e) {
715
+ this._colorMaskCache !== e && (this._colorMaskCache = e, this._renderer.gl.colorMask(
716
+ !!(e & 8),
717
+ !!(e & 4),
718
+ !!(e & 2),
719
+ !!(e & 1)
720
+ ));
721
+ }
722
+ }
723
+ ie.extension = {
724
+ type: [
725
+ d.WebGLSystem
726
+ ],
727
+ name: "colorMask"
728
+ };
729
+ class ae {
730
+ constructor(e) {
731
+ this.commandFinished = Promise.resolve(), this._renderer = e;
732
+ }
733
+ setGeometry(e, r) {
734
+ this._renderer.geometry.bind(e, r.glProgram);
735
+ }
736
+ finishRenderPass() {
737
+ }
738
+ draw(e) {
739
+ const r = this._renderer, { geometry: s, shader: n, state: i, skipSync: a, topology: o, size: c, start: u, instanceCount: _ } = e;
740
+ r.shader.bind(n, a), r.geometry.bind(s, r.shader._activeProgram), i && r.state.set(i), r.geometry.draw(o, c, u, _ ?? s.instanceCount);
741
+ }
742
+ destroy() {
743
+ this._renderer = null;
744
+ }
745
+ }
746
+ ae.extension = {
747
+ type: [
748
+ d.WebGLSystem
749
+ ],
750
+ name: "encoder"
751
+ };
752
+ class oe {
753
+ constructor(e) {
754
+ this._renderer = e;
755
+ }
756
+ contextChange() {
757
+ const e = this._renderer.gl;
758
+ this.maxTextures = e.getParameter(e.MAX_TEXTURE_IMAGE_UNITS), this.maxBatchableTextures = Ne(this.maxTextures, e);
759
+ const r = this._renderer.context.webGLVersion === 2;
760
+ this.maxUniformBindings = r ? e.getParameter(e.MAX_UNIFORM_BUFFER_BINDINGS) : 0;
761
+ }
762
+ destroy() {
763
+ }
764
+ }
765
+ oe.extension = {
766
+ type: [
767
+ d.WebGLSystem
768
+ ],
769
+ name: "limits"
770
+ };
771
+ class ze {
772
+ constructor() {
773
+ this.width = -1, this.height = -1, this.msaa = !1, this.msaaRenderBuffer = [];
774
+ }
775
+ }
776
+ class ce {
777
+ constructor(e) {
778
+ this._stencilCache = {
779
+ enabled: !1,
780
+ stencilReference: 0,
781
+ stencilMode: p.NONE
782
+ }, this._renderTargetStencilState = /* @__PURE__ */ Object.create(null), e.renderTarget.onRenderTargetChange.add(this);
783
+ }
784
+ contextChange(e) {
785
+ this._gl = e, this._comparisonFuncMapping = {
786
+ always: e.ALWAYS,
787
+ never: e.NEVER,
788
+ equal: e.EQUAL,
789
+ "not-equal": e.NOTEQUAL,
790
+ less: e.LESS,
791
+ "less-equal": e.LEQUAL,
792
+ greater: e.GREATER,
793
+ "greater-equal": e.GEQUAL
794
+ }, this._stencilOpsMapping = {
795
+ keep: e.KEEP,
796
+ zero: e.ZERO,
797
+ replace: e.REPLACE,
798
+ invert: e.INVERT,
799
+ "increment-clamp": e.INCR,
800
+ "decrement-clamp": e.DECR,
801
+ "increment-wrap": e.INCR_WRAP,
802
+ "decrement-wrap": e.DECR_WRAP
803
+ }, this.resetState();
804
+ }
805
+ onRenderTargetChange(e) {
806
+ if (this._activeRenderTarget === e)
807
+ return;
808
+ this._activeRenderTarget = e;
809
+ let r = this._renderTargetStencilState[e.uid];
810
+ r || (r = this._renderTargetStencilState[e.uid] = {
811
+ stencilMode: p.DISABLED,
812
+ stencilReference: 0
813
+ }), this.setStencilMode(r.stencilMode, r.stencilReference);
814
+ }
815
+ resetState() {
816
+ this._stencilCache.enabled = !1, this._stencilCache.stencilMode = p.NONE, this._stencilCache.stencilReference = 0;
817
+ }
818
+ setStencilMode(e, r) {
819
+ const s = this._renderTargetStencilState[this._activeRenderTarget.uid], n = this._gl, i = Fe[e], a = this._stencilCache;
820
+ if (s.stencilMode = e, s.stencilReference = r, e === p.DISABLED) {
821
+ this._stencilCache.enabled && (this._stencilCache.enabled = !1, n.disable(n.STENCIL_TEST));
822
+ return;
823
+ }
824
+ this._stencilCache.enabled || (this._stencilCache.enabled = !0, n.enable(n.STENCIL_TEST)), (e !== a.stencilMode || a.stencilReference !== r) && (a.stencilMode = e, a.stencilReference = r, n.stencilFunc(this._comparisonFuncMapping[i.stencilBack.compare], r, 255), n.stencilOp(n.KEEP, n.KEEP, this._stencilOpsMapping[i.stencilBack.passOp]));
825
+ }
826
+ }
827
+ ce.extension = {
828
+ type: [
829
+ d.WebGLSystem
830
+ ],
831
+ name: "stencil"
832
+ };
833
+ const ue = {
834
+ f32: 4,
835
+ i32: 4,
836
+ "vec2<f32>": 8,
837
+ "vec3<f32>": 12,
838
+ "vec4<f32>": 16,
839
+ "vec2<i32>": 8,
840
+ "vec3<i32>": 12,
841
+ "vec4<i32>": 16,
842
+ "mat2x2<f32>": 16 * 2,
843
+ "mat3x3<f32>": 16 * 3,
844
+ "mat4x4<f32>": 16 * 4
845
+ // TODO - not essential for now but support these in the future
846
+ // int: 4,
847
+ // ivec2: 8,
848
+ // ivec3: 12,
849
+ // ivec4: 16,
850
+ // uint: 4,
851
+ // uvec2: 8,
852
+ // uvec3: 12,
853
+ // uvec4: 16,
854
+ // bool: 4,
855
+ // bvec2: 8,
856
+ // bvec3: 12,
857
+ // bvec4: 16,
858
+ // mat2: 16 * 2,
859
+ // mat3: 16 * 3,
860
+ // mat4: 16 * 4,
861
+ };
862
+ function Ye(t) {
863
+ const e = t.map((i) => ({
864
+ data: i,
865
+ offset: 0,
866
+ size: 0
867
+ })), r = 16;
868
+ let s = 0, n = 0;
869
+ for (let i = 0; i < e.length; i++) {
870
+ const a = e[i];
871
+ if (s = ue[a.data.type], !s)
872
+ throw new Error(`Unknown type ${a.data.type}`);
873
+ a.data.size > 1 && (s = Math.max(s, r) * a.data.size);
874
+ const o = s === 12 ? 16 : s;
875
+ a.size = s;
876
+ const c = n % r;
877
+ c > 0 && r - c < o ? n += (r - c) % 16 : n += (s - c % s) % s, a.offset = n, n += s;
878
+ }
879
+ return n = Math.ceil(n / 16) * 16, { uboElements: e, size: n };
880
+ }
881
+ function qe(t, e) {
882
+ const r = Math.max(ue[t.data.type] / 16, 1), s = t.data.value.length / t.data.size, n = (4 - s % 4) % 4, i = t.data.type.indexOf("i32") >= 0 ? "dataInt32" : "data";
883
+ return `
884
+ v = uv.${t.data.name};
885
+ offset += ${e};
886
+
887
+ arrayOffset = offset;
888
+
889
+ t = 0;
890
+
891
+ for(var i=0; i < ${t.data.size * r}; i++)
892
+ {
893
+ for(var j = 0; j < ${s}; j++)
894
+ {
895
+ ${i}[arrayOffset++] = v[t++];
896
+ }
897
+ ${n !== 0 ? `arrayOffset += ${n};` : ""}
898
+ }
899
+ `;
900
+ }
901
+ function Ze(t) {
902
+ return Oe(
903
+ t,
904
+ "uboStd40",
905
+ qe,
906
+ Pe
907
+ );
908
+ }
909
+ class _e extends Me {
910
+ constructor() {
911
+ super({
912
+ createUboElements: Ye,
913
+ generateUboSync: Ze
914
+ });
915
+ }
916
+ }
917
+ _e.extension = {
918
+ type: [d.WebGLSystem],
919
+ name: "ubo"
920
+ };
921
+ class Qe {
922
+ constructor() {
923
+ this._clearColorCache = [0, 0, 0, 0], this._viewPortCache = new H();
924
+ }
925
+ init(e, r) {
926
+ this._renderer = e, this._renderTargetSystem = r, e.runners.contextChange.add(this);
927
+ }
928
+ contextChange() {
929
+ this._clearColorCache = [0, 0, 0, 0], this._viewPortCache = new H();
930
+ }
931
+ copyToTexture(e, r, s, n, i) {
932
+ const a = this._renderTargetSystem, o = this._renderer, c = a.getGpuRenderTarget(e), u = o.gl;
933
+ return this.finishRenderPass(e), u.bindFramebuffer(u.FRAMEBUFFER, c.resolveTargetFramebuffer), o.texture.bind(r, 0), u.copyTexSubImage2D(
934
+ u.TEXTURE_2D,
935
+ 0,
936
+ i.x,
937
+ i.y,
938
+ s.x,
939
+ s.y,
940
+ n.width,
941
+ n.height
942
+ ), r;
943
+ }
944
+ startRenderPass(e, r = !0, s, n) {
945
+ const i = this._renderTargetSystem, a = e.colorTexture, o = i.getGpuRenderTarget(e);
946
+ let c = n.y;
947
+ e.isRoot && (c = a.pixelHeight - n.height), e.colorTextures.forEach((f) => {
948
+ this._renderer.texture.unbind(f);
949
+ });
950
+ const u = this._renderer.gl;
951
+ u.bindFramebuffer(u.FRAMEBUFFER, o.framebuffer);
952
+ const _ = this._viewPortCache;
953
+ (_.x !== n.x || _.y !== c || _.width !== n.width || _.height !== n.height) && (_.x = n.x, _.y = c, _.width = n.width, _.height = n.height, u.viewport(
954
+ n.x,
955
+ c,
956
+ n.width,
957
+ n.height
958
+ )), !o.depthStencilRenderBuffer && (e.stencil || e.depth) && this._initStencil(o), this.clear(e, r, s);
959
+ }
960
+ finishRenderPass(e) {
961
+ const s = this._renderTargetSystem.getGpuRenderTarget(e);
962
+ if (!s.msaa)
963
+ return;
964
+ const n = this._renderer.gl;
965
+ n.bindFramebuffer(n.FRAMEBUFFER, s.resolveTargetFramebuffer), n.bindFramebuffer(n.READ_FRAMEBUFFER, s.framebuffer), n.blitFramebuffer(
966
+ 0,
967
+ 0,
968
+ s.width,
969
+ s.height,
970
+ 0,
971
+ 0,
972
+ s.width,
973
+ s.height,
974
+ n.COLOR_BUFFER_BIT,
975
+ n.NEAREST
976
+ ), n.bindFramebuffer(n.FRAMEBUFFER, s.framebuffer);
977
+ }
978
+ initGpuRenderTarget(e) {
979
+ const s = this._renderer.gl, n = new ze();
980
+ return e.colorTexture instanceof A ? (this._renderer.context.ensureCanvasSize(e.colorTexture.resource), n.framebuffer = null, n) : (this._initColor(e, n), s.bindFramebuffer(s.FRAMEBUFFER, null), n);
981
+ }
982
+ destroyGpuRenderTarget(e) {
983
+ const r = this._renderer.gl;
984
+ e.framebuffer && (r.deleteFramebuffer(e.framebuffer), e.framebuffer = null), e.resolveTargetFramebuffer && (r.deleteFramebuffer(e.resolveTargetFramebuffer), e.resolveTargetFramebuffer = null), e.depthStencilRenderBuffer && (r.deleteRenderbuffer(e.depthStencilRenderBuffer), e.depthStencilRenderBuffer = null), e.msaaRenderBuffer.forEach((s) => {
985
+ r.deleteRenderbuffer(s);
986
+ }), e.msaaRenderBuffer = null;
987
+ }
988
+ clear(e, r, s) {
989
+ if (!r)
990
+ return;
991
+ const n = this._renderTargetSystem;
992
+ typeof r == "boolean" && (r = r ? N.ALL : N.NONE);
993
+ const i = this._renderer.gl;
994
+ if (r & N.COLOR) {
995
+ s ?? (s = n.defaultClearColor);
996
+ const a = this._clearColorCache, o = s;
997
+ (a[0] !== o[0] || a[1] !== o[1] || a[2] !== o[2] || a[3] !== o[3]) && (a[0] = o[0], a[1] = o[1], a[2] = o[2], a[3] = o[3], i.clearColor(o[0], o[1], o[2], o[3]));
998
+ }
999
+ i.clear(r);
1000
+ }
1001
+ resizeGpuRenderTarget(e) {
1002
+ if (e.isRoot)
1003
+ return;
1004
+ const s = this._renderTargetSystem.getGpuRenderTarget(e);
1005
+ this._resizeColor(e, s), (e.stencil || e.depth) && this._resizeStencil(s);
1006
+ }
1007
+ _initColor(e, r) {
1008
+ const s = this._renderer, n = s.gl, i = n.createFramebuffer();
1009
+ if (r.resolveTargetFramebuffer = i, n.bindFramebuffer(n.FRAMEBUFFER, i), r.width = e.colorTexture.source.pixelWidth, r.height = e.colorTexture.source.pixelHeight, e.colorTextures.forEach((a, o) => {
1010
+ const c = a.source;
1011
+ c.antialias && (s.context.supports.msaa ? r.msaa = !0 : m("[RenderTexture] Antialiasing on textures is not supported in WebGL1")), s.texture.bindSource(c, 0);
1012
+ const _ = s.texture.getGlSource(c).texture;
1013
+ n.framebufferTexture2D(
1014
+ n.FRAMEBUFFER,
1015
+ n.COLOR_ATTACHMENT0 + o,
1016
+ 3553,
1017
+ // texture.target,
1018
+ _,
1019
+ 0
1020
+ );
1021
+ }), r.msaa) {
1022
+ const a = n.createFramebuffer();
1023
+ r.framebuffer = a, n.bindFramebuffer(n.FRAMEBUFFER, a), e.colorTextures.forEach((o, c) => {
1024
+ const u = n.createRenderbuffer();
1025
+ r.msaaRenderBuffer[c] = u;
1026
+ });
1027
+ } else
1028
+ r.framebuffer = i;
1029
+ this._resizeColor(e, r);
1030
+ }
1031
+ _resizeColor(e, r) {
1032
+ const s = e.colorTexture.source;
1033
+ if (r.width = s.pixelWidth, r.height = s.pixelHeight, e.colorTextures.forEach((n, i) => {
1034
+ i !== 0 && n.source.resize(s.width, s.height, s._resolution);
1035
+ }), r.msaa) {
1036
+ const n = this._renderer, i = n.gl, a = r.framebuffer;
1037
+ i.bindFramebuffer(i.FRAMEBUFFER, a), e.colorTextures.forEach((o, c) => {
1038
+ const u = o.source;
1039
+ n.texture.bindSource(u, 0);
1040
+ const f = n.texture.getGlSource(u).internalFormat, l = r.msaaRenderBuffer[c];
1041
+ i.bindRenderbuffer(
1042
+ i.RENDERBUFFER,
1043
+ l
1044
+ ), i.renderbufferStorageMultisample(
1045
+ i.RENDERBUFFER,
1046
+ 4,
1047
+ f,
1048
+ u.pixelWidth,
1049
+ u.pixelHeight
1050
+ ), i.framebufferRenderbuffer(
1051
+ i.FRAMEBUFFER,
1052
+ i.COLOR_ATTACHMENT0 + c,
1053
+ i.RENDERBUFFER,
1054
+ l
1055
+ );
1056
+ });
1057
+ }
1058
+ }
1059
+ _initStencil(e) {
1060
+ if (e.framebuffer === null)
1061
+ return;
1062
+ const r = this._renderer.gl, s = r.createRenderbuffer();
1063
+ e.depthStencilRenderBuffer = s, r.bindRenderbuffer(
1064
+ r.RENDERBUFFER,
1065
+ s
1066
+ ), r.framebufferRenderbuffer(
1067
+ r.FRAMEBUFFER,
1068
+ r.DEPTH_STENCIL_ATTACHMENT,
1069
+ r.RENDERBUFFER,
1070
+ s
1071
+ ), this._resizeStencil(e);
1072
+ }
1073
+ _resizeStencil(e) {
1074
+ const r = this._renderer.gl;
1075
+ r.bindRenderbuffer(
1076
+ r.RENDERBUFFER,
1077
+ e.depthStencilRenderBuffer
1078
+ ), e.msaa ? r.renderbufferStorageMultisample(
1079
+ r.RENDERBUFFER,
1080
+ 4,
1081
+ r.DEPTH24_STENCIL8,
1082
+ e.width,
1083
+ e.height
1084
+ ) : r.renderbufferStorage(
1085
+ r.RENDERBUFFER,
1086
+ this._renderer.context.webGLVersion === 2 ? r.DEPTH24_STENCIL8 : r.DEPTH_STENCIL,
1087
+ e.width,
1088
+ e.height
1089
+ );
1090
+ }
1091
+ prerender(e) {
1092
+ const r = e.colorTexture.resource;
1093
+ this._renderer.context.multiView && A.test(r) && this._renderer.context.ensureCanvasSize(r);
1094
+ }
1095
+ postrender(e) {
1096
+ if (this._renderer.context.multiView && A.test(e.colorTexture.resource)) {
1097
+ const r = this._renderer.context.canvas, s = e.colorTexture;
1098
+ s.context2D.drawImage(
1099
+ r,
1100
+ 0,
1101
+ s.pixelHeight - r.height
1102
+ );
1103
+ }
1104
+ }
1105
+ }
1106
+ class he extends Le {
1107
+ constructor(e) {
1108
+ super(e), this.adaptor = new Qe(), this.adaptor.init(e, this);
1109
+ }
1110
+ }
1111
+ he.extension = {
1112
+ type: [d.WebGLSystem],
1113
+ name: "renderTarget"
1114
+ };
1115
+ function Je(t, e) {
1116
+ const r = [], s = [`
1117
+ var g = s.groups;
1118
+ var sS = r.shader;
1119
+ var p = s.glProgram;
1120
+ var ugS = r.uniformGroup;
1121
+ var resources;
1122
+ `];
1123
+ let n = !1, i = 0;
1124
+ const a = e._getProgramData(t.glProgram);
1125
+ for (const c in t.groups) {
1126
+ const u = t.groups[c];
1127
+ r.push(`
1128
+ resources = g[${c}].resources;
1129
+ `);
1130
+ for (const _ in u.resources) {
1131
+ const f = u.resources[_];
1132
+ if (f instanceof F)
1133
+ if (f.ubo) {
1134
+ const l = t._uniformBindMap[c][Number(_)];
1135
+ r.push(`
1136
+ sS.bindUniformBlock(
1137
+ resources[${_}],
1138
+ '${l}',
1139
+ ${t.glProgram._uniformBlockData[l].index}
1140
+ );
1141
+ `);
1142
+ } else
1143
+ r.push(`
1144
+ ugS.updateUniformGroup(resources[${_}], p, sD);
1145
+ `);
1146
+ else if (f instanceof Q) {
1147
+ const l = t._uniformBindMap[c][Number(_)];
1148
+ r.push(`
1149
+ sS.bindUniformBlock(
1150
+ resources[${_}],
1151
+ '${l}',
1152
+ ${t.glProgram._uniformBlockData[l].index}
1153
+ );
1154
+ `);
1155
+ } else if (f instanceof $) {
1156
+ const l = t._uniformBindMap[c][_], E = a.uniformData[l];
1157
+ E && (n || (n = !0, s.push(`
1158
+ var tS = r.texture;
1159
+ `)), e._gl.uniform1i(E.location, i), r.push(`
1160
+ tS.bind(resources[${_}], ${i});
1161
+ `), i++);
1162
+ }
1163
+ }
1164
+ }
1165
+ const o = [...s, ...r].join(`
1166
+ `);
1167
+ return new Function("r", "s", "sD", o);
1168
+ }
1169
+ class et {
1170
+ /**
1171
+ * Makes a new Pixi program.
1172
+ * @param program - webgl program
1173
+ * @param uniformData - uniforms
1174
+ */
1175
+ constructor(e, r) {
1176
+ this.program = e, this.uniformData = r, this.uniformGroups = {}, this.uniformDirtyGroups = {}, this.uniformBlockBindings = {};
1177
+ }
1178
+ /** Destroys this program. */
1179
+ destroy() {
1180
+ this.uniformData = null, this.uniformGroups = null, this.uniformDirtyGroups = null, this.uniformBlockBindings = null, this.program = null;
1181
+ }
1182
+ }
1183
+ function V(t, e, r) {
1184
+ const s = t.createShader(e);
1185
+ return t.shaderSource(s, r), t.compileShader(s), s;
1186
+ }
1187
+ function C(t) {
1188
+ const e = new Array(t);
1189
+ for (let r = 0; r < e.length; r++)
1190
+ e[r] = !1;
1191
+ return e;
1192
+ }
1193
+ function fe(t, e) {
1194
+ switch (t) {
1195
+ case "float":
1196
+ return 0;
1197
+ case "vec2":
1198
+ return new Float32Array(2 * e);
1199
+ case "vec3":
1200
+ return new Float32Array(3 * e);
1201
+ case "vec4":
1202
+ return new Float32Array(4 * e);
1203
+ case "int":
1204
+ case "uint":
1205
+ case "sampler2D":
1206
+ case "sampler2DArray":
1207
+ return 0;
1208
+ case "ivec2":
1209
+ return new Int32Array(2 * e);
1210
+ case "ivec3":
1211
+ return new Int32Array(3 * e);
1212
+ case "ivec4":
1213
+ return new Int32Array(4 * e);
1214
+ case "uvec2":
1215
+ return new Uint32Array(2 * e);
1216
+ case "uvec3":
1217
+ return new Uint32Array(3 * e);
1218
+ case "uvec4":
1219
+ return new Uint32Array(4 * e);
1220
+ case "bool":
1221
+ return !1;
1222
+ case "bvec2":
1223
+ return C(2 * e);
1224
+ case "bvec3":
1225
+ return C(3 * e);
1226
+ case "bvec4":
1227
+ return C(4 * e);
1228
+ case "mat2":
1229
+ return new Float32Array([
1230
+ 1,
1231
+ 0,
1232
+ 0,
1233
+ 1
1234
+ ]);
1235
+ case "mat3":
1236
+ return new Float32Array([
1237
+ 1,
1238
+ 0,
1239
+ 0,
1240
+ 0,
1241
+ 1,
1242
+ 0,
1243
+ 0,
1244
+ 0,
1245
+ 1
1246
+ ]);
1247
+ case "mat4":
1248
+ return new Float32Array([
1249
+ 1,
1250
+ 0,
1251
+ 0,
1252
+ 0,
1253
+ 0,
1254
+ 1,
1255
+ 0,
1256
+ 0,
1257
+ 0,
1258
+ 0,
1259
+ 1,
1260
+ 0,
1261
+ 0,
1262
+ 0,
1263
+ 0,
1264
+ 1
1265
+ ]);
1266
+ }
1267
+ return null;
1268
+ }
1269
+ let g = null;
1270
+ const k = {
1271
+ FLOAT: "float",
1272
+ FLOAT_VEC2: "vec2",
1273
+ FLOAT_VEC3: "vec3",
1274
+ FLOAT_VEC4: "vec4",
1275
+ INT: "int",
1276
+ INT_VEC2: "ivec2",
1277
+ INT_VEC3: "ivec3",
1278
+ INT_VEC4: "ivec4",
1279
+ UNSIGNED_INT: "uint",
1280
+ UNSIGNED_INT_VEC2: "uvec2",
1281
+ UNSIGNED_INT_VEC3: "uvec3",
1282
+ UNSIGNED_INT_VEC4: "uvec4",
1283
+ BOOL: "bool",
1284
+ BOOL_VEC2: "bvec2",
1285
+ BOOL_VEC3: "bvec3",
1286
+ BOOL_VEC4: "bvec4",
1287
+ FLOAT_MAT2: "mat2",
1288
+ FLOAT_MAT3: "mat3",
1289
+ FLOAT_MAT4: "mat4",
1290
+ SAMPLER_2D: "sampler2D",
1291
+ INT_SAMPLER_2D: "sampler2D",
1292
+ UNSIGNED_INT_SAMPLER_2D: "sampler2D",
1293
+ SAMPLER_CUBE: "samplerCube",
1294
+ INT_SAMPLER_CUBE: "samplerCube",
1295
+ UNSIGNED_INT_SAMPLER_CUBE: "samplerCube",
1296
+ SAMPLER_2D_ARRAY: "sampler2DArray",
1297
+ INT_SAMPLER_2D_ARRAY: "sampler2DArray",
1298
+ UNSIGNED_INT_SAMPLER_2D_ARRAY: "sampler2DArray"
1299
+ }, tt = {
1300
+ float: "float32",
1301
+ vec2: "float32x2",
1302
+ vec3: "float32x3",
1303
+ vec4: "float32x4",
1304
+ int: "sint32",
1305
+ ivec2: "sint32x2",
1306
+ ivec3: "sint32x3",
1307
+ ivec4: "sint32x4",
1308
+ uint: "uint32",
1309
+ uvec2: "uint32x2",
1310
+ uvec3: "uint32x3",
1311
+ uvec4: "uint32x4",
1312
+ bool: "uint32",
1313
+ bvec2: "uint32x2",
1314
+ bvec3: "uint32x3",
1315
+ bvec4: "uint32x4"
1316
+ };
1317
+ function le(t, e) {
1318
+ if (!g) {
1319
+ const r = Object.keys(k);
1320
+ g = {};
1321
+ for (let s = 0; s < r.length; ++s) {
1322
+ const n = r[s];
1323
+ g[t[n]] = k[n];
1324
+ }
1325
+ }
1326
+ return g[e];
1327
+ }
1328
+ function rt(t, e) {
1329
+ const r = le(t, e);
1330
+ return tt[r] || "float32";
1331
+ }
1332
+ function st(t, e, r = !1) {
1333
+ const s = {}, n = e.getProgramParameter(t, e.ACTIVE_ATTRIBUTES);
1334
+ for (let a = 0; a < n; a++) {
1335
+ const o = e.getActiveAttrib(t, a);
1336
+ if (o.name.startsWith("gl_"))
1337
+ continue;
1338
+ const c = rt(e, o.type);
1339
+ s[o.name] = {
1340
+ location: 0,
1341
+ // set further down..
1342
+ format: c,
1343
+ stride: K(c).stride,
1344
+ offset: 0,
1345
+ instance: !1,
1346
+ start: 0
1347
+ };
1348
+ }
1349
+ const i = Object.keys(s);
1350
+ if (r) {
1351
+ i.sort((a, o) => a > o ? 1 : -1);
1352
+ for (let a = 0; a < i.length; a++)
1353
+ s[i[a]].location = a, e.bindAttribLocation(t, a, i[a]);
1354
+ e.linkProgram(t);
1355
+ } else
1356
+ for (let a = 0; a < i.length; a++)
1357
+ s[i[a]].location = e.getAttribLocation(t, i[a]);
1358
+ return s;
1359
+ }
1360
+ function nt(t, e) {
1361
+ if (!e.ACTIVE_UNIFORM_BLOCKS)
1362
+ return {};
1363
+ const r = {}, s = e.getProgramParameter(t, e.ACTIVE_UNIFORM_BLOCKS);
1364
+ for (let n = 0; n < s; n++) {
1365
+ const i = e.getActiveUniformBlockName(t, n), a = e.getUniformBlockIndex(t, i), o = e.getActiveUniformBlockParameter(t, n, e.UNIFORM_BLOCK_DATA_SIZE);
1366
+ r[i] = {
1367
+ name: i,
1368
+ index: a,
1369
+ size: o
1370
+ };
1371
+ }
1372
+ return r;
1373
+ }
1374
+ function it(t, e) {
1375
+ const r = {}, s = e.getProgramParameter(t, e.ACTIVE_UNIFORMS);
1376
+ for (let n = 0; n < s; n++) {
1377
+ const i = e.getActiveUniform(t, n), a = i.name.replace(/\[.*?\]$/, ""), o = !!i.name.match(/\[.*?\]$/), c = le(e, i.type);
1378
+ r[a] = {
1379
+ name: a,
1380
+ index: n,
1381
+ type: c,
1382
+ size: i.size,
1383
+ isArray: o,
1384
+ value: fe(c, i.size)
1385
+ };
1386
+ }
1387
+ return r;
1388
+ }
1389
+ function X(t, e) {
1390
+ const r = t.getShaderSource(e).split(`
1391
+ `).map((u, _) => `${_}: ${u}`), s = t.getShaderInfoLog(e), n = s.split(`
1392
+ `), i = {}, a = n.map((u) => parseFloat(u.replace(/^ERROR\: 0\:([\d]+)\:.*$/, "$1"))).filter((u) => u && !i[u] ? (i[u] = !0, !0) : !1), o = [""];
1393
+ a.forEach((u) => {
1394
+ r[u - 1] = `%c${r[u - 1]}%c`, o.push("background: #FF0000; color:#FFFFFF; font-size: 10px", "font-size: 10px");
1395
+ });
1396
+ const c = r.join(`
1397
+ `);
1398
+ o[0] = c, console.error(s), console.groupCollapsed("click to view full shader code"), console.warn(...o), console.groupEnd();
1399
+ }
1400
+ function at(t, e, r, s) {
1401
+ t.getProgramParameter(e, t.LINK_STATUS) || (t.getShaderParameter(r, t.COMPILE_STATUS) || X(t, r), t.getShaderParameter(s, t.COMPILE_STATUS) || X(t, s), console.error("PixiJS Error: Could not initialize shader."), t.getProgramInfoLog(e) !== "" && console.warn("PixiJS Warning: gl.getProgramInfoLog()", t.getProgramInfoLog(e)));
1402
+ }
1403
+ function ot(t, e) {
1404
+ const r = V(t, t.VERTEX_SHADER, e.vertex), s = V(t, t.FRAGMENT_SHADER, e.fragment), n = t.createProgram();
1405
+ t.attachShader(n, r), t.attachShader(n, s);
1406
+ const i = e.transformFeedbackVaryings;
1407
+ i && (typeof t.transformFeedbackVaryings != "function" ? m("TransformFeedback is not supported but TransformFeedbackVaryings are given.") : t.transformFeedbackVaryings(
1408
+ n,
1409
+ i.names,
1410
+ i.bufferMode === "separate" ? t.SEPARATE_ATTRIBS : t.INTERLEAVED_ATTRIBS
1411
+ )), t.linkProgram(n), t.getProgramParameter(n, t.LINK_STATUS) || at(t, n, r, s), e._attributeData = st(
1412
+ n,
1413
+ t,
1414
+ !/^[ \t]*#[ \t]*version[ \t]+300[ \t]+es[ \t]*$/m.test(e.vertex)
1415
+ ), e._uniformData = it(n, t), e._uniformBlockData = nt(n, t), t.deleteShader(r), t.deleteShader(s);
1416
+ const a = {};
1417
+ for (const c in e._uniformData) {
1418
+ const u = e._uniformData[c];
1419
+ a[c] = {
1420
+ location: t.getUniformLocation(n, c),
1421
+ value: fe(u.type, u.size)
1422
+ };
1423
+ }
1424
+ return new et(n, a);
1425
+ }
1426
+ const R = {
1427
+ textureCount: 0,
1428
+ blockIndex: 0
1429
+ };
1430
+ class de {
1431
+ constructor(e) {
1432
+ this._activeProgram = null, this._programDataHash = /* @__PURE__ */ Object.create(null), this._shaderSyncFunctions = /* @__PURE__ */ Object.create(null), this._renderer = e, this._renderer.renderableGC.addManagedHash(this, "_programDataHash");
1433
+ }
1434
+ contextChange(e) {
1435
+ this._gl = e, this._programDataHash = /* @__PURE__ */ Object.create(null), this._shaderSyncFunctions = /* @__PURE__ */ Object.create(null), this._activeProgram = null;
1436
+ }
1437
+ /**
1438
+ * Changes the current shader to the one given in parameter.
1439
+ * @param shader - the new shader
1440
+ * @param skipSync - false if the shader should automatically sync its uniforms.
1441
+ * @returns the glProgram that belongs to the shader.
1442
+ */
1443
+ bind(e, r) {
1444
+ if (this._setProgram(e.glProgram), r)
1445
+ return;
1446
+ R.textureCount = 0, R.blockIndex = 0;
1447
+ let s = this._shaderSyncFunctions[e.glProgram._key];
1448
+ s || (s = this._shaderSyncFunctions[e.glProgram._key] = this._generateShaderSync(e, this)), this._renderer.buffer.nextBindBase(!!e.glProgram.transformFeedbackVaryings), s(this._renderer, e, R);
1449
+ }
1450
+ /**
1451
+ * Updates the uniform group.
1452
+ * @param uniformGroup - the uniform group to update
1453
+ */
1454
+ updateUniformGroup(e) {
1455
+ this._renderer.uniformGroup.updateUniformGroup(e, this._activeProgram, R);
1456
+ }
1457
+ /**
1458
+ * Binds a uniform block to the shader.
1459
+ * @param uniformGroup - the uniform group to bind
1460
+ * @param name - the name of the uniform block
1461
+ * @param index - the index of the uniform block
1462
+ */
1463
+ bindUniformBlock(e, r, s = 0) {
1464
+ const n = this._renderer.buffer, i = this._getProgramData(this._activeProgram), a = e._bufferResource;
1465
+ a || this._renderer.ubo.updateUniformGroup(e);
1466
+ const o = e.buffer, c = n.updateBuffer(o), u = n.freeLocationForBufferBase(c);
1467
+ if (a) {
1468
+ const { offset: f, size: l } = e;
1469
+ f === 0 && l === o.data.byteLength ? n.bindBufferBase(c, u) : n.bindBufferRange(c, u, f);
1470
+ } else n.getLastBindBaseLocation(c) !== u && n.bindBufferBase(c, u);
1471
+ const _ = this._activeProgram._uniformBlockData[r].index;
1472
+ i.uniformBlockBindings[s] !== u && (i.uniformBlockBindings[s] = u, this._renderer.gl.uniformBlockBinding(i.program, _, u));
1473
+ }
1474
+ _setProgram(e) {
1475
+ if (this._activeProgram === e)
1476
+ return;
1477
+ this._activeProgram = e;
1478
+ const r = this._getProgramData(e);
1479
+ this._gl.useProgram(r.program);
1480
+ }
1481
+ /**
1482
+ * @param program - the program to get the data for
1483
+ * @internal
1484
+ */
1485
+ _getProgramData(e) {
1486
+ return this._programDataHash[e._key] || this._createProgramData(e);
1487
+ }
1488
+ _createProgramData(e) {
1489
+ const r = e._key;
1490
+ return this._programDataHash[r] = ot(this._gl, e), this._programDataHash[r];
1491
+ }
1492
+ destroy() {
1493
+ for (const e of Object.keys(this._programDataHash))
1494
+ this._programDataHash[e].destroy(), this._programDataHash[e] = null;
1495
+ this._programDataHash = null, this._shaderSyncFunctions = null, this._activeProgram = null, this._renderer = null, this._gl = null;
1496
+ }
1497
+ /**
1498
+ * Creates a function that can be executed that will sync the shader as efficiently as possible.
1499
+ * Overridden by the unsafe eval package if you don't want eval used in your project.
1500
+ * @param shader - the shader to generate the sync function for
1501
+ * @param shaderSystem - the shader system to use
1502
+ * @returns - the generated sync function
1503
+ * @ignore
1504
+ */
1505
+ _generateShaderSync(e, r) {
1506
+ return Je(e, r);
1507
+ }
1508
+ resetState() {
1509
+ this._activeProgram = null;
1510
+ }
1511
+ }
1512
+ de.extension = {
1513
+ type: [
1514
+ d.WebGLSystem
1515
+ ],
1516
+ name: "shader"
1517
+ };
1518
+ const ct = {
1519
+ f32: `if (cv !== v) {
1520
+ cu.value = v;
1521
+ gl.uniform1f(location, v);
1522
+ }`,
1523
+ "vec2<f32>": `if (cv[0] !== v[0] || cv[1] !== v[1]) {
1524
+ cv[0] = v[0];
1525
+ cv[1] = v[1];
1526
+ gl.uniform2f(location, v[0], v[1]);
1527
+ }`,
1528
+ "vec3<f32>": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2]) {
1529
+ cv[0] = v[0];
1530
+ cv[1] = v[1];
1531
+ cv[2] = v[2];
1532
+ gl.uniform3f(location, v[0], v[1], v[2]);
1533
+ }`,
1534
+ "vec4<f32>": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3]) {
1535
+ cv[0] = v[0];
1536
+ cv[1] = v[1];
1537
+ cv[2] = v[2];
1538
+ cv[3] = v[3];
1539
+ gl.uniform4f(location, v[0], v[1], v[2], v[3]);
1540
+ }`,
1541
+ i32: `if (cv !== v) {
1542
+ cu.value = v;
1543
+ gl.uniform1i(location, v);
1544
+ }`,
1545
+ "vec2<i32>": `if (cv[0] !== v[0] || cv[1] !== v[1]) {
1546
+ cv[0] = v[0];
1547
+ cv[1] = v[1];
1548
+ gl.uniform2i(location, v[0], v[1]);
1549
+ }`,
1550
+ "vec3<i32>": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2]) {
1551
+ cv[0] = v[0];
1552
+ cv[1] = v[1];
1553
+ cv[2] = v[2];
1554
+ gl.uniform3i(location, v[0], v[1], v[2]);
1555
+ }`,
1556
+ "vec4<i32>": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3]) {
1557
+ cv[0] = v[0];
1558
+ cv[1] = v[1];
1559
+ cv[2] = v[2];
1560
+ cv[3] = v[3];
1561
+ gl.uniform4i(location, v[0], v[1], v[2], v[3]);
1562
+ }`,
1563
+ u32: `if (cv !== v) {
1564
+ cu.value = v;
1565
+ gl.uniform1ui(location, v);
1566
+ }`,
1567
+ "vec2<u32>": `if (cv[0] !== v[0] || cv[1] !== v[1]) {
1568
+ cv[0] = v[0];
1569
+ cv[1] = v[1];
1570
+ gl.uniform2ui(location, v[0], v[1]);
1571
+ }`,
1572
+ "vec3<u32>": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2]) {
1573
+ cv[0] = v[0];
1574
+ cv[1] = v[1];
1575
+ cv[2] = v[2];
1576
+ gl.uniform3ui(location, v[0], v[1], v[2]);
1577
+ }`,
1578
+ "vec4<u32>": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3]) {
1579
+ cv[0] = v[0];
1580
+ cv[1] = v[1];
1581
+ cv[2] = v[2];
1582
+ cv[3] = v[3];
1583
+ gl.uniform4ui(location, v[0], v[1], v[2], v[3]);
1584
+ }`,
1585
+ bool: `if (cv !== v) {
1586
+ cu.value = v;
1587
+ gl.uniform1i(location, v);
1588
+ }`,
1589
+ "vec2<bool>": `if (cv[0] !== v[0] || cv[1] !== v[1]) {
1590
+ cv[0] = v[0];
1591
+ cv[1] = v[1];
1592
+ gl.uniform2i(location, v[0], v[1]);
1593
+ }`,
1594
+ "vec3<bool>": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2]) {
1595
+ cv[0] = v[0];
1596
+ cv[1] = v[1];
1597
+ cv[2] = v[2];
1598
+ gl.uniform3i(location, v[0], v[1], v[2]);
1599
+ }`,
1600
+ "vec4<bool>": `if (cv[0] !== v[0] || cv[1] !== v[1] || cv[2] !== v[2] || cv[3] !== v[3]) {
1601
+ cv[0] = v[0];
1602
+ cv[1] = v[1];
1603
+ cv[2] = v[2];
1604
+ cv[3] = v[3];
1605
+ gl.uniform4i(location, v[0], v[1], v[2], v[3]);
1606
+ }`,
1607
+ "mat2x2<f32>": "gl.uniformMatrix2fv(location, false, v);",
1608
+ "mat3x3<f32>": "gl.uniformMatrix3fv(location, false, v);",
1609
+ "mat4x4<f32>": "gl.uniformMatrix4fv(location, false, v);"
1610
+ }, ut = {
1611
+ f32: "gl.uniform1fv(location, v);",
1612
+ "vec2<f32>": "gl.uniform2fv(location, v);",
1613
+ "vec3<f32>": "gl.uniform3fv(location, v);",
1614
+ "vec4<f32>": "gl.uniform4fv(location, v);",
1615
+ "mat2x2<f32>": "gl.uniformMatrix2fv(location, false, v);",
1616
+ "mat3x3<f32>": "gl.uniformMatrix3fv(location, false, v);",
1617
+ "mat4x4<f32>": "gl.uniformMatrix4fv(location, false, v);",
1618
+ i32: "gl.uniform1iv(location, v);",
1619
+ "vec2<i32>": "gl.uniform2iv(location, v);",
1620
+ "vec3<i32>": "gl.uniform3iv(location, v);",
1621
+ "vec4<i32>": "gl.uniform4iv(location, v);",
1622
+ u32: "gl.uniform1iv(location, v);",
1623
+ "vec2<u32>": "gl.uniform2iv(location, v);",
1624
+ "vec3<u32>": "gl.uniform3iv(location, v);",
1625
+ "vec4<u32>": "gl.uniform4iv(location, v);",
1626
+ bool: "gl.uniform1iv(location, v);",
1627
+ "vec2<bool>": "gl.uniform2iv(location, v);",
1628
+ "vec3<bool>": "gl.uniform3iv(location, v);",
1629
+ "vec4<bool>": "gl.uniform4iv(location, v);"
1630
+ };
1631
+ function _t(t, e) {
1632
+ const r = [`
1633
+ var v = null;
1634
+ var cv = null;
1635
+ var cu = null;
1636
+ var t = 0;
1637
+ var gl = renderer.gl;
1638
+ var name = null;
1639
+ `];
1640
+ for (const s in t.uniforms) {
1641
+ if (!e[s]) {
1642
+ t.uniforms[s] instanceof F ? t.uniforms[s].ubo ? r.push(`
1643
+ renderer.shader.bindUniformBlock(uv.${s}, "${s}");
1644
+ `) : r.push(`
1645
+ renderer.shader.updateUniformGroup(uv.${s});
1646
+ `) : t.uniforms[s] instanceof Q && r.push(`
1647
+ renderer.shader.bindBufferResource(uv.${s}, "${s}");
1648
+ `);
1649
+ continue;
1650
+ }
1651
+ const n = t.uniformStructures[s];
1652
+ let i = !1;
1653
+ for (let a = 0; a < y.length; a++) {
1654
+ const o = y[a];
1655
+ if (n.type === o.type && o.test(n)) {
1656
+ r.push(`name = "${s}";`, y[a].uniform), i = !0;
1657
+ break;
1658
+ }
1659
+ }
1660
+ if (!i) {
1661
+ const o = (n.size === 1 ? ct : ut)[n.type].replace("location", `ud["${s}"].location`);
1662
+ r.push(`
1663
+ cu = ud["${s}"];
1664
+ cv = cu.value;
1665
+ v = uv["${s}"];
1666
+ ${o};`);
1667
+ }
1668
+ }
1669
+ return new Function("ud", "uv", "renderer", "syncData", r.join(`
1670
+ `));
1671
+ }
1672
+ class me {
1673
+ /** @param renderer - The renderer this System works for. */
1674
+ constructor(e) {
1675
+ this._cache = {}, this._uniformGroupSyncHash = {}, this._renderer = e, this.gl = null, this._cache = {};
1676
+ }
1677
+ contextChange(e) {
1678
+ this.gl = e;
1679
+ }
1680
+ /**
1681
+ * Uploads the uniforms values to the currently bound shader.
1682
+ * @param group - the uniforms values that be applied to the current shader
1683
+ * @param program
1684
+ * @param syncData
1685
+ * @param syncData.textureCount
1686
+ */
1687
+ updateUniformGroup(e, r, s) {
1688
+ const n = this._renderer.shader._getProgramData(r);
1689
+ (!e.isStatic || e._dirtyId !== n.uniformDirtyGroups[e.uid]) && (n.uniformDirtyGroups[e.uid] = e._dirtyId, this._getUniformSyncFunction(e, r)(n.uniformData, e.uniforms, this._renderer, s));
1690
+ }
1691
+ /**
1692
+ * Overridable by the pixi.js/unsafe-eval package to use static syncUniforms instead.
1693
+ * @param group
1694
+ * @param program
1695
+ */
1696
+ _getUniformSyncFunction(e, r) {
1697
+ var s;
1698
+ return ((s = this._uniformGroupSyncHash[e._signature]) == null ? void 0 : s[r._key]) || this._createUniformSyncFunction(e, r);
1699
+ }
1700
+ _createUniformSyncFunction(e, r) {
1701
+ const s = this._uniformGroupSyncHash[e._signature] || (this._uniformGroupSyncHash[e._signature] = {}), n = this._getSignature(e, r._uniformData, "u");
1702
+ return this._cache[n] || (this._cache[n] = this._generateUniformsSync(e, r._uniformData)), s[r._key] = this._cache[n], s[r._key];
1703
+ }
1704
+ _generateUniformsSync(e, r) {
1705
+ return _t(e, r);
1706
+ }
1707
+ /**
1708
+ * Takes a uniform group and data and generates a unique signature for them.
1709
+ * @param group - The uniform group to get signature of
1710
+ * @param group.uniforms
1711
+ * @param uniformData - Uniform information generated by the shader
1712
+ * @param preFix
1713
+ * @returns Unique signature of the uniform group
1714
+ */
1715
+ _getSignature(e, r, s) {
1716
+ const n = e.uniforms, i = [`${s}-`];
1717
+ for (const a in n)
1718
+ i.push(a), r[a] && i.push(r[a].type);
1719
+ return i.join("-");
1720
+ }
1721
+ /** Destroys this System and removes all its textures. */
1722
+ destroy() {
1723
+ this._renderer = null, this._cache = null;
1724
+ }
1725
+ }
1726
+ me.extension = {
1727
+ type: [
1728
+ d.WebGLSystem
1729
+ ],
1730
+ name: "uniformGroup"
1731
+ };
1732
+ function ht(t) {
1733
+ const e = {};
1734
+ if (e.normal = [t.ONE, t.ONE_MINUS_SRC_ALPHA], e.add = [t.ONE, t.ONE], e.multiply = [t.DST_COLOR, t.ONE_MINUS_SRC_ALPHA, t.ONE, t.ONE_MINUS_SRC_ALPHA], e.screen = [t.ONE, t.ONE_MINUS_SRC_COLOR, t.ONE, t.ONE_MINUS_SRC_ALPHA], e.none = [0, 0], e["normal-npm"] = [t.SRC_ALPHA, t.ONE_MINUS_SRC_ALPHA, t.ONE, t.ONE_MINUS_SRC_ALPHA], e["add-npm"] = [t.SRC_ALPHA, t.ONE, t.ONE, t.ONE], e["screen-npm"] = [t.SRC_ALPHA, t.ONE_MINUS_SRC_COLOR, t.ONE, t.ONE_MINUS_SRC_ALPHA], e.erase = [t.ZERO, t.ONE_MINUS_SRC_ALPHA], !(t instanceof S.get().getWebGLRenderingContext()))
1735
+ e.min = [t.ONE, t.ONE, t.ONE, t.ONE, t.MIN, t.MIN], e.max = [t.ONE, t.ONE, t.ONE, t.ONE, t.MAX, t.MAX];
1736
+ else {
1737
+ const s = t.getExtension("EXT_blend_minmax");
1738
+ s && (e.min = [t.ONE, t.ONE, t.ONE, t.ONE, s.MIN_EXT, s.MIN_EXT], e.max = [t.ONE, t.ONE, t.ONE, t.ONE, s.MAX_EXT, s.MAX_EXT]);
1739
+ }
1740
+ return e;
1741
+ }
1742
+ const ft = 0, lt = 1, dt = 2, mt = 3, Et = 4, bt = 5, Ee = class G {
1743
+ constructor(e) {
1744
+ this._invertFrontFace = !1, this.gl = null, this.stateId = 0, this.polygonOffset = 0, this.blendMode = "none", this._blendEq = !1, this.map = [], this.map[ft] = this.setBlend, this.map[lt] = this.setOffset, this.map[dt] = this.setCullFace, this.map[mt] = this.setDepthTest, this.map[Et] = this.setFrontFace, this.map[bt] = this.setDepthMask, this.checks = [], this.defaultState = O.for2d(), e.renderTarget.onRenderTargetChange.add(this);
1745
+ }
1746
+ onRenderTargetChange(e) {
1747
+ this._invertFrontFace = !e.isRoot, this._cullFace ? this.setFrontFace(this._frontFace) : this._frontFaceDirty = !0;
1748
+ }
1749
+ contextChange(e) {
1750
+ this.gl = e, this.blendModesMap = ht(e), this.resetState();
1751
+ }
1752
+ /**
1753
+ * Sets the current state
1754
+ * @param {*} state - The state to set.
1755
+ */
1756
+ set(e) {
1757
+ if (e || (e = this.defaultState), this.stateId !== e.data) {
1758
+ let r = this.stateId ^ e.data, s = 0;
1759
+ for (; r; )
1760
+ r & 1 && this.map[s].call(this, !!(e.data & 1 << s)), r >>= 1, s++;
1761
+ this.stateId = e.data;
1762
+ }
1763
+ for (let r = 0; r < this.checks.length; r++)
1764
+ this.checks[r](this, e);
1765
+ }
1766
+ /**
1767
+ * Sets the state, when previous state is unknown.
1768
+ * @param {*} state - The state to set
1769
+ */
1770
+ forceState(e) {
1771
+ e || (e = this.defaultState);
1772
+ for (let r = 0; r < this.map.length; r++)
1773
+ this.map[r].call(this, !!(e.data & 1 << r));
1774
+ for (let r = 0; r < this.checks.length; r++)
1775
+ this.checks[r](this, e);
1776
+ this.stateId = e.data;
1777
+ }
1778
+ /**
1779
+ * Sets whether to enable or disable blending.
1780
+ * @param value - Turn on or off WebGl blending.
1781
+ */
1782
+ setBlend(e) {
1783
+ this._updateCheck(G._checkBlendMode, e), this.gl[e ? "enable" : "disable"](this.gl.BLEND);
1784
+ }
1785
+ /**
1786
+ * Sets whether to enable or disable polygon offset fill.
1787
+ * @param value - Turn on or off webgl polygon offset testing.
1788
+ */
1789
+ setOffset(e) {
1790
+ this._updateCheck(G._checkPolygonOffset, e), this.gl[e ? "enable" : "disable"](this.gl.POLYGON_OFFSET_FILL);
1791
+ }
1792
+ /**
1793
+ * Sets whether to enable or disable depth test.
1794
+ * @param value - Turn on or off webgl depth testing.
1795
+ */
1796
+ setDepthTest(e) {
1797
+ this.gl[e ? "enable" : "disable"](this.gl.DEPTH_TEST);
1798
+ }
1799
+ /**
1800
+ * Sets whether to enable or disable depth mask.
1801
+ * @param value - Turn on or off webgl depth mask.
1802
+ */
1803
+ setDepthMask(e) {
1804
+ this.gl.depthMask(e);
1805
+ }
1806
+ /**
1807
+ * Sets whether to enable or disable cull face.
1808
+ * @param {boolean} value - Turn on or off webgl cull face.
1809
+ */
1810
+ setCullFace(e) {
1811
+ this._cullFace = e, this.gl[e ? "enable" : "disable"](this.gl.CULL_FACE), this._cullFace && this._frontFaceDirty && this.setFrontFace(this._frontFace);
1812
+ }
1813
+ /**
1814
+ * Sets the gl front face.
1815
+ * @param {boolean} value - true is clockwise and false is counter-clockwise
1816
+ */
1817
+ setFrontFace(e) {
1818
+ this._frontFace = e, this._frontFaceDirty = !1;
1819
+ const r = this._invertFrontFace ? !e : e;
1820
+ this._glFrontFace !== r && (this._glFrontFace = r, this.gl.frontFace(this.gl[r ? "CW" : "CCW"]));
1821
+ }
1822
+ /**
1823
+ * Sets the blend mode.
1824
+ * @param {number} value - The blend mode to set to.
1825
+ */
1826
+ setBlendMode(e) {
1827
+ if (this.blendModesMap[e] || (e = "normal"), e === this.blendMode)
1828
+ return;
1829
+ this.blendMode = e;
1830
+ const r = this.blendModesMap[e], s = this.gl;
1831
+ r.length === 2 ? s.blendFunc(r[0], r[1]) : s.blendFuncSeparate(r[0], r[1], r[2], r[3]), r.length === 6 ? (this._blendEq = !0, s.blendEquationSeparate(r[4], r[5])) : this._blendEq && (this._blendEq = !1, s.blendEquationSeparate(s.FUNC_ADD, s.FUNC_ADD));
1832
+ }
1833
+ /**
1834
+ * Sets the polygon offset.
1835
+ * @param {number} value - the polygon offset
1836
+ * @param {number} scale - the polygon offset scale
1837
+ */
1838
+ setPolygonOffset(e, r) {
1839
+ this.gl.polygonOffset(e, r);
1840
+ }
1841
+ /** Resets all the logic and disables the VAOs. */
1842
+ resetState() {
1843
+ this._glFrontFace = !1, this._frontFace = !1, this._cullFace = !1, this._frontFaceDirty = !1, this._invertFrontFace = !1, this.gl.frontFace(this.gl.CCW), this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, !1), this.forceState(this.defaultState), this._blendEq = !0, this.blendMode = "", this.setBlendMode("normal");
1844
+ }
1845
+ /**
1846
+ * Checks to see which updates should be checked based on which settings have been activated.
1847
+ *
1848
+ * For example, if blend is enabled then we should check the blend modes each time the state is changed
1849
+ * or if polygon fill is activated then we need to check if the polygon offset changes.
1850
+ * The idea is that we only check what we have too.
1851
+ * @param func - the checking function to add or remove
1852
+ * @param value - should the check function be added or removed.
1853
+ */
1854
+ _updateCheck(e, r) {
1855
+ const s = this.checks.indexOf(e);
1856
+ r && s === -1 ? this.checks.push(e) : !r && s !== -1 && this.checks.splice(s, 1);
1857
+ }
1858
+ /**
1859
+ * A private little wrapper function that we call to check the blend mode.
1860
+ * @param system - the System to perform the state check on
1861
+ * @param state - the state that the blendMode will pulled from
1862
+ */
1863
+ static _checkBlendMode(e, r) {
1864
+ e.setBlendMode(r.blendMode);
1865
+ }
1866
+ /**
1867
+ * A private little wrapper function that we call to check the polygon offset.
1868
+ * @param system - the System to perform the state check on
1869
+ * @param state - the state that the blendMode will pulled from
1870
+ */
1871
+ static _checkPolygonOffset(e, r) {
1872
+ e.setPolygonOffset(1, r.polygonOffset);
1873
+ }
1874
+ /** @ignore */
1875
+ destroy() {
1876
+ this.gl = null, this.checks.length = 0;
1877
+ }
1878
+ };
1879
+ Ee.extension = {
1880
+ type: [
1881
+ d.WebGLSystem
1882
+ ],
1883
+ name: "state"
1884
+ };
1885
+ let St = Ee;
1886
+ class pt {
1887
+ constructor(e) {
1888
+ this.target = re.TEXTURE_2D, this.texture = e, this.width = -1, this.height = -1, this.type = h.UNSIGNED_BYTE, this.internalFormat = D.RGBA, this.format = D.RGBA, this.samplerType = 0;
1889
+ }
1890
+ }
1891
+ const gt = {
1892
+ id: "buffer",
1893
+ upload(t, e, r) {
1894
+ e.width === t.width || e.height === t.height ? r.texSubImage2D(
1895
+ r.TEXTURE_2D,
1896
+ 0,
1897
+ 0,
1898
+ 0,
1899
+ t.width,
1900
+ t.height,
1901
+ e.format,
1902
+ e.type,
1903
+ t.resource
1904
+ ) : r.texImage2D(
1905
+ e.target,
1906
+ 0,
1907
+ e.internalFormat,
1908
+ t.width,
1909
+ t.height,
1910
+ 0,
1911
+ e.format,
1912
+ e.type,
1913
+ t.resource
1914
+ ), e.width = t.width, e.height = t.height;
1915
+ }
1916
+ }, Rt = {
1917
+ "bc1-rgba-unorm": !0,
1918
+ "bc1-rgba-unorm-srgb": !0,
1919
+ "bc2-rgba-unorm": !0,
1920
+ "bc2-rgba-unorm-srgb": !0,
1921
+ "bc3-rgba-unorm": !0,
1922
+ "bc3-rgba-unorm-srgb": !0,
1923
+ "bc4-r-unorm": !0,
1924
+ "bc4-r-snorm": !0,
1925
+ "bc5-rg-unorm": !0,
1926
+ "bc5-rg-snorm": !0,
1927
+ "bc6h-rgb-ufloat": !0,
1928
+ "bc6h-rgb-float": !0,
1929
+ "bc7-rgba-unorm": !0,
1930
+ "bc7-rgba-unorm-srgb": !0,
1931
+ // ETC2 compressed formats usable if "texture-compression-etc2" is both
1932
+ // supported by the device/user agent and enabled in requestDevice.
1933
+ "etc2-rgb8unorm": !0,
1934
+ "etc2-rgb8unorm-srgb": !0,
1935
+ "etc2-rgb8a1unorm": !0,
1936
+ "etc2-rgb8a1unorm-srgb": !0,
1937
+ "etc2-rgba8unorm": !0,
1938
+ "etc2-rgba8unorm-srgb": !0,
1939
+ "eac-r11unorm": !0,
1940
+ "eac-r11snorm": !0,
1941
+ "eac-rg11unorm": !0,
1942
+ "eac-rg11snorm": !0,
1943
+ // ASTC compressed formats usable if "texture-compression-astc" is both
1944
+ // supported by the device/user agent and enabled in requestDevice.
1945
+ "astc-4x4-unorm": !0,
1946
+ "astc-4x4-unorm-srgb": !0,
1947
+ "astc-5x4-unorm": !0,
1948
+ "astc-5x4-unorm-srgb": !0,
1949
+ "astc-5x5-unorm": !0,
1950
+ "astc-5x5-unorm-srgb": !0,
1951
+ "astc-6x5-unorm": !0,
1952
+ "astc-6x5-unorm-srgb": !0,
1953
+ "astc-6x6-unorm": !0,
1954
+ "astc-6x6-unorm-srgb": !0,
1955
+ "astc-8x5-unorm": !0,
1956
+ "astc-8x5-unorm-srgb": !0,
1957
+ "astc-8x6-unorm": !0,
1958
+ "astc-8x6-unorm-srgb": !0,
1959
+ "astc-8x8-unorm": !0,
1960
+ "astc-8x8-unorm-srgb": !0,
1961
+ "astc-10x5-unorm": !0,
1962
+ "astc-10x5-unorm-srgb": !0,
1963
+ "astc-10x6-unorm": !0,
1964
+ "astc-10x6-unorm-srgb": !0,
1965
+ "astc-10x8-unorm": !0,
1966
+ "astc-10x8-unorm-srgb": !0,
1967
+ "astc-10x10-unorm": !0,
1968
+ "astc-10x10-unorm-srgb": !0,
1969
+ "astc-12x10-unorm": !0,
1970
+ "astc-12x10-unorm-srgb": !0,
1971
+ "astc-12x12-unorm": !0,
1972
+ "astc-12x12-unorm-srgb": !0
1973
+ }, xt = {
1974
+ id: "compressed",
1975
+ upload(t, e, r) {
1976
+ r.pixelStorei(r.UNPACK_ALIGNMENT, 4);
1977
+ let s = t.pixelWidth, n = t.pixelHeight;
1978
+ const i = !!Rt[t.format];
1979
+ for (let a = 0; a < t.resource.length; a++) {
1980
+ const o = t.resource[a];
1981
+ i ? r.compressedTexImage2D(
1982
+ r.TEXTURE_2D,
1983
+ a,
1984
+ e.internalFormat,
1985
+ s,
1986
+ n,
1987
+ 0,
1988
+ o
1989
+ ) : r.texImage2D(
1990
+ r.TEXTURE_2D,
1991
+ a,
1992
+ e.internalFormat,
1993
+ s,
1994
+ n,
1995
+ 0,
1996
+ e.format,
1997
+ e.type,
1998
+ o
1999
+ ), s = Math.max(s >> 1, 1), n = Math.max(n >> 1, 1);
2000
+ }
2001
+ }
2002
+ }, be = {
2003
+ id: "image",
2004
+ upload(t, e, r, s) {
2005
+ const n = e.width, i = e.height, a = t.pixelWidth, o = t.pixelHeight, c = t.resourceWidth, u = t.resourceHeight;
2006
+ c < a || u < o ? ((n !== a || i !== o) && r.texImage2D(
2007
+ e.target,
2008
+ 0,
2009
+ e.internalFormat,
2010
+ a,
2011
+ o,
2012
+ 0,
2013
+ e.format,
2014
+ e.type,
2015
+ null
2016
+ ), s === 2 ? r.texSubImage2D(
2017
+ r.TEXTURE_2D,
2018
+ 0,
2019
+ 0,
2020
+ 0,
2021
+ c,
2022
+ u,
2023
+ e.format,
2024
+ e.type,
2025
+ t.resource
2026
+ ) : r.texSubImage2D(
2027
+ r.TEXTURE_2D,
2028
+ 0,
2029
+ 0,
2030
+ 0,
2031
+ e.format,
2032
+ e.type,
2033
+ t.resource
2034
+ )) : n === a && i === o ? r.texSubImage2D(
2035
+ r.TEXTURE_2D,
2036
+ 0,
2037
+ 0,
2038
+ 0,
2039
+ e.format,
2040
+ e.type,
2041
+ t.resource
2042
+ ) : s === 2 ? r.texImage2D(
2043
+ e.target,
2044
+ 0,
2045
+ e.internalFormat,
2046
+ a,
2047
+ o,
2048
+ 0,
2049
+ e.format,
2050
+ e.type,
2051
+ t.resource
2052
+ ) : r.texImage2D(
2053
+ e.target,
2054
+ 0,
2055
+ e.internalFormat,
2056
+ e.format,
2057
+ e.type,
2058
+ t.resource
2059
+ ), e.width = a, e.height = o;
2060
+ }
2061
+ }, Tt = {
2062
+ id: "video",
2063
+ upload(t, e, r, s) {
2064
+ if (!t.isValid) {
2065
+ r.texImage2D(
2066
+ e.target,
2067
+ 0,
2068
+ e.internalFormat,
2069
+ 1,
2070
+ 1,
2071
+ 0,
2072
+ e.format,
2073
+ e.type,
2074
+ null
2075
+ );
2076
+ return;
2077
+ }
2078
+ be.upload(t, e, r, s);
2079
+ }
2080
+ }, W = {
2081
+ linear: 9729,
2082
+ nearest: 9728
2083
+ }, vt = {
2084
+ linear: {
2085
+ linear: 9987,
2086
+ nearest: 9985
2087
+ },
2088
+ nearest: {
2089
+ linear: 9986,
2090
+ nearest: 9984
2091
+ }
2092
+ }, I = {
2093
+ "clamp-to-edge": 33071,
2094
+ repeat: 10497,
2095
+ "mirror-repeat": 33648
2096
+ }, Bt = {
2097
+ never: 512,
2098
+ less: 513,
2099
+ equal: 514,
2100
+ "less-equal": 515,
2101
+ greater: 516,
2102
+ "not-equal": 517,
2103
+ "greater-equal": 518,
2104
+ always: 519
2105
+ };
2106
+ function j(t, e, r, s, n, i, a, o) {
2107
+ const c = i;
2108
+ if (!o || t.addressModeU !== "repeat" || t.addressModeV !== "repeat" || t.addressModeW !== "repeat") {
2109
+ const u = I[a ? "clamp-to-edge" : t.addressModeU], _ = I[a ? "clamp-to-edge" : t.addressModeV], f = I[a ? "clamp-to-edge" : t.addressModeW];
2110
+ e[n](c, e.TEXTURE_WRAP_S, u), e[n](c, e.TEXTURE_WRAP_T, _), e.TEXTURE_WRAP_R && e[n](c, e.TEXTURE_WRAP_R, f);
2111
+ }
2112
+ if ((!o || t.magFilter !== "linear") && e[n](c, e.TEXTURE_MAG_FILTER, W[t.magFilter]), r) {
2113
+ if (!o || t.mipmapFilter !== "linear") {
2114
+ const u = vt[t.minFilter][t.mipmapFilter];
2115
+ e[n](c, e.TEXTURE_MIN_FILTER, u);
2116
+ }
2117
+ } else
2118
+ e[n](c, e.TEXTURE_MIN_FILTER, W[t.minFilter]);
2119
+ if (s && t.maxAnisotropy > 1) {
2120
+ const u = Math.min(t.maxAnisotropy, e.getParameter(s.MAX_TEXTURE_MAX_ANISOTROPY_EXT));
2121
+ e[n](c, s.TEXTURE_MAX_ANISOTROPY_EXT, u);
2122
+ }
2123
+ t.compare && e[n](c, e.TEXTURE_COMPARE_FUNC, Bt[t.compare]);
2124
+ }
2125
+ function At(t) {
2126
+ return {
2127
+ // 8-bit formats
2128
+ r8unorm: t.RED,
2129
+ r8snorm: t.RED,
2130
+ r8uint: t.RED,
2131
+ r8sint: t.RED,
2132
+ // 16-bit formats
2133
+ r16uint: t.RED,
2134
+ r16sint: t.RED,
2135
+ r16float: t.RED,
2136
+ rg8unorm: t.RG,
2137
+ rg8snorm: t.RG,
2138
+ rg8uint: t.RG,
2139
+ rg8sint: t.RG,
2140
+ // 32-bit formats
2141
+ r32uint: t.RED,
2142
+ r32sint: t.RED,
2143
+ r32float: t.RED,
2144
+ rg16uint: t.RG,
2145
+ rg16sint: t.RG,
2146
+ rg16float: t.RG,
2147
+ rgba8unorm: t.RGBA,
2148
+ "rgba8unorm-srgb": t.RGBA,
2149
+ // Packed 32-bit formats
2150
+ rgba8snorm: t.RGBA,
2151
+ rgba8uint: t.RGBA,
2152
+ rgba8sint: t.RGBA,
2153
+ bgra8unorm: t.RGBA,
2154
+ "bgra8unorm-srgb": t.RGBA,
2155
+ rgb9e5ufloat: t.RGB,
2156
+ rgb10a2unorm: t.RGBA,
2157
+ rg11b10ufloat: t.RGB,
2158
+ // 64-bit formats
2159
+ rg32uint: t.RG,
2160
+ rg32sint: t.RG,
2161
+ rg32float: t.RG,
2162
+ rgba16uint: t.RGBA,
2163
+ rgba16sint: t.RGBA,
2164
+ rgba16float: t.RGBA,
2165
+ // 128-bit formats
2166
+ rgba32uint: t.RGBA,
2167
+ rgba32sint: t.RGBA,
2168
+ rgba32float: t.RGBA,
2169
+ // Depth/stencil formats
2170
+ stencil8: t.STENCIL_INDEX8,
2171
+ depth16unorm: t.DEPTH_COMPONENT,
2172
+ depth24plus: t.DEPTH_COMPONENT,
2173
+ "depth24plus-stencil8": t.DEPTH_STENCIL,
2174
+ depth32float: t.DEPTH_COMPONENT,
2175
+ "depth32float-stencil8": t.DEPTH_STENCIL
2176
+ };
2177
+ }
2178
+ function Nt(t, e) {
2179
+ let r = {}, s = t.RGBA;
2180
+ return t instanceof S.get().getWebGLRenderingContext() ? e.srgb && (r = {
2181
+ "rgba8unorm-srgb": e.srgb.SRGB8_ALPHA8_EXT,
2182
+ "bgra8unorm-srgb": e.srgb.SRGB8_ALPHA8_EXT
2183
+ }) : (r = {
2184
+ "rgba8unorm-srgb": t.SRGB8_ALPHA8,
2185
+ "bgra8unorm-srgb": t.SRGB8_ALPHA8
2186
+ }, s = t.RGBA8), {
2187
+ // 8-bit formats
2188
+ r8unorm: t.R8,
2189
+ r8snorm: t.R8_SNORM,
2190
+ r8uint: t.R8UI,
2191
+ r8sint: t.R8I,
2192
+ // 16-bit formats
2193
+ r16uint: t.R16UI,
2194
+ r16sint: t.R16I,
2195
+ r16float: t.R16F,
2196
+ rg8unorm: t.RG8,
2197
+ rg8snorm: t.RG8_SNORM,
2198
+ rg8uint: t.RG8UI,
2199
+ rg8sint: t.RG8I,
2200
+ // 32-bit formats
2201
+ r32uint: t.R32UI,
2202
+ r32sint: t.R32I,
2203
+ r32float: t.R32F,
2204
+ rg16uint: t.RG16UI,
2205
+ rg16sint: t.RG16I,
2206
+ rg16float: t.RG16F,
2207
+ rgba8unorm: t.RGBA,
2208
+ ...r,
2209
+ // Packed 32-bit formats
2210
+ rgba8snorm: t.RGBA8_SNORM,
2211
+ rgba8uint: t.RGBA8UI,
2212
+ rgba8sint: t.RGBA8I,
2213
+ bgra8unorm: s,
2214
+ rgb9e5ufloat: t.RGB9_E5,
2215
+ rgb10a2unorm: t.RGB10_A2,
2216
+ rg11b10ufloat: t.R11F_G11F_B10F,
2217
+ // 64-bit formats
2218
+ rg32uint: t.RG32UI,
2219
+ rg32sint: t.RG32I,
2220
+ rg32float: t.RG32F,
2221
+ rgba16uint: t.RGBA16UI,
2222
+ rgba16sint: t.RGBA16I,
2223
+ rgba16float: t.RGBA16F,
2224
+ // 128-bit formats
2225
+ rgba32uint: t.RGBA32UI,
2226
+ rgba32sint: t.RGBA32I,
2227
+ rgba32float: t.RGBA32F,
2228
+ // Depth/stencil formats
2229
+ stencil8: t.STENCIL_INDEX8,
2230
+ depth16unorm: t.DEPTH_COMPONENT16,
2231
+ depth24plus: t.DEPTH_COMPONENT24,
2232
+ "depth24plus-stencil8": t.DEPTH24_STENCIL8,
2233
+ depth32float: t.DEPTH_COMPONENT32F,
2234
+ "depth32float-stencil8": t.DEPTH32F_STENCIL8,
2235
+ // Compressed formats
2236
+ ...e.s3tc ? {
2237
+ "bc1-rgba-unorm": e.s3tc.COMPRESSED_RGBA_S3TC_DXT1_EXT,
2238
+ "bc2-rgba-unorm": e.s3tc.COMPRESSED_RGBA_S3TC_DXT3_EXT,
2239
+ "bc3-rgba-unorm": e.s3tc.COMPRESSED_RGBA_S3TC_DXT5_EXT
2240
+ } : {},
2241
+ ...e.s3tc_sRGB ? {
2242
+ "bc1-rgba-unorm-srgb": e.s3tc_sRGB.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,
2243
+ "bc2-rgba-unorm-srgb": e.s3tc_sRGB.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,
2244
+ "bc3-rgba-unorm-srgb": e.s3tc_sRGB.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT
2245
+ } : {},
2246
+ ...e.rgtc ? {
2247
+ "bc4-r-unorm": e.rgtc.COMPRESSED_RED_RGTC1_EXT,
2248
+ "bc4-r-snorm": e.rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT,
2249
+ "bc5-rg-unorm": e.rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT,
2250
+ "bc5-rg-snorm": e.rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT
2251
+ } : {},
2252
+ ...e.bptc ? {
2253
+ "bc6h-rgb-float": e.bptc.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT,
2254
+ "bc6h-rgb-ufloat": e.bptc.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT,
2255
+ "bc7-rgba-unorm": e.bptc.COMPRESSED_RGBA_BPTC_UNORM_EXT,
2256
+ "bc7-rgba-unorm-srgb": e.bptc.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT
2257
+ } : {},
2258
+ ...e.etc ? {
2259
+ "etc2-rgb8unorm": e.etc.COMPRESSED_RGB8_ETC2,
2260
+ "etc2-rgb8unorm-srgb": e.etc.COMPRESSED_SRGB8_ETC2,
2261
+ "etc2-rgb8a1unorm": e.etc.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
2262
+ "etc2-rgb8a1unorm-srgb": e.etc.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
2263
+ "etc2-rgba8unorm": e.etc.COMPRESSED_RGBA8_ETC2_EAC,
2264
+ "etc2-rgba8unorm-srgb": e.etc.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
2265
+ "eac-r11unorm": e.etc.COMPRESSED_R11_EAC,
2266
+ // 'eac-r11snorm'
2267
+ "eac-rg11unorm": e.etc.COMPRESSED_SIGNED_RG11_EAC
2268
+ // 'eac-rg11snorm'
2269
+ } : {},
2270
+ ...e.astc ? {
2271
+ "astc-4x4-unorm": e.astc.COMPRESSED_RGBA_ASTC_4x4_KHR,
2272
+ "astc-4x4-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR,
2273
+ "astc-5x4-unorm": e.astc.COMPRESSED_RGBA_ASTC_5x4_KHR,
2274
+ "astc-5x4-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,
2275
+ "astc-5x5-unorm": e.astc.COMPRESSED_RGBA_ASTC_5x5_KHR,
2276
+ "astc-5x5-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR,
2277
+ "astc-6x5-unorm": e.astc.COMPRESSED_RGBA_ASTC_6x5_KHR,
2278
+ "astc-6x5-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,
2279
+ "astc-6x6-unorm": e.astc.COMPRESSED_RGBA_ASTC_6x6_KHR,
2280
+ "astc-6x6-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR,
2281
+ "astc-8x5-unorm": e.astc.COMPRESSED_RGBA_ASTC_8x5_KHR,
2282
+ "astc-8x5-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,
2283
+ "astc-8x6-unorm": e.astc.COMPRESSED_RGBA_ASTC_8x6_KHR,
2284
+ "astc-8x6-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR,
2285
+ "astc-8x8-unorm": e.astc.COMPRESSED_RGBA_ASTC_8x8_KHR,
2286
+ "astc-8x8-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,
2287
+ "astc-10x5-unorm": e.astc.COMPRESSED_RGBA_ASTC_10x5_KHR,
2288
+ "astc-10x5-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR,
2289
+ "astc-10x6-unorm": e.astc.COMPRESSED_RGBA_ASTC_10x6_KHR,
2290
+ "astc-10x6-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,
2291
+ "astc-10x8-unorm": e.astc.COMPRESSED_RGBA_ASTC_10x8_KHR,
2292
+ "astc-10x8-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR,
2293
+ "astc-10x10-unorm": e.astc.COMPRESSED_RGBA_ASTC_10x10_KHR,
2294
+ "astc-10x10-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
2295
+ "astc-12x10-unorm": e.astc.COMPRESSED_RGBA_ASTC_12x10_KHR,
2296
+ "astc-12x10-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR,
2297
+ "astc-12x12-unorm": e.astc.COMPRESSED_RGBA_ASTC_12x12_KHR,
2298
+ "astc-12x12-unorm-srgb": e.astc.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR
2299
+ } : {}
2300
+ };
2301
+ }
2302
+ function yt(t) {
2303
+ return {
2304
+ // 8-bit formats
2305
+ r8unorm: t.UNSIGNED_BYTE,
2306
+ r8snorm: t.BYTE,
2307
+ r8uint: t.UNSIGNED_BYTE,
2308
+ r8sint: t.BYTE,
2309
+ // 16-bit formats
2310
+ r16uint: t.UNSIGNED_SHORT,
2311
+ r16sint: t.SHORT,
2312
+ r16float: t.HALF_FLOAT,
2313
+ rg8unorm: t.UNSIGNED_BYTE,
2314
+ rg8snorm: t.BYTE,
2315
+ rg8uint: t.UNSIGNED_BYTE,
2316
+ rg8sint: t.BYTE,
2317
+ // 32-bit formats
2318
+ r32uint: t.UNSIGNED_INT,
2319
+ r32sint: t.INT,
2320
+ r32float: t.FLOAT,
2321
+ rg16uint: t.UNSIGNED_SHORT,
2322
+ rg16sint: t.SHORT,
2323
+ rg16float: t.HALF_FLOAT,
2324
+ rgba8unorm: t.UNSIGNED_BYTE,
2325
+ "rgba8unorm-srgb": t.UNSIGNED_BYTE,
2326
+ // Packed 32-bit formats
2327
+ rgba8snorm: t.BYTE,
2328
+ rgba8uint: t.UNSIGNED_BYTE,
2329
+ rgba8sint: t.BYTE,
2330
+ bgra8unorm: t.UNSIGNED_BYTE,
2331
+ "bgra8unorm-srgb": t.UNSIGNED_BYTE,
2332
+ rgb9e5ufloat: t.UNSIGNED_INT_5_9_9_9_REV,
2333
+ rgb10a2unorm: t.UNSIGNED_INT_2_10_10_10_REV,
2334
+ rg11b10ufloat: t.UNSIGNED_INT_10F_11F_11F_REV,
2335
+ // 64-bit formats
2336
+ rg32uint: t.UNSIGNED_INT,
2337
+ rg32sint: t.INT,
2338
+ rg32float: t.FLOAT,
2339
+ rgba16uint: t.UNSIGNED_SHORT,
2340
+ rgba16sint: t.SHORT,
2341
+ rgba16float: t.HALF_FLOAT,
2342
+ // 128-bit formats
2343
+ rgba32uint: t.UNSIGNED_INT,
2344
+ rgba32sint: t.INT,
2345
+ rgba32float: t.FLOAT,
2346
+ // Depth/stencil formats
2347
+ stencil8: t.UNSIGNED_BYTE,
2348
+ depth16unorm: t.UNSIGNED_SHORT,
2349
+ depth24plus: t.UNSIGNED_INT,
2350
+ "depth24plus-stencil8": t.UNSIGNED_INT_24_8,
2351
+ depth32float: t.FLOAT,
2352
+ "depth32float-stencil8": t.FLOAT_32_UNSIGNED_INT_24_8_REV
2353
+ };
2354
+ }
2355
+ const Ct = 4;
2356
+ class Se {
2357
+ constructor(e) {
2358
+ this.managedTextures = [], this._glTextures = /* @__PURE__ */ Object.create(null), this._glSamplers = /* @__PURE__ */ Object.create(null), this._boundTextures = [], this._activeTextureLocation = -1, this._boundSamplers = /* @__PURE__ */ Object.create(null), this._uploads = {
2359
+ image: be,
2360
+ buffer: gt,
2361
+ video: Tt,
2362
+ compressed: xt
2363
+ }, this._premultiplyAlpha = !1, this._useSeparateSamplers = !1, this._renderer = e, this._renderer.renderableGC.addManagedHash(this, "_glTextures"), this._renderer.renderableGC.addManagedHash(this, "_glSamplers");
2364
+ }
2365
+ contextChange(e) {
2366
+ this._gl = e, this._mapFormatToInternalFormat || (this._mapFormatToInternalFormat = Nt(e, this._renderer.context.extensions), this._mapFormatToType = yt(e), this._mapFormatToFormat = At(e)), this._glTextures = /* @__PURE__ */ Object.create(null), this._glSamplers = /* @__PURE__ */ Object.create(null), this._boundSamplers = /* @__PURE__ */ Object.create(null), this._premultiplyAlpha = !1;
2367
+ for (let r = 0; r < 16; r++)
2368
+ this.bind(b.EMPTY, r);
2369
+ }
2370
+ /**
2371
+ * Initializes a texture source, if it has already been initialized nothing will happen.
2372
+ * @param source - The texture source to initialize.
2373
+ * @returns The initialized texture source.
2374
+ */
2375
+ initSource(e) {
2376
+ this.bind(e);
2377
+ }
2378
+ bind(e, r = 0) {
2379
+ const s = e.source;
2380
+ e ? (this.bindSource(s, r), this._useSeparateSamplers && this._bindSampler(s.style, r)) : (this.bindSource(null, r), this._useSeparateSamplers && this._bindSampler(null, r));
2381
+ }
2382
+ bindSource(e, r = 0) {
2383
+ const s = this._gl;
2384
+ if (e._touched = this._renderer.textureGC.count, this._boundTextures[r] !== e) {
2385
+ this._boundTextures[r] = e, this._activateLocation(r), e || (e = b.EMPTY.source);
2386
+ const n = this.getGlSource(e);
2387
+ s.bindTexture(n.target, n.texture);
2388
+ }
2389
+ }
2390
+ _bindSampler(e, r = 0) {
2391
+ const s = this._gl;
2392
+ if (!e) {
2393
+ this._boundSamplers[r] = null, s.bindSampler(r, null);
2394
+ return;
2395
+ }
2396
+ const n = this._getGlSampler(e);
2397
+ this._boundSamplers[r] !== n && (this._boundSamplers[r] = n, s.bindSampler(r, n));
2398
+ }
2399
+ unbind(e) {
2400
+ const r = e.source, s = this._boundTextures, n = this._gl;
2401
+ for (let i = 0; i < s.length; i++)
2402
+ if (s[i] === r) {
2403
+ this._activateLocation(i);
2404
+ const a = this.getGlSource(r);
2405
+ n.bindTexture(a.target, null), s[i] = null;
2406
+ }
2407
+ }
2408
+ _activateLocation(e) {
2409
+ this._activeTextureLocation !== e && (this._activeTextureLocation = e, this._gl.activeTexture(this._gl.TEXTURE0 + e));
2410
+ }
2411
+ _initSource(e) {
2412
+ const r = this._gl, s = new pt(r.createTexture());
2413
+ if (s.type = this._mapFormatToType[e.format], s.internalFormat = this._mapFormatToInternalFormat[e.format], s.format = this._mapFormatToFormat[e.format], e.autoGenerateMipmaps && (this._renderer.context.supports.nonPowOf2mipmaps || e.isPowerOfTwo)) {
2414
+ const n = Math.max(e.width, e.height);
2415
+ e.mipLevelCount = Math.floor(Math.log2(n)) + 1;
2416
+ }
2417
+ return this._glTextures[e.uid] = s, this.managedTextures.includes(e) || (e.on("update", this.onSourceUpdate, this), e.on("resize", this.onSourceUpdate, this), e.on("styleChange", this.onStyleChange, this), e.on("destroy", this.onSourceDestroy, this), e.on("unload", this.onSourceUnload, this), e.on("updateMipmaps", this.onUpdateMipmaps, this), this.managedTextures.push(e)), this.onSourceUpdate(e), this.updateStyle(e, !1), s;
2418
+ }
2419
+ onStyleChange(e) {
2420
+ this.updateStyle(e, !1);
2421
+ }
2422
+ updateStyle(e, r) {
2423
+ const s = this._gl, n = this.getGlSource(e);
2424
+ s.bindTexture(s.TEXTURE_2D, n.texture), this._boundTextures[this._activeTextureLocation] = e, j(
2425
+ e.style,
2426
+ s,
2427
+ e.mipLevelCount > 1,
2428
+ this._renderer.context.extensions.anisotropicFiltering,
2429
+ "texParameteri",
2430
+ s.TEXTURE_2D,
2431
+ // will force a clamp to edge if the texture is not a power of two
2432
+ !this._renderer.context.supports.nonPowOf2wrapping && !e.isPowerOfTwo,
2433
+ r
2434
+ );
2435
+ }
2436
+ onSourceUnload(e) {
2437
+ const r = this._glTextures[e.uid];
2438
+ r && (this.unbind(e), this._glTextures[e.uid] = null, this._gl.deleteTexture(r.texture));
2439
+ }
2440
+ onSourceUpdate(e) {
2441
+ const r = this._gl, s = this.getGlSource(e);
2442
+ r.bindTexture(r.TEXTURE_2D, s.texture), this._boundTextures[this._activeTextureLocation] = e;
2443
+ const n = e.alphaMode === "premultiply-alpha-on-upload";
2444
+ this._premultiplyAlpha !== n && (this._premultiplyAlpha = n, r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL, n)), this._uploads[e.uploadMethodId] ? this._uploads[e.uploadMethodId].upload(e, s, r, this._renderer.context.webGLVersion) : r.texImage2D(r.TEXTURE_2D, 0, r.RGBA, e.pixelWidth, e.pixelHeight, 0, r.RGBA, r.UNSIGNED_BYTE, null), e.autoGenerateMipmaps && e.mipLevelCount > 1 && this.onUpdateMipmaps(e, !1);
2445
+ }
2446
+ onUpdateMipmaps(e, r = !0) {
2447
+ r && this.bindSource(e, 0);
2448
+ const s = this.getGlSource(e);
2449
+ this._gl.generateMipmap(s.target);
2450
+ }
2451
+ onSourceDestroy(e) {
2452
+ e.off("destroy", this.onSourceDestroy, this), e.off("update", this.onSourceUpdate, this), e.off("resize", this.onSourceUpdate, this), e.off("unload", this.onSourceUnload, this), e.off("styleChange", this.onStyleChange, this), e.off("updateMipmaps", this.onUpdateMipmaps, this), this.managedTextures.splice(this.managedTextures.indexOf(e), 1), this.onSourceUnload(e);
2453
+ }
2454
+ _initSampler(e) {
2455
+ const r = this._gl, s = this._gl.createSampler();
2456
+ return this._glSamplers[e._resourceId] = s, j(
2457
+ e,
2458
+ r,
2459
+ this._boundTextures[this._activeTextureLocation].mipLevelCount > 1,
2460
+ this._renderer.context.extensions.anisotropicFiltering,
2461
+ "samplerParameteri",
2462
+ s,
2463
+ !1,
2464
+ !0
2465
+ ), this._glSamplers[e._resourceId];
2466
+ }
2467
+ _getGlSampler(e) {
2468
+ return this._glSamplers[e._resourceId] || this._initSampler(e);
2469
+ }
2470
+ getGlSource(e) {
2471
+ return this._glTextures[e.uid] || this._initSource(e);
2472
+ }
2473
+ generateCanvas(e) {
2474
+ const { pixels: r, width: s, height: n } = this.getPixels(e), i = S.get().createCanvas();
2475
+ i.width = s, i.height = n;
2476
+ const a = i.getContext("2d");
2477
+ if (a) {
2478
+ const o = a.createImageData(s, n);
2479
+ o.data.set(r), a.putImageData(o, 0, 0);
2480
+ }
2481
+ return i;
2482
+ }
2483
+ getPixels(e) {
2484
+ const r = e.source.resolution, s = e.frame, n = Math.max(Math.round(s.width * r), 1), i = Math.max(Math.round(s.height * r), 1), a = new Uint8Array(Ct * n * i), o = this._renderer, c = o.renderTarget.getRenderTarget(e), u = o.renderTarget.getGpuRenderTarget(c), _ = o.gl;
2485
+ return _.bindFramebuffer(_.FRAMEBUFFER, u.resolveTargetFramebuffer), _.readPixels(
2486
+ Math.round(s.x * r),
2487
+ Math.round(s.y * r),
2488
+ n,
2489
+ i,
2490
+ _.RGBA,
2491
+ _.UNSIGNED_BYTE,
2492
+ a
2493
+ ), { pixels: new Uint8ClampedArray(a.buffer), width: n, height: i };
2494
+ }
2495
+ destroy() {
2496
+ this.managedTextures.slice().forEach((e) => this.onSourceDestroy(e)), this.managedTextures = null, this._glTextures = null, this._glSamplers = null, this._boundTextures = null, this._boundSamplers = null, this._mapFormatToInternalFormat = null, this._mapFormatToType = null, this._mapFormatToFormat = null, this._uploads = null, this._renderer = null;
2497
+ }
2498
+ resetState() {
2499
+ this._activeTextureLocation = -1, this._boundTextures.fill(b.EMPTY.source), this._boundSamplers = /* @__PURE__ */ Object.create(null);
2500
+ const e = this._gl;
2501
+ this._premultiplyAlpha = !1, e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this._premultiplyAlpha);
2502
+ }
2503
+ }
2504
+ Se.extension = {
2505
+ type: [
2506
+ d.WebGLSystem
2507
+ ],
2508
+ name: "texture"
2509
+ };
2510
+ class pe {
2511
+ contextChange(e) {
2512
+ const r = new F({
2513
+ uColor: { value: new Float32Array([1, 1, 1, 1]), type: "vec4<f32>" },
2514
+ uTransformMatrix: { value: new z(), type: "mat3x3<f32>" },
2515
+ uRound: { value: 0, type: "f32" }
2516
+ }), s = e.limits.maxBatchableTextures, n = Y({
2517
+ name: "graphics",
2518
+ bits: [
2519
+ ye,
2520
+ Ce(s),
2521
+ Z,
2522
+ q
2523
+ ]
2524
+ });
2525
+ this.shader = new U({
2526
+ glProgram: n,
2527
+ resources: {
2528
+ localUniforms: r,
2529
+ batchSamplers: Ie(s)
2530
+ }
2531
+ });
2532
+ }
2533
+ execute(e, r) {
2534
+ const s = r.context, n = s.customShader || this.shader, i = e.renderer, a = i.graphicsContext, {
2535
+ batcher: o,
2536
+ instructions: c
2537
+ } = a.getContextRenderData(s);
2538
+ n.groups[0] = i.globalUniforms.bindGroup, i.state.set(e.state), i.shader.bind(n), i.geometry.bind(o.geometry, n.glProgram);
2539
+ const u = c.instructions;
2540
+ for (let _ = 0; _ < c.instructionSize; _++) {
2541
+ const f = u[_];
2542
+ if (f.size) {
2543
+ for (let l = 0; l < f.textures.count; l++)
2544
+ i.texture.bind(f.textures.textures[l], l);
2545
+ i.geometry.draw(f.topology, f.size, f.start);
2546
+ }
2547
+ }
2548
+ }
2549
+ destroy() {
2550
+ this.shader.destroy(!0), this.shader = null;
2551
+ }
2552
+ }
2553
+ pe.extension = {
2554
+ type: [
2555
+ d.WebGLPipesAdaptor
2556
+ ],
2557
+ name: "graphics"
2558
+ };
2559
+ class ge {
2560
+ init() {
2561
+ const e = Y({
2562
+ name: "mesh",
2563
+ bits: [
2564
+ Z,
2565
+ He,
2566
+ q
2567
+ ]
2568
+ });
2569
+ this._shader = new U({
2570
+ glProgram: e,
2571
+ resources: {
2572
+ uTexture: b.EMPTY.source,
2573
+ textureUniforms: {
2574
+ uTextureMatrix: { type: "mat3x3<f32>", value: new z() }
2575
+ }
2576
+ }
2577
+ });
2578
+ }
2579
+ execute(e, r) {
2580
+ const s = e.renderer;
2581
+ let n = r._shader;
2582
+ if (n) {
2583
+ if (!n.glProgram) {
2584
+ m("Mesh shader has no glProgram", r.shader);
2585
+ return;
2586
+ }
2587
+ } else {
2588
+ n = this._shader;
2589
+ const i = r.texture, a = i.source;
2590
+ n.resources.uTexture = a, n.resources.uSampler = a.style, n.resources.textureUniforms.uniforms.uTextureMatrix = i.textureMatrix.mapCoord;
2591
+ }
2592
+ n.groups[100] = s.globalUniforms.bindGroup, n.groups[101] = e.localUniformsBindGroup, s.encoder.draw({
2593
+ geometry: r._geometry,
2594
+ shader: n,
2595
+ state: r.state
2596
+ });
2597
+ }
2598
+ destroy() {
2599
+ this._shader.destroy(!0), this._shader = null;
2600
+ }
2601
+ }
2602
+ ge.extension = {
2603
+ type: [
2604
+ d.WebGLPipesAdaptor
2605
+ ],
2606
+ name: "mesh"
2607
+ };
2608
+ const It = [
2609
+ ...we,
2610
+ _e,
2611
+ $e,
2612
+ Xe,
2613
+ oe,
2614
+ ee,
2615
+ Se,
2616
+ he,
2617
+ se,
2618
+ me,
2619
+ de,
2620
+ ae,
2621
+ St,
2622
+ ce,
2623
+ ie
2624
+ ], Dt = [...Ve], Gt = [J, ge, pe], Re = [], xe = [], Te = [];
2625
+ T.handleByNamedList(d.WebGLSystem, Re);
2626
+ T.handleByNamedList(d.WebGLPipes, xe);
2627
+ T.handleByNamedList(d.WebGLPipesAdaptor, Te);
2628
+ T.add(...It, ...Dt, ...Gt);
2629
+ class Pt extends De {
2630
+ constructor() {
2631
+ const e = {
2632
+ name: "webgl",
2633
+ type: Ge.WEBGL,
2634
+ systems: Re,
2635
+ renderPipes: xe,
2636
+ renderPipeAdaptors: Te
2637
+ };
2638
+ super(e);
2639
+ }
2640
+ }
2641
+ export {
2642
+ Pt as WebGLRenderer
2643
+ };
src/backend/gradio_polygonannotator/templates/component/WebGPURenderer-scPngJ2c.js ADDED
@@ -0,0 +1,1656 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { g as E, E as p, f as ae, D as B, S as C, B as T, b as ue, c as L, d as M, w as v, h as y, i as ce, j as de, k as A, M as k, l as D, m as he, o as pe, p as H, q as z, s as w, A as le, R as fe, e as S } from "./Index-Ct_1BCRd.js";
2
+ import { S as F, l as ge, a as me } from "./colorToUniform-zJcCVLeu.js";
3
+ import { c as _e, u as be, U as ye, B as xe, G as Ge, e as Be, R as Se, t as Pe, S as Te, a as Ce } from "./SharedSystems-DVDwWST4.js";
4
+ import { C as R } from "./CanvasPool-CO7699qB.js";
5
+ const x = F.for2d();
6
+ class O {
7
+ start(e, t, r) {
8
+ const s = e.renderer, i = s.encoder, n = r.gpuProgram;
9
+ this._shader = r, this._geometry = t, i.setGeometry(t, n), x.blendMode = "normal", s.pipeline.getPipeline(
10
+ t,
11
+ n,
12
+ x
13
+ );
14
+ const o = s.globalUniforms.bindGroup;
15
+ i.resetBindGroup(1), i.setBindGroup(0, o, n);
16
+ }
17
+ execute(e, t) {
18
+ const r = this._shader.gpuProgram, s = e.renderer, i = s.encoder;
19
+ if (!t.bindGroup) {
20
+ const u = t.textures;
21
+ t.bindGroup = E(
22
+ u.textures,
23
+ u.count,
24
+ s.limits.maxBatchableTextures
25
+ );
26
+ }
27
+ x.blendMode = t.blendMode;
28
+ const n = s.bindGroup.getBindGroup(
29
+ t.bindGroup,
30
+ r,
31
+ 1
32
+ ), o = s.pipeline.getPipeline(
33
+ this._geometry,
34
+ r,
35
+ x,
36
+ t.topology
37
+ );
38
+ t.bindGroup._touch(s.textureGC.count), i.setPipeline(o), i.renderPassEncoder.setBindGroup(1, n), i.renderPassEncoder.drawIndexed(t.size, 1, t.start);
39
+ }
40
+ }
41
+ O.extension = {
42
+ type: [
43
+ p.WebGPUPipesAdaptor
44
+ ],
45
+ name: "batch"
46
+ };
47
+ class I {
48
+ constructor(e) {
49
+ this._hash = /* @__PURE__ */ Object.create(null), this._renderer = e, this._renderer.renderableGC.addManagedHash(this, "_hash");
50
+ }
51
+ contextChange(e) {
52
+ this._gpu = e;
53
+ }
54
+ getBindGroup(e, t, r) {
55
+ return e._updateKey(), this._hash[e._key] || this._createBindGroup(e, t, r);
56
+ }
57
+ _createBindGroup(e, t, r) {
58
+ const s = this._gpu.device, i = t.layout[r], n = [], o = this._renderer;
59
+ for (const l in i) {
60
+ const h = e.resources[l] ?? e.resources[i[l]];
61
+ let f;
62
+ if (h._resourceType === "uniformGroup") {
63
+ const d = h;
64
+ o.ubo.updateUniformGroup(d);
65
+ const _ = d.buffer;
66
+ f = {
67
+ buffer: o.buffer.getGPUBuffer(_),
68
+ offset: 0,
69
+ size: _.descriptor.size
70
+ };
71
+ } else if (h._resourceType === "buffer") {
72
+ const d = h;
73
+ f = {
74
+ buffer: o.buffer.getGPUBuffer(d),
75
+ offset: 0,
76
+ size: d.descriptor.size
77
+ };
78
+ } else if (h._resourceType === "bufferResource") {
79
+ const d = h;
80
+ f = {
81
+ buffer: o.buffer.getGPUBuffer(d.buffer),
82
+ offset: d.offset,
83
+ size: d.size
84
+ };
85
+ } else if (h._resourceType === "textureSampler") {
86
+ const d = h;
87
+ f = o.texture.getGpuSampler(d);
88
+ } else if (h._resourceType === "textureSource") {
89
+ const d = h;
90
+ f = o.texture.getGpuSource(d).createView({});
91
+ }
92
+ n.push({
93
+ binding: i[l],
94
+ resource: f
95
+ });
96
+ }
97
+ const u = o.shader.getProgramData(t).bindGroups[r], c = s.createBindGroup({
98
+ layout: u,
99
+ entries: n
100
+ });
101
+ return this._hash[e._key] = c, c;
102
+ }
103
+ destroy() {
104
+ for (const e of Object.keys(this._hash))
105
+ this._hash[e] = null;
106
+ this._hash = null, this._renderer = null;
107
+ }
108
+ }
109
+ I.extension = {
110
+ type: [
111
+ p.WebGPUSystem
112
+ ],
113
+ name: "bindGroup"
114
+ };
115
+ class W {
116
+ constructor(e) {
117
+ this._gpuBuffers = /* @__PURE__ */ Object.create(null), this._managedBuffers = [], e.renderableGC.addManagedHash(this, "_gpuBuffers");
118
+ }
119
+ contextChange(e) {
120
+ this._gpu = e;
121
+ }
122
+ getGPUBuffer(e) {
123
+ return this._gpuBuffers[e.uid] || this.createGPUBuffer(e);
124
+ }
125
+ updateBuffer(e) {
126
+ const t = this._gpuBuffers[e.uid] || this.createGPUBuffer(e), r = e.data;
127
+ return e._updateID && r && (e._updateID = 0, this._gpu.device.queue.writeBuffer(
128
+ t,
129
+ 0,
130
+ r.buffer,
131
+ 0,
132
+ // round to the nearest 4 bytes
133
+ (e._updateSize || r.byteLength) + 3 & -4
134
+ )), t;
135
+ }
136
+ /** dispose all WebGL resources of all managed buffers */
137
+ destroyAll() {
138
+ for (const e in this._gpuBuffers)
139
+ this._gpuBuffers[e].destroy();
140
+ this._gpuBuffers = {};
141
+ }
142
+ createGPUBuffer(e) {
143
+ this._gpuBuffers[e.uid] || (e.on("update", this.updateBuffer, this), e.on("change", this.onBufferChange, this), e.on("destroy", this.onBufferDestroy, this), this._managedBuffers.push(e));
144
+ const t = this._gpu.device.createBuffer(e.descriptor);
145
+ return e._updateID = 0, e.data && (ae(e.data.buffer, t.getMappedRange()), t.unmap()), this._gpuBuffers[e.uid] = t, t;
146
+ }
147
+ onBufferChange(e) {
148
+ this._gpuBuffers[e.uid].destroy(), e._updateID = 0, this._gpuBuffers[e.uid] = this.createGPUBuffer(e);
149
+ }
150
+ /**
151
+ * Disposes buffer
152
+ * @param buffer - buffer with data
153
+ */
154
+ onBufferDestroy(e) {
155
+ this._managedBuffers.splice(this._managedBuffers.indexOf(e), 1), this._destroyBuffer(e);
156
+ }
157
+ destroy() {
158
+ this._managedBuffers.forEach((e) => this._destroyBuffer(e)), this._managedBuffers = null, this._gpuBuffers = null;
159
+ }
160
+ _destroyBuffer(e) {
161
+ this._gpuBuffers[e.uid].destroy(), e.off("update", this.updateBuffer, this), e.off("change", this.onBufferChange, this), e.off("destroy", this.onBufferDestroy, this), this._gpuBuffers[e.uid] = null;
162
+ }
163
+ }
164
+ W.extension = {
165
+ type: [
166
+ p.WebGPUSystem
167
+ ],
168
+ name: "buffer"
169
+ };
170
+ class ve {
171
+ constructor({ minUniformOffsetAlignment: e }) {
172
+ this._minUniformOffsetAlignment = 256, this.byteIndex = 0, this._minUniformOffsetAlignment = e, this.data = new Float32Array(65535);
173
+ }
174
+ clear() {
175
+ this.byteIndex = 0;
176
+ }
177
+ addEmptyGroup(e) {
178
+ if (e > this._minUniformOffsetAlignment / 4)
179
+ throw new Error(`UniformBufferBatch: array is too large: ${e * 4}`);
180
+ const t = this.byteIndex;
181
+ let r = t + e * 4;
182
+ if (r = Math.ceil(r / this._minUniformOffsetAlignment) * this._minUniformOffsetAlignment, r > this.data.length * 4)
183
+ throw new Error("UniformBufferBatch: ubo batch got too big");
184
+ return this.byteIndex = r, t;
185
+ }
186
+ addGroup(e) {
187
+ const t = this.addEmptyGroup(e.length);
188
+ for (let r = 0; r < e.length; r++)
189
+ this.data[t / 4 + r] = e[r];
190
+ return t;
191
+ }
192
+ destroy() {
193
+ this.data = null;
194
+ }
195
+ }
196
+ class V {
197
+ constructor(e) {
198
+ this._colorMaskCache = 15, this._renderer = e;
199
+ }
200
+ setMask(e) {
201
+ this._colorMaskCache !== e && (this._colorMaskCache = e, this._renderer.pipeline.setColorMask(e));
202
+ }
203
+ destroy() {
204
+ this._renderer = null, this._colorMaskCache = null;
205
+ }
206
+ }
207
+ V.extension = {
208
+ type: [
209
+ p.WebGPUSystem
210
+ ],
211
+ name: "colorMask"
212
+ };
213
+ class U {
214
+ /**
215
+ * @param {WebGPURenderer} renderer - The renderer this System works for.
216
+ */
217
+ constructor(e) {
218
+ this._renderer = e;
219
+ }
220
+ async init(e) {
221
+ return this._initPromise ? this._initPromise : (this._initPromise = (e.gpu ? Promise.resolve(e.gpu) : this._createDeviceAndAdaptor(e)).then((t) => {
222
+ this.gpu = t, this._renderer.runners.contextChange.emit(this.gpu);
223
+ }), this._initPromise);
224
+ }
225
+ /**
226
+ * Handle the context change event
227
+ * @param gpu
228
+ */
229
+ contextChange(e) {
230
+ this._renderer.gpu = e;
231
+ }
232
+ /**
233
+ * Helper class to create a WebGL Context
234
+ * @param {object} options - An options object that gets passed in to the canvas element containing the
235
+ * context attributes
236
+ * @see https://developer.mozilla.org/en/docs/Web/API/HTMLCanvasElement/getContext
237
+ * @returns {WebGLRenderingContext} the WebGL context
238
+ */
239
+ async _createDeviceAndAdaptor(e) {
240
+ const t = await B.get().getNavigator().gpu.requestAdapter({
241
+ powerPreference: e.powerPreference,
242
+ forceFallbackAdapter: e.forceFallbackAdapter
243
+ }), r = [
244
+ "texture-compression-bc",
245
+ "texture-compression-astc",
246
+ "texture-compression-etc2"
247
+ ].filter((i) => t.features.has(i)), s = await t.requestDevice({
248
+ requiredFeatures: r
249
+ });
250
+ return { adapter: t, device: s };
251
+ }
252
+ destroy() {
253
+ this.gpu = null, this._renderer = null;
254
+ }
255
+ }
256
+ U.extension = {
257
+ type: [
258
+ p.WebGPUSystem
259
+ ],
260
+ name: "device"
261
+ };
262
+ U.defaultOptions = {
263
+ /**
264
+ * {@link WebGPUOptions.powerPreference}
265
+ * @default default
266
+ */
267
+ powerPreference: void 0,
268
+ /**
269
+ * Force the use of the fallback adapter
270
+ * @default false
271
+ */
272
+ forceFallbackAdapter: !1
273
+ };
274
+ class N {
275
+ constructor(e) {
276
+ this._boundBindGroup = /* @__PURE__ */ Object.create(null), this._boundVertexBuffer = /* @__PURE__ */ Object.create(null), this._renderer = e;
277
+ }
278
+ renderStart() {
279
+ this.commandFinished = new Promise((e) => {
280
+ this._resolveCommandFinished = e;
281
+ }), this.commandEncoder = this._renderer.gpu.device.createCommandEncoder();
282
+ }
283
+ beginRenderPass(e) {
284
+ this.endRenderPass(), this._clearCache(), this.renderPassEncoder = this.commandEncoder.beginRenderPass(e.descriptor);
285
+ }
286
+ endRenderPass() {
287
+ this.renderPassEncoder && this.renderPassEncoder.end(), this.renderPassEncoder = null;
288
+ }
289
+ setViewport(e) {
290
+ this.renderPassEncoder.setViewport(e.x, e.y, e.width, e.height, 0, 1);
291
+ }
292
+ setPipelineFromGeometryProgramAndState(e, t, r, s) {
293
+ const i = this._renderer.pipeline.getPipeline(e, t, r, s);
294
+ this.setPipeline(i);
295
+ }
296
+ setPipeline(e) {
297
+ this._boundPipeline !== e && (this._boundPipeline = e, this.renderPassEncoder.setPipeline(e));
298
+ }
299
+ _setVertexBuffer(e, t) {
300
+ this._boundVertexBuffer[e] !== t && (this._boundVertexBuffer[e] = t, this.renderPassEncoder.setVertexBuffer(e, this._renderer.buffer.updateBuffer(t)));
301
+ }
302
+ _setIndexBuffer(e) {
303
+ if (this._boundIndexBuffer === e)
304
+ return;
305
+ this._boundIndexBuffer = e;
306
+ const t = e.data.BYTES_PER_ELEMENT === 2 ? "uint16" : "uint32";
307
+ this.renderPassEncoder.setIndexBuffer(this._renderer.buffer.updateBuffer(e), t);
308
+ }
309
+ resetBindGroup(e) {
310
+ this._boundBindGroup[e] = null;
311
+ }
312
+ setBindGroup(e, t, r) {
313
+ if (this._boundBindGroup[e] === t)
314
+ return;
315
+ this._boundBindGroup[e] = t, t._touch(this._renderer.textureGC.count);
316
+ const s = this._renderer.bindGroup.getBindGroup(t, r, e);
317
+ this.renderPassEncoder.setBindGroup(e, s);
318
+ }
319
+ setGeometry(e, t) {
320
+ const r = this._renderer.pipeline.getBufferNamesToBind(e, t);
321
+ for (const s in r)
322
+ this._setVertexBuffer(parseInt(s, 10), e.attributes[r[s]].buffer);
323
+ e.indexBuffer && this._setIndexBuffer(e.indexBuffer);
324
+ }
325
+ _setShaderBindGroups(e, t) {
326
+ for (const r in e.groups) {
327
+ const s = e.groups[r];
328
+ t || this._syncBindGroup(s), this.setBindGroup(r, s, e.gpuProgram);
329
+ }
330
+ }
331
+ _syncBindGroup(e) {
332
+ for (const t in e.resources) {
333
+ const r = e.resources[t];
334
+ r.isUniformGroup && this._renderer.ubo.updateUniformGroup(r);
335
+ }
336
+ }
337
+ draw(e) {
338
+ const { geometry: t, shader: r, state: s, topology: i, size: n, start: o, instanceCount: u, skipSync: c } = e;
339
+ this.setPipelineFromGeometryProgramAndState(t, r.gpuProgram, s, i), this.setGeometry(t, r.gpuProgram), this._setShaderBindGroups(r, c), t.indexBuffer ? this.renderPassEncoder.drawIndexed(
340
+ n || t.indexBuffer.data.length,
341
+ u ?? t.instanceCount,
342
+ o || 0
343
+ ) : this.renderPassEncoder.draw(n || t.getSize(), u ?? t.instanceCount, o || 0);
344
+ }
345
+ finishRenderPass() {
346
+ this.renderPassEncoder && (this.renderPassEncoder.end(), this.renderPassEncoder = null);
347
+ }
348
+ postrender() {
349
+ this.finishRenderPass(), this._gpu.device.queue.submit([this.commandEncoder.finish()]), this._resolveCommandFinished(), this.commandEncoder = null;
350
+ }
351
+ // restores a render pass if finishRenderPass was called
352
+ // not optimised as really used for debugging!
353
+ // used when we want to stop drawing and log a texture..
354
+ restoreRenderPass() {
355
+ const e = this._renderer.renderTarget.adaptor.getDescriptor(
356
+ this._renderer.renderTarget.renderTarget,
357
+ !1,
358
+ [0, 0, 0, 1]
359
+ );
360
+ this.renderPassEncoder = this.commandEncoder.beginRenderPass(e);
361
+ const t = this._boundPipeline, r = { ...this._boundVertexBuffer }, s = this._boundIndexBuffer, i = { ...this._boundBindGroup };
362
+ this._clearCache();
363
+ const n = this._renderer.renderTarget.viewport;
364
+ this.renderPassEncoder.setViewport(n.x, n.y, n.width, n.height, 0, 1), this.setPipeline(t);
365
+ for (const o in r)
366
+ this._setVertexBuffer(o, r[o]);
367
+ for (const o in i)
368
+ this.setBindGroup(o, i[o], null);
369
+ this._setIndexBuffer(s);
370
+ }
371
+ _clearCache() {
372
+ for (let e = 0; e < 16; e++)
373
+ this._boundBindGroup[e] = null, this._boundVertexBuffer[e] = null;
374
+ this._boundIndexBuffer = null, this._boundPipeline = null;
375
+ }
376
+ destroy() {
377
+ this._renderer = null, this._gpu = null, this._boundBindGroup = null, this._boundVertexBuffer = null, this._boundIndexBuffer = null, this._boundPipeline = null;
378
+ }
379
+ contextChange(e) {
380
+ this._gpu = e;
381
+ }
382
+ }
383
+ N.extension = {
384
+ type: [p.WebGPUSystem],
385
+ name: "encoder",
386
+ priority: 1
387
+ };
388
+ class j {
389
+ constructor(e) {
390
+ this._renderer = e;
391
+ }
392
+ contextChange() {
393
+ this.maxTextures = this._renderer.device.gpu.device.limits.maxSampledTexturesPerShaderStage, this.maxBatchableTextures = this.maxTextures;
394
+ }
395
+ destroy() {
396
+ }
397
+ }
398
+ j.extension = {
399
+ type: [
400
+ p.WebGPUSystem
401
+ ],
402
+ name: "limits"
403
+ };
404
+ class K {
405
+ constructor(e) {
406
+ this._renderTargetStencilState = /* @__PURE__ */ Object.create(null), this._renderer = e, e.renderTarget.onRenderTargetChange.add(this);
407
+ }
408
+ onRenderTargetChange(e) {
409
+ let t = this._renderTargetStencilState[e.uid];
410
+ t || (t = this._renderTargetStencilState[e.uid] = {
411
+ stencilMode: C.DISABLED,
412
+ stencilReference: 0
413
+ }), this._activeRenderTarget = e, this.setStencilMode(t.stencilMode, t.stencilReference);
414
+ }
415
+ setStencilMode(e, t) {
416
+ const r = this._renderTargetStencilState[this._activeRenderTarget.uid];
417
+ r.stencilMode = e, r.stencilReference = t;
418
+ const s = this._renderer;
419
+ s.pipeline.setStencilMode(e), s.encoder.renderPassEncoder.setStencilReference(t);
420
+ }
421
+ destroy() {
422
+ this._renderer.renderTarget.onRenderTargetChange.remove(this), this._renderer = null, this._activeRenderTarget = null, this._renderTargetStencilState = null;
423
+ }
424
+ }
425
+ K.extension = {
426
+ type: [
427
+ p.WebGPUSystem
428
+ ],
429
+ name: "stencil"
430
+ };
431
+ const G = {
432
+ i32: { align: 4, size: 4 },
433
+ u32: { align: 4, size: 4 },
434
+ f32: { align: 4, size: 4 },
435
+ f16: { align: 2, size: 2 },
436
+ "vec2<i32>": { align: 8, size: 8 },
437
+ "vec2<u32>": { align: 8, size: 8 },
438
+ "vec2<f32>": { align: 8, size: 8 },
439
+ "vec2<f16>": { align: 4, size: 4 },
440
+ "vec3<i32>": { align: 16, size: 12 },
441
+ "vec3<u32>": { align: 16, size: 12 },
442
+ "vec3<f32>": { align: 16, size: 12 },
443
+ "vec3<f16>": { align: 8, size: 6 },
444
+ "vec4<i32>": { align: 16, size: 16 },
445
+ "vec4<u32>": { align: 16, size: 16 },
446
+ "vec4<f32>": { align: 16, size: 16 },
447
+ "vec4<f16>": { align: 8, size: 8 },
448
+ "mat2x2<f32>": { align: 8, size: 16 },
449
+ "mat2x2<f16>": { align: 4, size: 8 },
450
+ "mat3x2<f32>": { align: 8, size: 24 },
451
+ "mat3x2<f16>": { align: 4, size: 12 },
452
+ "mat4x2<f32>": { align: 8, size: 32 },
453
+ "mat4x2<f16>": { align: 4, size: 16 },
454
+ "mat2x3<f32>": { align: 16, size: 32 },
455
+ "mat2x3<f16>": { align: 8, size: 16 },
456
+ "mat3x3<f32>": { align: 16, size: 48 },
457
+ "mat3x3<f16>": { align: 8, size: 24 },
458
+ "mat4x3<f32>": { align: 16, size: 64 },
459
+ "mat4x3<f16>": { align: 8, size: 32 },
460
+ "mat2x4<f32>": { align: 16, size: 32 },
461
+ "mat2x4<f16>": { align: 8, size: 16 },
462
+ "mat3x4<f32>": { align: 16, size: 48 },
463
+ "mat3x4<f16>": { align: 8, size: 24 },
464
+ "mat4x4<f32>": { align: 16, size: 64 },
465
+ "mat4x4<f16>": { align: 8, size: 32 }
466
+ };
467
+ function Ue(a) {
468
+ const e = a.map((r) => ({
469
+ data: r,
470
+ offset: 0,
471
+ size: 0
472
+ }));
473
+ let t = 0;
474
+ for (let r = 0; r < e.length; r++) {
475
+ const s = e[r];
476
+ let i = G[s.data.type].size;
477
+ const n = G[s.data.type].align;
478
+ if (!G[s.data.type])
479
+ throw new Error(`[Pixi.js] WebGPU UniformBuffer: Unknown type ${s.data.type}`);
480
+ s.data.size > 1 && (i = Math.max(i, n) * s.data.size), t = Math.ceil(t / n) * n, s.size = i, s.offset = t, t += i;
481
+ }
482
+ return t = Math.ceil(t / 16) * 16, { uboElements: e, size: t };
483
+ }
484
+ function Me(a, e) {
485
+ const { size: t, align: r } = G[a.data.type], s = (r - t) / 4, i = a.data.type.indexOf("i32") >= 0 ? "dataInt32" : "data";
486
+ return `
487
+ v = uv.${a.data.name};
488
+ ${e !== 0 ? `offset += ${e};` : ""}
489
+
490
+ arrayOffset = offset;
491
+
492
+ t = 0;
493
+
494
+ for(var i=0; i < ${a.data.size * (t / 4)}; i++)
495
+ {
496
+ for(var j = 0; j < ${t / 4}; j++)
497
+ {
498
+ ${i}[arrayOffset++] = v[t++];
499
+ }
500
+ ${s !== 0 ? `arrayOffset += ${s};` : ""}
501
+ }
502
+ `;
503
+ }
504
+ function we(a) {
505
+ return _e(
506
+ a,
507
+ "uboWgsl",
508
+ Me,
509
+ be
510
+ );
511
+ }
512
+ class q extends ye {
513
+ constructor() {
514
+ super({
515
+ createUboElements: Ue,
516
+ generateUboSync: we
517
+ });
518
+ }
519
+ }
520
+ q.extension = {
521
+ type: [p.WebGPUSystem],
522
+ name: "ubo"
523
+ };
524
+ const b = 128;
525
+ class Y {
526
+ constructor(e) {
527
+ this._bindGroupHash = /* @__PURE__ */ Object.create(null), this._buffers = [], this._bindGroups = [], this._bufferResources = [], this._renderer = e, this._renderer.renderableGC.addManagedHash(this, "_bindGroupHash"), this._batchBuffer = new ve({ minUniformOffsetAlignment: b });
528
+ const t = 256 / b;
529
+ for (let r = 0; r < t; r++) {
530
+ let s = T.UNIFORM | T.COPY_DST;
531
+ r === 0 && (s |= T.COPY_SRC), this._buffers.push(new ue({
532
+ data: this._batchBuffer.data,
533
+ usage: s
534
+ }));
535
+ }
536
+ }
537
+ renderEnd() {
538
+ this._uploadBindGroups(), this._resetBindGroups();
539
+ }
540
+ _resetBindGroups() {
541
+ for (const e in this._bindGroupHash)
542
+ this._bindGroupHash[e] = null;
543
+ this._batchBuffer.clear();
544
+ }
545
+ // just works for single bind groups for now
546
+ getUniformBindGroup(e, t) {
547
+ if (!t && this._bindGroupHash[e.uid])
548
+ return this._bindGroupHash[e.uid];
549
+ this._renderer.ubo.ensureUniformGroup(e);
550
+ const r = e.buffer.data, s = this._batchBuffer.addEmptyGroup(r.length);
551
+ return this._renderer.ubo.syncUniformGroup(e, this._batchBuffer.data, s / 4), this._bindGroupHash[e.uid] = this._getBindGroup(s / b), this._bindGroupHash[e.uid];
552
+ }
553
+ getUboResource(e) {
554
+ this._renderer.ubo.updateUniformGroup(e);
555
+ const t = e.buffer.data, r = this._batchBuffer.addGroup(t);
556
+ return this._getBufferResource(r / b);
557
+ }
558
+ getArrayBindGroup(e) {
559
+ const t = this._batchBuffer.addGroup(e);
560
+ return this._getBindGroup(t / b);
561
+ }
562
+ getArrayBufferResource(e) {
563
+ const r = this._batchBuffer.addGroup(e) / b;
564
+ return this._getBufferResource(r);
565
+ }
566
+ _getBufferResource(e) {
567
+ if (!this._bufferResources[e]) {
568
+ const t = this._buffers[e % 2];
569
+ this._bufferResources[e] = new xe({
570
+ buffer: t,
571
+ offset: (e / 2 | 0) * 256,
572
+ size: b
573
+ });
574
+ }
575
+ return this._bufferResources[e];
576
+ }
577
+ _getBindGroup(e) {
578
+ if (!this._bindGroups[e]) {
579
+ const t = new L({
580
+ 0: this._getBufferResource(e)
581
+ });
582
+ this._bindGroups[e] = t;
583
+ }
584
+ return this._bindGroups[e];
585
+ }
586
+ _uploadBindGroups() {
587
+ const e = this._renderer.buffer, t = this._buffers[0];
588
+ t.update(this._batchBuffer.byteIndex), e.updateBuffer(t);
589
+ const r = this._renderer.gpu.device.createCommandEncoder();
590
+ for (let s = 1; s < this._buffers.length; s++) {
591
+ const i = this._buffers[s];
592
+ r.copyBufferToBuffer(
593
+ e.getGPUBuffer(t),
594
+ b,
595
+ e.getGPUBuffer(i),
596
+ 0,
597
+ this._batchBuffer.byteIndex
598
+ );
599
+ }
600
+ this._renderer.gpu.device.queue.submit([r.finish()]);
601
+ }
602
+ destroy() {
603
+ var e;
604
+ for (let t = 0; t < this._bindGroups.length; t++)
605
+ (e = this._bindGroups[t]) == null || e.destroy();
606
+ this._bindGroups = null, this._bindGroupHash = null;
607
+ for (let t = 0; t < this._buffers.length; t++)
608
+ this._buffers[t].destroy();
609
+ this._buffers = null;
610
+ for (let t = 0; t < this._bufferResources.length; t++)
611
+ this._bufferResources[t].destroy();
612
+ this._bufferResources = null, this._batchBuffer.destroy(), this._bindGroupHash = null, this._renderer = null;
613
+ }
614
+ }
615
+ Y.extension = {
616
+ type: [
617
+ p.WebGPUPipes
618
+ ],
619
+ name: "uniformBatch"
620
+ };
621
+ const Re = {
622
+ "point-list": 0,
623
+ "line-list": 1,
624
+ "line-strip": 2,
625
+ "triangle-list": 3,
626
+ "triangle-strip": 4
627
+ };
628
+ function Ee(a, e, t, r, s) {
629
+ return a << 24 | e << 16 | t << 10 | r << 5 | s;
630
+ }
631
+ function Le(a, e, t, r) {
632
+ return t << 6 | a << 3 | r << 1 | e;
633
+ }
634
+ class $ {
635
+ constructor(e) {
636
+ this._moduleCache = /* @__PURE__ */ Object.create(null), this._bufferLayoutsCache = /* @__PURE__ */ Object.create(null), this._bindingNamesCache = /* @__PURE__ */ Object.create(null), this._pipeCache = /* @__PURE__ */ Object.create(null), this._pipeStateCaches = /* @__PURE__ */ Object.create(null), this._colorMask = 15, this._multisampleCount = 1, this._renderer = e;
637
+ }
638
+ contextChange(e) {
639
+ this._gpu = e, this.setStencilMode(C.DISABLED), this._updatePipeHash();
640
+ }
641
+ setMultisampleCount(e) {
642
+ this._multisampleCount !== e && (this._multisampleCount = e, this._updatePipeHash());
643
+ }
644
+ setRenderTarget(e) {
645
+ this._multisampleCount = e.msaaSamples, this._depthStencilAttachment = e.descriptor.depthStencilAttachment ? 1 : 0, this._updatePipeHash();
646
+ }
647
+ setColorMask(e) {
648
+ this._colorMask !== e && (this._colorMask = e, this._updatePipeHash());
649
+ }
650
+ setStencilMode(e) {
651
+ this._stencilMode !== e && (this._stencilMode = e, this._stencilState = Ge[e], this._updatePipeHash());
652
+ }
653
+ setPipeline(e, t, r, s) {
654
+ const i = this.getPipeline(e, t, r);
655
+ s.setPipeline(i);
656
+ }
657
+ getPipeline(e, t, r, s) {
658
+ e._layoutKey || (Be(e, t.attributeData), this._generateBufferKey(e)), s || (s = e.topology);
659
+ const i = Ee(
660
+ e._layoutKey,
661
+ t._layoutKey,
662
+ r.data,
663
+ r._blendModeId,
664
+ Re[s]
665
+ );
666
+ return this._pipeCache[i] ? this._pipeCache[i] : (this._pipeCache[i] = this._createPipeline(e, t, r, s), this._pipeCache[i]);
667
+ }
668
+ _createPipeline(e, t, r, s) {
669
+ const i = this._gpu.device, n = this._createVertexBufferLayouts(e, t), o = this._renderer.state.getColorTargets(r);
670
+ o[0].writeMask = this._stencilMode === C.RENDERING_MASK_ADD ? 0 : this._colorMask;
671
+ const u = this._renderer.shader.getProgramData(t).pipeline, c = {
672
+ // TODO later check if its helpful to create..
673
+ // layout,
674
+ vertex: {
675
+ module: this._getModule(t.vertex.source),
676
+ entryPoint: t.vertex.entryPoint,
677
+ // geometry..
678
+ buffers: n
679
+ },
680
+ fragment: {
681
+ module: this._getModule(t.fragment.source),
682
+ entryPoint: t.fragment.entryPoint,
683
+ targets: o
684
+ },
685
+ primitive: {
686
+ topology: s,
687
+ cullMode: r.cullMode
688
+ },
689
+ layout: u,
690
+ multisample: {
691
+ count: this._multisampleCount
692
+ },
693
+ // depthStencil,
694
+ label: "PIXI Pipeline"
695
+ };
696
+ return this._depthStencilAttachment && (c.depthStencil = {
697
+ ...this._stencilState,
698
+ format: "depth24plus-stencil8",
699
+ depthWriteEnabled: r.depthTest,
700
+ depthCompare: r.depthTest ? "less" : "always"
701
+ }), i.createRenderPipeline(c);
702
+ }
703
+ _getModule(e) {
704
+ return this._moduleCache[e] || this._createModule(e);
705
+ }
706
+ _createModule(e) {
707
+ const t = this._gpu.device;
708
+ return this._moduleCache[e] = t.createShaderModule({
709
+ code: e
710
+ }), this._moduleCache[e];
711
+ }
712
+ _generateBufferKey(e) {
713
+ const t = [];
714
+ let r = 0;
715
+ const s = Object.keys(e.attributes).sort();
716
+ for (let n = 0; n < s.length; n++) {
717
+ const o = e.attributes[s[n]];
718
+ t[r++] = o.offset, t[r++] = o.format, t[r++] = o.stride, t[r++] = o.instance;
719
+ }
720
+ const i = t.join("|");
721
+ return e._layoutKey = M(i, "geometry"), e._layoutKey;
722
+ }
723
+ _generateAttributeLocationsKey(e) {
724
+ const t = [];
725
+ let r = 0;
726
+ const s = Object.keys(e.attributeData).sort();
727
+ for (let n = 0; n < s.length; n++) {
728
+ const o = e.attributeData[s[n]];
729
+ t[r++] = o.location;
730
+ }
731
+ const i = t.join("|");
732
+ return e._attributeLocationsKey = M(i, "programAttributes"), e._attributeLocationsKey;
733
+ }
734
+ /**
735
+ * Returns a hash of buffer names mapped to bind locations.
736
+ * This is used to bind the correct buffer to the correct location in the shader.
737
+ * @param geometry - The geometry where to get the buffer names
738
+ * @param program - The program where to get the buffer names
739
+ * @returns An object of buffer names mapped to the bind location.
740
+ */
741
+ getBufferNamesToBind(e, t) {
742
+ const r = e._layoutKey << 16 | t._attributeLocationsKey;
743
+ if (this._bindingNamesCache[r])
744
+ return this._bindingNamesCache[r];
745
+ const s = this._createVertexBufferLayouts(e, t), i = /* @__PURE__ */ Object.create(null), n = t.attributeData;
746
+ for (let o = 0; o < s.length; o++) {
747
+ const c = Object.values(s[o].attributes)[0].shaderLocation;
748
+ for (const l in n)
749
+ if (n[l].location === c) {
750
+ i[o] = l;
751
+ break;
752
+ }
753
+ }
754
+ return this._bindingNamesCache[r] = i, i;
755
+ }
756
+ _createVertexBufferLayouts(e, t) {
757
+ t._attributeLocationsKey || this._generateAttributeLocationsKey(t);
758
+ const r = e._layoutKey << 16 | t._attributeLocationsKey;
759
+ if (this._bufferLayoutsCache[r])
760
+ return this._bufferLayoutsCache[r];
761
+ const s = [];
762
+ return e.buffers.forEach((i) => {
763
+ const n = {
764
+ arrayStride: 0,
765
+ stepMode: "vertex",
766
+ attributes: []
767
+ }, o = n.attributes;
768
+ for (const u in t.attributeData) {
769
+ const c = e.attributes[u];
770
+ (c.divisor ?? 1) !== 1 && v(`Attribute ${u} has an invalid divisor value of '${c.divisor}'. WebGPU only supports a divisor value of 1`), c.buffer === i && (n.arrayStride = c.stride, n.stepMode = c.instance ? "instance" : "vertex", o.push({
771
+ shaderLocation: t.attributeData[u].location,
772
+ offset: c.offset,
773
+ format: c.format
774
+ }));
775
+ }
776
+ o.length && s.push(n);
777
+ }), this._bufferLayoutsCache[r] = s, s;
778
+ }
779
+ _updatePipeHash() {
780
+ const e = Le(
781
+ this._stencilMode,
782
+ this._multisampleCount,
783
+ this._colorMask,
784
+ this._depthStencilAttachment
785
+ );
786
+ this._pipeStateCaches[e] || (this._pipeStateCaches[e] = /* @__PURE__ */ Object.create(null)), this._pipeCache = this._pipeStateCaches[e];
787
+ }
788
+ destroy() {
789
+ this._renderer = null, this._bufferLayoutsCache = null;
790
+ }
791
+ }
792
+ $.extension = {
793
+ type: [p.WebGPUSystem],
794
+ name: "pipeline"
795
+ };
796
+ class Ae {
797
+ constructor() {
798
+ this.contexts = [], this.msaaTextures = [], this.msaaSamples = 1;
799
+ }
800
+ }
801
+ class ke {
802
+ init(e, t) {
803
+ this._renderer = e, this._renderTargetSystem = t;
804
+ }
805
+ copyToTexture(e, t, r, s, i) {
806
+ const n = this._renderer, o = this._getGpuColorTexture(
807
+ e
808
+ ), u = n.texture.getGpuSource(
809
+ t.source
810
+ );
811
+ return n.encoder.commandEncoder.copyTextureToTexture(
812
+ {
813
+ texture: o,
814
+ origin: r
815
+ },
816
+ {
817
+ texture: u,
818
+ origin: i
819
+ },
820
+ s
821
+ ), t;
822
+ }
823
+ startRenderPass(e, t = !0, r, s) {
824
+ const n = this._renderTargetSystem.getGpuRenderTarget(e), o = this.getDescriptor(e, t, r);
825
+ n.descriptor = o, this._renderer.pipeline.setRenderTarget(n), this._renderer.encoder.beginRenderPass(n), this._renderer.encoder.setViewport(s);
826
+ }
827
+ finishRenderPass() {
828
+ this._renderer.encoder.endRenderPass();
829
+ }
830
+ /**
831
+ * returns the gpu texture for the first color texture in the render target
832
+ * mainly used by the filter manager to get copy the texture for blending
833
+ * @param renderTarget
834
+ * @returns a gpu texture
835
+ */
836
+ _getGpuColorTexture(e) {
837
+ const t = this._renderTargetSystem.getGpuRenderTarget(e);
838
+ return t.contexts[0] ? t.contexts[0].getCurrentTexture() : this._renderer.texture.getGpuSource(
839
+ e.colorTextures[0].source
840
+ );
841
+ }
842
+ getDescriptor(e, t, r) {
843
+ typeof t == "boolean" && (t = t ? y.ALL : y.NONE);
844
+ const s = this._renderTargetSystem, i = s.getGpuRenderTarget(e), n = e.colorTextures.map(
845
+ (c, l) => {
846
+ const h = i.contexts[l];
847
+ let f, d;
848
+ h ? f = h.getCurrentTexture().createView() : f = this._renderer.texture.getGpuSource(c).createView({
849
+ mipLevelCount: 1
850
+ }), i.msaaTextures[l] && (d = f, f = this._renderer.texture.getTextureView(
851
+ i.msaaTextures[l]
852
+ ));
853
+ const _ = t & y.COLOR ? "clear" : "load";
854
+ return r ?? (r = s.defaultClearColor), {
855
+ view: f,
856
+ resolveTarget: d,
857
+ clearValue: r,
858
+ storeOp: "store",
859
+ loadOp: _
860
+ };
861
+ }
862
+ );
863
+ let o;
864
+ if ((e.stencil || e.depth) && !e.depthStencilTexture && (e.ensureDepthStencilTexture(), e.depthStencilTexture.source.sampleCount = i.msaa ? 4 : 1), e.depthStencilTexture) {
865
+ const c = t & y.STENCIL ? "clear" : "load", l = t & y.DEPTH ? "clear" : "load";
866
+ o = {
867
+ view: this._renderer.texture.getGpuSource(e.depthStencilTexture.source).createView(),
868
+ stencilStoreOp: "store",
869
+ stencilLoadOp: c,
870
+ depthClearValue: 1,
871
+ depthLoadOp: l,
872
+ depthStoreOp: "store"
873
+ };
874
+ }
875
+ return {
876
+ colorAttachments: n,
877
+ depthStencilAttachment: o
878
+ };
879
+ }
880
+ clear(e, t = !0, r, s) {
881
+ if (!t)
882
+ return;
883
+ const { gpu: i, encoder: n } = this._renderer, o = i.device;
884
+ if (n.commandEncoder === null) {
885
+ const c = o.createCommandEncoder(), l = this.getDescriptor(e, t, r), h = c.beginRenderPass(l);
886
+ h.setViewport(s.x, s.y, s.width, s.height, 0, 1), h.end();
887
+ const f = c.finish();
888
+ o.queue.submit([f]);
889
+ } else
890
+ this.startRenderPass(e, t, r, s);
891
+ }
892
+ initGpuRenderTarget(e) {
893
+ e.isRoot = !0;
894
+ const t = new Ae();
895
+ return e.colorTextures.forEach((r, s) => {
896
+ if (r instanceof ce) {
897
+ const i = r.resource.getContext(
898
+ "webgpu"
899
+ ), n = r.transparent ? "premultiplied" : "opaque";
900
+ try {
901
+ i.configure({
902
+ device: this._renderer.gpu.device,
903
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC,
904
+ format: "bgra8unorm",
905
+ alphaMode: n
906
+ });
907
+ } catch (o) {
908
+ console.error(o);
909
+ }
910
+ t.contexts[s] = i;
911
+ }
912
+ if (t.msaa = r.source.antialias, r.source.antialias) {
913
+ const i = new de({
914
+ width: 0,
915
+ height: 0,
916
+ sampleCount: 4
917
+ });
918
+ t.msaaTextures[s] = i;
919
+ }
920
+ }), t.msaa && (t.msaaSamples = 4, e.depthStencilTexture && (e.depthStencilTexture.source.sampleCount = 4)), t;
921
+ }
922
+ destroyGpuRenderTarget(e) {
923
+ e.contexts.forEach((t) => {
924
+ t.unconfigure();
925
+ }), e.msaaTextures.forEach((t) => {
926
+ t.destroy();
927
+ }), e.msaaTextures.length = 0, e.contexts.length = 0;
928
+ }
929
+ ensureDepthStencilTexture(e) {
930
+ const t = this._renderTargetSystem.getGpuRenderTarget(e);
931
+ e.depthStencilTexture && t.msaa && (e.depthStencilTexture.source.sampleCount = 4);
932
+ }
933
+ resizeGpuRenderTarget(e) {
934
+ const t = this._renderTargetSystem.getGpuRenderTarget(e);
935
+ t.width = e.width, t.height = e.height, t.msaa && e.colorTextures.forEach((r, s) => {
936
+ const i = t.msaaTextures[s];
937
+ i == null || i.resize(
938
+ r.source.width,
939
+ r.source.height,
940
+ r.source._resolution
941
+ );
942
+ });
943
+ }
944
+ }
945
+ class X extends Se {
946
+ constructor(e) {
947
+ super(e), this.adaptor = new ke(), this.adaptor.init(e, this);
948
+ }
949
+ }
950
+ X.extension = {
951
+ type: [p.WebGPUSystem],
952
+ name: "renderTarget"
953
+ };
954
+ class Z {
955
+ constructor() {
956
+ this._gpuProgramData = /* @__PURE__ */ Object.create(null);
957
+ }
958
+ contextChange(e) {
959
+ this._gpu = e;
960
+ }
961
+ getProgramData(e) {
962
+ return this._gpuProgramData[e._layoutKey] || this._createGPUProgramData(e);
963
+ }
964
+ _createGPUProgramData(e) {
965
+ const t = this._gpu.device, r = e.gpuLayout.map((i) => t.createBindGroupLayout({ entries: i })), s = { bindGroupLayouts: r };
966
+ return this._gpuProgramData[e._layoutKey] = {
967
+ bindGroups: r,
968
+ pipeline: t.createPipelineLayout(s)
969
+ }, this._gpuProgramData[e._layoutKey];
970
+ }
971
+ destroy() {
972
+ this._gpu = null, this._gpuProgramData = null;
973
+ }
974
+ }
975
+ Z.extension = {
976
+ type: [
977
+ p.WebGPUSystem
978
+ ],
979
+ name: "shader"
980
+ };
981
+ const g = {};
982
+ g.normal = {
983
+ alpha: {
984
+ srcFactor: "one",
985
+ dstFactor: "one-minus-src-alpha",
986
+ operation: "add"
987
+ },
988
+ color: {
989
+ srcFactor: "one",
990
+ dstFactor: "one-minus-src-alpha",
991
+ operation: "add"
992
+ }
993
+ };
994
+ g.add = {
995
+ alpha: {
996
+ srcFactor: "src-alpha",
997
+ dstFactor: "one-minus-src-alpha",
998
+ operation: "add"
999
+ },
1000
+ color: {
1001
+ srcFactor: "one",
1002
+ dstFactor: "one",
1003
+ operation: "add"
1004
+ }
1005
+ };
1006
+ g.multiply = {
1007
+ alpha: {
1008
+ srcFactor: "one",
1009
+ dstFactor: "one-minus-src-alpha",
1010
+ operation: "add"
1011
+ },
1012
+ color: {
1013
+ srcFactor: "dst",
1014
+ dstFactor: "one-minus-src-alpha",
1015
+ operation: "add"
1016
+ }
1017
+ };
1018
+ g.screen = {
1019
+ alpha: {
1020
+ srcFactor: "one",
1021
+ dstFactor: "one-minus-src-alpha",
1022
+ operation: "add"
1023
+ },
1024
+ color: {
1025
+ srcFactor: "one",
1026
+ dstFactor: "one-minus-src",
1027
+ operation: "add"
1028
+ }
1029
+ };
1030
+ g.overlay = {
1031
+ alpha: {
1032
+ srcFactor: "one",
1033
+ dstFactor: "one-minus-src-alpha",
1034
+ operation: "add"
1035
+ },
1036
+ color: {
1037
+ srcFactor: "one",
1038
+ dstFactor: "one-minus-src",
1039
+ operation: "add"
1040
+ }
1041
+ };
1042
+ g.none = {
1043
+ alpha: {
1044
+ srcFactor: "one",
1045
+ dstFactor: "one-minus-src-alpha",
1046
+ operation: "add"
1047
+ },
1048
+ color: {
1049
+ srcFactor: "zero",
1050
+ dstFactor: "zero",
1051
+ operation: "add"
1052
+ }
1053
+ };
1054
+ g["normal-npm"] = {
1055
+ alpha: {
1056
+ srcFactor: "one",
1057
+ dstFactor: "one-minus-src-alpha",
1058
+ operation: "add"
1059
+ },
1060
+ color: {
1061
+ srcFactor: "src-alpha",
1062
+ dstFactor: "one-minus-src-alpha",
1063
+ operation: "add"
1064
+ }
1065
+ };
1066
+ g["add-npm"] = {
1067
+ alpha: {
1068
+ srcFactor: "one",
1069
+ dstFactor: "one",
1070
+ operation: "add"
1071
+ },
1072
+ color: {
1073
+ srcFactor: "src-alpha",
1074
+ dstFactor: "one",
1075
+ operation: "add"
1076
+ }
1077
+ };
1078
+ g["screen-npm"] = {
1079
+ alpha: {
1080
+ srcFactor: "one",
1081
+ dstFactor: "one-minus-src-alpha",
1082
+ operation: "add"
1083
+ },
1084
+ color: {
1085
+ srcFactor: "src-alpha",
1086
+ dstFactor: "one-minus-src",
1087
+ operation: "add"
1088
+ }
1089
+ };
1090
+ g.erase = {
1091
+ alpha: {
1092
+ srcFactor: "zero",
1093
+ dstFactor: "one-minus-src-alpha",
1094
+ operation: "add"
1095
+ },
1096
+ color: {
1097
+ srcFactor: "zero",
1098
+ dstFactor: "one-minus-src",
1099
+ operation: "add"
1100
+ }
1101
+ };
1102
+ g.min = {
1103
+ alpha: {
1104
+ srcFactor: "one",
1105
+ dstFactor: "one",
1106
+ operation: "min"
1107
+ },
1108
+ color: {
1109
+ srcFactor: "one",
1110
+ dstFactor: "one",
1111
+ operation: "min"
1112
+ }
1113
+ };
1114
+ g.max = {
1115
+ alpha: {
1116
+ srcFactor: "one",
1117
+ dstFactor: "one",
1118
+ operation: "max"
1119
+ },
1120
+ color: {
1121
+ srcFactor: "one",
1122
+ dstFactor: "one",
1123
+ operation: "max"
1124
+ }
1125
+ };
1126
+ class J {
1127
+ constructor() {
1128
+ this.defaultState = new F(), this.defaultState.blend = !0;
1129
+ }
1130
+ contextChange(e) {
1131
+ this.gpu = e;
1132
+ }
1133
+ /**
1134
+ * Gets the blend mode data for the current state
1135
+ * @param state - The state to get the blend mode from
1136
+ */
1137
+ getColorTargets(e) {
1138
+ return [
1139
+ {
1140
+ format: "bgra8unorm",
1141
+ writeMask: 0,
1142
+ blend: g[e.blendMode] || g.normal
1143
+ }
1144
+ ];
1145
+ }
1146
+ destroy() {
1147
+ this.gpu = null;
1148
+ }
1149
+ }
1150
+ J.extension = {
1151
+ type: [
1152
+ p.WebGPUSystem
1153
+ ],
1154
+ name: "state"
1155
+ };
1156
+ const De = {
1157
+ type: "image",
1158
+ upload(a, e, t) {
1159
+ const r = a.resource, s = (a.pixelWidth | 0) * (a.pixelHeight | 0), i = r.byteLength / s;
1160
+ t.device.queue.writeTexture(
1161
+ { texture: e },
1162
+ r,
1163
+ {
1164
+ offset: 0,
1165
+ rowsPerImage: a.pixelHeight,
1166
+ bytesPerRow: a.pixelHeight * i
1167
+ },
1168
+ {
1169
+ width: a.pixelWidth,
1170
+ height: a.pixelHeight,
1171
+ depthOrArrayLayers: 1
1172
+ }
1173
+ );
1174
+ }
1175
+ }, Q = {
1176
+ "bc1-rgba-unorm": { blockBytes: 8, blockWidth: 4, blockHeight: 4 },
1177
+ "bc2-rgba-unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 },
1178
+ "bc3-rgba-unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 },
1179
+ "bc7-rgba-unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 },
1180
+ "etc1-rgb-unorm": { blockBytes: 8, blockWidth: 4, blockHeight: 4 },
1181
+ "etc2-rgba8unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 },
1182
+ "astc-4x4-unorm": { blockBytes: 16, blockWidth: 4, blockHeight: 4 }
1183
+ }, He = { blockBytes: 4, blockWidth: 1, blockHeight: 1 }, ze = {
1184
+ type: "compressed",
1185
+ upload(a, e, t) {
1186
+ let r = a.pixelWidth, s = a.pixelHeight;
1187
+ const i = Q[a.format] || He;
1188
+ for (let n = 0; n < a.resource.length; n++) {
1189
+ const o = a.resource[n], u = Math.ceil(r / i.blockWidth) * i.blockBytes;
1190
+ t.device.queue.writeTexture(
1191
+ {
1192
+ texture: e,
1193
+ mipLevel: n
1194
+ },
1195
+ o,
1196
+ {
1197
+ offset: 0,
1198
+ bytesPerRow: u
1199
+ },
1200
+ {
1201
+ width: Math.ceil(r / i.blockWidth) * i.blockWidth,
1202
+ height: Math.ceil(s / i.blockHeight) * i.blockHeight,
1203
+ depthOrArrayLayers: 1
1204
+ }
1205
+ ), r = Math.max(r >> 1, 1), s = Math.max(s >> 1, 1);
1206
+ }
1207
+ }
1208
+ }, ee = {
1209
+ type: "image",
1210
+ upload(a, e, t) {
1211
+ const r = a.resource;
1212
+ if (!r)
1213
+ return;
1214
+ if (globalThis.HTMLImageElement && r instanceof HTMLImageElement) {
1215
+ const o = B.get().createCanvas(r.width, r.height);
1216
+ o.getContext("2d").drawImage(r, 0, 0, r.width, r.height), a.resource = o, v("ImageSource: Image element passed, converting to canvas and replacing resource.");
1217
+ }
1218
+ const s = Math.min(e.width, a.resourceWidth || a.pixelWidth), i = Math.min(e.height, a.resourceHeight || a.pixelHeight), n = a.alphaMode === "premultiply-alpha-on-upload";
1219
+ t.device.queue.copyExternalImageToTexture(
1220
+ { source: r },
1221
+ { texture: e, premultipliedAlpha: n },
1222
+ {
1223
+ width: s,
1224
+ height: i
1225
+ }
1226
+ );
1227
+ }
1228
+ }, Fe = {
1229
+ type: "video",
1230
+ upload(a, e, t) {
1231
+ ee.upload(a, e, t);
1232
+ }
1233
+ };
1234
+ class Oe {
1235
+ constructor(e) {
1236
+ this.device = e, this.sampler = e.createSampler({ minFilter: "linear" }), this.pipelines = {};
1237
+ }
1238
+ _getMipmapPipeline(e) {
1239
+ let t = this.pipelines[e];
1240
+ return t || (this.mipmapShaderModule || (this.mipmapShaderModule = this.device.createShaderModule({
1241
+ code: (
1242
+ /* wgsl */
1243
+ `
1244
+ var<private> pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
1245
+ vec2<f32>(-1.0, -1.0), vec2<f32>(-1.0, 3.0), vec2<f32>(3.0, -1.0));
1246
+
1247
+ struct VertexOutput {
1248
+ @builtin(position) position : vec4<f32>,
1249
+ @location(0) texCoord : vec2<f32>,
1250
+ };
1251
+
1252
+ @vertex
1253
+ fn vertexMain(@builtin(vertex_index) vertexIndex : u32) -> VertexOutput {
1254
+ var output : VertexOutput;
1255
+ output.texCoord = pos[vertexIndex] * vec2<f32>(0.5, -0.5) + vec2<f32>(0.5);
1256
+ output.position = vec4<f32>(pos[vertexIndex], 0.0, 1.0);
1257
+ return output;
1258
+ }
1259
+
1260
+ @group(0) @binding(0) var imgSampler : sampler;
1261
+ @group(0) @binding(1) var img : texture_2d<f32>;
1262
+
1263
+ @fragment
1264
+ fn fragmentMain(@location(0) texCoord : vec2<f32>) -> @location(0) vec4<f32> {
1265
+ return textureSample(img, imgSampler, texCoord);
1266
+ }
1267
+ `
1268
+ )
1269
+ })), t = this.device.createRenderPipeline({
1270
+ layout: "auto",
1271
+ vertex: {
1272
+ module: this.mipmapShaderModule,
1273
+ entryPoint: "vertexMain"
1274
+ },
1275
+ fragment: {
1276
+ module: this.mipmapShaderModule,
1277
+ entryPoint: "fragmentMain",
1278
+ targets: [{ format: e }]
1279
+ }
1280
+ }), this.pipelines[e] = t), t;
1281
+ }
1282
+ /**
1283
+ * Generates mipmaps for the given GPUTexture from the data in level 0.
1284
+ * @param {module:External.GPUTexture} texture - Texture to generate mipmaps for.
1285
+ * @returns {module:External.GPUTexture} - The originally passed texture
1286
+ */
1287
+ generateMipmap(e) {
1288
+ const t = this._getMipmapPipeline(e.format);
1289
+ if (e.dimension === "3d" || e.dimension === "1d")
1290
+ throw new Error("Generating mipmaps for non-2d textures is currently unsupported!");
1291
+ let r = e;
1292
+ const s = e.depthOrArrayLayers || 1, i = e.usage & GPUTextureUsage.RENDER_ATTACHMENT;
1293
+ if (!i) {
1294
+ const u = {
1295
+ size: {
1296
+ width: Math.ceil(e.width / 2),
1297
+ height: Math.ceil(e.height / 2),
1298
+ depthOrArrayLayers: s
1299
+ },
1300
+ format: e.format,
1301
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
1302
+ mipLevelCount: e.mipLevelCount - 1
1303
+ };
1304
+ r = this.device.createTexture(u);
1305
+ }
1306
+ const n = this.device.createCommandEncoder({}), o = t.getBindGroupLayout(0);
1307
+ for (let u = 0; u < s; ++u) {
1308
+ let c = e.createView({
1309
+ baseMipLevel: 0,
1310
+ mipLevelCount: 1,
1311
+ dimension: "2d",
1312
+ baseArrayLayer: u,
1313
+ arrayLayerCount: 1
1314
+ }), l = i ? 1 : 0;
1315
+ for (let h = 1; h < e.mipLevelCount; ++h) {
1316
+ const f = r.createView({
1317
+ baseMipLevel: l++,
1318
+ mipLevelCount: 1,
1319
+ dimension: "2d",
1320
+ baseArrayLayer: u,
1321
+ arrayLayerCount: 1
1322
+ }), d = n.beginRenderPass({
1323
+ colorAttachments: [{
1324
+ view: f,
1325
+ storeOp: "store",
1326
+ loadOp: "clear",
1327
+ clearValue: { r: 0, g: 0, b: 0, a: 0 }
1328
+ }]
1329
+ }), _ = this.device.createBindGroup({
1330
+ layout: o,
1331
+ entries: [{
1332
+ binding: 0,
1333
+ resource: this.sampler
1334
+ }, {
1335
+ binding: 1,
1336
+ resource: c
1337
+ }]
1338
+ });
1339
+ d.setPipeline(t), d.setBindGroup(0, _), d.draw(3, 1, 0, 0), d.end(), c = f;
1340
+ }
1341
+ }
1342
+ if (!i) {
1343
+ const u = {
1344
+ width: Math.ceil(e.width / 2),
1345
+ height: Math.ceil(e.height / 2),
1346
+ depthOrArrayLayers: s
1347
+ };
1348
+ for (let c = 1; c < e.mipLevelCount; ++c)
1349
+ n.copyTextureToTexture({
1350
+ texture: r,
1351
+ mipLevel: c - 1
1352
+ }, {
1353
+ texture: e,
1354
+ mipLevel: c
1355
+ }, u), u.width = Math.ceil(u.width / 2), u.height = Math.ceil(u.height / 2);
1356
+ }
1357
+ return this.device.queue.submit([n.finish()]), i || r.destroy(), e;
1358
+ }
1359
+ }
1360
+ class te {
1361
+ constructor(e) {
1362
+ this.managedTextures = [], this._gpuSources = /* @__PURE__ */ Object.create(null), this._gpuSamplers = /* @__PURE__ */ Object.create(null), this._bindGroupHash = /* @__PURE__ */ Object.create(null), this._textureViewHash = /* @__PURE__ */ Object.create(null), this._uploads = {
1363
+ image: ee,
1364
+ buffer: De,
1365
+ video: Fe,
1366
+ compressed: ze
1367
+ }, this._renderer = e, e.renderableGC.addManagedHash(this, "_gpuSources"), e.renderableGC.addManagedHash(this, "_gpuSamplers"), e.renderableGC.addManagedHash(this, "_bindGroupHash"), e.renderableGC.addManagedHash(this, "_textureViewHash");
1368
+ }
1369
+ contextChange(e) {
1370
+ this._gpu = e;
1371
+ }
1372
+ /**
1373
+ * Initializes a texture source, if it has already been initialized nothing will happen.
1374
+ * @param source - The texture source to initialize.
1375
+ * @returns The initialized texture source.
1376
+ */
1377
+ initSource(e) {
1378
+ return this._gpuSources[e.uid] ? this._gpuSources[e.uid] : this._initSource(e);
1379
+ }
1380
+ _initSource(e) {
1381
+ if (e.autoGenerateMipmaps) {
1382
+ const u = Math.max(e.pixelWidth, e.pixelHeight);
1383
+ e.mipLevelCount = Math.floor(Math.log2(u)) + 1;
1384
+ }
1385
+ let t = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST;
1386
+ e.uploadMethodId !== "compressed" && (t |= GPUTextureUsage.RENDER_ATTACHMENT, t |= GPUTextureUsage.COPY_SRC);
1387
+ const r = Q[e.format] || { blockWidth: 1, blockHeight: 1 }, s = Math.ceil(e.pixelWidth / r.blockWidth) * r.blockWidth, i = Math.ceil(e.pixelHeight / r.blockHeight) * r.blockHeight, n = {
1388
+ label: e.label,
1389
+ size: { width: s, height: i },
1390
+ format: e.format,
1391
+ sampleCount: e.sampleCount,
1392
+ mipLevelCount: e.mipLevelCount,
1393
+ dimension: e.dimension,
1394
+ usage: t
1395
+ }, o = this._gpuSources[e.uid] = this._gpu.device.createTexture(n);
1396
+ return this.managedTextures.includes(e) || (e.on("update", this.onSourceUpdate, this), e.on("resize", this.onSourceResize, this), e.on("destroy", this.onSourceDestroy, this), e.on("unload", this.onSourceUnload, this), e.on("updateMipmaps", this.onUpdateMipmaps, this), this.managedTextures.push(e)), this.onSourceUpdate(e), o;
1397
+ }
1398
+ onSourceUpdate(e) {
1399
+ const t = this.getGpuSource(e);
1400
+ t && (this._uploads[e.uploadMethodId] && this._uploads[e.uploadMethodId].upload(e, t, this._gpu), e.autoGenerateMipmaps && e.mipLevelCount > 1 && this.onUpdateMipmaps(e));
1401
+ }
1402
+ onSourceUnload(e) {
1403
+ const t = this._gpuSources[e.uid];
1404
+ t && (this._gpuSources[e.uid] = null, t.destroy());
1405
+ }
1406
+ onUpdateMipmaps(e) {
1407
+ this._mipmapGenerator || (this._mipmapGenerator = new Oe(this._gpu.device));
1408
+ const t = this.getGpuSource(e);
1409
+ this._mipmapGenerator.generateMipmap(t);
1410
+ }
1411
+ onSourceDestroy(e) {
1412
+ e.off("update", this.onSourceUpdate, this), e.off("unload", this.onSourceUnload, this), e.off("destroy", this.onSourceDestroy, this), e.off("resize", this.onSourceResize, this), e.off("updateMipmaps", this.onUpdateMipmaps, this), this.managedTextures.splice(this.managedTextures.indexOf(e), 1), this.onSourceUnload(e);
1413
+ }
1414
+ onSourceResize(e) {
1415
+ const t = this._gpuSources[e.uid];
1416
+ t ? (t.width !== e.pixelWidth || t.height !== e.pixelHeight) && (this._textureViewHash[e.uid] = null, this._bindGroupHash[e.uid] = null, this.onSourceUnload(e), this.initSource(e)) : this.initSource(e);
1417
+ }
1418
+ _initSampler(e) {
1419
+ return this._gpuSamplers[e._resourceId] = this._gpu.device.createSampler(e), this._gpuSamplers[e._resourceId];
1420
+ }
1421
+ getGpuSampler(e) {
1422
+ return this._gpuSamplers[e._resourceId] || this._initSampler(e);
1423
+ }
1424
+ getGpuSource(e) {
1425
+ return this._gpuSources[e.uid] || this.initSource(e);
1426
+ }
1427
+ /**
1428
+ * this returns s bind group for a specific texture, the bind group contains
1429
+ * - the texture source
1430
+ * - the texture style
1431
+ * - the texture matrix
1432
+ * This is cached so the bind group should only be created once per texture
1433
+ * @param texture - the texture you want the bindgroup for
1434
+ * @returns the bind group for the texture
1435
+ */
1436
+ getTextureBindGroup(e) {
1437
+ return this._bindGroupHash[e.uid] ?? this._createTextureBindGroup(e);
1438
+ }
1439
+ _createTextureBindGroup(e) {
1440
+ const t = e.source;
1441
+ return this._bindGroupHash[e.uid] = new L({
1442
+ 0: t,
1443
+ 1: t.style,
1444
+ 2: new A({
1445
+ uTextureMatrix: { type: "mat3x3<f32>", value: e.textureMatrix.mapCoord }
1446
+ })
1447
+ }), this._bindGroupHash[e.uid];
1448
+ }
1449
+ getTextureView(e) {
1450
+ const t = e.source;
1451
+ return this._textureViewHash[t.uid] ?? this._createTextureView(t);
1452
+ }
1453
+ _createTextureView(e) {
1454
+ return this._textureViewHash[e.uid] = this.getGpuSource(e).createView(), this._textureViewHash[e.uid];
1455
+ }
1456
+ generateCanvas(e) {
1457
+ const t = this._renderer, r = t.gpu.device.createCommandEncoder(), s = B.get().createCanvas();
1458
+ s.width = e.source.pixelWidth, s.height = e.source.pixelHeight;
1459
+ const i = s.getContext("webgpu");
1460
+ return i.configure({
1461
+ device: t.gpu.device,
1462
+ usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC,
1463
+ format: B.get().getNavigator().gpu.getPreferredCanvasFormat(),
1464
+ alphaMode: "premultiplied"
1465
+ }), r.copyTextureToTexture({
1466
+ texture: t.texture.getGpuSource(e.source),
1467
+ origin: {
1468
+ x: 0,
1469
+ y: 0
1470
+ }
1471
+ }, {
1472
+ texture: i.getCurrentTexture()
1473
+ }, {
1474
+ width: s.width,
1475
+ height: s.height
1476
+ }), t.gpu.device.queue.submit([r.finish()]), s;
1477
+ }
1478
+ getPixels(e) {
1479
+ const t = this.generateCanvas(e), r = R.getOptimalCanvasAndContext(t.width, t.height), s = r.context;
1480
+ s.drawImage(t, 0, 0);
1481
+ const { width: i, height: n } = t, o = s.getImageData(0, 0, i, n), u = new Uint8ClampedArray(o.data.buffer);
1482
+ return R.returnCanvasAndContext(r), { pixels: u, width: i, height: n };
1483
+ }
1484
+ destroy() {
1485
+ this.managedTextures.slice().forEach((e) => this.onSourceDestroy(e)), this.managedTextures = null;
1486
+ for (const e of Object.keys(this._bindGroupHash)) {
1487
+ const t = Number(e), r = this._bindGroupHash[t];
1488
+ r == null || r.destroy(), this._bindGroupHash[t] = null;
1489
+ }
1490
+ this._gpu = null, this._mipmapGenerator = null, this._gpuSources = null, this._bindGroupHash = null, this._textureViewHash = null, this._gpuSamplers = null;
1491
+ }
1492
+ }
1493
+ te.extension = {
1494
+ type: [
1495
+ p.WebGPUSystem
1496
+ ],
1497
+ name: "texture"
1498
+ };
1499
+ class re {
1500
+ constructor() {
1501
+ this._maxTextures = 0;
1502
+ }
1503
+ contextChange(e) {
1504
+ const t = new A({
1505
+ uTransformMatrix: { value: new k(), type: "mat3x3<f32>" },
1506
+ uColor: { value: new Float32Array([1, 1, 1, 1]), type: "vec4<f32>" },
1507
+ uRound: { value: 0, type: "f32" }
1508
+ });
1509
+ this._maxTextures = e.limits.maxBatchableTextures;
1510
+ const r = D({
1511
+ name: "graphics",
1512
+ bits: [
1513
+ he,
1514
+ pe(this._maxTextures),
1515
+ ge,
1516
+ H
1517
+ ]
1518
+ });
1519
+ this.shader = new z({
1520
+ gpuProgram: r,
1521
+ resources: {
1522
+ // added on the fly!
1523
+ localUniforms: t
1524
+ }
1525
+ });
1526
+ }
1527
+ execute(e, t) {
1528
+ const r = t.context, s = r.customShader || this.shader, i = e.renderer, n = i.graphicsContext, {
1529
+ batcher: o,
1530
+ instructions: u
1531
+ } = n.getContextRenderData(r), c = i.encoder;
1532
+ c.setGeometry(o.geometry, s.gpuProgram);
1533
+ const l = i.globalUniforms.bindGroup;
1534
+ c.setBindGroup(0, l, s.gpuProgram);
1535
+ const h = i.renderPipes.uniformBatch.getUniformBindGroup(s.resources.localUniforms, !0);
1536
+ c.setBindGroup(2, h, s.gpuProgram);
1537
+ const f = u.instructions;
1538
+ let d = null;
1539
+ for (let _ = 0; _ < u.instructionSize; _++) {
1540
+ const m = f[_];
1541
+ if (m.topology !== d && (d = m.topology, c.setPipelineFromGeometryProgramAndState(
1542
+ o.geometry,
1543
+ s.gpuProgram,
1544
+ e.state,
1545
+ m.topology
1546
+ )), s.groups[1] = m.bindGroup, !m.gpuBindGroup) {
1547
+ const P = m.textures;
1548
+ m.bindGroup = E(
1549
+ P.textures,
1550
+ P.count,
1551
+ this._maxTextures
1552
+ ), m.gpuBindGroup = i.bindGroup.getBindGroup(
1553
+ m.bindGroup,
1554
+ s.gpuProgram,
1555
+ 1
1556
+ );
1557
+ }
1558
+ c.setBindGroup(1, m.bindGroup, s.gpuProgram), c.renderPassEncoder.drawIndexed(m.size, 1, m.start);
1559
+ }
1560
+ }
1561
+ destroy() {
1562
+ this.shader.destroy(!0), this.shader = null;
1563
+ }
1564
+ }
1565
+ re.extension = {
1566
+ type: [
1567
+ p.WebGPUPipesAdaptor
1568
+ ],
1569
+ name: "graphics"
1570
+ };
1571
+ class se {
1572
+ init() {
1573
+ const e = D({
1574
+ name: "mesh",
1575
+ bits: [
1576
+ me,
1577
+ Pe,
1578
+ H
1579
+ ]
1580
+ });
1581
+ this._shader = new z({
1582
+ gpuProgram: e,
1583
+ resources: {
1584
+ uTexture: w.EMPTY._source,
1585
+ uSampler: w.EMPTY._source.style,
1586
+ textureUniforms: {
1587
+ uTextureMatrix: { type: "mat3x3<f32>", value: new k() }
1588
+ }
1589
+ }
1590
+ });
1591
+ }
1592
+ execute(e, t) {
1593
+ const r = e.renderer;
1594
+ let s = t._shader;
1595
+ if (!s)
1596
+ s = this._shader, s.groups[2] = r.texture.getTextureBindGroup(t.texture);
1597
+ else if (!s.gpuProgram) {
1598
+ v("Mesh shader has no gpuProgram", t.shader);
1599
+ return;
1600
+ }
1601
+ const i = s.gpuProgram;
1602
+ if (i.autoAssignGlobalUniforms && (s.groups[0] = r.globalUniforms.bindGroup), i.autoAssignLocalUniforms) {
1603
+ const n = e.localUniforms;
1604
+ s.groups[1] = r.renderPipes.uniformBatch.getUniformBindGroup(n, !0);
1605
+ }
1606
+ r.encoder.draw({
1607
+ geometry: t._geometry,
1608
+ shader: s,
1609
+ state: t.state
1610
+ });
1611
+ }
1612
+ destroy() {
1613
+ this._shader.destroy(!0), this._shader = null;
1614
+ }
1615
+ }
1616
+ se.extension = {
1617
+ type: [
1618
+ p.WebGPUPipesAdaptor
1619
+ ],
1620
+ name: "mesh"
1621
+ };
1622
+ const Ie = [
1623
+ ...Te,
1624
+ q,
1625
+ N,
1626
+ U,
1627
+ j,
1628
+ W,
1629
+ te,
1630
+ X,
1631
+ Z,
1632
+ J,
1633
+ $,
1634
+ V,
1635
+ K,
1636
+ I
1637
+ ], We = [...Ce, Y], Ve = [O, se, re], ie = [], ne = [], oe = [];
1638
+ S.handleByNamedList(p.WebGPUSystem, ie);
1639
+ S.handleByNamedList(p.WebGPUPipes, ne);
1640
+ S.handleByNamedList(p.WebGPUPipesAdaptor, oe);
1641
+ S.add(...Ie, ...We, ...Ve);
1642
+ class Ye extends le {
1643
+ constructor() {
1644
+ const e = {
1645
+ name: "webgpu",
1646
+ type: fe.WEBGPU,
1647
+ systems: ie,
1648
+ renderPipes: ne,
1649
+ renderPipeAdaptors: oe
1650
+ };
1651
+ super(e);
1652
+ }
1653
+ }
1654
+ export {
1655
+ Ye as WebGPURenderer
1656
+ };
src/backend/gradio_polygonannotator/templates/component/browserAll-CBYXns0T.js ADDED
@@ -0,0 +1,1869 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { T as A, U as Z, P as g, r as te, E as b, a as ie, w as y, e as w, C as V } from "./Index-Ct_1BCRd.js";
2
+ import "./webworkerAll-FY7_jo4S.js";
3
+ class q {
4
+ constructor(e) {
5
+ this._lastTransform = "", this._observer = null, this._tickerAttached = !1, this.updateTranslation = () => {
6
+ if (!this._canvas)
7
+ return;
8
+ const t = this._canvas.getBoundingClientRect(), i = this._canvas.width, n = this._canvas.height, s = t.width / i * this._renderer.resolution, o = t.height / n * this._renderer.resolution, r = t.left, l = t.top, d = `translate(${r}px, ${l}px) scale(${s}, ${o})`;
9
+ d !== this._lastTransform && (this._domElement.style.transform = d, this._lastTransform = d);
10
+ }, this._domElement = e.domElement, this._renderer = e.renderer, !(globalThis.OffscreenCanvas && this._renderer.canvas instanceof OffscreenCanvas) && (this._canvas = this._renderer.canvas, this._attachObserver());
11
+ }
12
+ /** The canvas element that this CanvasObserver is associated with. */
13
+ get canvas() {
14
+ return this._canvas;
15
+ }
16
+ /** Attaches the DOM element to the canvas parent if it is not already attached. */
17
+ ensureAttached() {
18
+ !this._domElement.parentNode && this._canvas.parentNode && (this._canvas.parentNode.appendChild(this._domElement), this.updateTranslation());
19
+ }
20
+ /** Sets up a ResizeObserver if available. This ensures that the DOM element is kept in sync with the canvas size . */
21
+ _attachObserver() {
22
+ "ResizeObserver" in globalThis ? (this._observer && (this._observer.disconnect(), this._observer = null), this._observer = new ResizeObserver((e) => {
23
+ for (const t of e) {
24
+ if (t.target !== this._canvas)
25
+ continue;
26
+ const i = this.canvas.width, n = this.canvas.height, s = t.contentRect.width / i * this._renderer.resolution, o = t.contentRect.height / n * this._renderer.resolution;
27
+ (this._lastScaleX !== s || this._lastScaleY !== o) && (this.updateTranslation(), this._lastScaleX = s, this._lastScaleY = o);
28
+ }
29
+ }), this._observer.observe(this._canvas)) : this._tickerAttached || A.shared.add(this.updateTranslation, this, Z.HIGH);
30
+ }
31
+ /** Destroys the CanvasObserver instance, cleaning up observers and Ticker. */
32
+ destroy() {
33
+ this._observer ? (this._observer.disconnect(), this._observer = null) : this._tickerAttached && A.shared.remove(this.updateTranslation), this._domElement = null, this._renderer = null, this._canvas = null, this._tickerAttached = !1, this._lastTransform = "", this._lastScaleX = null, this._lastScaleY = null;
34
+ }
35
+ }
36
+ class M {
37
+ /**
38
+ * @param manager - The event boundary which manages this event. Propagation can only occur
39
+ * within the boundary's jurisdiction.
40
+ */
41
+ constructor(e) {
42
+ this.bubbles = !0, this.cancelBubble = !0, this.cancelable = !1, this.composed = !1, this.defaultPrevented = !1, this.eventPhase = M.prototype.NONE, this.propagationStopped = !1, this.propagationImmediatelyStopped = !1, this.layer = new g(), this.page = new g(), this.NONE = 0, this.CAPTURING_PHASE = 1, this.AT_TARGET = 2, this.BUBBLING_PHASE = 3, this.manager = e;
43
+ }
44
+ /** @readonly */
45
+ get layerX() {
46
+ return this.layer.x;
47
+ }
48
+ /** @readonly */
49
+ get layerY() {
50
+ return this.layer.y;
51
+ }
52
+ /** @readonly */
53
+ get pageX() {
54
+ return this.page.x;
55
+ }
56
+ /** @readonly */
57
+ get pageY() {
58
+ return this.page.y;
59
+ }
60
+ /**
61
+ * Fallback for the deprecated `InteractionEvent.data`.
62
+ * @deprecated since 7.0.0
63
+ */
64
+ get data() {
65
+ return this;
66
+ }
67
+ /**
68
+ * The propagation path for this event. Alias for {@link EventBoundary.propagationPath}.
69
+ * @advanced
70
+ */
71
+ composedPath() {
72
+ return this.manager && (!this.path || this.path[this.path.length - 1] !== this.target) && (this.path = this.target ? this.manager.propagationPath(this.target) : []), this.path;
73
+ }
74
+ /**
75
+ * Unimplemented method included for implementing the DOM interface `Event`. It will throw an `Error`.
76
+ * @deprecated
77
+ * @ignore
78
+ * @param _type
79
+ * @param _bubbles
80
+ * @param _cancelable
81
+ */
82
+ initEvent(e, t, i) {
83
+ throw new Error("initEvent() is a legacy DOM API. It is not implemented in the Federated Events API.");
84
+ }
85
+ /**
86
+ * Unimplemented method included for implementing the DOM interface `UIEvent`. It will throw an `Error`.
87
+ * @ignore
88
+ * @deprecated
89
+ * @param _typeArg
90
+ * @param _bubblesArg
91
+ * @param _cancelableArg
92
+ * @param _viewArg
93
+ * @param _detailArg
94
+ */
95
+ initUIEvent(e, t, i, n, s) {
96
+ throw new Error("initUIEvent() is a legacy DOM API. It is not implemented in the Federated Events API.");
97
+ }
98
+ /**
99
+ * Prevent default behavior of both PixiJS and the user agent.
100
+ * @example
101
+ * ```ts
102
+ * sprite.on('click', (event) => {
103
+ * // Prevent both browser's default click behavior
104
+ * // and PixiJS's default handling
105
+ * event.preventDefault();
106
+ *
107
+ * // Custom handling
108
+ * customClickHandler();
109
+ * });
110
+ * ```
111
+ * @remarks
112
+ * - Only works if the native event is cancelable
113
+ * - Does not stop event propagation
114
+ */
115
+ preventDefault() {
116
+ this.nativeEvent instanceof Event && this.nativeEvent.cancelable && this.nativeEvent.preventDefault(), this.defaultPrevented = !0;
117
+ }
118
+ /**
119
+ * Stop this event from propagating to any additional listeners, including those
120
+ * on the current target and any following targets in the propagation path.
121
+ * @example
122
+ * ```ts
123
+ * container.on('pointerdown', (event) => {
124
+ * // Stop all further event handling
125
+ * event.stopImmediatePropagation();
126
+ *
127
+ * // These handlers won't be called:
128
+ * // - Other pointerdown listeners on this container
129
+ * // - Any pointerdown listeners on parent containers
130
+ * });
131
+ * ```
132
+ * @remarks
133
+ * - Immediately stops all event propagation
134
+ * - Prevents other listeners on same target from being called
135
+ * - More aggressive than stopPropagation()
136
+ */
137
+ stopImmediatePropagation() {
138
+ this.propagationImmediatelyStopped = !0;
139
+ }
140
+ /**
141
+ * Stop this event from propagating to the next target in the propagation path.
142
+ * The rest of the listeners on the current target will still be notified.
143
+ * @example
144
+ * ```ts
145
+ * child.on('pointermove', (event) => {
146
+ * // Handle event on child
147
+ * updateChild();
148
+ *
149
+ * // Prevent parent handlers from being called
150
+ * event.stopPropagation();
151
+ * });
152
+ *
153
+ * // This won't be called if child handles the event
154
+ * parent.on('pointermove', (event) => {
155
+ * updateParent();
156
+ * });
157
+ * ```
158
+ * @remarks
159
+ * - Stops event bubbling to parent containers
160
+ * - Does not prevent other listeners on same target
161
+ * - Less aggressive than stopImmediatePropagation()
162
+ */
163
+ stopPropagation() {
164
+ this.propagationStopped = !0;
165
+ }
166
+ }
167
+ var I = /iPhone/i, C = /iPod/i, L = /iPad/i, U = /\biOS-universal(?:.+)Mac\b/i, k = /\bAndroid(?:.+)Mobile\b/i, R = /Android/i, E = /(?:SD4930UR|\bSilk(?:.+)Mobile\b)/i, O = /Silk/i, m = /Windows Phone/i, X = /\bWindows(?:.+)ARM\b/i, Y = /BlackBerry/i, H = /BB10/i, F = /Opera Mini/i, N = /\b(CriOS|Chrome)(?:.+)Mobile/i, $ = /Mobile(?:.+)Firefox\b/i, K = function(a) {
168
+ return typeof a < "u" && a.platform === "MacIntel" && typeof a.maxTouchPoints == "number" && a.maxTouchPoints > 1 && typeof MSStream > "u";
169
+ };
170
+ function ne(a) {
171
+ return function(e) {
172
+ return e.test(a);
173
+ };
174
+ }
175
+ function G(a) {
176
+ var e = {
177
+ userAgent: "",
178
+ platform: "",
179
+ maxTouchPoints: 0
180
+ };
181
+ !a && typeof navigator < "u" ? e = {
182
+ userAgent: navigator.userAgent,
183
+ platform: navigator.platform,
184
+ maxTouchPoints: navigator.maxTouchPoints || 0
185
+ } : typeof a == "string" ? e.userAgent = a : a && a.userAgent && (e = {
186
+ userAgent: a.userAgent,
187
+ platform: a.platform,
188
+ maxTouchPoints: a.maxTouchPoints || 0
189
+ });
190
+ var t = e.userAgent, i = t.split("[FBAN");
191
+ typeof i[1] < "u" && (t = i[0]), i = t.split("Twitter"), typeof i[1] < "u" && (t = i[0]);
192
+ var n = ne(t), s = {
193
+ apple: {
194
+ phone: n(I) && !n(m),
195
+ ipod: n(C),
196
+ tablet: !n(I) && (n(L) || K(e)) && !n(m),
197
+ universal: n(U),
198
+ device: (n(I) || n(C) || n(L) || n(U) || K(e)) && !n(m)
199
+ },
200
+ amazon: {
201
+ phone: n(E),
202
+ tablet: !n(E) && n(O),
203
+ device: n(E) || n(O)
204
+ },
205
+ android: {
206
+ phone: !n(m) && n(E) || !n(m) && n(k),
207
+ tablet: !n(m) && !n(E) && !n(k) && (n(O) || n(R)),
208
+ device: !n(m) && (n(E) || n(O) || n(k) || n(R)) || n(/\bokhttp\b/i)
209
+ },
210
+ windows: {
211
+ phone: n(m),
212
+ tablet: n(X),
213
+ device: n(m) || n(X)
214
+ },
215
+ other: {
216
+ blackberry: n(Y),
217
+ blackberry10: n(H),
218
+ opera: n(F),
219
+ firefox: n($),
220
+ chrome: n(N),
221
+ device: n(Y) || n(H) || n(F) || n($) || n(N)
222
+ },
223
+ any: !1,
224
+ phone: !1,
225
+ tablet: !1
226
+ };
227
+ return s.any = s.apple.device || s.android.device || s.windows.device || s.other.device, s.phone = s.apple.phone || s.android.phone || s.windows.phone, s.tablet = s.apple.tablet || s.android.tablet || s.windows.tablet, s;
228
+ }
229
+ const se = G.default ?? G, oe = se(globalThis.navigator), re = 9, W = 100, ae = 0, he = 0, j = 2, z = 1, le = -1e3, ce = -1e3, de = 2, S = class J {
230
+ // eslint-disable-next-line jsdoc/require-param
231
+ /**
232
+ * @param {WebGLRenderer|WebGPURenderer} renderer - A reference to the current renderer
233
+ */
234
+ constructor(e, t = oe) {
235
+ this._mobileInfo = t, this.debug = !1, this._activateOnTab = !0, this._deactivateOnMouseMove = !0, this._isActive = !1, this._isMobileAccessibility = !1, this._div = null, this._pool = [], this._renderId = 0, this._children = [], this._androidUpdateCount = 0, this._androidUpdateFrequency = 500, this._hookDiv = null, (t.tablet || t.phone) && this._createTouchHook(), this._renderer = e;
236
+ }
237
+ /**
238
+ * Value of `true` if accessibility is currently active and accessibility layers are showing.
239
+ * @type {boolean}
240
+ * @readonly
241
+ */
242
+ get isActive() {
243
+ return this._isActive;
244
+ }
245
+ /**
246
+ * Value of `true` if accessibility is enabled for touch devices.
247
+ * @type {boolean}
248
+ * @readonly
249
+ */
250
+ get isMobileAccessibility() {
251
+ return this._isMobileAccessibility;
252
+ }
253
+ /**
254
+ * The DOM element that will sit over the PixiJS element. This is where the div overlays will go.
255
+ * @readonly
256
+ */
257
+ get hookDiv() {
258
+ return this._hookDiv;
259
+ }
260
+ /**
261
+ * Creates the touch hooks.
262
+ * @private
263
+ */
264
+ _createTouchHook() {
265
+ const e = document.createElement("button");
266
+ e.style.width = `${z}px`, e.style.height = `${z}px`, e.style.position = "absolute", e.style.top = `${le}px`, e.style.left = `${ce}px`, e.style.zIndex = de.toString(), e.style.backgroundColor = "#FF0000", e.title = "select to enable accessibility for this content", e.addEventListener("focus", () => {
267
+ this._isMobileAccessibility = !0, this._activate(), this._destroyTouchHook();
268
+ }), document.body.appendChild(e), this._hookDiv = e;
269
+ }
270
+ /**
271
+ * Destroys the touch hooks.
272
+ * @private
273
+ */
274
+ _destroyTouchHook() {
275
+ this._hookDiv && (document.body.removeChild(this._hookDiv), this._hookDiv = null);
276
+ }
277
+ /**
278
+ * Activating will cause the Accessibility layer to be shown.
279
+ * This is called when a user presses the tab key.
280
+ * @private
281
+ */
282
+ _activate() {
283
+ if (this._isActive)
284
+ return;
285
+ this._isActive = !0, this._div || (this._div = document.createElement("div"), this._div.style.position = "absolute", this._div.style.top = `${ae}px`, this._div.style.left = `${he}px`, this._div.style.pointerEvents = "none", this._div.style.zIndex = j.toString(), this._canvasObserver = new q({
286
+ domElement: this._div,
287
+ renderer: this._renderer
288
+ })), this._activateOnTab && (this._onKeyDown = this._onKeyDown.bind(this), globalThis.addEventListener("keydown", this._onKeyDown, !1)), this._deactivateOnMouseMove && (this._onMouseMove = this._onMouseMove.bind(this), globalThis.document.addEventListener("mousemove", this._onMouseMove, !0));
289
+ const e = this._renderer.view.canvas;
290
+ if (e.parentNode)
291
+ this._canvasObserver.ensureAttached(), this._initAccessibilitySetup();
292
+ else {
293
+ const t = new MutationObserver(() => {
294
+ e.parentNode && (t.disconnect(), this._canvasObserver.ensureAttached(), this._initAccessibilitySetup());
295
+ });
296
+ t.observe(document.body, { childList: !0, subtree: !0 });
297
+ }
298
+ }
299
+ // New method to handle initialization after div is ready
300
+ _initAccessibilitySetup() {
301
+ this._renderer.runners.postrender.add(this), this._renderer.lastObjectRendered && this._updateAccessibleObjects(this._renderer.lastObjectRendered);
302
+ }
303
+ /**
304
+ * Deactivates the accessibility system. Removes listeners and accessibility elements.
305
+ * @private
306
+ */
307
+ _deactivate() {
308
+ if (!(!this._isActive || this._isMobileAccessibility)) {
309
+ this._isActive = !1, globalThis.document.removeEventListener("mousemove", this._onMouseMove, !0), this._activateOnTab && globalThis.addEventListener("keydown", this._onKeyDown, !1), this._renderer.runners.postrender.remove(this);
310
+ for (const e of this._children)
311
+ e._accessibleDiv && e._accessibleDiv.parentNode && (e._accessibleDiv.parentNode.removeChild(e._accessibleDiv), e._accessibleDiv = null), e._accessibleActive = !1;
312
+ this._pool.forEach((e) => {
313
+ e.parentNode && e.parentNode.removeChild(e);
314
+ }), this._div && this._div.parentNode && this._div.parentNode.removeChild(this._div), this._pool = [], this._children = [];
315
+ }
316
+ }
317
+ /**
318
+ * This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.
319
+ * @private
320
+ * @param {Container} container - The Container to check.
321
+ */
322
+ _updateAccessibleObjects(e) {
323
+ if (!e.visible || !e.accessibleChildren)
324
+ return;
325
+ e.accessible && (e._accessibleActive || this._addChild(e), e._renderId = this._renderId);
326
+ const t = e.children;
327
+ if (t)
328
+ for (let i = 0; i < t.length; i++)
329
+ this._updateAccessibleObjects(t[i]);
330
+ }
331
+ /**
332
+ * Runner init called, view is available at this point.
333
+ * @ignore
334
+ */
335
+ init(e) {
336
+ const i = {
337
+ accessibilityOptions: {
338
+ ...J.defaultOptions,
339
+ ...(e == null ? void 0 : e.accessibilityOptions) || {}
340
+ }
341
+ };
342
+ this.debug = i.accessibilityOptions.debug, this._activateOnTab = i.accessibilityOptions.activateOnTab, this._deactivateOnMouseMove = i.accessibilityOptions.deactivateOnMouseMove, i.accessibilityOptions.enabledByDefault ? this._activate() : this._activateOnTab && (this._onKeyDown = this._onKeyDown.bind(this), globalThis.addEventListener("keydown", this._onKeyDown, !1)), this._renderer.runners.postrender.remove(this);
343
+ }
344
+ /**
345
+ * Updates the accessibility layer during rendering.
346
+ * - Removes divs for containers no longer in the scene
347
+ * - Updates the position and dimensions of the root div
348
+ * - Updates positions of active accessibility divs
349
+ * Only fires while the accessibility system is active.
350
+ * @ignore
351
+ */
352
+ postrender() {
353
+ const e = performance.now();
354
+ if (this._mobileInfo.android.device && e < this._androidUpdateCount || (this._androidUpdateCount = e + this._androidUpdateFrequency, !this._renderer.renderingToScreen || !this._renderer.view.canvas))
355
+ return;
356
+ const t = /* @__PURE__ */ new Set();
357
+ if (this._renderer.lastObjectRendered) {
358
+ this._updateAccessibleObjects(this._renderer.lastObjectRendered);
359
+ for (const i of this._children)
360
+ i._renderId === this._renderId && t.add(this._children.indexOf(i));
361
+ }
362
+ for (let i = this._children.length - 1; i >= 0; i--) {
363
+ const n = this._children[i];
364
+ t.has(i) || (n._accessibleDiv && n._accessibleDiv.parentNode && (n._accessibleDiv.parentNode.removeChild(n._accessibleDiv), this._pool.push(n._accessibleDiv), n._accessibleDiv = null), n._accessibleActive = !1, te(this._children, i, 1));
365
+ }
366
+ this._renderer.renderingToScreen && this._canvasObserver.ensureAttached();
367
+ for (let i = 0; i < this._children.length; i++) {
368
+ const n = this._children[i];
369
+ if (!n._accessibleActive || !n._accessibleDiv)
370
+ continue;
371
+ const s = n._accessibleDiv, o = n.hitArea || n.getBounds().rectangle;
372
+ if (n.hitArea) {
373
+ const r = n.worldTransform;
374
+ s.style.left = `${r.tx + o.x * r.a}px`, s.style.top = `${r.ty + o.y * r.d}px`, s.style.width = `${o.width * r.a}px`, s.style.height = `${o.height * r.d}px`;
375
+ } else
376
+ this._capHitArea(o), s.style.left = `${o.x}px`, s.style.top = `${o.y}px`, s.style.width = `${o.width}px`, s.style.height = `${o.height}px`;
377
+ }
378
+ this._renderId++;
379
+ }
380
+ /**
381
+ * private function that will visually add the information to the
382
+ * accessibility div
383
+ * @param {HTMLElement} div -
384
+ */
385
+ _updateDebugHTML(e) {
386
+ e.innerHTML = `type: ${e.type}</br> title : ${e.title}</br> tabIndex: ${e.tabIndex}`;
387
+ }
388
+ /**
389
+ * Adjust the hit area based on the bounds of a display object
390
+ * @param {Rectangle} hitArea - Bounds of the child
391
+ */
392
+ _capHitArea(e) {
393
+ e.x < 0 && (e.width += e.x, e.x = 0), e.y < 0 && (e.height += e.y, e.y = 0);
394
+ const { width: t, height: i } = this._renderer;
395
+ e.x + e.width > t && (e.width = t - e.x), e.y + e.height > i && (e.height = i - e.y);
396
+ }
397
+ /**
398
+ * Creates or reuses a div element for a Container and adds it to the accessibility layer.
399
+ * Sets up ARIA attributes, event listeners, and positioning based on the container's properties.
400
+ * @private
401
+ * @param {Container} container - The child to make accessible.
402
+ */
403
+ _addChild(e) {
404
+ let t = this._pool.pop();
405
+ t || (e.accessibleType === "button" ? t = document.createElement("button") : (t = document.createElement(e.accessibleType), t.style.cssText = `
406
+ color: transparent;
407
+ pointer-events: none;
408
+ padding: 0;
409
+ margin: 0;
410
+ border: 0;
411
+ outline: 0;
412
+ background: transparent;
413
+ box-sizing: border-box;
414
+ user-select: none;
415
+ -webkit-user-select: none;
416
+ -moz-user-select: none;
417
+ -ms-user-select: none;
418
+ `, e.accessibleText && (t.innerText = e.accessibleText)), t.style.width = `${W}px`, t.style.height = `${W}px`, t.style.backgroundColor = this.debug ? "rgba(255,255,255,0.5)" : "transparent", t.style.position = "absolute", t.style.zIndex = j.toString(), t.style.borderStyle = "none", navigator.userAgent.toLowerCase().includes("chrome") ? t.setAttribute("aria-live", "off") : t.setAttribute("aria-live", "polite"), navigator.userAgent.match(/rv:.*Gecko\//) ? t.setAttribute("aria-relevant", "additions") : t.setAttribute("aria-relevant", "text"), t.addEventListener("click", this._onClick.bind(this)), t.addEventListener("focus", this._onFocus.bind(this)), t.addEventListener("focusout", this._onFocusOut.bind(this))), t.style.pointerEvents = e.accessiblePointerEvents, t.type = e.accessibleType, e.accessibleTitle && e.accessibleTitle !== null ? t.title = e.accessibleTitle : (!e.accessibleHint || e.accessibleHint === null) && (t.title = `container ${e.tabIndex}`), e.accessibleHint && e.accessibleHint !== null && t.setAttribute("aria-label", e.accessibleHint), e.interactive ? t.tabIndex = e.tabIndex : t.tabIndex = 0, this.debug && this._updateDebugHTML(t), e._accessibleActive = !0, e._accessibleDiv = t, t.container = e, this._children.push(e), this._div.appendChild(e._accessibleDiv);
419
+ }
420
+ /**
421
+ * Dispatch events with the EventSystem.
422
+ * @param e
423
+ * @param type
424
+ * @private
425
+ */
426
+ _dispatchEvent(e, t) {
427
+ const { container: i } = e.target, n = this._renderer.events.rootBoundary, s = Object.assign(new M(n), { target: i });
428
+ n.rootTarget = this._renderer.lastObjectRendered, t.forEach((o) => n.dispatchEvent(s, o));
429
+ }
430
+ /**
431
+ * Maps the div button press to pixi's EventSystem (click)
432
+ * @private
433
+ * @param {MouseEvent} e - The click event.
434
+ */
435
+ _onClick(e) {
436
+ this._dispatchEvent(e, ["click", "pointertap", "tap"]);
437
+ }
438
+ /**
439
+ * Maps the div focus events to pixi's EventSystem (mouseover)
440
+ * @private
441
+ * @param {FocusEvent} e - The focus event.
442
+ */
443
+ _onFocus(e) {
444
+ e.target.getAttribute("aria-live") || e.target.setAttribute("aria-live", "assertive"), this._dispatchEvent(e, ["mouseover"]);
445
+ }
446
+ /**
447
+ * Maps the div focus events to pixi's EventSystem (mouseout)
448
+ * @private
449
+ * @param {FocusEvent} e - The focusout event.
450
+ */
451
+ _onFocusOut(e) {
452
+ e.target.getAttribute("aria-live") || e.target.setAttribute("aria-live", "polite"), this._dispatchEvent(e, ["mouseout"]);
453
+ }
454
+ /**
455
+ * Is called when a key is pressed
456
+ * @private
457
+ * @param {KeyboardEvent} e - The keydown event.
458
+ */
459
+ _onKeyDown(e) {
460
+ e.keyCode !== re || !this._activateOnTab || this._activate();
461
+ }
462
+ /**
463
+ * Is called when the mouse moves across the renderer element
464
+ * @private
465
+ * @param {MouseEvent} e - The mouse event.
466
+ */
467
+ _onMouseMove(e) {
468
+ e.movementX === 0 && e.movementY === 0 || this._deactivate();
469
+ }
470
+ /**
471
+ * Destroys the accessibility system. Removes all elements and listeners.
472
+ * > [!IMPORTANT] This is typically called automatically when the {@link Application} is destroyed.
473
+ * > A typically user should not need to call this method directly.
474
+ */
475
+ destroy() {
476
+ var e;
477
+ this._deactivate(), this._destroyTouchHook(), (e = this._canvasObserver) == null || e.destroy(), this._canvasObserver = null, this._div = null, this._pool = null, this._children = null, this._renderer = null, this._activateOnTab && globalThis.removeEventListener("keydown", this._onKeyDown);
478
+ }
479
+ /**
480
+ * Enables or disables the accessibility system.
481
+ * @param enabled - Whether to enable or disable accessibility.
482
+ * @example
483
+ * ```js
484
+ * app.renderer.accessibility.setAccessibilityEnabled(true); // Enable accessibility
485
+ * app.renderer.accessibility.setAccessibilityEnabled(false); // Disable accessibility
486
+ * ```
487
+ */
488
+ setAccessibilityEnabled(e) {
489
+ e ? this._activate() : this._deactivate();
490
+ }
491
+ };
492
+ S.extension = {
493
+ type: [
494
+ b.WebGLSystem,
495
+ b.WebGPUSystem
496
+ ],
497
+ name: "accessibility"
498
+ };
499
+ S.defaultOptions = {
500
+ /**
501
+ * Whether to enable accessibility features on initialization
502
+ * @default false
503
+ */
504
+ enabledByDefault: !1,
505
+ /**
506
+ * Whether to visually show the accessibility divs for debugging
507
+ * @default false
508
+ */
509
+ debug: !1,
510
+ /**
511
+ * Whether to activate accessibility when tab key is pressed
512
+ * @default true
513
+ */
514
+ activateOnTab: !0,
515
+ /**
516
+ * Whether to deactivate accessibility when mouse moves
517
+ * @default true
518
+ */
519
+ deactivateOnMouseMove: !0
520
+ };
521
+ let ue = S;
522
+ const pe = {
523
+ accessible: !1,
524
+ accessibleTitle: null,
525
+ accessibleHint: null,
526
+ tabIndex: 0,
527
+ accessibleType: "button",
528
+ accessibleText: null,
529
+ accessiblePointerEvents: "auto",
530
+ accessibleChildren: !0,
531
+ _accessibleActive: !1,
532
+ _accessibleDiv: null,
533
+ _renderId: -1
534
+ };
535
+ class Q {
536
+ /**
537
+ * Constructor for the DOMPipe class.
538
+ * @param renderer - The renderer instance that this DOMPipe will be associated with.
539
+ */
540
+ constructor(e) {
541
+ this._attachedDomElements = [], this._renderer = e, this._renderer.runners.postrender.add(this), this._renderer.runners.init.add(this), this._domElement = document.createElement("div"), this._domElement.style.position = "absolute", this._domElement.style.top = "0", this._domElement.style.left = "0", this._domElement.style.pointerEvents = "none", this._domElement.style.zIndex = "1000";
542
+ }
543
+ /** Initializes the DOMPipe, setting up the main DOM element and adding it to the document body. */
544
+ init() {
545
+ this._canvasObserver = new q({
546
+ domElement: this._domElement,
547
+ renderer: this._renderer
548
+ });
549
+ }
550
+ /**
551
+ * Adds a renderable DOM container to the list of attached elements.
552
+ * @param domContainer - The DOM container to be added.
553
+ * @param _instructionSet - The instruction set (unused).
554
+ */
555
+ addRenderable(e, t) {
556
+ this._attachedDomElements.includes(e) || this._attachedDomElements.push(e);
557
+ }
558
+ /**
559
+ * Updates a renderable DOM container.
560
+ * @param _domContainer - The DOM container to be updated (unused).
561
+ */
562
+ updateRenderable(e) {
563
+ }
564
+ /**
565
+ * Validates a renderable DOM container.
566
+ * @param _domContainer - The DOM container to be validated (unused).
567
+ * @returns Always returns true as validation is not required.
568
+ */
569
+ validateRenderable(e) {
570
+ return !0;
571
+ }
572
+ /** Handles the post-rendering process, ensuring DOM elements are correctly positioned and visible. */
573
+ postrender() {
574
+ const e = this._attachedDomElements;
575
+ if (e.length === 0) {
576
+ this._domElement.remove();
577
+ return;
578
+ }
579
+ this._canvasObserver.ensureAttached();
580
+ for (let t = 0; t < e.length; t++) {
581
+ const i = e[t], n = i.element;
582
+ if (!i.parent || i.globalDisplayStatus < 7)
583
+ n == null || n.remove(), e.splice(t, 1), t--;
584
+ else {
585
+ this._domElement.contains(n) || (n.style.position = "absolute", n.style.pointerEvents = "auto", this._domElement.appendChild(n));
586
+ const s = i.worldTransform, o = i._anchor, r = i.width * o.x, l = i.height * o.y;
587
+ n.style.transformOrigin = `${r}px ${l}px`, n.style.transform = `matrix(${s.a}, ${s.b}, ${s.c}, ${s.d}, ${s.tx - r}, ${s.ty - l})`, n.style.opacity = i.groupAlpha.toString();
588
+ }
589
+ }
590
+ }
591
+ /** Destroys the DOMPipe, removing all attached DOM elements and cleaning up resources. */
592
+ destroy() {
593
+ var e;
594
+ this._renderer.runners.postrender.remove(this);
595
+ for (let t = 0; t < this._attachedDomElements.length; t++)
596
+ (e = this._attachedDomElements[t].element) == null || e.remove();
597
+ this._attachedDomElements.length = 0, this._domElement.remove(), this._canvasObserver.destroy(), this._renderer = null;
598
+ }
599
+ }
600
+ Q.extension = {
601
+ type: [
602
+ b.WebGLPipes,
603
+ b.WebGPUPipes,
604
+ b.CanvasPipes
605
+ ],
606
+ name: "dom"
607
+ };
608
+ class ve {
609
+ constructor() {
610
+ this.interactionFrequency = 10, this._deltaTime = 0, this._didMove = !1, this._tickerAdded = !1, this._pauseUpdate = !0;
611
+ }
612
+ /**
613
+ * Initializes the event ticker.
614
+ * @param events - The event system.
615
+ */
616
+ init(e) {
617
+ this.removeTickerListener(), this.events = e, this.interactionFrequency = 10, this._deltaTime = 0, this._didMove = !1, this._tickerAdded = !1, this._pauseUpdate = !0;
618
+ }
619
+ /** Whether to pause the update checks or not. */
620
+ get pauseUpdate() {
621
+ return this._pauseUpdate;
622
+ }
623
+ set pauseUpdate(e) {
624
+ this._pauseUpdate = e;
625
+ }
626
+ /** Adds the ticker listener. */
627
+ addTickerListener() {
628
+ this._tickerAdded || !this.domElement || (A.system.add(this._tickerUpdate, this, Z.INTERACTION), this._tickerAdded = !0);
629
+ }
630
+ /** Removes the ticker listener. */
631
+ removeTickerListener() {
632
+ this._tickerAdded && (A.system.remove(this._tickerUpdate, this), this._tickerAdded = !1);
633
+ }
634
+ /** Sets flag to not fire extra events when the user has already moved there mouse */
635
+ pointerMoved() {
636
+ this._didMove = !0;
637
+ }
638
+ /** Updates the state of interactive objects. */
639
+ _update() {
640
+ if (!this.domElement || this._pauseUpdate)
641
+ return;
642
+ if (this._didMove) {
643
+ this._didMove = !1;
644
+ return;
645
+ }
646
+ const e = this.events._rootPointerEvent;
647
+ this.events.supportsTouchEvents && e.pointerType === "touch" || globalThis.document.dispatchEvent(this.events.supportsPointerEvents ? new PointerEvent("pointermove", {
648
+ clientX: e.clientX,
649
+ clientY: e.clientY,
650
+ pointerType: e.pointerType,
651
+ pointerId: e.pointerId
652
+ }) : new MouseEvent("mousemove", {
653
+ clientX: e.clientX,
654
+ clientY: e.clientY
655
+ }));
656
+ }
657
+ /**
658
+ * Updates the state of interactive objects if at least {@link interactionFrequency}
659
+ * milliseconds have passed since the last invocation.
660
+ *
661
+ * Invoked by a throttled ticker update from {@link Ticker.system}.
662
+ * @param ticker - The throttled ticker.
663
+ */
664
+ _tickerUpdate(e) {
665
+ this._deltaTime += e.deltaTime, !(this._deltaTime < this.interactionFrequency) && (this._deltaTime = 0, this._update());
666
+ }
667
+ /** Destroys the event ticker. */
668
+ destroy() {
669
+ this.removeTickerListener(), this.events = null, this.domElement = null, this._deltaTime = 0, this._didMove = !1, this._tickerAdded = !1, this._pauseUpdate = !0;
670
+ }
671
+ }
672
+ const _ = new ve();
673
+ class D extends M {
674
+ constructor() {
675
+ super(...arguments), this.client = new g(), this.movement = new g(), this.offset = new g(), this.global = new g(), this.screen = new g();
676
+ }
677
+ /** @readonly */
678
+ get clientX() {
679
+ return this.client.x;
680
+ }
681
+ /** @readonly */
682
+ get clientY() {
683
+ return this.client.y;
684
+ }
685
+ /**
686
+ * Alias for {@link FederatedMouseEvent.clientX this.clientX}.
687
+ * @readonly
688
+ */
689
+ get x() {
690
+ return this.clientX;
691
+ }
692
+ /**
693
+ * Alias for {@link FederatedMouseEvent.clientY this.clientY}.
694
+ * @readonly
695
+ */
696
+ get y() {
697
+ return this.clientY;
698
+ }
699
+ /** @readonly */
700
+ get movementX() {
701
+ return this.movement.x;
702
+ }
703
+ /** @readonly */
704
+ get movementY() {
705
+ return this.movement.y;
706
+ }
707
+ /** @readonly */
708
+ get offsetX() {
709
+ return this.offset.x;
710
+ }
711
+ /** @readonly */
712
+ get offsetY() {
713
+ return this.offset.y;
714
+ }
715
+ /** @readonly */
716
+ get globalX() {
717
+ return this.global.x;
718
+ }
719
+ /** @readonly */
720
+ get globalY() {
721
+ return this.global.y;
722
+ }
723
+ /**
724
+ * The pointer coordinates in the renderer's screen. Alias for `screen.x`.
725
+ * @readonly
726
+ */
727
+ get screenX() {
728
+ return this.screen.x;
729
+ }
730
+ /**
731
+ * The pointer coordinates in the renderer's screen. Alias for `screen.y`.
732
+ * @readonly
733
+ */
734
+ get screenY() {
735
+ return this.screen.y;
736
+ }
737
+ /**
738
+ * Converts global coordinates into container-local coordinates.
739
+ *
740
+ * This method transforms coordinates from world space to a container's local space,
741
+ * useful for precise positioning and hit testing.
742
+ * @param container - The Container to get local coordinates for
743
+ * @param point - Optional Point object to store the result. If not provided, a new Point will be created
744
+ * @param globalPos - Optional custom global coordinates. If not provided, the event's global position is used
745
+ * @returns The local coordinates as a Point object
746
+ * @example
747
+ * ```ts
748
+ * // Basic usage - get local coordinates relative to a container
749
+ * sprite.on('pointermove', (event: FederatedMouseEvent) => {
750
+ * // Get position relative to the sprite
751
+ * const localPos = event.getLocalPosition(sprite);
752
+ * console.log('Local position:', localPos.x, localPos.y);
753
+ * });
754
+ * // Using custom global coordinates
755
+ * const customGlobal = new Point(100, 100);
756
+ * sprite.on('pointermove', (event: FederatedMouseEvent) => {
757
+ * // Transform custom coordinates
758
+ * const localPos = event.getLocalPosition(sprite, undefined, customGlobal);
759
+ * console.log('Custom local position:', localPos.x, localPos.y);
760
+ * });
761
+ * ```
762
+ * @see {@link Container.worldTransform} For the transformation matrix
763
+ * @see {@link Point} For the point class used to store coordinates
764
+ */
765
+ getLocalPosition(e, t, i) {
766
+ return e.worldTransform.applyInverse(i || this.global, t);
767
+ }
768
+ /**
769
+ * Whether the modifier key was pressed when this event natively occurred.
770
+ * @param key - The modifier key.
771
+ */
772
+ getModifierState(e) {
773
+ return "getModifierState" in this.nativeEvent && this.nativeEvent.getModifierState(e);
774
+ }
775
+ /**
776
+ * Not supported.
777
+ * @param _typeArg
778
+ * @param _canBubbleArg
779
+ * @param _cancelableArg
780
+ * @param _viewArg
781
+ * @param _detailArg
782
+ * @param _screenXArg
783
+ * @param _screenYArg
784
+ * @param _clientXArg
785
+ * @param _clientYArg
786
+ * @param _ctrlKeyArg
787
+ * @param _altKeyArg
788
+ * @param _shiftKeyArg
789
+ * @param _metaKeyArg
790
+ * @param _buttonArg
791
+ * @param _relatedTargetArg
792
+ * @deprecated since 7.0.0
793
+ * @ignore
794
+ */
795
+ // eslint-disable-next-line max-params
796
+ initMouseEvent(e, t, i, n, s, o, r, l, d, p, u, h, v, c, Ee) {
797
+ throw new Error("Method not implemented.");
798
+ }
799
+ }
800
+ class f extends D {
801
+ constructor() {
802
+ super(...arguments), this.width = 0, this.height = 0, this.isPrimary = !1;
803
+ }
804
+ /**
805
+ * Only included for completeness for now
806
+ * @ignore
807
+ */
808
+ getCoalescedEvents() {
809
+ return this.type === "pointermove" || this.type === "mousemove" || this.type === "touchmove" ? [this] : [];
810
+ }
811
+ /**
812
+ * Only included for completeness for now
813
+ * @ignore
814
+ */
815
+ getPredictedEvents() {
816
+ throw new Error("getPredictedEvents is not supported!");
817
+ }
818
+ }
819
+ class T extends D {
820
+ constructor() {
821
+ super(...arguments), this.DOM_DELTA_PIXEL = 0, this.DOM_DELTA_LINE = 1, this.DOM_DELTA_PAGE = 2;
822
+ }
823
+ }
824
+ T.DOM_DELTA_PIXEL = 0;
825
+ T.DOM_DELTA_LINE = 1;
826
+ T.DOM_DELTA_PAGE = 2;
827
+ const fe = 2048, me = new g(), P = new g();
828
+ class _e {
829
+ /**
830
+ * @param rootTarget - The holder of the event boundary.
831
+ */
832
+ constructor(e) {
833
+ this.dispatch = new ie(), this.moveOnAll = !1, this.enableGlobalMoveEvents = !0, this.mappingState = {
834
+ trackingData: {}
835
+ }, this.eventPool = /* @__PURE__ */ new Map(), this._allInteractiveElements = [], this._hitElements = [], this._isPointerMoveEvent = !1, this.rootTarget = e, this.hitPruneFn = this.hitPruneFn.bind(this), this.hitTestFn = this.hitTestFn.bind(this), this.mapPointerDown = this.mapPointerDown.bind(this), this.mapPointerMove = this.mapPointerMove.bind(this), this.mapPointerOut = this.mapPointerOut.bind(this), this.mapPointerOver = this.mapPointerOver.bind(this), this.mapPointerUp = this.mapPointerUp.bind(this), this.mapPointerUpOutside = this.mapPointerUpOutside.bind(this), this.mapWheel = this.mapWheel.bind(this), this.mappingTable = {}, this.addEventMapping("pointerdown", this.mapPointerDown), this.addEventMapping("pointermove", this.mapPointerMove), this.addEventMapping("pointerout", this.mapPointerOut), this.addEventMapping("pointerleave", this.mapPointerOut), this.addEventMapping("pointerover", this.mapPointerOver), this.addEventMapping("pointerup", this.mapPointerUp), this.addEventMapping("pointerupoutside", this.mapPointerUpOutside), this.addEventMapping("wheel", this.mapWheel);
836
+ }
837
+ /**
838
+ * Adds an event mapping for the event `type` handled by `fn`.
839
+ *
840
+ * Event mappings can be used to implement additional or custom events. They take an event
841
+ * coming from the upstream scene (or directly from the {@link EventSystem}) and dispatch new downstream events
842
+ * generally trickling down and bubbling up to {@link EventBoundary.rootTarget this.rootTarget}.
843
+ *
844
+ * To modify the semantics of existing events, the built-in mapping methods of EventBoundary should be overridden
845
+ * instead.
846
+ * @param type - The type of upstream event to map.
847
+ * @param fn - The mapping method. The context of this function must be bound manually, if desired.
848
+ */
849
+ addEventMapping(e, t) {
850
+ this.mappingTable[e] || (this.mappingTable[e] = []), this.mappingTable[e].push({
851
+ fn: t,
852
+ priority: 0
853
+ }), this.mappingTable[e].sort((i, n) => i.priority - n.priority);
854
+ }
855
+ /**
856
+ * Dispatches the given event
857
+ * @param e - The event to dispatch.
858
+ * @param type - The type of event to dispatch. Defaults to `e.type`.
859
+ */
860
+ dispatchEvent(e, t) {
861
+ e.propagationStopped = !1, e.propagationImmediatelyStopped = !1, this.propagate(e, t), this.dispatch.emit(t || e.type, e);
862
+ }
863
+ /**
864
+ * Maps the given upstream event through the event boundary and propagates it downstream.
865
+ * @param e - The event to map.
866
+ */
867
+ mapEvent(e) {
868
+ if (!this.rootTarget)
869
+ return;
870
+ const t = this.mappingTable[e.type];
871
+ if (t)
872
+ for (let i = 0, n = t.length; i < n; i++)
873
+ t[i].fn(e);
874
+ else
875
+ y(`[EventBoundary]: Event mapping not defined for ${e.type}`);
876
+ }
877
+ /**
878
+ * Finds the Container that is the target of a event at the given coordinates.
879
+ *
880
+ * The passed (x,y) coordinates are in the world space above this event boundary.
881
+ * @param x - The x coordinate of the event.
882
+ * @param y - The y coordinate of the event.
883
+ */
884
+ hitTest(e, t) {
885
+ _.pauseUpdate = !0;
886
+ const n = this._isPointerMoveEvent && this.enableGlobalMoveEvents ? "hitTestMoveRecursive" : "hitTestRecursive", s = this[n](
887
+ this.rootTarget,
888
+ this.rootTarget.eventMode,
889
+ me.set(e, t),
890
+ this.hitTestFn,
891
+ this.hitPruneFn
892
+ );
893
+ return s && s[0];
894
+ }
895
+ /**
896
+ * Propagate the passed event from from {@link EventBoundary.rootTarget this.rootTarget} to its
897
+ * target `e.target`.
898
+ * @param e - The event to propagate.
899
+ * @param type - The type of event to propagate. Defaults to `e.type`.
900
+ */
901
+ propagate(e, t) {
902
+ if (!e.target)
903
+ return;
904
+ const i = e.composedPath();
905
+ e.eventPhase = e.CAPTURING_PHASE;
906
+ for (let n = 0, s = i.length - 1; n < s; n++)
907
+ if (e.currentTarget = i[n], this.notifyTarget(e, t), e.propagationStopped || e.propagationImmediatelyStopped)
908
+ return;
909
+ if (e.eventPhase = e.AT_TARGET, e.currentTarget = e.target, this.notifyTarget(e, t), !(e.propagationStopped || e.propagationImmediatelyStopped)) {
910
+ e.eventPhase = e.BUBBLING_PHASE;
911
+ for (let n = i.length - 2; n >= 0; n--)
912
+ if (e.currentTarget = i[n], this.notifyTarget(e, t), e.propagationStopped || e.propagationImmediatelyStopped)
913
+ return;
914
+ }
915
+ }
916
+ /**
917
+ * Emits the event `e` to all interactive containers. The event is propagated in the bubbling phase always.
918
+ *
919
+ * This is used in the `globalpointermove` event.
920
+ * @param e - The emitted event.
921
+ * @param type - The listeners to notify.
922
+ * @param targets - The targets to notify.
923
+ */
924
+ all(e, t, i = this._allInteractiveElements) {
925
+ if (i.length === 0)
926
+ return;
927
+ e.eventPhase = e.BUBBLING_PHASE;
928
+ const n = Array.isArray(t) ? t : [t];
929
+ for (let s = i.length - 1; s >= 0; s--)
930
+ n.forEach((o) => {
931
+ e.currentTarget = i[s], this.notifyTarget(e, o);
932
+ });
933
+ }
934
+ /**
935
+ * Finds the propagation path from {@link EventBoundary.rootTarget rootTarget} to the passed
936
+ * `target`. The last element in the path is `target`.
937
+ * @param target - The target to find the propagation path to.
938
+ */
939
+ propagationPath(e) {
940
+ const t = [e];
941
+ for (let i = 0; i < fe && e !== this.rootTarget && e.parent; i++) {
942
+ if (!e.parent)
943
+ throw new Error("Cannot find propagation path to disconnected target");
944
+ t.push(e.parent), e = e.parent;
945
+ }
946
+ return t.reverse(), t;
947
+ }
948
+ hitTestMoveRecursive(e, t, i, n, s, o = !1) {
949
+ let r = !1;
950
+ if (this._interactivePrune(e))
951
+ return null;
952
+ if ((e.eventMode === "dynamic" || t === "dynamic") && (_.pauseUpdate = !1), e.interactiveChildren && e.children) {
953
+ const p = e.children;
954
+ for (let u = p.length - 1; u >= 0; u--) {
955
+ const h = p[u], v = this.hitTestMoveRecursive(
956
+ h,
957
+ this._isInteractive(t) ? t : h.eventMode,
958
+ i,
959
+ n,
960
+ s,
961
+ o || s(e, i)
962
+ );
963
+ if (v) {
964
+ if (v.length > 0 && !v[v.length - 1].parent)
965
+ continue;
966
+ const c = e.isInteractive();
967
+ (v.length > 0 || c) && (c && this._allInteractiveElements.push(e), v.push(e)), this._hitElements.length === 0 && (this._hitElements = v), r = !0;
968
+ }
969
+ }
970
+ }
971
+ const l = this._isInteractive(t), d = e.isInteractive();
972
+ return d && d && this._allInteractiveElements.push(e), o || this._hitElements.length > 0 ? null : r ? this._hitElements : l && !s(e, i) && n(e, i) ? d ? [e] : [] : null;
973
+ }
974
+ /**
975
+ * Recursive implementation for {@link EventBoundary.hitTest hitTest}.
976
+ * @param currentTarget - The Container that is to be hit tested.
977
+ * @param eventMode - The event mode for the `currentTarget` or one of its parents.
978
+ * @param location - The location that is being tested for overlap.
979
+ * @param testFn - Callback that determines whether the target passes hit testing. This callback
980
+ * can assume that `pruneFn` failed to prune the container.
981
+ * @param pruneFn - Callback that determiness whether the target and all of its children
982
+ * cannot pass the hit test. It is used as a preliminary optimization to prune entire subtrees
983
+ * of the scene graph.
984
+ * @returns An array holding the hit testing target and all its ancestors in order. The first element
985
+ * is the target itself and the last is {@link EventBoundary.rootTarget rootTarget}. This is the opposite
986
+ * order w.r.t. the propagation path. If no hit testing target is found, null is returned.
987
+ */
988
+ hitTestRecursive(e, t, i, n, s) {
989
+ if (this._interactivePrune(e) || s(e, i))
990
+ return null;
991
+ if ((e.eventMode === "dynamic" || t === "dynamic") && (_.pauseUpdate = !1), e.interactiveChildren && e.children) {
992
+ const l = e.children, d = i;
993
+ for (let p = l.length - 1; p >= 0; p--) {
994
+ const u = l[p], h = this.hitTestRecursive(
995
+ u,
996
+ this._isInteractive(t) ? t : u.eventMode,
997
+ d,
998
+ n,
999
+ s
1000
+ );
1001
+ if (h) {
1002
+ if (h.length > 0 && !h[h.length - 1].parent)
1003
+ continue;
1004
+ const v = e.isInteractive();
1005
+ return (h.length > 0 || v) && h.push(e), h;
1006
+ }
1007
+ }
1008
+ }
1009
+ const o = this._isInteractive(t), r = e.isInteractive();
1010
+ return o && n(e, i) ? r ? [e] : [] : null;
1011
+ }
1012
+ _isInteractive(e) {
1013
+ return e === "static" || e === "dynamic";
1014
+ }
1015
+ _interactivePrune(e) {
1016
+ return !e || !e.visible || !e.renderable || !e.measurable || e.eventMode === "none" || e.eventMode === "passive" && !e.interactiveChildren;
1017
+ }
1018
+ /**
1019
+ * Checks whether the container or any of its children cannot pass the hit test at all.
1020
+ *
1021
+ * {@link EventBoundary}'s implementation uses the {@link Container.hitArea hitArea}
1022
+ * and {@link Container._maskEffect} for pruning.
1023
+ * @param container - The container to prune.
1024
+ * @param location - The location to test for overlap.
1025
+ */
1026
+ hitPruneFn(e, t) {
1027
+ if (e.hitArea && (e.worldTransform.applyInverse(t, P), !e.hitArea.contains(P.x, P.y)))
1028
+ return !0;
1029
+ if (e.effects && e.effects.length)
1030
+ for (let i = 0; i < e.effects.length; i++) {
1031
+ const n = e.effects[i];
1032
+ if (n.containsPoint && !n.containsPoint(t, this.hitTestFn))
1033
+ return !0;
1034
+ }
1035
+ return !1;
1036
+ }
1037
+ /**
1038
+ * Checks whether the container passes hit testing for the given location.
1039
+ * @param container - The container to test.
1040
+ * @param location - The location to test for overlap.
1041
+ * @returns - Whether `container` passes hit testing for `location`.
1042
+ */
1043
+ hitTestFn(e, t) {
1044
+ return e.hitArea ? !0 : e != null && e.containsPoint ? (e.worldTransform.applyInverse(t, P), e.containsPoint(P)) : !1;
1045
+ }
1046
+ /**
1047
+ * Notify all the listeners to the event's `currentTarget`.
1048
+ *
1049
+ * If the `currentTarget` contains the property `on<type>`, then it is called here,
1050
+ * simulating the behavior from version 6.x and prior.
1051
+ * @param e - The event passed to the target.
1052
+ * @param type - The type of event to notify. Defaults to `e.type`.
1053
+ */
1054
+ notifyTarget(e, t) {
1055
+ var s, o;
1056
+ if (!e.currentTarget.isInteractive())
1057
+ return;
1058
+ t ?? (t = e.type);
1059
+ const i = `on${t}`;
1060
+ (o = (s = e.currentTarget)[i]) == null || o.call(s, e);
1061
+ const n = e.eventPhase === e.CAPTURING_PHASE || e.eventPhase === e.AT_TARGET ? `${t}capture` : t;
1062
+ this._notifyListeners(e, n), e.eventPhase === e.AT_TARGET && this._notifyListeners(e, t);
1063
+ }
1064
+ /**
1065
+ * Maps the upstream `pointerdown` events to a downstream `pointerdown` event.
1066
+ *
1067
+ * `touchstart`, `rightdown`, `mousedown` events are also dispatched for specific pointer types.
1068
+ * @param from - The upstream `pointerdown` event.
1069
+ */
1070
+ mapPointerDown(e) {
1071
+ if (!(e instanceof f)) {
1072
+ y("EventBoundary cannot map a non-pointer event as a pointer event");
1073
+ return;
1074
+ }
1075
+ const t = this.createPointerEvent(e);
1076
+ if (this.dispatchEvent(t, "pointerdown"), t.pointerType === "touch")
1077
+ this.dispatchEvent(t, "touchstart");
1078
+ else if (t.pointerType === "mouse" || t.pointerType === "pen") {
1079
+ const n = t.button === 2;
1080
+ this.dispatchEvent(t, n ? "rightdown" : "mousedown");
1081
+ }
1082
+ const i = this.trackingData(e.pointerId);
1083
+ i.pressTargetsByButton[e.button] = t.composedPath(), this.freeEvent(t);
1084
+ }
1085
+ /**
1086
+ * Maps the upstream `pointermove` to downstream `pointerout`, `pointerover`, and `pointermove` events, in that order.
1087
+ *
1088
+ * The tracking data for the specific pointer has an updated `overTarget`. `mouseout`, `mouseover`,
1089
+ * `mousemove`, and `touchmove` events are fired as well for specific pointer types.
1090
+ * @param from - The upstream `pointermove` event.
1091
+ */
1092
+ mapPointerMove(e) {
1093
+ var l, d;
1094
+ if (!(e instanceof f)) {
1095
+ y("EventBoundary cannot map a non-pointer event as a pointer event");
1096
+ return;
1097
+ }
1098
+ this._allInteractiveElements.length = 0, this._hitElements.length = 0, this._isPointerMoveEvent = !0;
1099
+ const t = this.createPointerEvent(e);
1100
+ this._isPointerMoveEvent = !1;
1101
+ const i = t.pointerType === "mouse" || t.pointerType === "pen", n = this.trackingData(e.pointerId), s = this.findMountedTarget(n.overTargets);
1102
+ if (((l = n.overTargets) == null ? void 0 : l.length) > 0 && s !== t.target) {
1103
+ const p = e.type === "mousemove" ? "mouseout" : "pointerout", u = this.createPointerEvent(e, p, s);
1104
+ if (this.dispatchEvent(u, "pointerout"), i && this.dispatchEvent(u, "mouseout"), !t.composedPath().includes(s)) {
1105
+ const h = this.createPointerEvent(e, "pointerleave", s);
1106
+ for (h.eventPhase = h.AT_TARGET; h.target && !t.composedPath().includes(h.target); )
1107
+ h.currentTarget = h.target, this.notifyTarget(h), i && this.notifyTarget(h, "mouseleave"), h.target = h.target.parent;
1108
+ this.freeEvent(h);
1109
+ }
1110
+ this.freeEvent(u);
1111
+ }
1112
+ if (s !== t.target) {
1113
+ const p = e.type === "mousemove" ? "mouseover" : "pointerover", u = this.clonePointerEvent(t, p);
1114
+ this.dispatchEvent(u, "pointerover"), i && this.dispatchEvent(u, "mouseover");
1115
+ let h = s == null ? void 0 : s.parent;
1116
+ for (; h && h !== this.rootTarget.parent && h !== t.target; )
1117
+ h = h.parent;
1118
+ if (!h || h === this.rootTarget.parent) {
1119
+ const c = this.clonePointerEvent(t, "pointerenter");
1120
+ for (c.eventPhase = c.AT_TARGET; c.target && c.target !== s && c.target !== this.rootTarget.parent; )
1121
+ c.currentTarget = c.target, this.notifyTarget(c), i && this.notifyTarget(c, "mouseenter"), c.target = c.target.parent;
1122
+ this.freeEvent(c);
1123
+ }
1124
+ this.freeEvent(u);
1125
+ }
1126
+ const o = [], r = this.enableGlobalMoveEvents ?? !0;
1127
+ this.moveOnAll ? o.push("pointermove") : this.dispatchEvent(t, "pointermove"), r && o.push("globalpointermove"), t.pointerType === "touch" && (this.moveOnAll ? o.splice(1, 0, "touchmove") : this.dispatchEvent(t, "touchmove"), r && o.push("globaltouchmove")), i && (this.moveOnAll ? o.splice(1, 0, "mousemove") : this.dispatchEvent(t, "mousemove"), r && o.push("globalmousemove"), this.cursor = (d = t.target) == null ? void 0 : d.cursor), o.length > 0 && this.all(t, o), this._allInteractiveElements.length = 0, this._hitElements.length = 0, n.overTargets = t.composedPath(), this.freeEvent(t);
1128
+ }
1129
+ /**
1130
+ * Maps the upstream `pointerover` to downstream `pointerover` and `pointerenter` events, in that order.
1131
+ *
1132
+ * The tracking data for the specific pointer gets a new `overTarget`.
1133
+ * @param from - The upstream `pointerover` event.
1134
+ */
1135
+ mapPointerOver(e) {
1136
+ var o;
1137
+ if (!(e instanceof f)) {
1138
+ y("EventBoundary cannot map a non-pointer event as a pointer event");
1139
+ return;
1140
+ }
1141
+ const t = this.trackingData(e.pointerId), i = this.createPointerEvent(e), n = i.pointerType === "mouse" || i.pointerType === "pen";
1142
+ this.dispatchEvent(i, "pointerover"), n && this.dispatchEvent(i, "mouseover"), i.pointerType === "mouse" && (this.cursor = (o = i.target) == null ? void 0 : o.cursor);
1143
+ const s = this.clonePointerEvent(i, "pointerenter");
1144
+ for (s.eventPhase = s.AT_TARGET; s.target && s.target !== this.rootTarget.parent; )
1145
+ s.currentTarget = s.target, this.notifyTarget(s), n && this.notifyTarget(s, "mouseenter"), s.target = s.target.parent;
1146
+ t.overTargets = i.composedPath(), this.freeEvent(i), this.freeEvent(s);
1147
+ }
1148
+ /**
1149
+ * Maps the upstream `pointerout` to downstream `pointerout`, `pointerleave` events, in that order.
1150
+ *
1151
+ * The tracking data for the specific pointer is cleared of a `overTarget`.
1152
+ * @param from - The upstream `pointerout` event.
1153
+ */
1154
+ mapPointerOut(e) {
1155
+ if (!(e instanceof f)) {
1156
+ y("EventBoundary cannot map a non-pointer event as a pointer event");
1157
+ return;
1158
+ }
1159
+ const t = this.trackingData(e.pointerId);
1160
+ if (t.overTargets) {
1161
+ const i = e.pointerType === "mouse" || e.pointerType === "pen", n = this.findMountedTarget(t.overTargets), s = this.createPointerEvent(e, "pointerout", n);
1162
+ this.dispatchEvent(s), i && this.dispatchEvent(s, "mouseout");
1163
+ const o = this.createPointerEvent(e, "pointerleave", n);
1164
+ for (o.eventPhase = o.AT_TARGET; o.target && o.target !== this.rootTarget.parent; )
1165
+ o.currentTarget = o.target, this.notifyTarget(o), i && this.notifyTarget(o, "mouseleave"), o.target = o.target.parent;
1166
+ t.overTargets = null, this.freeEvent(s), this.freeEvent(o);
1167
+ }
1168
+ this.cursor = null;
1169
+ }
1170
+ /**
1171
+ * Maps the upstream `pointerup` event to downstream `pointerup`, `pointerupoutside`,
1172
+ * and `click`/`rightclick`/`pointertap` events, in that order.
1173
+ *
1174
+ * The `pointerupoutside` event bubbles from the original `pointerdown` target to the most specific
1175
+ * ancestor of the `pointerdown` and `pointerup` targets, which is also the `click` event's target. `touchend`,
1176
+ * `rightup`, `mouseup`, `touchendoutside`, `rightupoutside`, `mouseupoutside`, and `tap` are fired as well for
1177
+ * specific pointer types.
1178
+ * @param from - The upstream `pointerup` event.
1179
+ */
1180
+ mapPointerUp(e) {
1181
+ if (!(e instanceof f)) {
1182
+ y("EventBoundary cannot map a non-pointer event as a pointer event");
1183
+ return;
1184
+ }
1185
+ const t = performance.now(), i = this.createPointerEvent(e);
1186
+ if (this.dispatchEvent(i, "pointerup"), i.pointerType === "touch")
1187
+ this.dispatchEvent(i, "touchend");
1188
+ else if (i.pointerType === "mouse" || i.pointerType === "pen") {
1189
+ const r = i.button === 2;
1190
+ this.dispatchEvent(i, r ? "rightup" : "mouseup");
1191
+ }
1192
+ const n = this.trackingData(e.pointerId), s = this.findMountedTarget(n.pressTargetsByButton[e.button]);
1193
+ let o = s;
1194
+ if (s && !i.composedPath().includes(s)) {
1195
+ let r = s;
1196
+ for (; r && !i.composedPath().includes(r); ) {
1197
+ if (i.currentTarget = r, this.notifyTarget(i, "pointerupoutside"), i.pointerType === "touch")
1198
+ this.notifyTarget(i, "touchendoutside");
1199
+ else if (i.pointerType === "mouse" || i.pointerType === "pen") {
1200
+ const l = i.button === 2;
1201
+ this.notifyTarget(i, l ? "rightupoutside" : "mouseupoutside");
1202
+ }
1203
+ r = r.parent;
1204
+ }
1205
+ delete n.pressTargetsByButton[e.button], o = r;
1206
+ }
1207
+ if (o) {
1208
+ const r = this.clonePointerEvent(i, "click");
1209
+ r.target = o, r.path = null, n.clicksByButton[e.button] || (n.clicksByButton[e.button] = {
1210
+ clickCount: 0,
1211
+ target: r.target,
1212
+ timeStamp: t
1213
+ });
1214
+ const l = n.clicksByButton[e.button];
1215
+ if (l.target === r.target && t - l.timeStamp < 200 ? ++l.clickCount : l.clickCount = 1, l.target = r.target, l.timeStamp = t, r.detail = l.clickCount, r.pointerType === "mouse") {
1216
+ const d = r.button === 2;
1217
+ this.dispatchEvent(r, d ? "rightclick" : "click");
1218
+ } else r.pointerType === "touch" && this.dispatchEvent(r, "tap");
1219
+ this.dispatchEvent(r, "pointertap"), this.freeEvent(r);
1220
+ }
1221
+ this.freeEvent(i);
1222
+ }
1223
+ /**
1224
+ * Maps the upstream `pointerupoutside` event to a downstream `pointerupoutside` event, bubbling from the original
1225
+ * `pointerdown` target to `rootTarget`.
1226
+ *
1227
+ * (The most specific ancestor of the `pointerdown` event and the `pointerup` event must the
1228
+ * `{@link EventBoundary}'s root because the `pointerup` event occurred outside of the boundary.)
1229
+ *
1230
+ * `touchendoutside`, `mouseupoutside`, and `rightupoutside` events are fired as well for specific pointer
1231
+ * types. The tracking data for the specific pointer is cleared of a `pressTarget`.
1232
+ * @param from - The upstream `pointerupoutside` event.
1233
+ */
1234
+ mapPointerUpOutside(e) {
1235
+ if (!(e instanceof f)) {
1236
+ y("EventBoundary cannot map a non-pointer event as a pointer event");
1237
+ return;
1238
+ }
1239
+ const t = this.trackingData(e.pointerId), i = this.findMountedTarget(t.pressTargetsByButton[e.button]), n = this.createPointerEvent(e);
1240
+ if (i) {
1241
+ let s = i;
1242
+ for (; s; )
1243
+ n.currentTarget = s, this.notifyTarget(n, "pointerupoutside"), n.pointerType === "touch" ? this.notifyTarget(n, "touchendoutside") : (n.pointerType === "mouse" || n.pointerType === "pen") && this.notifyTarget(n, n.button === 2 ? "rightupoutside" : "mouseupoutside"), s = s.parent;
1244
+ delete t.pressTargetsByButton[e.button];
1245
+ }
1246
+ this.freeEvent(n);
1247
+ }
1248
+ /**
1249
+ * Maps the upstream `wheel` event to a downstream `wheel` event.
1250
+ * @param from - The upstream `wheel` event.
1251
+ */
1252
+ mapWheel(e) {
1253
+ if (!(e instanceof T)) {
1254
+ y("EventBoundary cannot map a non-wheel event as a wheel event");
1255
+ return;
1256
+ }
1257
+ const t = this.createWheelEvent(e);
1258
+ this.dispatchEvent(t), this.freeEvent(t);
1259
+ }
1260
+ /**
1261
+ * Finds the most specific event-target in the given propagation path that is still mounted in the scene graph.
1262
+ *
1263
+ * This is used to find the correct `pointerup` and `pointerout` target in the case that the original `pointerdown`
1264
+ * or `pointerover` target was unmounted from the scene graph.
1265
+ * @param propagationPath - The propagation path was valid in the past.
1266
+ * @returns - The most specific event-target still mounted at the same location in the scene graph.
1267
+ */
1268
+ findMountedTarget(e) {
1269
+ if (!e)
1270
+ return null;
1271
+ let t = e[0];
1272
+ for (let i = 1; i < e.length && e[i].parent === t; i++)
1273
+ t = e[i];
1274
+ return t;
1275
+ }
1276
+ /**
1277
+ * Creates an event whose `originalEvent` is `from`, with an optional `type` and `target` override.
1278
+ *
1279
+ * The event is allocated using {@link EventBoundary#allocateEvent this.allocateEvent}.
1280
+ * @param from - The `originalEvent` for the returned event.
1281
+ * @param [type=from.type] - The type of the returned event.
1282
+ * @param target - The target of the returned event.
1283
+ */
1284
+ createPointerEvent(e, t, i) {
1285
+ const n = this.allocateEvent(f);
1286
+ return this.copyPointerData(e, n), this.copyMouseData(e, n), this.copyData(e, n), n.nativeEvent = e.nativeEvent, n.originalEvent = e, n.target = i ?? this.hitTest(n.global.x, n.global.y) ?? this._hitElements[0], typeof t == "string" && (n.type = t), n;
1287
+ }
1288
+ /**
1289
+ * Creates a wheel event whose `originalEvent` is `from`.
1290
+ *
1291
+ * The event is allocated using {@link EventBoundary#allocateEvent this.allocateEvent}.
1292
+ * @param from - The upstream wheel event.
1293
+ */
1294
+ createWheelEvent(e) {
1295
+ const t = this.allocateEvent(T);
1296
+ return this.copyWheelData(e, t), this.copyMouseData(e, t), this.copyData(e, t), t.nativeEvent = e.nativeEvent, t.originalEvent = e, t.target = this.hitTest(t.global.x, t.global.y), t;
1297
+ }
1298
+ /**
1299
+ * Clones the event `from`, with an optional `type` override.
1300
+ *
1301
+ * The event is allocated using {@link EventBoundary#allocateEvent this.allocateEvent}.
1302
+ * @param from - The event to clone.
1303
+ * @param [type=from.type] - The type of the returned event.
1304
+ */
1305
+ clonePointerEvent(e, t) {
1306
+ const i = this.allocateEvent(f);
1307
+ return i.nativeEvent = e.nativeEvent, i.originalEvent = e.originalEvent, this.copyPointerData(e, i), this.copyMouseData(e, i), this.copyData(e, i), i.target = e.target, i.path = e.composedPath().slice(), i.type = t ?? i.type, i;
1308
+ }
1309
+ /**
1310
+ * Copies wheel {@link FederatedWheelEvent} data from `from` into `to`.
1311
+ *
1312
+ * The following properties are copied:
1313
+ * + deltaMode
1314
+ * + deltaX
1315
+ * + deltaY
1316
+ * + deltaZ
1317
+ * @param from - The event to copy data from.
1318
+ * @param to - The event to copy data into.
1319
+ */
1320
+ copyWheelData(e, t) {
1321
+ t.deltaMode = e.deltaMode, t.deltaX = e.deltaX, t.deltaY = e.deltaY, t.deltaZ = e.deltaZ;
1322
+ }
1323
+ /**
1324
+ * Copies pointer {@link FederatedPointerEvent} data from `from` into `to`.
1325
+ *
1326
+ * The following properties are copied:
1327
+ * + pointerId
1328
+ * + width
1329
+ * + height
1330
+ * + isPrimary
1331
+ * + pointerType
1332
+ * + pressure
1333
+ * + tangentialPressure
1334
+ * + tiltX
1335
+ * + tiltY
1336
+ * @param from - The event to copy data from.
1337
+ * @param to - The event to copy data into.
1338
+ */
1339
+ copyPointerData(e, t) {
1340
+ e instanceof f && t instanceof f && (t.pointerId = e.pointerId, t.width = e.width, t.height = e.height, t.isPrimary = e.isPrimary, t.pointerType = e.pointerType, t.pressure = e.pressure, t.tangentialPressure = e.tangentialPressure, t.tiltX = e.tiltX, t.tiltY = e.tiltY, t.twist = e.twist);
1341
+ }
1342
+ /**
1343
+ * Copies mouse {@link FederatedMouseEvent} data from `from` to `to`.
1344
+ *
1345
+ * The following properties are copied:
1346
+ * + altKey
1347
+ * + button
1348
+ * + buttons
1349
+ * + clientX
1350
+ * + clientY
1351
+ * + metaKey
1352
+ * + movementX
1353
+ * + movementY
1354
+ * + pageX
1355
+ * + pageY
1356
+ * + x
1357
+ * + y
1358
+ * + screen
1359
+ * + shiftKey
1360
+ * + global
1361
+ * @param from - The event to copy data from.
1362
+ * @param to - The event to copy data into.
1363
+ */
1364
+ copyMouseData(e, t) {
1365
+ e instanceof D && t instanceof D && (t.altKey = e.altKey, t.button = e.button, t.buttons = e.buttons, t.client.copyFrom(e.client), t.ctrlKey = e.ctrlKey, t.metaKey = e.metaKey, t.movement.copyFrom(e.movement), t.screen.copyFrom(e.screen), t.shiftKey = e.shiftKey, t.global.copyFrom(e.global));
1366
+ }
1367
+ /**
1368
+ * Copies base {@link FederatedEvent} data from `from` into `to`.
1369
+ *
1370
+ * The following properties are copied:
1371
+ * + isTrusted
1372
+ * + srcElement
1373
+ * + timeStamp
1374
+ * + type
1375
+ * @param from - The event to copy data from.
1376
+ * @param to - The event to copy data into.
1377
+ */
1378
+ copyData(e, t) {
1379
+ t.isTrusted = e.isTrusted, t.srcElement = e.srcElement, t.timeStamp = performance.now(), t.type = e.type, t.detail = e.detail, t.view = e.view, t.which = e.which, t.layer.copyFrom(e.layer), t.page.copyFrom(e.page);
1380
+ }
1381
+ /**
1382
+ * @param id - The pointer ID.
1383
+ * @returns The tracking data stored for the given pointer. If no data exists, a blank
1384
+ * state will be created.
1385
+ */
1386
+ trackingData(e) {
1387
+ return this.mappingState.trackingData[e] || (this.mappingState.trackingData[e] = {
1388
+ pressTargetsByButton: {},
1389
+ clicksByButton: {},
1390
+ overTarget: null
1391
+ }), this.mappingState.trackingData[e];
1392
+ }
1393
+ /**
1394
+ * Allocate a specific type of event from {@link EventBoundary#eventPool this.eventPool}.
1395
+ *
1396
+ * This allocation is constructor-agnostic, as long as it only takes one argument - this event
1397
+ * boundary.
1398
+ * @param constructor - The event's constructor.
1399
+ * @returns An event of the given type.
1400
+ */
1401
+ allocateEvent(e) {
1402
+ this.eventPool.has(e) || this.eventPool.set(e, []);
1403
+ const t = this.eventPool.get(e).pop() || new e(this);
1404
+ return t.eventPhase = t.NONE, t.currentTarget = null, t.defaultPrevented = !1, t.path = null, t.target = null, t;
1405
+ }
1406
+ /**
1407
+ * Frees the event and puts it back into the event pool.
1408
+ *
1409
+ * It is illegal to reuse the event until it is allocated again, using `this.allocateEvent`.
1410
+ *
1411
+ * It is also advised that events not allocated from {@link EventBoundary#allocateEvent this.allocateEvent}
1412
+ * not be freed. This is because of the possibility that the same event is freed twice, which can cause
1413
+ * it to be allocated twice & result in overwriting.
1414
+ * @param event - The event to be freed.
1415
+ * @throws Error if the event is managed by another event boundary.
1416
+ */
1417
+ freeEvent(e) {
1418
+ if (e.manager !== this)
1419
+ throw new Error("It is illegal to free an event not managed by this EventBoundary!");
1420
+ const t = e.constructor;
1421
+ this.eventPool.has(t) || this.eventPool.set(t, []), this.eventPool.get(t).push(e);
1422
+ }
1423
+ /**
1424
+ * Similar to {@link EventEmitter.emit}, except it stops if the `propagationImmediatelyStopped` flag
1425
+ * is set on the event.
1426
+ * @param e - The event to call each listener with.
1427
+ * @param type - The event key.
1428
+ */
1429
+ _notifyListeners(e, t) {
1430
+ const i = e.currentTarget._events[t];
1431
+ if (i)
1432
+ if ("fn" in i)
1433
+ i.once && e.currentTarget.removeListener(t, i.fn, void 0, !0), i.fn.call(i.context, e);
1434
+ else
1435
+ for (let n = 0, s = i.length; n < s && !e.propagationImmediatelyStopped; n++)
1436
+ i[n].once && e.currentTarget.removeListener(t, i[n].fn, void 0, !0), i[n].fn.call(i[n].context, e);
1437
+ }
1438
+ }
1439
+ const ge = 1, ye = {
1440
+ touchstart: "pointerdown",
1441
+ touchend: "pointerup",
1442
+ touchendoutside: "pointerupoutside",
1443
+ touchmove: "pointermove",
1444
+ touchcancel: "pointercancel"
1445
+ }, B = class x {
1446
+ /**
1447
+ * @param {Renderer} renderer
1448
+ */
1449
+ constructor(e) {
1450
+ this.supportsTouchEvents = "ontouchstart" in globalThis, this.supportsPointerEvents = !!globalThis.PointerEvent, this.domElement = null, this.resolution = 1, this.renderer = e, this.rootBoundary = new _e(null), _.init(this), this.autoPreventDefault = !0, this._eventsAdded = !1, this._rootPointerEvent = new f(null), this._rootWheelEvent = new T(null), this.cursorStyles = {
1451
+ default: "inherit",
1452
+ pointer: "pointer"
1453
+ }, this.features = new Proxy({ ...x.defaultEventFeatures }, {
1454
+ set: (t, i, n) => (i === "globalMove" && (this.rootBoundary.enableGlobalMoveEvents = n), t[i] = n, !0)
1455
+ }), this._onPointerDown = this._onPointerDown.bind(this), this._onPointerMove = this._onPointerMove.bind(this), this._onPointerUp = this._onPointerUp.bind(this), this._onPointerOverOut = this._onPointerOverOut.bind(this), this.onWheel = this.onWheel.bind(this);
1456
+ }
1457
+ /**
1458
+ * The default interaction mode for all display objects.
1459
+ * @see Container.eventMode
1460
+ * @type {EventMode}
1461
+ * @readonly
1462
+ * @since 7.2.0
1463
+ */
1464
+ static get defaultEventMode() {
1465
+ return this._defaultEventMode;
1466
+ }
1467
+ /**
1468
+ * Runner init called, view is available at this point.
1469
+ * @ignore
1470
+ */
1471
+ init(e) {
1472
+ const { canvas: t, resolution: i } = this.renderer;
1473
+ this.setTargetElement(t), this.resolution = i, x._defaultEventMode = e.eventMode ?? "passive", Object.assign(this.features, e.eventFeatures ?? {}), this.rootBoundary.enableGlobalMoveEvents = this.features.globalMove;
1474
+ }
1475
+ /**
1476
+ * Handle changing resolution.
1477
+ * @ignore
1478
+ */
1479
+ resolutionChange(e) {
1480
+ this.resolution = e;
1481
+ }
1482
+ /** Destroys all event listeners and detaches the renderer. */
1483
+ destroy() {
1484
+ _.destroy(), this.setTargetElement(null), this.renderer = null, this._currentCursor = null;
1485
+ }
1486
+ /**
1487
+ * Sets the current cursor mode, handling any callbacks or CSS style changes.
1488
+ * The cursor can be a CSS cursor string, a custom callback function, or a key from the cursorStyles dictionary.
1489
+ * @param mode - Cursor mode to set. Can be:
1490
+ * - A CSS cursor string (e.g., 'pointer', 'grab')
1491
+ * - A key from the cursorStyles dictionary
1492
+ * - null/undefined to reset to default
1493
+ * @example
1494
+ * ```ts
1495
+ * // Using predefined cursor styles
1496
+ * app.renderer.events.setCursor('pointer'); // Set standard pointer cursor
1497
+ * app.renderer.events.setCursor('grab'); // Set grab cursor
1498
+ * app.renderer.events.setCursor(null); // Reset to default
1499
+ *
1500
+ * // Using custom cursor styles
1501
+ * app.renderer.events.cursorStyles.custom = 'url("cursor.png"), auto';
1502
+ * app.renderer.events.setCursor('custom'); // Apply custom cursor
1503
+ *
1504
+ * // Using callback-based cursor
1505
+ * app.renderer.events.cursorStyles.dynamic = (mode) => {
1506
+ * document.body.style.cursor = mode === 'hover' ? 'pointer' : 'default';
1507
+ * };
1508
+ * app.renderer.events.setCursor('dynamic'); // Trigger cursor callback
1509
+ * ```
1510
+ * @remarks
1511
+ * - Has no effect on OffscreenCanvas except for callback-based cursors
1512
+ * - Caches current cursor to avoid unnecessary DOM updates
1513
+ * - Supports CSS cursor values, style objects, and callback functions
1514
+ * @see {@link EventSystem.cursorStyles} For defining custom cursor styles
1515
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/cursor} MDN Cursor Reference
1516
+ */
1517
+ setCursor(e) {
1518
+ e || (e = "default");
1519
+ let t = !0;
1520
+ if (globalThis.OffscreenCanvas && this.domElement instanceof OffscreenCanvas && (t = !1), this._currentCursor === e)
1521
+ return;
1522
+ this._currentCursor = e;
1523
+ const i = this.cursorStyles[e];
1524
+ if (i)
1525
+ switch (typeof i) {
1526
+ case "string":
1527
+ t && (this.domElement.style.cursor = i);
1528
+ break;
1529
+ case "function":
1530
+ i(e);
1531
+ break;
1532
+ case "object":
1533
+ t && Object.assign(this.domElement.style, i);
1534
+ break;
1535
+ }
1536
+ else t && typeof e == "string" && !Object.prototype.hasOwnProperty.call(this.cursorStyles, e) && (this.domElement.style.cursor = e);
1537
+ }
1538
+ /**
1539
+ * The global pointer event instance containing the most recent pointer state.
1540
+ * This is useful for accessing pointer information without listening to events.
1541
+ * @example
1542
+ * ```ts
1543
+ * // Access current pointer position at any time
1544
+ * const eventSystem = app.renderer.events;
1545
+ * const pointer = eventSystem.pointer;
1546
+ *
1547
+ * // Get global coordinates
1548
+ * console.log('Position:', pointer.global.x, pointer.global.y);
1549
+ *
1550
+ * // Check button state
1551
+ * console.log('Buttons pressed:', pointer.buttons);
1552
+ *
1553
+ * // Get pointer type and pressure
1554
+ * console.log('Type:', pointer.pointerType);
1555
+ * console.log('Pressure:', pointer.pressure);
1556
+ * ```
1557
+ * @readonly
1558
+ * @since 7.2.0
1559
+ * @see {@link FederatedPointerEvent} For all available pointer properties
1560
+ */
1561
+ get pointer() {
1562
+ return this._rootPointerEvent;
1563
+ }
1564
+ /**
1565
+ * Event handler for pointer down events on {@link EventSystem#domElement this.domElement}.
1566
+ * @param nativeEvent - The native mouse/pointer/touch event.
1567
+ */
1568
+ _onPointerDown(e) {
1569
+ if (!this.features.click)
1570
+ return;
1571
+ this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;
1572
+ const t = this._normalizeToPointerData(e);
1573
+ this.autoPreventDefault && t[0].isNormalized && (e.cancelable || !("cancelable" in e)) && e.preventDefault();
1574
+ for (let i = 0, n = t.length; i < n; i++) {
1575
+ const s = t[i], o = this._bootstrapEvent(this._rootPointerEvent, s);
1576
+ this.rootBoundary.mapEvent(o);
1577
+ }
1578
+ this.setCursor(this.rootBoundary.cursor);
1579
+ }
1580
+ /**
1581
+ * Event handler for pointer move events on on {@link EventSystem#domElement this.domElement}.
1582
+ * @param nativeEvent - The native mouse/pointer/touch events.
1583
+ */
1584
+ _onPointerMove(e) {
1585
+ if (!this.features.move)
1586
+ return;
1587
+ this.rootBoundary.rootTarget = this.renderer.lastObjectRendered, _.pointerMoved();
1588
+ const t = this._normalizeToPointerData(e);
1589
+ for (let i = 0, n = t.length; i < n; i++) {
1590
+ const s = this._bootstrapEvent(this._rootPointerEvent, t[i]);
1591
+ this.rootBoundary.mapEvent(s);
1592
+ }
1593
+ this.setCursor(this.rootBoundary.cursor);
1594
+ }
1595
+ /**
1596
+ * Event handler for pointer up events on {@link EventSystem#domElement this.domElement}.
1597
+ * @param nativeEvent - The native mouse/pointer/touch event.
1598
+ */
1599
+ _onPointerUp(e) {
1600
+ if (!this.features.click)
1601
+ return;
1602
+ this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;
1603
+ let t = e.target;
1604
+ e.composedPath && e.composedPath().length > 0 && (t = e.composedPath()[0]);
1605
+ const i = t !== this.domElement ? "outside" : "", n = this._normalizeToPointerData(e);
1606
+ for (let s = 0, o = n.length; s < o; s++) {
1607
+ const r = this._bootstrapEvent(this._rootPointerEvent, n[s]);
1608
+ r.type += i, this.rootBoundary.mapEvent(r);
1609
+ }
1610
+ this.setCursor(this.rootBoundary.cursor);
1611
+ }
1612
+ /**
1613
+ * Event handler for pointer over & out events on {@link EventSystem#domElement this.domElement}.
1614
+ * @param nativeEvent - The native mouse/pointer/touch event.
1615
+ */
1616
+ _onPointerOverOut(e) {
1617
+ if (!this.features.click)
1618
+ return;
1619
+ this.rootBoundary.rootTarget = this.renderer.lastObjectRendered;
1620
+ const t = this._normalizeToPointerData(e);
1621
+ for (let i = 0, n = t.length; i < n; i++) {
1622
+ const s = this._bootstrapEvent(this._rootPointerEvent, t[i]);
1623
+ this.rootBoundary.mapEvent(s);
1624
+ }
1625
+ this.setCursor(this.rootBoundary.cursor);
1626
+ }
1627
+ /**
1628
+ * Passive handler for `wheel` events on {@link EventSystem.domElement this.domElement}.
1629
+ * @param nativeEvent - The native wheel event.
1630
+ */
1631
+ onWheel(e) {
1632
+ if (!this.features.wheel)
1633
+ return;
1634
+ const t = this.normalizeWheelEvent(e);
1635
+ this.rootBoundary.rootTarget = this.renderer.lastObjectRendered, this.rootBoundary.mapEvent(t);
1636
+ }
1637
+ /**
1638
+ * Sets the {@link EventSystem#domElement domElement} and binds event listeners.
1639
+ * This method manages the DOM event bindings for the event system, allowing you to
1640
+ * change or remove the target element that receives input events.
1641
+ * > [!IMPORTANT] This will default to the canvas element of the renderer, so you
1642
+ * > should not need to call this unless you are using a custom element.
1643
+ * @param element - The new DOM element to bind events to, or null to remove all event bindings
1644
+ * @example
1645
+ * ```ts
1646
+ * // Set a new canvas element as the target
1647
+ * const canvas = document.createElement('canvas');
1648
+ * app.renderer.events.setTargetElement(canvas);
1649
+ *
1650
+ * // Remove all event bindings
1651
+ * app.renderer.events.setTargetElement(null);
1652
+ *
1653
+ * // Switch to a different canvas
1654
+ * const newCanvas = document.querySelector('#game-canvas');
1655
+ * app.renderer.events.setTargetElement(newCanvas);
1656
+ * ```
1657
+ * @remarks
1658
+ * - Automatically removes event listeners from previous element
1659
+ * - Required for the event system to function
1660
+ * - Safe to call multiple times
1661
+ * @see {@link EventSystem#domElement} The current DOM element
1662
+ * @see {@link EventsTicker} For the ticker system that tracks pointer movement
1663
+ */
1664
+ setTargetElement(e) {
1665
+ this._removeEvents(), this.domElement = e, _.domElement = e, this._addEvents();
1666
+ }
1667
+ /** Register event listeners on {@link Renderer#domElement this.domElement}. */
1668
+ _addEvents() {
1669
+ if (this._eventsAdded || !this.domElement)
1670
+ return;
1671
+ _.addTickerListener();
1672
+ const e = this.domElement.style;
1673
+ e && (globalThis.navigator.msPointerEnabled ? (e.msContentZooming = "none", e.msTouchAction = "none") : this.supportsPointerEvents && (e.touchAction = "none")), this.supportsPointerEvents ? (globalThis.document.addEventListener("pointermove", this._onPointerMove, !0), this.domElement.addEventListener("pointerdown", this._onPointerDown, !0), this.domElement.addEventListener("pointerleave", this._onPointerOverOut, !0), this.domElement.addEventListener("pointerover", this._onPointerOverOut, !0), globalThis.addEventListener("pointerup", this._onPointerUp, !0)) : (globalThis.document.addEventListener("mousemove", this._onPointerMove, !0), this.domElement.addEventListener("mousedown", this._onPointerDown, !0), this.domElement.addEventListener("mouseout", this._onPointerOverOut, !0), this.domElement.addEventListener("mouseover", this._onPointerOverOut, !0), globalThis.addEventListener("mouseup", this._onPointerUp, !0), this.supportsTouchEvents && (this.domElement.addEventListener("touchstart", this._onPointerDown, !0), this.domElement.addEventListener("touchend", this._onPointerUp, !0), this.domElement.addEventListener("touchmove", this._onPointerMove, !0))), this.domElement.addEventListener("wheel", this.onWheel, {
1674
+ passive: !0,
1675
+ capture: !0
1676
+ }), this._eventsAdded = !0;
1677
+ }
1678
+ /** Unregister event listeners on {@link EventSystem#domElement this.domElement}. */
1679
+ _removeEvents() {
1680
+ if (!this._eventsAdded || !this.domElement)
1681
+ return;
1682
+ _.removeTickerListener();
1683
+ const e = this.domElement.style;
1684
+ e && (globalThis.navigator.msPointerEnabled ? (e.msContentZooming = "", e.msTouchAction = "") : this.supportsPointerEvents && (e.touchAction = "")), this.supportsPointerEvents ? (globalThis.document.removeEventListener("pointermove", this._onPointerMove, !0), this.domElement.removeEventListener("pointerdown", this._onPointerDown, !0), this.domElement.removeEventListener("pointerleave", this._onPointerOverOut, !0), this.domElement.removeEventListener("pointerover", this._onPointerOverOut, !0), globalThis.removeEventListener("pointerup", this._onPointerUp, !0)) : (globalThis.document.removeEventListener("mousemove", this._onPointerMove, !0), this.domElement.removeEventListener("mousedown", this._onPointerDown, !0), this.domElement.removeEventListener("mouseout", this._onPointerOverOut, !0), this.domElement.removeEventListener("mouseover", this._onPointerOverOut, !0), globalThis.removeEventListener("mouseup", this._onPointerUp, !0), this.supportsTouchEvents && (this.domElement.removeEventListener("touchstart", this._onPointerDown, !0), this.domElement.removeEventListener("touchend", this._onPointerUp, !0), this.domElement.removeEventListener("touchmove", this._onPointerMove, !0))), this.domElement.removeEventListener("wheel", this.onWheel, !0), this.domElement = null, this._eventsAdded = !1;
1685
+ }
1686
+ /**
1687
+ * Maps coordinates from DOM/screen space into PixiJS normalized coordinates.
1688
+ * This takes into account the current scale, position, and resolution of the DOM element.
1689
+ * @param point - The point to store the mapped coordinates in
1690
+ * @param x - The x coordinate in DOM/client space
1691
+ * @param y - The y coordinate in DOM/client space
1692
+ * @example
1693
+ * ```ts
1694
+ * // Map mouse coordinates to PixiJS space
1695
+ * const point = new Point();
1696
+ * app.renderer.events.mapPositionToPoint(
1697
+ * point,
1698
+ * event.clientX,
1699
+ * event.clientY
1700
+ * );
1701
+ * console.log('Mapped position:', point.x, point.y);
1702
+ *
1703
+ * // Using with pointer events
1704
+ * sprite.on('pointermove', (event) => {
1705
+ * // event.global already contains mapped coordinates
1706
+ * console.log('Global:', event.global.x, event.global.y);
1707
+ *
1708
+ * // Map to local coordinates
1709
+ * const local = event.getLocalPosition(sprite);
1710
+ * console.log('Local:', local.x, local.y);
1711
+ * });
1712
+ * ```
1713
+ * @remarks
1714
+ * - Accounts for element scaling and positioning
1715
+ * - Adjusts for device pixel ratio/resolution
1716
+ */
1717
+ mapPositionToPoint(e, t, i) {
1718
+ const n = this.domElement.isConnected ? this.domElement.getBoundingClientRect() : {
1719
+ width: this.domElement.width,
1720
+ height: this.domElement.height,
1721
+ left: 0,
1722
+ top: 0
1723
+ }, s = 1 / this.resolution;
1724
+ e.x = (t - n.left) * (this.domElement.width / n.width) * s, e.y = (i - n.top) * (this.domElement.height / n.height) * s;
1725
+ }
1726
+ /**
1727
+ * Ensures that the original event object contains all data that a regular pointer event would have
1728
+ * @param event - The original event data from a touch or mouse event
1729
+ * @returns An array containing a single normalized pointer event, in the case of a pointer
1730
+ * or mouse event, or a multiple normalized pointer events if there are multiple changed touches
1731
+ */
1732
+ _normalizeToPointerData(e) {
1733
+ const t = [];
1734
+ if (this.supportsTouchEvents && e instanceof TouchEvent)
1735
+ for (let i = 0, n = e.changedTouches.length; i < n; i++) {
1736
+ const s = e.changedTouches[i];
1737
+ typeof s.button > "u" && (s.button = 0), typeof s.buttons > "u" && (s.buttons = 1), typeof s.isPrimary > "u" && (s.isPrimary = e.touches.length === 1 && e.type === "touchstart"), typeof s.width > "u" && (s.width = s.radiusX || 1), typeof s.height > "u" && (s.height = s.radiusY || 1), typeof s.tiltX > "u" && (s.tiltX = 0), typeof s.tiltY > "u" && (s.tiltY = 0), typeof s.pointerType > "u" && (s.pointerType = "touch"), typeof s.pointerId > "u" && (s.pointerId = s.identifier || 0), typeof s.pressure > "u" && (s.pressure = s.force || 0.5), typeof s.twist > "u" && (s.twist = 0), typeof s.tangentialPressure > "u" && (s.tangentialPressure = 0), typeof s.layerX > "u" && (s.layerX = s.offsetX = s.clientX), typeof s.layerY > "u" && (s.layerY = s.offsetY = s.clientY), s.isNormalized = !0, s.type = e.type, t.push(s);
1738
+ }
1739
+ else if (!globalThis.MouseEvent || e instanceof MouseEvent && (!this.supportsPointerEvents || !(e instanceof globalThis.PointerEvent))) {
1740
+ const i = e;
1741
+ typeof i.isPrimary > "u" && (i.isPrimary = !0), typeof i.width > "u" && (i.width = 1), typeof i.height > "u" && (i.height = 1), typeof i.tiltX > "u" && (i.tiltX = 0), typeof i.tiltY > "u" && (i.tiltY = 0), typeof i.pointerType > "u" && (i.pointerType = "mouse"), typeof i.pointerId > "u" && (i.pointerId = ge), typeof i.pressure > "u" && (i.pressure = 0.5), typeof i.twist > "u" && (i.twist = 0), typeof i.tangentialPressure > "u" && (i.tangentialPressure = 0), i.isNormalized = !0, t.push(i);
1742
+ } else
1743
+ t.push(e);
1744
+ return t;
1745
+ }
1746
+ /**
1747
+ * Normalizes the native {@link https://w3c.github.io/uievents/#interface-wheelevent WheelEvent}.
1748
+ *
1749
+ * The returned {@link FederatedWheelEvent} is a shared instance. It will not persist across
1750
+ * multiple native wheel events.
1751
+ * @param nativeEvent - The native wheel event that occurred on the canvas.
1752
+ * @returns A federated wheel event.
1753
+ */
1754
+ normalizeWheelEvent(e) {
1755
+ const t = this._rootWheelEvent;
1756
+ return this._transferMouseData(t, e), t.deltaX = e.deltaX, t.deltaY = e.deltaY, t.deltaZ = e.deltaZ, t.deltaMode = e.deltaMode, this.mapPositionToPoint(t.screen, e.clientX, e.clientY), t.global.copyFrom(t.screen), t.offset.copyFrom(t.screen), t.nativeEvent = e, t.type = e.type, t;
1757
+ }
1758
+ /**
1759
+ * Normalizes the `nativeEvent` into a federateed {@link FederatedPointerEvent}.
1760
+ * @param event
1761
+ * @param nativeEvent
1762
+ */
1763
+ _bootstrapEvent(e, t) {
1764
+ return e.originalEvent = null, e.nativeEvent = t, e.pointerId = t.pointerId, e.width = t.width, e.height = t.height, e.isPrimary = t.isPrimary, e.pointerType = t.pointerType, e.pressure = t.pressure, e.tangentialPressure = t.tangentialPressure, e.tiltX = t.tiltX, e.tiltY = t.tiltY, e.twist = t.twist, this._transferMouseData(e, t), this.mapPositionToPoint(e.screen, t.clientX, t.clientY), e.global.copyFrom(e.screen), e.offset.copyFrom(e.screen), e.isTrusted = t.isTrusted, e.type === "pointerleave" && (e.type = "pointerout"), e.type.startsWith("mouse") && (e.type = e.type.replace("mouse", "pointer")), e.type.startsWith("touch") && (e.type = ye[e.type] || e.type), e;
1765
+ }
1766
+ /**
1767
+ * Transfers base & mouse event data from the `nativeEvent` to the federated event.
1768
+ * @param event
1769
+ * @param nativeEvent
1770
+ */
1771
+ _transferMouseData(e, t) {
1772
+ e.isTrusted = t.isTrusted, e.srcElement = t.srcElement, e.timeStamp = performance.now(), e.type = t.type, e.altKey = t.altKey, e.button = t.button, e.buttons = t.buttons, e.client.x = t.clientX, e.client.y = t.clientY, e.ctrlKey = t.ctrlKey, e.metaKey = t.metaKey, e.movement.x = t.movementX, e.movement.y = t.movementY, e.page.x = t.pageX, e.page.y = t.pageY, e.relatedTarget = null, e.shiftKey = t.shiftKey;
1773
+ }
1774
+ };
1775
+ B.extension = {
1776
+ name: "events",
1777
+ type: [
1778
+ b.WebGLSystem,
1779
+ b.CanvasSystem,
1780
+ b.WebGPUSystem
1781
+ ],
1782
+ priority: -1
1783
+ };
1784
+ B.defaultEventFeatures = {
1785
+ /** Enables pointer events associated with pointer movement. */
1786
+ move: !0,
1787
+ /** Enables global pointer move events. */
1788
+ globalMove: !0,
1789
+ /** Enables pointer events associated with clicking. */
1790
+ click: !0,
1791
+ /** Enables wheel events. */
1792
+ wheel: !0
1793
+ };
1794
+ let ee = B;
1795
+ const be = {
1796
+ onclick: null,
1797
+ onmousedown: null,
1798
+ onmouseenter: null,
1799
+ onmouseleave: null,
1800
+ onmousemove: null,
1801
+ onglobalmousemove: null,
1802
+ onmouseout: null,
1803
+ onmouseover: null,
1804
+ onmouseup: null,
1805
+ onmouseupoutside: null,
1806
+ onpointercancel: null,
1807
+ onpointerdown: null,
1808
+ onpointerenter: null,
1809
+ onpointerleave: null,
1810
+ onpointermove: null,
1811
+ onglobalpointermove: null,
1812
+ onpointerout: null,
1813
+ onpointerover: null,
1814
+ onpointertap: null,
1815
+ onpointerup: null,
1816
+ onpointerupoutside: null,
1817
+ onrightclick: null,
1818
+ onrightdown: null,
1819
+ onrightup: null,
1820
+ onrightupoutside: null,
1821
+ ontap: null,
1822
+ ontouchcancel: null,
1823
+ ontouchend: null,
1824
+ ontouchendoutside: null,
1825
+ ontouchmove: null,
1826
+ onglobaltouchmove: null,
1827
+ ontouchstart: null,
1828
+ onwheel: null,
1829
+ get interactive() {
1830
+ return this.eventMode === "dynamic" || this.eventMode === "static";
1831
+ },
1832
+ set interactive(a) {
1833
+ this.eventMode = a ? "static" : "passive";
1834
+ },
1835
+ _internalEventMode: void 0,
1836
+ get eventMode() {
1837
+ return this._internalEventMode ?? ee.defaultEventMode;
1838
+ },
1839
+ set eventMode(a) {
1840
+ this._internalEventMode = a;
1841
+ },
1842
+ isInteractive() {
1843
+ return this.eventMode === "static" || this.eventMode === "dynamic";
1844
+ },
1845
+ interactiveChildren: !0,
1846
+ hitArea: null,
1847
+ addEventListener(a, e, t) {
1848
+ const i = typeof t == "boolean" && t || typeof t == "object" && t.capture, n = typeof t == "object" ? t.signal : void 0, s = typeof t == "object" ? t.once === !0 : !1, o = typeof e == "function" ? void 0 : e;
1849
+ a = i ? `${a}capture` : a;
1850
+ const r = typeof e == "function" ? e : e.handleEvent, l = this;
1851
+ n && n.addEventListener("abort", () => {
1852
+ l.off(a, r, o);
1853
+ }), s ? l.once(a, r, o) : l.on(a, r, o);
1854
+ },
1855
+ removeEventListener(a, e, t) {
1856
+ const i = typeof t == "boolean" && t || typeof t == "object" && t.capture, n = typeof e == "function" ? void 0 : e;
1857
+ a = i ? `${a}capture` : a, e = typeof e == "function" ? e : e.handleEvent, this.off(a, e, n);
1858
+ },
1859
+ dispatchEvent(a) {
1860
+ if (!(a instanceof M))
1861
+ throw new Error("Container cannot propagate events outside of the Federated Events API");
1862
+ return a.defaultPrevented = !1, a.path = null, a.target = this, a.manager.dispatchEvent(a), !a.defaultPrevented;
1863
+ }
1864
+ };
1865
+ w.add(ue);
1866
+ w.mixin(V, pe);
1867
+ w.add(ee);
1868
+ w.mixin(V, be);
1869
+ w.add(Q);
src/backend/gradio_polygonannotator/templates/component/colorToUniform-zJcCVLeu.js ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const f = {
2
+ normal: 0,
3
+ add: 1,
4
+ multiply: 2,
5
+ screen: 3,
6
+ overlay: 4,
7
+ erase: 5,
8
+ "normal-npm": 6,
9
+ "add-npm": 7,
10
+ "screen-npm": 8,
11
+ min: 9,
12
+ max: 10
13
+ }, n = 0, i = 1, r = 2, a = 3, l = 4, d = 5, h = class u {
14
+ constructor() {
15
+ this.data = 0, this.blendMode = "normal", this.polygonOffset = 0, this.blend = !0, this.depthMask = !0;
16
+ }
17
+ /**
18
+ * Activates blending of the computed fragment color values.
19
+ * @default true
20
+ */
21
+ get blend() {
22
+ return !!(this.data & 1 << n);
23
+ }
24
+ set blend(t) {
25
+ !!(this.data & 1 << n) !== t && (this.data ^= 1 << n);
26
+ }
27
+ /**
28
+ * Activates adding an offset to depth values of polygon's fragments
29
+ * @default false
30
+ */
31
+ get offsets() {
32
+ return !!(this.data & 1 << i);
33
+ }
34
+ set offsets(t) {
35
+ !!(this.data & 1 << i) !== t && (this.data ^= 1 << i);
36
+ }
37
+ /** The culling settings for this state none - No culling back - Back face culling front - Front face culling */
38
+ set cullMode(t) {
39
+ if (t === "none") {
40
+ this.culling = !1;
41
+ return;
42
+ }
43
+ this.culling = !0, this.clockwiseFrontFace = t === "front";
44
+ }
45
+ get cullMode() {
46
+ return this.culling ? this.clockwiseFrontFace ? "front" : "back" : "none";
47
+ }
48
+ /**
49
+ * Activates culling of polygons.
50
+ * @default false
51
+ */
52
+ get culling() {
53
+ return !!(this.data & 1 << r);
54
+ }
55
+ set culling(t) {
56
+ !!(this.data & 1 << r) !== t && (this.data ^= 1 << r);
57
+ }
58
+ /**
59
+ * Activates depth comparisons and updates to the depth buffer.
60
+ * @default false
61
+ */
62
+ get depthTest() {
63
+ return !!(this.data & 1 << a);
64
+ }
65
+ set depthTest(t) {
66
+ !!(this.data & 1 << a) !== t && (this.data ^= 1 << a);
67
+ }
68
+ /**
69
+ * Enables or disables writing to the depth buffer.
70
+ * @default true
71
+ */
72
+ get depthMask() {
73
+ return !!(this.data & 1 << d);
74
+ }
75
+ set depthMask(t) {
76
+ !!(this.data & 1 << d) !== t && (this.data ^= 1 << d);
77
+ }
78
+ /**
79
+ * Specifies whether or not front or back-facing polygons can be culled.
80
+ * @default false
81
+ */
82
+ get clockwiseFrontFace() {
83
+ return !!(this.data & 1 << l);
84
+ }
85
+ set clockwiseFrontFace(t) {
86
+ !!(this.data & 1 << l) !== t && (this.data ^= 1 << l);
87
+ }
88
+ /**
89
+ * The blend mode to be applied when this state is set. Apply a value of `normal` to reset the blend mode.
90
+ * Setting this mode to anything other than NO_BLEND will automatically switch blending on.
91
+ * @default 'normal'
92
+ */
93
+ get blendMode() {
94
+ return this._blendMode;
95
+ }
96
+ set blendMode(t) {
97
+ this.blend = t !== "none", this._blendMode = t, this._blendModeId = f[t] || 0;
98
+ }
99
+ /**
100
+ * The polygon offset. Setting this property to anything other than 0 will automatically enable polygon offset fill.
101
+ * @default 0
102
+ */
103
+ get polygonOffset() {
104
+ return this._polygonOffset;
105
+ }
106
+ set polygonOffset(t) {
107
+ this.offsets = !!t, this._polygonOffset = t;
108
+ }
109
+ toString() {
110
+ return `[pixi.js/core:State blendMode=${this.blendMode} clockwiseFrontFace=${this.clockwiseFrontFace} culling=${this.culling} depthMask=${this.depthMask} polygonOffset=${this.polygonOffset}]`;
111
+ }
112
+ /**
113
+ * A quickly getting an instance of a State that is configured for 2d rendering.
114
+ * @returns a new State with values set for 2d rendering
115
+ */
116
+ static for2d() {
117
+ const t = new u();
118
+ return t.depthTest = !1, t.blend = !0, t;
119
+ }
120
+ };
121
+ h.default2d = h.for2d();
122
+ let m = h;
123
+ const c = {
124
+ name: "local-uniform-bit",
125
+ vertex: {
126
+ header: (
127
+ /* wgsl */
128
+ `
129
+
130
+ struct LocalUniforms {
131
+ uTransformMatrix:mat3x3<f32>,
132
+ uColor:vec4<f32>,
133
+ uRound:f32,
134
+ }
135
+
136
+ @group(1) @binding(0) var<uniform> localUniforms : LocalUniforms;
137
+ `
138
+ ),
139
+ main: (
140
+ /* wgsl */
141
+ `
142
+ vColor *= localUniforms.uColor;
143
+ modelMatrix *= localUniforms.uTransformMatrix;
144
+ `
145
+ ),
146
+ end: (
147
+ /* wgsl */
148
+ `
149
+ if(localUniforms.uRound == 1)
150
+ {
151
+ vPosition = vec4(roundPixels(vPosition.xy, globalUniforms.uResolution), vPosition.zw);
152
+ }
153
+ `
154
+ )
155
+ }
156
+ }, g = {
157
+ ...c,
158
+ vertex: {
159
+ ...c.vertex,
160
+ // replace the group!
161
+ header: c.vertex.header.replace("group(1)", "group(2)")
162
+ }
163
+ }, p = {
164
+ name: "local-uniform-bit",
165
+ vertex: {
166
+ header: (
167
+ /* glsl */
168
+ `
169
+
170
+ uniform mat3 uTransformMatrix;
171
+ uniform vec4 uColor;
172
+ uniform float uRound;
173
+ `
174
+ ),
175
+ main: (
176
+ /* glsl */
177
+ `
178
+ vColor *= uColor;
179
+ modelMatrix = uTransformMatrix;
180
+ `
181
+ ),
182
+ end: (
183
+ /* glsl */
184
+ `
185
+ if(uRound == 1.)
186
+ {
187
+ gl_Position.xy = roundPixels(gl_Position.xy, uResolution);
188
+ }
189
+ `
190
+ )
191
+ }
192
+ };
193
+ class b {
194
+ constructor() {
195
+ this.batcherName = "default", this.topology = "triangle-list", this.attributeSize = 4, this.indexSize = 6, this.packAsQuad = !0, this.roundPixels = 0, this._attributeStart = 0, this._batcher = null, this._batch = null;
196
+ }
197
+ get blendMode() {
198
+ return this.renderable.groupBlendMode;
199
+ }
200
+ get color() {
201
+ return this.renderable.groupColorAlpha;
202
+ }
203
+ reset() {
204
+ this.renderable = null, this.texture = null, this._batcher = null, this._batch = null, this.bounds = null;
205
+ }
206
+ destroy() {
207
+ }
208
+ }
209
+ function M(e, t, o) {
210
+ const s = (e >> 24 & 255) / 255;
211
+ t[o++] = (e & 255) / 255 * s, t[o++] = (e >> 8 & 255) / 255 * s, t[o++] = (e >> 16 & 255) / 255 * s, t[o++] = s;
212
+ }
213
+ export {
214
+ b as B,
215
+ m as S,
216
+ c as a,
217
+ p as b,
218
+ M as c,
219
+ g as l
220
+ };
src/backend/gradio_polygonannotator/templates/component/index.js ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ import { ap as f } from "./Index-Ct_1BCRd.js";
2
+ export {
3
+ f as default
4
+ };
src/backend/gradio_polygonannotator/templates/component/style.css ADDED
@@ -0,0 +1 @@
 
 
1
+ .block.svelte-239wnu{position:relative;margin:0;box-shadow:var(--block-shadow);border-width:var(--block-border-width);border-color:var(--block-border-color);border-radius:var(--block-radius);background:var(--block-background-fill);width:100%;line-height:var(--line-sm)}.block.fullscreen.svelte-239wnu{border-radius:0}.auto-margin.svelte-239wnu{margin-left:auto;margin-right:auto}.block.border_focus.svelte-239wnu{border-color:var(--color-accent)}.block.border_contrast.svelte-239wnu{border-color:var(--body-text-color)}.padded.svelte-239wnu{padding:var(--block-padding)}.hidden.svelte-239wnu{display:none}.flex.svelte-239wnu{display:flex;flex-direction:column}.hide-container.svelte-239wnu:not(.fullscreen){margin:0;box-shadow:none;--block-border-width:0;background:transparent;padding:0;overflow:visible}.resize-handle.svelte-239wnu{position:absolute;bottom:0;right:0;width:10px;height:10px;fill:var(--block-border-color);cursor:nwse-resize}.fullscreen.svelte-239wnu{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:1000;overflow:auto}.animating.svelte-239wnu{animation:svelte-239wnu-pop-out .1s ease-out forwards}@keyframes svelte-239wnu-pop-out{0%{position:fixed;top:var(--start-top);left:var(--start-left);width:var(--start-width);height:var(--start-height);z-index:100}to{position:fixed;top:0vh;left:0vw;width:100vw;height:100vh;z-index:1000}}.placeholder.svelte-239wnu{border-radius:var(--block-radius);border-width:var(--block-border-width);border-color:var(--block-border-color);border-style:dashed}Tables */ table,tr,td,th{margin-top:var(--spacing-sm);margin-bottom:var(--spacing-sm);padding:var(--spacing-xl)}.md code,.md pre{background:none;font-family:var(--font-mono);font-size:var(--text-sm);text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:2;tab-size:2;-webkit-hyphens:none;hyphens:none}.md pre[class*=language-]::selection,.md pre[class*=language-] ::selection,.md code[class*=language-]::selection,.md code[class*=language-] ::selection{text-shadow:none;background:#b3d4fc}.md pre{padding:1em;margin:.5em 0;overflow:auto;position:relative;margin-top:var(--spacing-sm);margin-bottom:var(--spacing-sm);box-shadow:none;border:none;border-radius:var(--radius-md);background:var(--code-background-fill);padding:var(--spacing-xxl);font-family:var(--font-mono);text-shadow:none;border-radius:var(--radius-sm);white-space:nowrap;display:block;white-space:pre}.md :not(pre)>code{padding:.1em;border-radius:var(--radius-xs);white-space:normal;background:var(--code-background-fill);border:1px solid var(--panel-border-color);padding:var(--spacing-xxs) var(--spacing-xs)}.md .token.comment,.md .token.prolog,.md .token.doctype,.md .token.cdata{color:#708090}.md .token.punctuation{color:#999}.md .token.namespace{opacity:.7}.md .token.property,.md .token.tag,.md .token.boolean,.md .token.number,.md .token.constant,.md .token.symbol,.md .token.deleted{color:#905}.md .token.selector,.md .token.attr-name,.md .token.string,.md .token.char,.md .token.builtin,.md .token.inserted{color:#690}.md .token.atrule,.md .token.attr-value,.md .token.keyword{color:#07a}.md .token.function,.md .token.class-name{color:#dd4a68}.md .token.regex,.md .token.important,.md .token.variable{color:#e90}.md .token.important,.md .token.bold{font-weight:700}.md .token.italic{font-style:italic}.md .token.entity{cursor:help}.dark .md .token.comment,.dark .md .token.prolog,.dark .md .token.cdata{color:#5c6370}.dark .md .token.doctype,.dark .md .token.punctuation,.dark .md .token.entity{color:#abb2bf}.dark .md .token.attr-name,.dark .md .token.class-name,.dark .md .token.boolean,.dark .md .token.constant,.dark .md .token.number,.dark .md .token.atrule{color:#d19a66}.dark .md .token.keyword{color:#c678dd}.dark .md .token.property,.dark .md .token.tag,.dark .md .token.symbol,.dark .md .token.deleted,.dark .md .token.important{color:#e06c75}.dark .md .token.selector,.dark .md .token.string,.dark .md .token.char,.dark .md .token.builtin,.dark .md .token.inserted,.dark .md .token.regex,.dark .md .token.attr-value,.dark .md .token.attr-value>.token.punctuation{color:#98c379}.dark .md .token.variable,.dark .md .token.operator,.dark .md .token.function{color:#61afef}.dark .md .token.url{color:#56b6c2}span.svelte-1m32c2s div[class*=code_wrap]{position:relative}span.svelte-1m32c2s span.katex{font-size:var(--text-lg);direction:ltr}span.svelte-1m32c2s div[class*=code_wrap]>button{z-index:1;cursor:pointer;border-bottom-left-radius:var(--radius-sm);padding:var(--spacing-md);width:25px;height:25px;position:absolute;right:0}span.svelte-1m32c2s .check{opacity:0;z-index:var(--layer-top);transition:opacity .2s;background:var(--code-background-fill);color:var(--body-text-color);position:absolute;top:var(--size-1-5);left:var(--size-1-5)}span.svelte-1m32c2s p:not(:first-child){margin-top:var(--spacing-xxl)}span.svelte-1m32c2s .md-header-anchor{margin-left:-25px;padding-right:8px;line-height:1;color:var(--body-text-color-subdued);opacity:0}span.svelte-1m32c2s h1:hover .md-header-anchor,span.svelte-1m32c2s h2:hover .md-header-anchor,span.svelte-1m32c2s h3:hover .md-header-anchor,span.svelte-1m32c2s h4:hover .md-header-anchor,span.svelte-1m32c2s h5:hover .md-header-anchor,span.svelte-1m32c2s h6:hover .md-header-anchor{opacity:1}span.md.svelte-1m32c2s .md-header-anchor>svg{color:var(--body-text-color-subdued)}span.svelte-1m32c2s table{word-break:break-word}div.svelte-17qq50w>.md.prose{font-weight:var(--block-info-text-weight);font-size:var(--block-info-text-size);line-height:var(--line-sm)}div.svelte-17qq50w>.md.prose *{color:var(--block-info-text-color)}div.svelte-17qq50w{margin-bottom:var(--spacing-md)}span.has-info.svelte-zgrq3{margin-bottom:var(--spacing-xs)}span.svelte-zgrq3:not(.has-info){margin-bottom:var(--spacing-lg)}span.svelte-zgrq3{display:inline-block;position:relative;z-index:var(--layer-4);border:solid var(--block-title-border-width) var(--block-title-border-color);border-radius:var(--block-title-radius);background:var(--block-title-background-fill);padding:var(--block-title-padding);color:var(--block-title-text-color);font-weight:var(--block-title-text-weight);font-size:var(--block-title-text-size);line-height:var(--line-sm)}span[dir=rtl].svelte-zgrq3{display:block}.hide.svelte-zgrq3{margin:0;height:0}label.svelte-igqdol.svelte-igqdol{display:inline-flex;align-items:center;z-index:var(--layer-2);box-shadow:var(--block-label-shadow);border:var(--block-label-border-width) solid var(--block-label-border-color);border-top:none;border-left:none;border-radius:var(--block-label-radius);background:var(--block-label-background-fill);padding:var(--block-label-padding);pointer-events:none;color:var(--block-label-text-color);font-weight:var(--block-label-text-weight);font-size:var(--block-label-text-size);line-height:var(--line-sm)}.gr-group label.svelte-igqdol.svelte-igqdol{border-top-left-radius:0}label.float.svelte-igqdol.svelte-igqdol{position:absolute;top:var(--block-label-margin);left:var(--block-label-margin)}label.svelte-igqdol.svelte-igqdol:not(.float){position:static;margin-top:var(--block-label-margin);margin-left:var(--block-label-margin)}.hide.svelte-igqdol.svelte-igqdol{display:none}span.svelte-igqdol.svelte-igqdol{opacity:.8;margin-right:var(--size-2);width:calc(var(--block-label-text-size) - 1px);height:calc(var(--block-label-text-size) - 1px)}.hide-label.svelte-igqdol.svelte-igqdol{box-shadow:none;border-width:0;background:transparent;overflow:visible}label[dir=rtl].svelte-igqdol.svelte-igqdol{border:var(--block-label-border-width) solid var(--block-label-border-color);border-top:none;border-right:none;border-bottom-left-radius:var(--block-radius);border-bottom-right-radius:var(--block-label-radius);border-top-left-radius:var(--block-label-radius)}label[dir=rtl].svelte-igqdol span.svelte-igqdol{margin-left:var(--size-2);margin-right:0}.unstyled-link.svelte-151nsdd{all:unset;cursor:pointer}button.svelte-y0enk4{display:flex;justify-content:center;align-items:center;gap:1px;z-index:var(--layer-2);border-radius:var(--radius-xs);color:var(--block-label-text-color);border:1px solid var(--border-color);padding:var(--spacing-xxs)}button.svelte-y0enk4:hover{background-color:var(--background-fill-secondary)}button[disabled].svelte-y0enk4{opacity:.5;box-shadow:none}button[disabled].svelte-y0enk4:hover{cursor:not-allowed}.padded.svelte-y0enk4{background:var(--bg-color)}button.svelte-y0enk4:hover,button.highlight.svelte-y0enk4{cursor:pointer;color:var(--color-accent)}.padded.svelte-y0enk4:hover{color:var(--block-label-text-color)}span.svelte-y0enk4{padding:0 1px;font-size:10px}div.svelte-y0enk4{display:flex;align-items:center;justify-content:center;transition:filter .2s ease-in-out}.x-small.svelte-y0enk4{width:10px;height:10px}.small.svelte-y0enk4{width:14px;height:14px}.medium.svelte-y0enk4{width:20px;height:20px}.large.svelte-y0enk4{width:22px;height:22px}.pending.svelte-y0enk4{animation:svelte-y0enk4-flash .5s infinite}@keyframes svelte-y0enk4-flash{0%{opacity:.5}50%{opacity:1}to{opacity:.5}}.transparent.svelte-y0enk4{background:transparent;border:none;box-shadow:none}.empty.svelte-3w3rth{display:flex;justify-content:center;align-items:center;margin-top:calc(0px - var(--size-6));height:var(--size-full)}.icon.svelte-3w3rth{opacity:.5;height:var(--size-5);color:var(--body-text-color)}.small.svelte-3w3rth{min-height:calc(var(--size-32) - 20px)}.large.svelte-3w3rth{min-height:calc(var(--size-64) - 20px)}.unpadded_box.svelte-3w3rth{margin-top:0}.small_parent.svelte-3w3rth{min-height:100%!important}.dropdown-arrow.svelte-145leq6,.dropdown-arrow.svelte-ihhdbf{fill:currentColor}.circle.svelte-ihhdbf{fill:currentColor;opacity:.1}svg.svelte-pb9pol{animation:svelte-pb9pol-spin 1.5s linear infinite}@keyframes svelte-pb9pol-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}h2.svelte-1xg7h5n{font-size:var(--text-xl)!important}p.svelte-1xg7h5n,h2.svelte-1xg7h5n{white-space:pre-line}.wrap.svelte-1xg7h5n{display:flex;flex-direction:column;justify-content:center;align-items:center;min-height:var(--size-60);color:var(--block-label-text-color);line-height:var(--line-md);height:100%;padding-top:var(--size-3);text-align:center;margin:auto var(--spacing-lg)}.or.svelte-1xg7h5n{color:var(--body-text-color-subdued);display:flex}.icon-wrap.svelte-1xg7h5n{width:30px;margin-bottom:var(--spacing-lg)}@media (--screen-md){.wrap.svelte-1xg7h5n{font-size:var(--text-lg)}}.hovered.svelte-1xg7h5n{color:var(--color-accent)}div.svelte-q32hvf{border-top:1px solid transparent;display:flex;max-height:100%;justify-content:center;align-items:center;gap:var(--spacing-sm);height:auto;align-items:flex-end;color:var(--block-label-text-color);flex-shrink:0}.show_border.svelte-q32hvf{border-top:1px solid var(--block-border-color);margin-top:var(--spacing-xxl);box-shadow:var(--shadow-drop)}.source-selection.svelte-15ls1gu{display:flex;align-items:center;justify-content:center;border-top:1px solid var(--border-color-primary);width:100%;margin-left:auto;margin-right:auto;height:var(--size-10)}.icon.svelte-15ls1gu{width:22px;height:22px;margin:var(--spacing-lg) var(--spacing-xs);padding:var(--spacing-xs);color:var(--neutral-400);border-radius:var(--radius-md)}.selected.svelte-15ls1gu{color:var(--color-accent)}.icon.svelte-15ls1gu:hover,.icon.svelte-15ls1gu:focus{color:var(--color-accent)}.icon-button-wrapper.svelte-1h0hs6p{display:flex;flex-direction:row;align-items:center;justify-content:center;z-index:var(--layer-2);gap:var(--spacing-sm);box-shadow:var(--shadow-drop);border:1px solid var(--border-color-primary);background:var(--block-background-fill);padding:var(--spacing-xxs)}.icon-button-wrapper.hide-top-corner.svelte-1h0hs6p{border-top:none;border-right:none;border-radius:var(--block-label-right-radius)}.icon-button-wrapper.display-top-corner.svelte-1h0hs6p{border-radius:var(--radius-sm) 0 0 var(--radius-sm);top:var(--spacing-sm);right:-1px}.icon-button-wrapper.svelte-1h0hs6p:not(.top-panel){border:1px solid var(--border-color-primary);border-radius:var(--radius-sm)}.top-panel.svelte-1h0hs6p{position:absolute;top:var(--block-label-margin);right:var(--block-label-margin);margin:0}.icon-button-wrapper.svelte-1h0hs6p button{margin:var(--spacing-xxs);border-radius:var(--radius-xs);position:relative}.icon-button-wrapper.svelte-1h0hs6p a.download-link:not(:last-child),.icon-button-wrapper.svelte-1h0hs6p button:not(:last-child){margin-right:var(--spacing-xxs)}.icon-button-wrapper.svelte-1h0hs6p a.download-link:not(:last-child):not(.no-border *):after,.icon-button-wrapper.svelte-1h0hs6p button:not(:last-child):not(.no-border *):after{content:"";position:absolute;right:-4.5px;top:15%;height:70%;width:1px;background-color:var(--border-color-primary)}.icon-button-wrapper.svelte-1h0hs6p>*{height:100%}svg.svelte-43sxxs.svelte-43sxxs{width:var(--size-20);height:var(--size-20)}svg.svelte-43sxxs path.svelte-43sxxs{fill:var(--loader-color)}div.svelte-43sxxs.svelte-43sxxs{z-index:var(--layer-2)}.margin.svelte-43sxxs.svelte-43sxxs{margin:var(--size-4)}.wrap.svelte-vusapu.svelte-vusapu{display:flex;flex-direction:column;justify-content:center;align-items:center;z-index:var(--layer-3);transition:opacity .1s ease-in-out;border-radius:var(--block-radius);background:var(--block-background-fill);padding:0 var(--size-6);overflow:hidden;pointer-events:none}.wrap.center.svelte-vusapu.svelte-vusapu{top:0;right:0;left:0}.wrap.default.svelte-vusapu.svelte-vusapu{top:0;right:0;bottom:0;left:0}.hide.svelte-vusapu.svelte-vusapu{opacity:0;pointer-events:none}.generating.svelte-vusapu.svelte-vusapu{animation:svelte-vusapu-pulseStart 1s cubic-bezier(.4,0,.6,1),svelte-vusapu-pulse 2s cubic-bezier(.4,0,.6,1) 1s infinite;border:2px solid var(--color-accent);background:transparent;z-index:var(--layer-1);pointer-events:none}.translucent.svelte-vusapu.svelte-vusapu{background:none}@keyframes svelte-vusapu-pulseStart{0%{opacity:0}to{opacity:1}}@keyframes svelte-vusapu-pulse{0%,to{opacity:1}50%{opacity:.5}}.loading.svelte-vusapu.svelte-vusapu{z-index:var(--layer-2);color:var(--body-text-color)}.eta-bar.svelte-vusapu.svelte-vusapu{position:absolute;top:0;right:0;bottom:0;left:0;transform-origin:left;opacity:.8;z-index:var(--layer-1);transition:10ms;background:var(--background-fill-secondary)}.progress-bar-wrap.svelte-vusapu.svelte-vusapu{border:1px solid var(--border-color-primary);background:var(--background-fill-primary);width:55.5%;height:var(--size-4)}.progress-bar.svelte-vusapu.svelte-vusapu{transform-origin:left;background-color:var(--loader-color);width:var(--size-full);height:var(--size-full)}.progress-level.svelte-vusapu.svelte-vusapu{display:flex;flex-direction:column;align-items:center;gap:1;z-index:var(--layer-2);width:var(--size-full)}.progress-level-inner.svelte-vusapu.svelte-vusapu{margin:var(--size-2) auto;color:var(--body-text-color);font-size:var(--text-sm);font-family:var(--font-mono)}.meta-text.svelte-vusapu.svelte-vusapu{position:absolute;bottom:0;right:0;z-index:var(--layer-2);padding:var(--size-1) var(--size-2);font-size:var(--text-sm);font-family:var(--font-mono)}.meta-text-center.svelte-vusapu.svelte-vusapu{display:flex;position:absolute;top:0;right:0;justify-content:center;align-items:center;transform:translateY(var(--size-6));z-index:var(--layer-2);padding:var(--size-1) var(--size-2);font-size:var(--text-sm);font-family:var(--font-mono);text-align:center}.error.svelte-vusapu.svelte-vusapu{box-shadow:var(--shadow-drop);border:solid 1px var(--error-border-color);border-radius:var(--radius-full);background:var(--error-background-fill);padding-right:var(--size-4);padding-left:var(--size-4);color:var(--error-text-color);font-weight:var(--weight-semibold);font-size:var(--text-lg);line-height:var(--line-lg);font-family:var(--font)}.validation-error.svelte-vusapu.svelte-vusapu{pointer-events:auto;color:var(--error-text-color);font-weight:var(--weight-semibold);font-size:var(--text-lg);line-height:var(--line-lg);font-family:var(--font);position:absolute;background:var(--error-background-fill);top:0;right:0;z-index:var(--layer-3);padding:var(--size-1) var(--size-2);font-size:var(--text-md);text-align:center;border-bottom-left-radius:var(--radius-sm);border-bottom:1px solid var(--error-border-color);border-left:1px solid var(--error-border-color);display:flex;justify-content:space-between;align-items:center;gap:var(--spacing-xl)}.minimal.svelte-vusapu.svelte-vusapu{pointer-events:none}.minimal.svelte-vusapu .progress-text.svelte-vusapu{background:var(--block-background-fill)}.border.svelte-vusapu.svelte-vusapu{border:1px solid var(--border-color-primary)}.clear-status.svelte-vusapu.svelte-vusapu{position:absolute;display:flex;top:var(--size-2);right:var(--size-2);justify-content:flex-end;gap:var(--spacing-sm);z-index:var(--layer-1)}.toast-body.svelte-syezpc{display:flex;position:relative;right:0;left:0;align-items:center;margin:var(--size-6) var(--size-4);margin:auto;border-radius:var(--container-radius);overflow:hidden;pointer-events:auto}.toast-body.error.svelte-syezpc{border:1px solid var(--color-red-700);background:var(--color-red-50)}.dark .toast-body.error.svelte-syezpc{border:1px solid var(--color-red-500);background-color:var(--color-grey-950)}.toast-body.warning.svelte-syezpc{border:1px solid var(--color-yellow-700);background:var(--color-yellow-50)}.dark .toast-body.warning.svelte-syezpc{border:1px solid var(--color-yellow-500);background-color:var(--color-grey-950)}.toast-body.info.svelte-syezpc{border:1px solid var(--color-grey-700);background:var(--color-grey-50)}.dark .toast-body.info.svelte-syezpc{border:1px solid var(--color-grey-500);background-color:var(--color-grey-950)}.toast-body.success.svelte-syezpc{border:1px solid var(--color-green-700);background:var(--color-green-50)}.dark .toast-body.success.svelte-syezpc{border:1px solid var(--color-green-500);background-color:var(--color-grey-950)}.toast-title.svelte-syezpc{display:flex;align-items:center;font-weight:var(--weight-bold);font-size:var(--text-lg);line-height:var(--line-sm)}.toast-title.error.svelte-syezpc{color:var(--color-red-700)}.dark .toast-title.error.svelte-syezpc{color:var(--color-red-50)}.toast-title.warning.svelte-syezpc{color:var(--color-yellow-700)}.dark .toast-title.warning.svelte-syezpc{color:var(--color-yellow-50)}.toast-title.info.svelte-syezpc{color:var(--color-grey-700)}.dark .toast-title.info.svelte-syezpc{color:var(--color-grey-50)}.toast-title.success.svelte-syezpc{color:var(--color-green-700)}.dark .toast-title.success.svelte-syezpc{color:var(--color-green-50)}.toast-close.svelte-syezpc{margin:0 var(--size-3);border-radius:var(--size-3);padding:0px var(--size-1-5);font-size:var(--size-5);line-height:var(--size-5)}.toast-close.error.svelte-syezpc{color:var(--color-red-700)}.dark .toast-close.error.svelte-syezpc{color:var(--color-red-500)}.toast-close.warning.svelte-syezpc{color:var(--color-yellow-700)}.dark .toast-close.warning.svelte-syezpc{color:var(--color-yellow-500)}.toast-close.info.svelte-syezpc{color:var(--color-grey-700)}.dark .toast-close.info.svelte-syezpc{color:var(--color-grey-500)}.toast-close.success.svelte-syezpc{color:var(--color-green-700)}.dark .toast-close.success.svelte-syezpc{color:var(--color-green-500)}.toast-text.svelte-syezpc{font-size:var(--text-lg);word-wrap:break-word;overflow-wrap:break-word;word-break:break-word}.toast-text.error.svelte-syezpc{color:var(--color-red-700)}.dark .toast-text.error.svelte-syezpc{color:var(--color-red-50)}.toast-text.warning.svelte-syezpc{color:var(--color-yellow-700)}.dark .toast-text.warning.svelte-syezpc{color:var(--color-yellow-50)}.toast-text.info.svelte-syezpc{color:var(--color-grey-700)}.dark .toast-text.info.svelte-syezpc{color:var(--color-grey-50)}.toast-text.success.svelte-syezpc{color:var(--color-green-700)}.dark .toast-text.success.svelte-syezpc{color:var(--color-green-50)}.toast-details.svelte-syezpc{margin:var(--size-3) var(--size-3) var(--size-3) 0;width:100%}.toast-icon.svelte-syezpc{display:flex;position:absolute;position:relative;flex-shrink:0;justify-content:center;align-items:center;margin:var(--size-2);border-radius:var(--radius-full);padding:var(--size-1);padding-left:calc(var(--size-1) - 1px);width:35px;height:35px}.toast-icon.error.svelte-syezpc{color:var(--color-red-700)}.dark .toast-icon.error.svelte-syezpc{color:var(--color-red-500)}.toast-icon.warning.svelte-syezpc{color:var(--color-yellow-700)}.dark .toast-icon.warning.svelte-syezpc{color:var(--color-yellow-500)}.toast-icon.info.svelte-syezpc{color:var(--color-grey-700)}.dark .toast-icon.info.svelte-syezpc{color:var(--color-grey-500)}.toast-icon.success.svelte-syezpc{color:var(--color-green-700)}.dark .toast-icon.success.svelte-syezpc{color:var(--color-green-500)}@keyframes svelte-syezpc-countdown{0%{transform:scaleX(1)}to{transform:scaleX(0)}}.timer.svelte-syezpc{position:absolute;bottom:0;left:0;transform-origin:0 0;animation:svelte-syezpc-countdown 10s linear forwards;width:100%;height:var(--size-1)}.timer.error.svelte-syezpc{background:var(--color-red-700)}.dark .timer.error.svelte-syezpc{background:var(--color-red-500)}.timer.warning.svelte-syezpc{background:var(--color-yellow-700)}.dark .timer.warning.svelte-syezpc{background:var(--color-yellow-500)}.timer.info.svelte-syezpc{background:var(--color-grey-700)}.dark .timer.info.svelte-syezpc{background:var(--color-grey-500)}.timer.success.svelte-syezpc{background:var(--color-green-700)}.dark .timer.success.svelte-syezpc{background:var(--color-green-500)}.hidden.svelte-syezpc{display:none}.toast-text.svelte-syezpc a{text-decoration:underline}.toast-wrap.svelte-je2isz{--toast-top:var(--size-4);display:flex;position:fixed;top:calc(var(--toast-top) + var(--size-4));right:var(--size-4);flex-direction:column;align-items:end;gap:var(--size-2);z-index:var(--layer-top);width:calc(100% - var(--size-8))}@media (--screen-sm){.toast-wrap.svelte-je2isz{width:calc(var(--size-96) + var(--size-10))}}.streaming-bar.svelte-ga0jj6{position:absolute;bottom:0;left:0;right:0;height:4px;background-color:var(--primary-600);animation:svelte-ga0jj6-countdown linear forwards;z-index:1}@keyframes svelte-ga0jj6-countdown{0%{transform:translate(0)}to{transform:translate(-100%)}}.container.svelte-1i532j3{display:flex;position:relative;flex-direction:column;justify-content:center;align-items:center;width:100%;height:100%}.canvas-container.svelte-1i532j3{position:relative;width:100%;height:100%;min-height:400px;overflow:hidden;display:flex;justify-content:center;align-items:center;background-color:#f0f0f0}.canvas-container canvas{display:block;width:100%;height:100%;object-fit:contain}
src/backend/gradio_polygonannotator/templates/component/webworkerAll-FY7_jo4S.js ADDED
The diff for this file is too large to render. See raw diff
 
src/backend/gradio_polygonannotator/templates/example/index.js ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const {
2
+ SvelteComponent: q,
3
+ append_hydration: u,
4
+ attr: c,
5
+ children: I,
6
+ claim_element: h,
7
+ claim_space: D,
8
+ claim_text: _,
9
+ detach: g,
10
+ element: m,
11
+ empty: v,
12
+ init: V,
13
+ insert_hydration: p,
14
+ noop: y,
15
+ safe_not_equal: C,
16
+ set_data: b,
17
+ space: G,
18
+ src_url_equal: k,
19
+ text: d,
20
+ toggle_class: r
21
+ } = window.__gradio__svelte__internal;
22
+ function w(a) {
23
+ let e, l, o, s, t = (
24
+ /*value*/
25
+ a[0].polygons && /*value*/
26
+ a[0].polygons.length > 0 && E(a)
27
+ );
28
+ return {
29
+ c() {
30
+ e = m("div"), l = m("img"), s = G(), t && t.c(), this.h();
31
+ },
32
+ l(n) {
33
+ e = h(n, "DIV", { class: !0 });
34
+ var i = I(e);
35
+ l = h(i, "IMG", { src: !0, alt: !0, class: !0 }), s = D(i), t && t.l(i), i.forEach(g), this.h();
36
+ },
37
+ h() {
38
+ k(l.src, o = /*value*/
39
+ a[0].image.url || /*value*/
40
+ a[0].image.path) || c(l, "src", o), c(l, "alt", ""), c(l, "class", "svelte-84dw5"), c(e, "class", "container svelte-84dw5"), r(
41
+ e,
42
+ "table",
43
+ /*type*/
44
+ a[1] === "table"
45
+ ), r(
46
+ e,
47
+ "gallery",
48
+ /*type*/
49
+ a[1] === "gallery"
50
+ ), r(
51
+ e,
52
+ "selected",
53
+ /*selected*/
54
+ a[2]
55
+ );
56
+ },
57
+ m(n, i) {
58
+ p(n, e, i), u(e, l), u(e, s), t && t.m(e, null);
59
+ },
60
+ p(n, i) {
61
+ i & /*value*/
62
+ 1 && !k(l.src, o = /*value*/
63
+ n[0].image.url || /*value*/
64
+ n[0].image.path) && c(l, "src", o), /*value*/
65
+ n[0].polygons && /*value*/
66
+ n[0].polygons.length > 0 ? t ? t.p(n, i) : (t = E(n), t.c(), t.m(e, null)) : t && (t.d(1), t = null), i & /*type*/
67
+ 2 && r(
68
+ e,
69
+ "table",
70
+ /*type*/
71
+ n[1] === "table"
72
+ ), i & /*type*/
73
+ 2 && r(
74
+ e,
75
+ "gallery",
76
+ /*type*/
77
+ n[1] === "gallery"
78
+ ), i & /*selected*/
79
+ 4 && r(
80
+ e,
81
+ "selected",
82
+ /*selected*/
83
+ n[2]
84
+ );
85
+ },
86
+ d(n) {
87
+ n && g(e), t && t.d();
88
+ }
89
+ };
90
+ }
91
+ function E(a) {
92
+ let e, l = (
93
+ /*value*/
94
+ a[0].polygons.length + ""
95
+ ), o, s, t = (
96
+ /*value*/
97
+ a[0].polygons.length !== 1 ? "s" : ""
98
+ ), n;
99
+ return {
100
+ c() {
101
+ e = m("div"), o = d(l), s = d(" polygon"), n = d(t), this.h();
102
+ },
103
+ l(i) {
104
+ e = h(i, "DIV", { class: !0 });
105
+ var f = I(e);
106
+ o = _(f, l), s = _(f, " polygon"), n = _(f, t), f.forEach(g), this.h();
107
+ },
108
+ h() {
109
+ c(e, "class", "polygon-count svelte-84dw5");
110
+ },
111
+ m(i, f) {
112
+ p(i, e, f), u(e, o), u(e, s), u(e, n);
113
+ },
114
+ p(i, f) {
115
+ f & /*value*/
116
+ 1 && l !== (l = /*value*/
117
+ i[0].polygons.length + "") && b(o, l), f & /*value*/
118
+ 1 && t !== (t = /*value*/
119
+ i[0].polygons.length !== 1 ? "s" : "") && b(n, t);
120
+ },
121
+ d(i) {
122
+ i && g(e);
123
+ }
124
+ };
125
+ }
126
+ function M(a) {
127
+ var o;
128
+ let e, l = (
129
+ /*value*/
130
+ ((o = a[0]) == null ? void 0 : o.image) && w(a)
131
+ );
132
+ return {
133
+ c() {
134
+ l && l.c(), e = v();
135
+ },
136
+ l(s) {
137
+ l && l.l(s), e = v();
138
+ },
139
+ m(s, t) {
140
+ l && l.m(s, t), p(s, e, t);
141
+ },
142
+ p(s, [t]) {
143
+ var n;
144
+ /*value*/
145
+ (n = s[0]) != null && n.image ? l ? l.p(s, t) : (l = w(s), l.c(), l.m(e.parentNode, e)) : l && (l.d(1), l = null);
146
+ },
147
+ i: y,
148
+ o: y,
149
+ d(s) {
150
+ s && g(e), l && l.d(s);
151
+ }
152
+ };
153
+ }
154
+ function N(a, e, l) {
155
+ let { value: o } = e, { type: s } = e, { selected: t = !1 } = e;
156
+ const n = 0;
157
+ return a.$$set = (i) => {
158
+ "value" in i && l(0, o = i.value), "type" in i && l(1, s = i.type), "selected" in i && l(2, t = i.selected);
159
+ }, [o, s, t, n];
160
+ }
161
+ class S extends q {
162
+ constructor(e) {
163
+ super(), V(this, e, N, M, C, { value: 0, type: 1, selected: 2, index: 3 });
164
+ }
165
+ get index() {
166
+ return this.$$.ctx[3];
167
+ }
168
+ }
169
+ export {
170
+ S as default
171
+ };
src/backend/gradio_polygonannotator/templates/example/style.css ADDED
@@ -0,0 +1 @@
 
 
1
+ .container.svelte-84dw5 img{width:100%;height:100%}.container.selected.svelte-84dw5.svelte-84dw5{border-color:var(--border-color-accent)}.container.table.svelte-84dw5.svelte-84dw5{margin:0 auto;border:2px solid var(--border-color-primary);border-radius:var(--radius-lg);overflow:hidden;width:var(--size-20);height:var(--size-20);object-fit:cover}.container.gallery.svelte-84dw5.svelte-84dw5{height:var(--size-20);max-height:var(--size-20);object-fit:cover}.container.svelte-84dw5 img.svelte-84dw5{object-fit:cover}.polygon-count.svelte-84dw5.svelte-84dw5{position:absolute;bottom:4px;right:4px;background:#000000b3;color:#fff;padding:2px 6px;border-radius:3px;font-size:11px;font-weight:500}.container.svelte-84dw5.svelte-84dw5{position:relative}
src/demo/__init__.py ADDED
File without changes
src/demo/app.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from gradio_polygonannotator import PolygonAnnotator
3
+
4
+ # Example with document regions
5
+ example_data = {
6
+ "image": "https://images.unsplash.com/photo-1544816155-12df9643f363?w=800&h=1200",
7
+ "polygons": [
8
+ {
9
+ "id": "title",
10
+ "coordinates": [[180, 150], [580, 150], [580, 200], [180, 200]],
11
+ "color": "#FF6B6B",
12
+ "mask_opacity": 0.15,
13
+ "stroke_width": 1.0,
14
+ "stroke_opacity": 0.8,
15
+ },
16
+ {
17
+ "id": "paragraph_1",
18
+ "coordinates": [[100, 400], [750, 400], [750, 600], [100, 600]],
19
+ "color": "#4ECDC4",
20
+ "mask_opacity": 0.15,
21
+ "stroke_width": 0.7,
22
+ "stroke_opacity": 0.6,
23
+ },
24
+ {
25
+ "id": "paragraph_2",
26
+ "coordinates": [[100, 650], [750, 650], [750, 950], [100, 950]],
27
+ "color": "#4ECDC4",
28
+ "mask_opacity": 0.15,
29
+ "stroke_width": 0.7,
30
+ "stroke_opacity": 0.6,
31
+ },
32
+ {
33
+ "id": "signature",
34
+ "coordinates": [[400, 1020], [650, 1020], [650, 1080], [400, 1080]],
35
+ "color": "#FFE66D",
36
+ "mask_opacity": 0.2,
37
+ "stroke_width": 1.5,
38
+ "stroke_opacity": 0.8,
39
+ }
40
+ ]
41
+ }
42
+
43
+ def handle_selection(data, evt: gr.SelectData):
44
+ """Handle polygon selection and display info"""
45
+ if evt.value and data:
46
+ selected_ids = evt.value if isinstance(evt.value, list) else [evt.value]
47
+ info = f"Selected {len(selected_ids)} polygon(s):\n"
48
+ for poly_id in selected_ids:
49
+ polygon = next((p for p in data["polygons"] if p["id"] == poly_id), None)
50
+ if polygon:
51
+ info += f"• {poly_id}\n"
52
+ return info
53
+ return "Click on polygons to select them. Use Ctrl/Cmd+Click for multi-selection."
54
+
55
+ with gr.Blocks() as demo:
56
+ gr.Markdown("""
57
+ # PolygonAnnotator - Interactive Polygon Selection
58
+
59
+ Click on polygons to select them. Use **Ctrl/Cmd+Click** for multiple selections.
60
+ Click selected polygons to deselect.
61
+ """)
62
+
63
+ with gr.Row():
64
+ with gr.Column(scale=3):
65
+ annotator = PolygonAnnotator(
66
+ value=example_data,
67
+ label="Document with Region Annotations",
68
+ height=600,
69
+ )
70
+
71
+ with gr.Column(scale=1):
72
+ selected_info = gr.Textbox(
73
+ label="Selected Regions",
74
+ lines=6,
75
+ value="Click on polygons to select them. Use Ctrl/Cmd+Click for multi-selection."
76
+ )
77
+
78
+ # Handle selection events
79
+ annotator.select(
80
+ handle_selection,
81
+ inputs=[annotator],
82
+ outputs=[selected_info]
83
+ )
84
+
85
+ if __name__ == "__main__":
86
+ demo.launch()
src/demo/css.css ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ html {
2
+ font-family: Inter;
3
+ font-size: 16px;
4
+ font-weight: 400;
5
+ line-height: 1.5;
6
+ -webkit-text-size-adjust: 100%;
7
+ background: #fff;
8
+ color: #323232;
9
+ -webkit-font-smoothing: antialiased;
10
+ -moz-osx-font-smoothing: grayscale;
11
+ text-rendering: optimizeLegibility;
12
+ }
13
+
14
+ :root {
15
+ --space: 1;
16
+ --vspace: calc(var(--space) * 1rem);
17
+ --vspace-0: calc(3 * var(--space) * 1rem);
18
+ --vspace-1: calc(2 * var(--space) * 1rem);
19
+ --vspace-2: calc(1.5 * var(--space) * 1rem);
20
+ --vspace-3: calc(0.5 * var(--space) * 1rem);
21
+ }
22
+
23
+ .app {
24
+ max-width: 748px !important;
25
+ }
26
+
27
+ .prose p {
28
+ margin: var(--vspace) 0;
29
+ line-height: var(--vspace * 2);
30
+ font-size: 1rem;
31
+ }
32
+
33
+ code {
34
+ font-family: "Inconsolata", sans-serif;
35
+ font-size: 16px;
36
+ }
37
+
38
+ h1,
39
+ h1 code {
40
+ font-weight: 400;
41
+ line-height: calc(2.5 / var(--space) * var(--vspace));
42
+ }
43
+
44
+ h1 code {
45
+ background: none;
46
+ border: none;
47
+ letter-spacing: 0.05em;
48
+ padding-bottom: 5px;
49
+ position: relative;
50
+ padding: 0;
51
+ }
52
+
53
+ h2 {
54
+ margin: var(--vspace-1) 0 var(--vspace-2) 0;
55
+ line-height: 1em;
56
+ }
57
+
58
+ h3,
59
+ h3 code {
60
+ margin: var(--vspace-1) 0 var(--vspace-2) 0;
61
+ line-height: 1em;
62
+ }
63
+
64
+ h4,
65
+ h5,
66
+ h6 {
67
+ margin: var(--vspace-3) 0 var(--vspace-3) 0;
68
+ line-height: var(--vspace);
69
+ }
70
+
71
+ .bigtitle,
72
+ h1,
73
+ h1 code {
74
+ font-size: calc(8px * 4.5);
75
+ word-break: break-word;
76
+ }
77
+
78
+ .title,
79
+ h2,
80
+ h2 code {
81
+ font-size: calc(8px * 3.375);
82
+ font-weight: lighter;
83
+ word-break: break-word;
84
+ border: none;
85
+ background: none;
86
+ }
87
+
88
+ .subheading1,
89
+ h3,
90
+ h3 code {
91
+ font-size: calc(8px * 1.8);
92
+ font-weight: 600;
93
+ border: none;
94
+ background: none;
95
+ letter-spacing: 0.1em;
96
+ text-transform: uppercase;
97
+ }
98
+
99
+ h2 code {
100
+ padding: 0;
101
+ position: relative;
102
+ letter-spacing: 0.05em;
103
+ }
104
+
105
+ blockquote {
106
+ font-size: calc(8px * 1.1667);
107
+ font-style: italic;
108
+ line-height: calc(1.1667 * var(--vspace));
109
+ margin: var(--vspace-2) var(--vspace-2);
110
+ }
111
+
112
+ .subheading2,
113
+ h4 {
114
+ font-size: calc(8px * 1.4292);
115
+ text-transform: uppercase;
116
+ font-weight: 600;
117
+ }
118
+
119
+ .subheading3,
120
+ h5 {
121
+ font-size: calc(8px * 1.2917);
122
+ line-height: calc(1.2917 * var(--vspace));
123
+
124
+ font-weight: lighter;
125
+ text-transform: uppercase;
126
+ letter-spacing: 0.15em;
127
+ }
128
+
129
+ h6 {
130
+ font-size: calc(8px * 1.1667);
131
+ font-size: 1.1667em;
132
+ font-weight: normal;
133
+ font-style: italic;
134
+ font-family: "le-monde-livre-classic-byol", serif !important;
135
+ letter-spacing: 0px !important;
136
+ }
137
+
138
+ #start .md > *:first-child {
139
+ margin-top: 0;
140
+ }
141
+
142
+ h2 + h3 {
143
+ margin-top: 0;
144
+ }
145
+
146
+ .md hr {
147
+ border: none;
148
+ border-top: 1px solid var(--block-border-color);
149
+ margin: var(--vspace-2) 0 var(--vspace-2) 0;
150
+ }
151
+ .prose ul {
152
+ margin: var(--vspace-2) 0 var(--vspace-1) 0;
153
+ }
154
+
155
+ .gap {
156
+ gap: 0;
157
+ }
src/demo/space.py ADDED
@@ -0,0 +1,208 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ from app import demo as app
4
+ import os
5
+
6
+ _docs = {'PolygonAnnotator': {'description': 'Interactive polygon annotation component for visualizing and selecting polygon regions on images.\n\nThe PolygonAnnotator displays an image with customizable polygon overlays that users can interact with.\nFeatures include multi-selection with Ctrl/Cmd+click, hover effects, and customizable appearance including\nstroke width, opacity settings for both fill and stroke, with separate settings for selected states.\n\nPerfect for:\n- Document layout analysis and region selection\n- Image segmentation visualization\n- Interactive annotation review and editing\n- Object detection result visualization', 'members': {'__init__': {'value': {'type': 'dict | None', 'default': 'None', 'description': "Dictionary containing 'image' (FileData), 'polygons' (list with id, coordinates, color, opacities),"}, 'label': {'type': 'str | I18nData | None', 'default': 'None', 'description': 'Component label shown above the annotator.'}, 'every': {'type': 'Timer | float | None', 'default': 'None', 'description': 'Continuously calls `value` to recalculate it if `value` is a function.'}, 'inputs': {'type': 'Component | Sequence[Component] | set[Component] | None', 'default': 'None', 'description': "Components used as inputs to calculate `value` if it's a function."}, 'show_label': {'type': 'bool | None', 'default': 'None', 'description': 'Whether to display the label.'}, 'show_download_button': {'type': 'bool', 'default': 'True', 'description': 'Whether to show image download button.'}, 'height': {'type': 'int | str | None', 'default': 'None', 'description': 'Component height in pixels or CSS units.'}, 'width': {'type': 'int | str | None', 'default': 'None', 'description': 'Component width in pixels or CSS units.'}, 'container': {'type': 'bool', 'default': 'True', 'description': 'Whether to wrap component in a container with padding.'}, 'scale': {'type': 'int | None', 'default': 'None', 'description': 'Relative size compared to adjacent components.'}, 'min_width': {'type': 'int', 'default': '160', 'description': 'Minimum pixel width before wrapping.'}, 'interactive': {'type': 'bool | None', 'default': 'None', 'description': 'Whether users can interact with polygons (selection/deselection).'}, 'visible': {'type': 'bool | Literal["hidden"]', 'default': 'True', 'description': 'Whether component is visible ("hidden" keeps it in DOM but invisible).'}, 'elem_id': {'type': 'str | None', 'default': 'None', 'description': 'HTML DOM id for CSS targeting.'}, 'elem_classes': {'type': 'list[str] | str | None', 'default': 'None', 'description': 'HTML DOM classes for CSS targeting.'}, 'render': {'type': 'bool', 'default': 'True', 'description': 'Whether to render the component immediately.'}, 'key': {'type': 'int | str | tuple[int | str, ...] | None', 'default': 'None', 'description': 'Key for maintaining component identity across re-renders.'}, 'preserved_by_key': {'type': 'list[str] | str | None', 'default': '"value"', 'description': 'Parameters preserved across re-renders with same key.'}}, 'postprocess': {'value': {'type': 'dict | None', 'description': "Dictionary containing 'image' (file path or URL), 'polygons' (list of polygon dictionaries"}}, 'preprocess': {'return': {'type': 'dict | None', 'description': 'Dictionary with image path, polygon data including coordinates, colors, opacities,'}, 'value': None}}, 'events': {'clear': {'type': None, 'default': None, 'description': 'This listener is triggered when the user clears the PolygonAnnotator using the clear button for the component.'}, 'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the PolygonAnnotator changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}, 'upload': {'type': None, 'default': None, 'description': 'This listener is triggered when the user uploads a file into the PolygonAnnotator.'}, 'select': {'type': None, 'default': None, 'description': 'Event listener for when the user selects or deselects the PolygonAnnotator. Uses event data gradio.SelectData to carry `value` referring to the label of the PolygonAnnotator, and `selected` to refer to state of the PolygonAnnotator. See EventData documentation on how to use this event data'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'PolygonAnnotator': []}}}
7
+
8
+ abs_path = os.path.join(os.path.dirname(__file__), "css.css")
9
+
10
+ with gr.Blocks(
11
+ css=abs_path,
12
+ theme=gr.themes.Default(
13
+ font_mono=[
14
+ gr.themes.GoogleFont("Inconsolata"),
15
+ "monospace",
16
+ ],
17
+ ),
18
+ ) as demo:
19
+ gr.Markdown(
20
+ """
21
+ # `gradio_polygonannotator`
22
+
23
+ <div style="display: flex; gap: 7px;">
24
+ <img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.1.0%20-%20orange"> <a href="https://github.com/yourusername/gradio-polygonannotator/issues" target="_blank"><img alt="Static Badge" src="https://img.shields.io/badge/Issues-white?logo=github&logoColor=black"></a>
25
+ </div>
26
+
27
+ Interactive polygon annotation component for Gradio with multi-selection, hover effects, and customizable appearance
28
+ """, elem_classes=["md-custom"], header_links=True)
29
+ app.render()
30
+ gr.Markdown(
31
+ """
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install gradio_polygonannotator
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```python
41
+ import gradio as gr
42
+ from gradio_polygonannotator import PolygonAnnotator
43
+
44
+ # Example with document regions
45
+ example_data = {
46
+ "image": "https://images.unsplash.com/photo-1544816155-12df9643f363?w=800&h=1200",
47
+ "polygons": [
48
+ {
49
+ "id": "title",
50
+ "coordinates": [[180, 150], [580, 150], [580, 200], [180, 200]],
51
+ "color": "#FF6B6B",
52
+ "mask_opacity": 0.15,
53
+ "stroke_width": 1.0,
54
+ "stroke_opacity": 0.8,
55
+ },
56
+ {
57
+ "id": "paragraph_1",
58
+ "coordinates": [[100, 400], [750, 400], [750, 600], [100, 600]],
59
+ "color": "#4ECDC4",
60
+ "mask_opacity": 0.15,
61
+ "stroke_width": 0.7,
62
+ "stroke_opacity": 0.6,
63
+ },
64
+ {
65
+ "id": "paragraph_2",
66
+ "coordinates": [[100, 650], [750, 650], [750, 950], [100, 950]],
67
+ "color": "#4ECDC4",
68
+ "mask_opacity": 0.15,
69
+ "stroke_width": 0.7,
70
+ "stroke_opacity": 0.6,
71
+ },
72
+ {
73
+ "id": "signature",
74
+ "coordinates": [[400, 1020], [650, 1020], [650, 1080], [400, 1080]],
75
+ "color": "#FFE66D",
76
+ "mask_opacity": 0.2,
77
+ "stroke_width": 1.5,
78
+ "stroke_opacity": 0.8,
79
+ }
80
+ ]
81
+ }
82
+
83
+ def handle_selection(data, evt: gr.SelectData):
84
+ \"\"\"Handle polygon selection and display info\"\"\"
85
+ if evt.value and data:
86
+ selected_ids = evt.value if isinstance(evt.value, list) else [evt.value]
87
+ info = f"Selected {len(selected_ids)} polygon(s):\n"
88
+ for poly_id in selected_ids:
89
+ polygon = next((p for p in data["polygons"] if p["id"] == poly_id), None)
90
+ if polygon:
91
+ info += f"• {poly_id}\n"
92
+ return info
93
+ return "Click on polygons to select them. Use Ctrl/Cmd+Click for multi-selection."
94
+
95
+ with gr.Blocks() as demo:
96
+ gr.Markdown(\"\"\"
97
+ # PolygonAnnotator - Interactive Polygon Selection
98
+
99
+ Click on polygons to select them. Use **Ctrl/Cmd+Click** for multiple selections.
100
+ Click selected polygons to deselect.
101
+ \"\"\")
102
+
103
+ with gr.Row():
104
+ with gr.Column(scale=3):
105
+ annotator = PolygonAnnotator(
106
+ value=example_data,
107
+ label="Document with Region Annotations",
108
+ height=600,
109
+ )
110
+
111
+ with gr.Column(scale=1):
112
+ selected_info = gr.Textbox(
113
+ label="Selected Regions",
114
+ lines=6,
115
+ value="Click on polygons to select them. Use Ctrl/Cmd+Click for multi-selection."
116
+ )
117
+
118
+ # Handle selection events
119
+ annotator.select(
120
+ handle_selection,
121
+ inputs=[annotator],
122
+ outputs=[selected_info]
123
+ )
124
+
125
+ if __name__ == "__main__":
126
+ demo.launch()
127
+
128
+ ```
129
+ """, elem_classes=["md-custom"], header_links=True)
130
+
131
+
132
+ gr.Markdown("""
133
+ ## `PolygonAnnotator`
134
+
135
+ ### Initialization
136
+ """, elem_classes=["md-custom"], header_links=True)
137
+
138
+ gr.ParamViewer(value=_docs["PolygonAnnotator"]["members"]["__init__"], linkify=[])
139
+
140
+
141
+ gr.Markdown("### Events")
142
+ gr.ParamViewer(value=_docs["PolygonAnnotator"]["events"], linkify=['Event'])
143
+
144
+
145
+
146
+
147
+ gr.Markdown("""
148
+
149
+ ### User function
150
+
151
+ The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
152
+
153
+ - When used as an Input, the component only impacts the input signature of the user function.
154
+ - When used as an output, the component only impacts the return signature of the user function.
155
+
156
+ The code snippet below is accurate in cases where the component is used as both an input and an output.
157
+
158
+ - **As input:** Is passed, dictionary with image path, polygon data including coordinates, colors, opacities,.
159
+ - **As output:** Should return, dictionary containing 'image' (file path or URL), 'polygons' (list of polygon dictionaries.
160
+
161
+ ```python
162
+ def predict(
163
+ value: dict | None
164
+ ) -> dict | None:
165
+ return value
166
+ ```
167
+ """, elem_classes=["md-custom", "PolygonAnnotator-user-fn"], header_links=True)
168
+
169
+
170
+
171
+
172
+ demo.load(None, js=r"""function() {
173
+ const refs = {};
174
+ const user_fn_refs = {
175
+ PolygonAnnotator: [], };
176
+ requestAnimationFrame(() => {
177
+
178
+ Object.entries(user_fn_refs).forEach(([key, refs]) => {
179
+ if (refs.length > 0) {
180
+ const el = document.querySelector(`.${key}-user-fn`);
181
+ if (!el) return;
182
+ refs.forEach(ref => {
183
+ el.innerHTML = el.innerHTML.replace(
184
+ new RegExp("\\b"+ref+"\\b", "g"),
185
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
186
+ );
187
+ })
188
+ }
189
+ })
190
+
191
+ Object.entries(refs).forEach(([key, refs]) => {
192
+ if (refs.length > 0) {
193
+ const el = document.querySelector(`.${key}`);
194
+ if (!el) return;
195
+ refs.forEach(ref => {
196
+ el.innerHTML = el.innerHTML.replace(
197
+ new RegExp("\\b"+ref+"\\b", "g"),
198
+ `<a href="#h-${ref.toLowerCase()}">${ref}</a>`
199
+ );
200
+ })
201
+ }
202
+ })
203
+ })
204
+ }
205
+
206
+ """)
207
+
208
+ demo.launch()
src/frontend/Example.svelte ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { FileData } from "@gradio/client";
3
+
4
+ export let value: null | { image: FileData; polygons: Array<{id: string, coordinates: number[][], color: string}> };
5
+ export let type: "gallery" | "table";
6
+ export let selected = false;
7
+ export const index: number = 0;
8
+ </script>
9
+
10
+ {#if value?.image}
11
+ <div
12
+ class="container"
13
+ class:table={type === "table"}
14
+ class:gallery={type === "gallery"}
15
+ class:selected
16
+ >
17
+ <img src={value.image.url || value.image.path} alt="" />
18
+ {#if value.polygons && value.polygons.length > 0}
19
+ <div class="polygon-count">
20
+ {value.polygons.length} polygon{value.polygons.length !== 1 ? 's' : ''}
21
+ </div>
22
+ {/if}
23
+ </div>
24
+ {/if}
25
+
26
+ <style>
27
+ .container :global(img) {
28
+ width: 100%;
29
+ height: 100%;
30
+ }
31
+
32
+ .container.selected {
33
+ border-color: var(--border-color-accent);
34
+ }
35
+
36
+ .container.table {
37
+ margin: 0 auto;
38
+ border: 2px solid var(--border-color-primary);
39
+ border-radius: var(--radius-lg);
40
+ overflow: hidden;
41
+ width: var(--size-20);
42
+ height: var(--size-20);
43
+ object-fit: cover;
44
+ }
45
+
46
+ .container.gallery {
47
+ height: var(--size-20);
48
+ max-height: var(--size-20);
49
+ object-fit: cover;
50
+ }
51
+ .container img {
52
+ object-fit: cover;
53
+ }
54
+
55
+ .polygon-count {
56
+ position: absolute;
57
+ bottom: 4px;
58
+ right: 4px;
59
+ background: rgba(0, 0, 0, 0.7);
60
+ color: white;
61
+ padding: 2px 6px;
62
+ border-radius: 3px;
63
+ font-size: 11px;
64
+ font-weight: 500;
65
+ }
66
+
67
+ .container {
68
+ position: relative;
69
+ }
70
+ </style>
src/frontend/Index.svelte ADDED
@@ -0,0 +1,465 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <svelte:options accessors={true} />
2
+
3
+ <script lang="ts">
4
+ import { onMount, onDestroy, tick } from "svelte";
5
+ import * as PIXI from "pixi.js";
6
+ import type { Gradio } from "@gradio/utils";
7
+ import { Block, BlockLabel } from "@gradio/atoms";
8
+ import { Image as ImageIcon } from "@gradio/icons";
9
+ import { StatusTracker } from "@gradio/statustracker";
10
+ import type { LoadingStatus } from "@gradio/statustracker";
11
+ import type { FileData } from "@gradio/client";
12
+
13
+ export let elem_id = "";
14
+ export let elem_classes: string[] = [];
15
+ export let visible: boolean | "hidden" = true;
16
+ export let value: {
17
+ image: FileData;
18
+ polygons: Array<{
19
+ id: string;
20
+ coordinates: number[][];
21
+ color: string;
22
+ mask_opacity?: number;
23
+ stroke_width?: number;
24
+ stroke_opacity?: number;
25
+ selected_mask_opacity?: number;
26
+ selected_stroke_opacity?: number;
27
+ }>;
28
+ selected_polygons?: string[] | null;
29
+ } | null = null;
30
+ export let label: string;
31
+ export let show_label: boolean;
32
+ export let height: number | string | undefined = undefined;
33
+ export let width: number | string | undefined = undefined;
34
+ export let container = true;
35
+ export let scale: number | null = null;
36
+ export let min_width: number | undefined = undefined;
37
+ export let loading_status: LoadingStatus;
38
+ export let root: string;
39
+
40
+ export let gradio: Gradio<{
41
+ change: never;
42
+ upload: never;
43
+ clear: never;
44
+ select: { index: number | null; value: any };
45
+ clear_status: LoadingStatus;
46
+ }>;
47
+
48
+ let canvasContainer: HTMLDivElement;
49
+ let app: PIXI.Application;
50
+ let imageSprite: PIXI.Sprite | null = null;
51
+ let polygonGraphics: Map<string, PIXI.Graphics> = new Map();
52
+ let selectedPolygonIds: string[] = [];
53
+ type ImageRect = {
54
+ left: number;
55
+ top: number;
56
+ right: number;
57
+ bottom: number;
58
+ width: number;
59
+ height: number;
60
+ naturalWidth: number;
61
+ naturalHeight: number;
62
+ };
63
+ let imageRect: ImageRect = {
64
+ left: 0,
65
+ top: 0,
66
+ right: 1,
67
+ bottom: 1,
68
+ width: 1,
69
+ height: 1,
70
+ naturalWidth: 2,
71
+ naturalHeight: 2,
72
+ };
73
+
74
+ $: (value, handleValueChange());
75
+
76
+ async function handleValueChange() {
77
+ if (!app || !value) return;
78
+ selectedPolygonIds = value.selected_polygons || [];
79
+ await renderAnnotations();
80
+ }
81
+
82
+ function updateSelection(newSelectedIds: string[]) {
83
+ if (!value || !imageSprite) return;
84
+
85
+ polygonGraphics.forEach((graphics, polygonId) => {
86
+ const polygon = value.polygons.find((p) => p.id === polygonId);
87
+ if (!polygon) return;
88
+
89
+ const originalMaskAlpha = polygon.mask_opacity ?? 0.2;
90
+ const selectedMaskAlpha = polygon.selected_mask_opacity ?? 0.5;
91
+ const originalStrokeAlpha = polygon.stroke_opacity ?? 0.6;
92
+ const selectedStrokeAlpha = polygon.selected_stroke_opacity ?? 1.0;
93
+ const strokeWidth = polygon.stroke_width ?? 0.7;
94
+
95
+ graphics.clear();
96
+ if (newSelectedIds.includes(polygonId)) {
97
+ drawPolygonPath(graphics, polygon, imageSprite!, selectedMaskAlpha, strokeWidth, selectedStrokeAlpha);
98
+ } else {
99
+ drawPolygonPath(graphics, polygon, imageSprite!, originalMaskAlpha, strokeWidth, originalStrokeAlpha);
100
+ }
101
+ });
102
+ }
103
+
104
+ async function initPixiApp() {
105
+ if (!canvasContainer) return;
106
+
107
+ const containerWidth = canvasContainer.clientWidth || 800;
108
+ const containerHeight = canvasContainer.clientHeight || 600;
109
+
110
+ app = new PIXI.Application();
111
+ await app.init({
112
+ width: containerWidth,
113
+ height: containerHeight,
114
+ backgroundColor: 0xf0f0f0,
115
+ antialias: true,
116
+ resolution: window.devicePixelRatio || 1,
117
+ autoDensity: true,
118
+ });
119
+
120
+ canvasContainer.appendChild(app.canvas as HTMLCanvasElement);
121
+
122
+ app.stage.eventMode = "static";
123
+ app.stage.hitArea = app.screen;
124
+ }
125
+
126
+ async function renderAnnotations() {
127
+ if (!app || !value) return;
128
+
129
+ app.stage.removeChildren();
130
+ polygonGraphics.clear();
131
+ if (value.image) {
132
+ let imageUrl = "";
133
+
134
+ if (typeof value.image === "string") {
135
+ imageUrl = value.image;
136
+ } else if (value.image.url) {
137
+ imageUrl = value.image.url;
138
+ } else if (value.image.path) {
139
+ if (root && !value.image.path.startsWith("http")) {
140
+ imageUrl = `${root}/file=${value.image.path}`;
141
+ } else {
142
+ imageUrl = value.image.path;
143
+ }
144
+ }
145
+
146
+ if (imageUrl) {
147
+ try {
148
+ const img = new Image();
149
+ img.crossOrigin = "anonymous";
150
+
151
+ const imageLoadPromise = new Promise<HTMLImageElement>(
152
+ (resolve, reject) => {
153
+ img.onload = () => resolve(img);
154
+ img.onerror = reject;
155
+ img.src = imageUrl;
156
+ },
157
+ );
158
+
159
+ const loadedImage = await imageLoadPromise;
160
+ const texture = PIXI.Texture.from(loadedImage);
161
+ imageSprite = new PIXI.Sprite(texture);
162
+
163
+ const scaleX = app.screen.width / texture.width;
164
+ const scaleY = app.screen.height / texture.height;
165
+ const scale = Math.min(scaleX, scaleY);
166
+
167
+ imageSprite.scale.set(scale);
168
+
169
+ const displayWidth = texture.width * scale;
170
+ const displayHeight = texture.height * scale;
171
+
172
+ imageSprite.x = (app.screen.width - displayWidth) / 2;
173
+ imageSprite.y = (app.screen.height - displayHeight) / 2;
174
+
175
+ imageRect = {
176
+ left: imageSprite.x,
177
+ top: imageSprite.y,
178
+ right: imageSprite.x + displayWidth,
179
+ bottom: imageSprite.y + displayHeight,
180
+ width: displayWidth,
181
+ height: displayHeight,
182
+ naturalWidth: texture.width,
183
+ naturalHeight: texture.height,
184
+ };
185
+
186
+ app.stage.addChild(imageSprite);
187
+ } catch (error) {
188
+ console.error("Failed to load image:", error);
189
+ return;
190
+ }
191
+ }
192
+ }
193
+
194
+ if (value.polygons && value.polygons.length > 0 && imageSprite) {
195
+ value.polygons.forEach((polygon) => {
196
+ const graphics = new PIXI.Graphics();
197
+
198
+ let color = 0xff0000;
199
+ try {
200
+ if (polygon.color) {
201
+ const colorStr = polygon.color.replace("#", "");
202
+ color = parseInt(colorStr, 16);
203
+ }
204
+ } catch (e) {
205
+ console.error("Error parsing color:", e);
206
+ }
207
+
208
+ const polygonMaskOpacity = polygon.mask_opacity ?? 0.2;
209
+ const selectedMaskAlpha = polygon.selected_mask_opacity ?? 0.5;
210
+ const polygonStrokeOpacity = polygon.stroke_opacity ?? 0.6;
211
+ const selectedStrokeAlpha = polygon.selected_stroke_opacity ?? 1.0;
212
+ const strokeWidth = polygon.stroke_width ?? 0.7;
213
+ const initialMaskAlpha = selectedPolygonIds.includes(polygon.id)
214
+ ? selectedMaskAlpha
215
+ : polygonMaskOpacity;
216
+ const initialStrokeAlpha = selectedPolygonIds.includes(polygon.id)
217
+ ? selectedStrokeAlpha
218
+ : polygonStrokeOpacity;
219
+
220
+ if (polygon.coordinates && polygon.coordinates.length > 0) {
221
+ const displayCoords = polygon.coordinates.map((coord) => {
222
+ return [
223
+ (coord[0] / (imageRect.naturalWidth - 1)) *
224
+ imageRect.width +
225
+ imageRect.left,
226
+ (coord[1] / (imageRect.naturalHeight - 1)) *
227
+ imageRect.height +
228
+ imageRect.top,
229
+ ];
230
+ });
231
+
232
+ graphics.poly(displayCoords.flat());
233
+ graphics.fill({ color: color, alpha: initialMaskAlpha });
234
+ graphics.stroke({ width: strokeWidth, color: color, alpha: initialStrokeAlpha });
235
+ }
236
+
237
+ graphics.eventMode = "static";
238
+ graphics.cursor = "pointer";
239
+
240
+ const originalMaskAlpha = polygonMaskOpacity;
241
+ const hoverMaskAlpha = Math.min(polygonMaskOpacity + 0.1, 1.0);
242
+ const hoverStrokeAlpha = Math.min(polygonStrokeOpacity + 0.2, 1.0);
243
+
244
+ graphics.on("pointerover", () => {
245
+ if (!selectedPolygonIds.includes(polygon.id)) {
246
+ graphics.clear();
247
+ drawPolygonPath(
248
+ graphics,
249
+ polygon,
250
+ imageSprite!,
251
+ hoverMaskAlpha,
252
+ strokeWidth,
253
+ hoverStrokeAlpha,
254
+ );
255
+ }
256
+ });
257
+
258
+ graphics.on("pointerout", () => {
259
+ if (!selectedPolygonIds.includes(polygon.id)) {
260
+ graphics.clear();
261
+ drawPolygonPath(
262
+ graphics,
263
+ polygon,
264
+ imageSprite!,
265
+ originalMaskAlpha,
266
+ strokeWidth,
267
+ polygonStrokeOpacity,
268
+ );
269
+ }
270
+ });
271
+
272
+ graphics.on("pointerdown", (event) => {
273
+ // Check if Ctrl/Cmd key is held for multi-selection
274
+ const isMultiSelect = event.ctrlKey || event.metaKey;
275
+
276
+ if (selectedPolygonIds.includes(polygon.id)) {
277
+ // Deselect this polygon
278
+ const newSelectedIds = selectedPolygonIds.filter(
279
+ (id) => id !== polygon.id,
280
+ );
281
+ updateSelection(newSelectedIds);
282
+ selectedPolygonIds = newSelectedIds;
283
+
284
+ // Dispatch deselection event to Gradio
285
+ gradio.dispatch("select", {
286
+ index:
287
+ newSelectedIds.length > 0
288
+ ? value.polygons.findIndex(
289
+ (p) =>
290
+ p.id ===
291
+ newSelectedIds[
292
+ newSelectedIds.length - 1
293
+ ],
294
+ )
295
+ : null,
296
+ value:
297
+ newSelectedIds.length > 0
298
+ ? newSelectedIds
299
+ : null,
300
+ });
301
+ return;
302
+ }
303
+
304
+ // Select polygon
305
+ let newSelectedIds: string[];
306
+ if (isMultiSelect) {
307
+ // Add to existing selection
308
+ newSelectedIds = [...selectedPolygonIds, polygon.id];
309
+ } else {
310
+ // Replace selection
311
+ newSelectedIds = [polygon.id];
312
+ }
313
+
314
+ updateSelection(newSelectedIds);
315
+ selectedPolygonIds = newSelectedIds;
316
+
317
+ // Dispatch select event to Gradio
318
+ gradio.dispatch("select", {
319
+ index: value.polygons.findIndex(
320
+ (p) => p.id === polygon.id,
321
+ ),
322
+ value: newSelectedIds,
323
+ });
324
+ });
325
+
326
+ app.stage.addChild(graphics);
327
+ polygonGraphics.set(polygon.id, graphics);
328
+ });
329
+ }
330
+ }
331
+
332
+ function drawPolygonPath(
333
+ graphics: PIXI.Graphics,
334
+ polygon: any,
335
+ imageSprite: PIXI.Sprite,
336
+ maskAlpha: number = 0.2,
337
+ strokeWidth: number = 0.7,
338
+ strokeAlpha: number = 0.6,
339
+ ) {
340
+ if (polygon.coordinates && polygon.coordinates.length > 0) {
341
+ // Transform coordinates from natural image space to display space
342
+ const displayCoords = polygon.coordinates.map((coord: number[]) => {
343
+ return [
344
+ (coord[0] / (imageRect.naturalWidth - 1)) *
345
+ imageRect.width +
346
+ imageRect.left,
347
+ (coord[1] / (imageRect.naturalHeight - 1)) *
348
+ imageRect.height +
349
+ imageRect.top,
350
+ ];
351
+ });
352
+
353
+ let color = 0xff0000;
354
+ try {
355
+ if (polygon.color) {
356
+ const colorStr = polygon.color.replace("#", "");
357
+ color = parseInt(colorStr, 16);
358
+ }
359
+ } catch (e) {
360
+ console.error("Error parsing color in drawPolygonPath:", e);
361
+ }
362
+
363
+ // Use Pixi.js 8 drawing API
364
+ graphics.poly(displayCoords.flat());
365
+ graphics.fill({ color: color, alpha: maskAlpha });
366
+ graphics.stroke({ width: strokeWidth, color: color, alpha: strokeAlpha });
367
+ }
368
+ }
369
+
370
+ onMount(async () => {
371
+ await tick();
372
+ await initPixiApp();
373
+ if (value) {
374
+ await renderAnnotations();
375
+ }
376
+ });
377
+
378
+ onDestroy(() => {
379
+ if (app) {
380
+ app.destroy(true, { children: true, texture: true });
381
+ }
382
+ });
383
+
384
+ // Handle canvas resize
385
+ async function handleResize() {
386
+ if (!canvasContainer || !app) return;
387
+
388
+ const newWidth = canvasContainer.clientWidth;
389
+ const newHeight = canvasContainer.clientHeight;
390
+
391
+ if (newWidth !== app.screen.width || newHeight !== app.screen.height) {
392
+ app.renderer.resize(newWidth, newHeight);
393
+ // Re-render annotations with updated canvas dimensions
394
+ await renderAnnotations();
395
+ }
396
+ }
397
+
398
+ $: if (canvasContainer) {
399
+ handleResize();
400
+ }
401
+
402
+ $: (value, gradio.dispatch("change"));
403
+ </script>
404
+
405
+ <Block
406
+ {visible}
407
+ variant={"solid"}
408
+ padding={false}
409
+ {elem_id}
410
+ {elem_classes}
411
+ allow_overflow={false}
412
+ {container}
413
+ {scale}
414
+ {min_width}
415
+ {height}
416
+ {width}
417
+ >
418
+ <StatusTracker
419
+ autoscroll={gradio.autoscroll}
420
+ i18n={gradio.i18n}
421
+ {...loading_status}
422
+ on:clear_status={() => gradio.dispatch("clear_status", loading_status)}
423
+ />
424
+
425
+ <BlockLabel
426
+ {show_label}
427
+ Icon={ImageIcon}
428
+ label={label || "Image Annotations"}
429
+ />
430
+
431
+ <div class="container">
432
+ <div class="canvas-container" bind:this={canvasContainer} />
433
+ </div>
434
+ </Block>
435
+
436
+ <style>
437
+ .container {
438
+ display: flex;
439
+ position: relative;
440
+ flex-direction: column;
441
+ justify-content: center;
442
+ align-items: center;
443
+ width: 100%;
444
+ height: 100%;
445
+ }
446
+
447
+ .canvas-container {
448
+ position: relative;
449
+ width: 100%;
450
+ height: 100%;
451
+ min-height: 400px;
452
+ overflow: hidden;
453
+ display: flex;
454
+ justify-content: center;
455
+ align-items: center;
456
+ background-color: #f0f0f0;
457
+ }
458
+
459
+ :global(.canvas-container canvas) {
460
+ display: block;
461
+ width: 100%;
462
+ height: 100%;
463
+ object-fit: contain;
464
+ }
465
+ </style>
src/frontend/gradio.config.js ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ export default {
2
+ plugins: [],
3
+ svelte: {
4
+ preprocess: [],
5
+ },
6
+ build: {
7
+ target: "modules",
8
+ },
9
+ };
src/frontend/package-lock.json ADDED
The diff for this file is too large to render. See raw diff
 
src/frontend/package.json ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "gradio_annoviewer",
3
+ "version": "0.9.0",
4
+ "description": "Gradio UI packages",
5
+ "type": "module",
6
+ "author": "",
7
+ "license": "ISC",
8
+ "private": false,
9
+ "dependencies": {
10
+ "@gradio/atoms": "0.18.0",
11
+ "@gradio/client": "1.19.0",
12
+ "@gradio/icons": "0.14.0",
13
+ "@gradio/statustracker": "0.11.1",
14
+ "@gradio/upload": "0.17.0",
15
+ "@gradio/utils": "0.10.2",
16
+ "cropperjs": "^1.5.12",
17
+ "lazy-brush": "^1.0.1",
18
+ "pixi.js": "^8.0.0",
19
+ "resize-observer-polyfill": "^1.5.1"
20
+ },
21
+ "devDependencies": {
22
+ "@gradio/preview": "0.14.0"
23
+ },
24
+ "main_changeset": true,
25
+ "main": "./Index.svelte",
26
+ "exports": {
27
+ "./package.json": "./package.json",
28
+ ".": {
29
+ "gradio": "./Index.svelte",
30
+ "svelte": "./dist/Index.svelte",
31
+ "types": "./dist/Index.svelte.d.ts"
32
+ },
33
+ "./example": {
34
+ "gradio": "./Example.svelte",
35
+ "svelte": "./dist/Example.svelte",
36
+ "types": "./dist/Example.svelte.d.ts"
37
+ },
38
+ "./base": {
39
+ "gradio": "./shared/ImagePreview.svelte",
40
+ "svelte": "./dist/shared/ImagePreview.svelte",
41
+ "types": "./dist/shared/ImagePreview.svelte.d.ts"
42
+ }
43
+ },
44
+ "peerDependencies": {
45
+ "svelte": "^4.0.0"
46
+ },
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git+https://github.com/gradio-app/gradio.git",
50
+ "directory": "js/simpleimage"
51
+ }
52
+ }
src/frontend/shared/ClearImage.svelte ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { createEventDispatcher } from "svelte";
3
+ import { IconButton, IconButtonWrapper } from "@gradio/atoms";
4
+ import { Clear } from "@gradio/icons";
5
+
6
+ const dispatch = createEventDispatcher();
7
+ </script>
8
+
9
+ <IconButtonWrapper>
10
+ <IconButton
11
+ Icon={Clear}
12
+ label="Remove Image"
13
+ on:click={(event) => {
14
+ dispatch("remove_image");
15
+ event.stopPropagation();
16
+ }}
17
+ />
18
+ </IconButtonWrapper>
src/frontend/shared/ImagePreview.svelte ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import {
3
+ BlockLabel,
4
+ Empty,
5
+ IconButton,
6
+ IconButtonWrapper,
7
+ DownloadLink
8
+ } from "@gradio/atoms";
9
+ import { Download } from "@gradio/icons";
10
+
11
+ import { Image as ImageIcon } from "@gradio/icons";
12
+ import { type FileData } from "@gradio/client";
13
+ import type { I18nFormatter } from "@gradio/utils";
14
+
15
+ export let value: null | FileData;
16
+ export let label: string | undefined = undefined;
17
+ export let show_label: boolean;
18
+ export let show_download_button = true;
19
+ export let selectable = false;
20
+ export let i18n: I18nFormatter;
21
+ </script>
22
+
23
+ <BlockLabel
24
+ {show_label}
25
+ Icon={ImageIcon}
26
+ label={label || i18n("image.image")}
27
+ />
28
+ {#if value === null || !value.url}
29
+ <Empty unpadded_box={true} size="large"><ImageIcon /></Empty>
30
+ {:else}
31
+ <IconButtonWrapper>
32
+ {#if show_download_button}
33
+ <DownloadLink href={value.url} download={value.orig_name || "image"}>
34
+ <IconButton Icon={Download} label={i18n("common.download")} />
35
+ </DownloadLink>
36
+ {/if}
37
+ </IconButtonWrapper>
38
+ <button>
39
+ <div class:selectable class="image-container">
40
+ <img src={value.url} alt="" loading="lazy" />
41
+ </div>
42
+ </button>
43
+ {/if}
44
+
45
+ <style>
46
+ .image-container {
47
+ height: 100%;
48
+ }
49
+ .image-container :global(img),
50
+ button {
51
+ width: var(--size-full);
52
+ height: var(--size-full);
53
+ object-fit: scale-down;
54
+ display: block;
55
+ border-radius: var(--radius-lg);
56
+ }
57
+
58
+ .selectable {
59
+ cursor: crosshair;
60
+ }
61
+ </style>
src/frontend/shared/ImageUploader.svelte ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { createEventDispatcher } from "svelte";
3
+ import { BlockLabel } from "@gradio/atoms";
4
+ import { Image as ImageIcon } from "@gradio/icons";
5
+
6
+ import { Upload } from "@gradio/upload";
7
+ import type { FileData, Client } from "@gradio/client";
8
+ import ClearImage from "./ClearImage.svelte";
9
+
10
+ export let value: null | FileData;
11
+ export let label: string | undefined = undefined;
12
+ export let show_label: boolean;
13
+ export let root: string;
14
+ export let upload: Client["upload"];
15
+ export let stream_handler: Client["stream"];
16
+
17
+ let upload_component: Upload;
18
+ let uploading = false;
19
+
20
+ function handle_upload({ detail }: CustomEvent<FileData>): void {
21
+ value = detail;
22
+ dispatch("upload");
23
+ }
24
+ $: if (uploading) value = null;
25
+
26
+ const dispatch = createEventDispatcher<{
27
+ change?: never;
28
+ clear?: never;
29
+ drag: boolean;
30
+ upload?: never;
31
+ }>();
32
+
33
+ let dragging = false;
34
+ $: dispatch("drag", dragging);
35
+ </script>
36
+
37
+ <BlockLabel {show_label} Icon={ImageIcon} label={label || "Image"} />
38
+
39
+ <div data-testid="image" class="image-container">
40
+ {#if value?.url}
41
+ <ClearImage
42
+ on:remove_image={() => {
43
+ value = null;
44
+ dispatch("clear");
45
+ }}
46
+ />
47
+ {/if}
48
+ <div class="upload-container">
49
+ <Upload
50
+ {upload}
51
+ {stream_handler}
52
+ hidden={value !== null}
53
+ bind:this={upload_component}
54
+ bind:uploading
55
+ bind:dragging
56
+ filetype="image/*"
57
+ on:load={handle_upload}
58
+ on:error
59
+ {root}
60
+ >
61
+ {#if value === null}
62
+ <slot />
63
+ {/if}
64
+ </Upload>
65
+ {#if value !== null}
66
+ <div class="image-frame">
67
+ <img src={value.url} alt={value.alt_text} />
68
+ </div>
69
+ {/if}
70
+ </div>
71
+ </div>
72
+
73
+ <style>
74
+ .image-frame :global(img) {
75
+ width: var(--size-full);
76
+ height: var(--size-full);
77
+ object-fit: scale-down;
78
+ }
79
+
80
+ .image-frame {
81
+ width: 100%;
82
+ height: 100%;
83
+ }
84
+
85
+ .upload-container {
86
+ height: 100%;
87
+ flex-shrink: 1;
88
+ max-height: 100%;
89
+ }
90
+
91
+ .image-container {
92
+ display: flex;
93
+ height: 100%;
94
+ flex-direction: column;
95
+ justify-content: center;
96
+ align-items: center;
97
+ max-height: 100%;
98
+ }
99
+ </style>