Spaces:
Runtime error
Runtime error
Upload 27 files
Browse files- .gitattributes +4 -0
- README.md +36 -4
- app.py +229 -0
- chair.png +0 -0
- common/utils.py +173 -0
- css/main.css +125 -0
- generate_img.py +77 -0
- house.mp4 +3 -0
- house.png +3 -0
- image_process.py +131 -0
- javascript/lazyload/posex-webui.js +415 -0
- javascript/posex-webui.js +104 -0
- js/DragControls.js +228 -0
- js/LICENSE/THREE.MeshLine +21 -0
- js/LICENSE/es-module-shims +10 -0
- js/LICENSE/three +21 -0
- js/THREE.MeshLine.Module.min.js +15 -0
- js/TrackballControls.js +821 -0
- js/app.js +145 -0
- js/es-module-shims.js +790 -0
- js/posex.js +945 -0
- js/three.module.js +0 -0
- person.png +3 -0
- person_control.mp4 +3 -0
- pipeline_stable_diffusion_controlnet_inpaint.py +521 -0
- requirements.txt +23 -0
- script.js +104 -0
- style.css +159 -0
.gitattributes
CHANGED
@@ -32,3 +32,7 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
32 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
33 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
34 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
35 |
+
house.mp4 filter=lfs diff=lfs merge=lfs -text
|
36 |
+
house.png filter=lfs diff=lfs merge=lfs -text
|
37 |
+
person_control.mp4 filter=lfs diff=lfs merge=lfs -text
|
38 |
+
person.png filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
@@ -1,13 +1,45 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
emoji: 🌖
|
4 |
-
colorFrom:
|
5 |
colorTo: blue
|
6 |
sdk: gradio
|
7 |
-
sdk_version: 3.28.
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
license: mit
|
|
|
|
|
|
|
11 |
---
|
12 |
|
13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
---
|
2 |
+
title: ControlnetWithBackground
|
3 |
emoji: 🌖
|
4 |
+
colorFrom: gray
|
5 |
colorTo: blue
|
6 |
sdk: gradio
|
7 |
+
sdk_version: 3.28.2
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
license: mit
|
11 |
+
|
12 |
+
tags:
|
13 |
+
- jax-diffusers-event
|
14 |
---
|
15 |
|
16 |
+
# ControlnetWithBackground
|
17 |
+
### Controlnet
|
18 |
+
### Inpainting
|
19 |
+
### Stable diffusion
|
20 |
+
|
21 |
+
Use controlnet to generate sketches and characters, and keep the background unchanged.
|
22 |
+
|
23 |
+
Usually when we generate a very perfect background image, we want to add image elements, but using controlnet directly will affect the original background. This project aims to add elements to the page while keeping the background unchanged, and can directly operate on the original background.
|
24 |
+
|
25 |
+
Support skeletal character generation and sketch generation.
|
26 |
+
|
27 |
+
Optimize an inpaint model for the general domain against the stablediffusion-inpaint model.
|
28 |
+
|
29 |
+
### Two modes, openpose control and manuscript control
|
30 |
+
#### openpose control
|
31 |
+
Add character skeletons to a forest scene generated by SD, and keep the background unchanged to generate controllable characters
|
32 |
+
<img src="https://huggingface.co/spaces/hirol/ControlnetWithBackground/resolve/main/person.png" width="400" height="300">
|
33 |
+
<video width="320" height="240" controls>
|
34 |
+
<source src="https://huggingface.co/spaces/hirol/ControlnetWithBackground/resolve/main/person_control.mp4" type="video/mp4">
|
35 |
+
</video>
|
36 |
+
|
37 |
+
#### manuscript control
|
38 |
+
Added manuscript houses to an SD generated forest scene
|
39 |
+
<img src="https://huggingface.co/spaces/hirol/ControlnetWithBackground/resolve/main/house.png" width="600" height="300">
|
40 |
+
<video width="320" height="240" controls>
|
41 |
+
<source src="https://huggingface.co/spaces/hirol/ControlnetWithBackground/resolve/main/house.mp4" type="video/mp4">
|
42 |
+
</video>
|
43 |
+
Added manuscript chairs to an SD generated snow scene
|
44 |
+
<img src="https://huggingface.co/spaces/hirol/ControlnetWithBackground/resolve/main/chair.png" width="600" height="300">
|
45 |
+
|
app.py
ADDED
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import io
|
3 |
+
import base64
|
4 |
+
import json
|
5 |
+
from typing import Callable, Any
|
6 |
+
from PIL import Image
|
7 |
+
import gradio as gr
|
8 |
+
from common import utils as posex
|
9 |
+
project_dir = os.path.dirname(os.path.abspath(__file__))
|
10 |
+
print(project_dir)
|
11 |
+
|
12 |
+
if '__file__' in globals():
|
13 |
+
posex.set_save_dir(os.path.join(os.path.dirname(__file__), '', 'saved_poses'))
|
14 |
+
else:
|
15 |
+
# cf. https://stackoverflow.com/a/53293924
|
16 |
+
import inspect
|
17 |
+
posex.set_save_dir(os.path.join(os.path.dirname(inspect.getfile(lambda: None)), '', 'saved_poses'))
|
18 |
+
|
19 |
+
|
20 |
+
def js2py(
|
21 |
+
name: str,
|
22 |
+
id: Callable[[str], str],
|
23 |
+
js: Callable[[str], str],
|
24 |
+
sink: gr.components.IOComponent,
|
25 |
+
) -> gr.Textbox:
|
26 |
+
v_set = gr.Button(elem_id=id(f'{name}_set'),visible=False)
|
27 |
+
v = gr.Textbox(elem_id=id(name),visible=False)
|
28 |
+
v_sink = gr.Textbox(visible=False)
|
29 |
+
v_set.click(fn=None, _js=js(name), outputs=[v, v_sink])
|
30 |
+
v_sink.change(fn=None, _js=js(f'{name}_after'), outputs=[sink])
|
31 |
+
return v
|
32 |
+
|
33 |
+
|
34 |
+
def py2js(
|
35 |
+
name: str,
|
36 |
+
fn: Callable[[], str],
|
37 |
+
id: Callable[[str], str],
|
38 |
+
js: Callable[[str], str],
|
39 |
+
sink: gr.components.IOComponent,
|
40 |
+
) -> None:
|
41 |
+
v_fire = gr.Button(elem_id=id(f'{name}_get'),visible=False)
|
42 |
+
v_sink = gr.Textbox(visible=False)
|
43 |
+
v_sink2 = gr.Textbox(visible=False)
|
44 |
+
v_fire.click(fn=wrap_api(fn), outputs=[v_sink, v_sink2])
|
45 |
+
v_sink2.change(fn=None, _js=js(name), inputs=[v_sink], outputs=[sink])
|
46 |
+
|
47 |
+
|
48 |
+
def jscall(
|
49 |
+
name: str,
|
50 |
+
fn: Callable[[str], str],
|
51 |
+
id: Callable[[str], str],
|
52 |
+
js: Callable[[str], str],
|
53 |
+
sink: gr.components.IOComponent,
|
54 |
+
) -> None:
|
55 |
+
v_args_set = gr.Button(elem_id=id(f'{name}_args_set'), visible=False)
|
56 |
+
|
57 |
+
v_args = gr.JSON(elem_id=id(f'{name}_args'), visible=False)
|
58 |
+
v_args_sink = gr.JSON(visible=False)
|
59 |
+
v_args_set.click(fn=None, _js=js(f'{name}_args'), outputs=[v_args, v_args_sink])
|
60 |
+
v_args_sink.change(fn=None, _js=js(f'{name}_args_after'), outputs=[sink])
|
61 |
+
|
62 |
+
v_fire = gr.Button(elem_id=id(f'{name}_get'),visible=False)
|
63 |
+
v_sink = gr.Textbox(visible=False)
|
64 |
+
v_sink2 = gr.Textbox(visible=False)
|
65 |
+
v_fire.click(fn=wrap_api(fn), inputs=[v_args], outputs=[v_sink, v_sink2])
|
66 |
+
v_sink2.change(fn=None, _js=js(name), inputs=[v_sink], outputs=[sink])
|
67 |
+
|
68 |
+
def generatecall(
|
69 |
+
name: str,
|
70 |
+
fn: Callable[[str], str],
|
71 |
+
id: Callable[[str], str],
|
72 |
+
js: Callable[[str], str],
|
73 |
+
sink: gr.components.IOComponent,
|
74 |
+
prompt,
|
75 |
+
prompt_n,
|
76 |
+
output_img,
|
77 |
+
) -> None:
|
78 |
+
v_args_set = gr.Button(elem_id=id(f'{name}_args_set'), visible=False)
|
79 |
+
v_args = gr.JSON(elem_id=id(f'{name}_args'), visible=False)
|
80 |
+
v_args_sink = gr.JSON(visible=False)
|
81 |
+
v_args_set.click(fn=None, _js=js(f'{name}_args'), outputs=[v_args, v_args_sink])
|
82 |
+
v_args_sink.change(fn=None, _js=js(f'{name}_args_after'), outputs=[sink])
|
83 |
+
|
84 |
+
v_fire = gr.Button(elem_id=id(f'{name}_get'),visible=False)
|
85 |
+
v_sink = gr.Textbox(visible=False)
|
86 |
+
v_sink2 = gr.Textbox(visible=False)
|
87 |
+
v_fire.click(fn=fn, inputs=[v_args,prompt,prompt_n], outputs=[output_img])
|
88 |
+
v_sink2.change(fn=None, _js=js(name), inputs=[v_sink], outputs=[sink])
|
89 |
+
|
90 |
+
|
91 |
+
def get_self_extension():
|
92 |
+
if '__file__' in globals():
|
93 |
+
filepath = __file__
|
94 |
+
else:
|
95 |
+
import inspect
|
96 |
+
filepath = inspect.getfile(lambda: None)
|
97 |
+
|
98 |
+
|
99 |
+
|
100 |
+
# APIs
|
101 |
+
|
102 |
+
def wrap_api(fn):
|
103 |
+
_r = 0
|
104 |
+
|
105 |
+
def f(*args, **kwargs):
|
106 |
+
nonlocal _r
|
107 |
+
_r += 1
|
108 |
+
v = fn(*args, **kwargs)
|
109 |
+
return v, str(_r)
|
110 |
+
|
111 |
+
return f
|
112 |
+
|
113 |
+
|
114 |
+
def all_pose():
|
115 |
+
return json.dumps(list(posex.all_poses()))
|
116 |
+
|
117 |
+
|
118 |
+
def delete_pose(args):
|
119 |
+
posex.delete_pose(json.loads(args)[0])
|
120 |
+
return ''
|
121 |
+
|
122 |
+
|
123 |
+
def save_pose(args):
|
124 |
+
posex.save_pose(json.loads(args)[0])
|
125 |
+
return ''
|
126 |
+
|
127 |
+
|
128 |
+
def load_pose(args):
|
129 |
+
return json.dumps(posex.load_pose(json.loads(args)[0]))
|
130 |
+
|
131 |
+
# def get_imgs(args):
|
132 |
+
# return posex.get_img(args)
|
133 |
+
|
134 |
+
def generate_imgs(data, image_prompt, image_n_prompt):
|
135 |
+
return posex.generate_img(data, image_prompt, image_n_prompt)
|
136 |
+
def get_image_sketch(image_prompt, image_n_prompt, image):
|
137 |
+
return posex.get_image_sketch(image, image_prompt, image_n_prompt)
|
138 |
+
|
139 |
+
|
140 |
+
def javascript_html():
|
141 |
+
script_js = f'script.js?{os.path.getmtime(os.path.join(project_dir,"script.js"))}'
|
142 |
+
path7 = f'javascript/posex-webui.js?{os.path.getmtime(os.path.join(project_dir,"javascript/posex-webui.js"))}'
|
143 |
+
head = f'<script type="text/javascript" src="file={script_js}"></script>\n'
|
144 |
+
head += f'<script type="text/javascript" src="file={path7}"></script>\n'
|
145 |
+
|
146 |
+
return head
|
147 |
+
|
148 |
+
|
149 |
+
def css_html():
|
150 |
+
head = f'<link rel="stylesheet" property="stylesheet" href="file=style.css">'
|
151 |
+
|
152 |
+
return head
|
153 |
+
|
154 |
+
|
155 |
+
def reload_javascript():
|
156 |
+
js = javascript_html()
|
157 |
+
css = css_html()
|
158 |
+
|
159 |
+
def template_response(*args, **kwargs):
|
160 |
+
res = GradioTemplateResponseOriginal(*args, **kwargs)
|
161 |
+
res.body = res.body.replace(b'</head>', f'{js}</head>'.encode("utf8"))
|
162 |
+
res.body = res.body.replace(b'</body>', f'{css}</body>'.encode("utf8"))
|
163 |
+
res.init_headers()
|
164 |
+
return res
|
165 |
+
gr.routes.templates.TemplateResponse = template_response
|
166 |
+
|
167 |
+
GradioTemplateResponseOriginal = gr.routes.templates.TemplateResponse
|
168 |
+
|
169 |
+
|
170 |
+
if __name__ == '__main__':
|
171 |
+
reload_javascript()
|
172 |
+
app = gr.Blocks()
|
173 |
+
with app:
|
174 |
+
is_img2img = []
|
175 |
+
# id = lambda s: f'posex-{["t2i", "i2i"]}-{s}'
|
176 |
+
id = lambda s: f'posex-t2i-{s}'
|
177 |
+
js = lambda s: f'globalThis["{id(s)}"]'
|
178 |
+
|
179 |
+
ext = get_self_extension()
|
180 |
+
|
181 |
+
xpath = os.path.join(project_dir,"javascript/lazyload/posex-webui.js")
|
182 |
+
js_ = [project_dir, f'{xpath}?{os.path.getmtime(xpath)}']
|
183 |
+
print(js_)
|
184 |
+
with gr.Blocks() as demo:
|
185 |
+
with gr.Tab("sketch"):
|
186 |
+
with gr.Row():
|
187 |
+
image_prompt_sketch = gr.Textbox(label="image prompt", value='', elem_id=id('image_prompt'))
|
188 |
+
image_n_prompt_sketch = gr.Textbox(label="negative prompt", value='',
|
189 |
+
elem_id=id('image_n_prompt'))
|
190 |
+
with gr.Row():
|
191 |
+
image_sketch = gr.Image(interactive=True,source='upload', type="numpy", tool="sketch").style(height=512, width=512)
|
192 |
+
result_img = gr.Gallery(label='Output', show_label=False, elem_id="gallery").style(grid=2,
|
193 |
+
height='auto')
|
194 |
+
with gr.Row():
|
195 |
+
generate_result_button = gr.Button(value='generate')
|
196 |
+
generate_result_button.click(fn=get_image_sketch,inputs=[image_prompt_sketch, image_n_prompt_sketch, image_sketch],
|
197 |
+
outputs=[result_img])
|
198 |
+
|
199 |
+
with gr.Tab("openpose", elem_id=id('tab')):
|
200 |
+
# with gr.Row():
|
201 |
+
# enabled = gr.Checkbox(value=False, label='Send this image to ControlNet.', elem_id=id('enabled'))
|
202 |
+
# cn_num = gr.Number(value=0, precision=0, label='Target ControlNet number', visible=True)
|
203 |
+
with gr.Row():
|
204 |
+
# segment_prompt = gr.Textbox(label="segment prompt", value='',
|
205 |
+
# elem_id=id('segment_prompt'))
|
206 |
+
image_prompt = gr.Textbox(label="image prompt", value='', elem_id=id('image_prompt'))
|
207 |
+
image_n_prompt = gr.Textbox(label="negative prompt", value='',
|
208 |
+
elem_id=id('image_n_prompt'))
|
209 |
+
|
210 |
+
gr.HTML(value='\n'.join(js_), elem_id=id('js'), visible=False)
|
211 |
+
|
212 |
+
gr.HTML(value='', elem_id=id('html'))
|
213 |
+
|
214 |
+
generate_button = gr.Button(elem_id=id(f'generate'), value='generate')
|
215 |
+
|
216 |
+
with gr.Column():
|
217 |
+
result_img = gr.Gallery(label='Output', show_label=False, elem_id="gallery").style(grid=2,
|
218 |
+
height='auto')
|
219 |
+
|
220 |
+
with gr.Group(visible=False):
|
221 |
+
sink = gr.HTML(value='', visible=False) # to suppress error in javascript
|
222 |
+
base64 = js2py('base64', id, js, sink)
|
223 |
+
py2js('allposes', all_pose, id, js, sink)
|
224 |
+
jscall('delpose', delete_pose, id, js, sink)
|
225 |
+
jscall('savepose', save_pose, id, js, sink)
|
226 |
+
jscall('loadpose', load_pose, id, js, sink)
|
227 |
+
# jscall('getimgs', get_imgs, id, js, sink)
|
228 |
+
generatecall('getimgs', generate_imgs, id, js, sink, image_prompt, image_n_prompt, result_img)
|
229 |
+
app.launch()
|
chair.png
ADDED
common/utils.py
ADDED
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os, glob, json, base64, re
|
2 |
+
from io import BytesIO
|
3 |
+
from PIL import Image, PngImagePlugin
|
4 |
+
from image_process import image_canny,image_pose_mask,image_pose_mask_numpy
|
5 |
+
from generate_img import generate_image, generate_image_sketch
|
6 |
+
|
7 |
+
_SAVED_POSES_DIR = ''
|
8 |
+
|
9 |
+
image_cache = dict()
|
10 |
+
|
11 |
+
def set_save_dir(dir: str):
|
12 |
+
global _SAVED_POSES_DIR
|
13 |
+
_SAVED_POSES_DIR = os.path.realpath(str(dir))
|
14 |
+
|
15 |
+
def get_save_dir():
|
16 |
+
assert len(_SAVED_POSES_DIR) != 0
|
17 |
+
return _SAVED_POSES_DIR
|
18 |
+
|
19 |
+
def get_saved_path(name: str):
|
20 |
+
#return os.path.realpath(os.path.join(get_save_dir(), name))
|
21 |
+
return os.path.join(get_save_dir(), name)
|
22 |
+
|
23 |
+
def atoi(text):
|
24 |
+
return int(text) if text.isdigit() else text
|
25 |
+
|
26 |
+
def natural_keys(text):
|
27 |
+
return [ atoi(c) for c in re.split(r'(\d+)', text) ]
|
28 |
+
|
29 |
+
def sorted_glob(path):
|
30 |
+
return sorted(glob.glob(path), key=natural_keys)
|
31 |
+
|
32 |
+
def name2path(name: str):
|
33 |
+
if not isinstance(name, str):
|
34 |
+
raise ValueError(f'str object expected, but {type(name)}')
|
35 |
+
|
36 |
+
if len(name) == 0:
|
37 |
+
raise ValueError(f'empty name')
|
38 |
+
|
39 |
+
if '.' in name or '/' in name or '\\' in name:
|
40 |
+
raise ValueError(f'invalid name: {name}')
|
41 |
+
|
42 |
+
path = get_saved_path(f'{name}.png')
|
43 |
+
if not path.startswith(get_save_dir()):
|
44 |
+
raise ValueError(f'invalid name: {name}')
|
45 |
+
|
46 |
+
return path
|
47 |
+
|
48 |
+
def saved_poses():
|
49 |
+
for path in sorted_glob(os.path.join(get_save_dir(), '*.png')):
|
50 |
+
yield Image.open(path)
|
51 |
+
|
52 |
+
def all_poses():
|
53 |
+
for img in saved_poses():
|
54 |
+
buffer = BytesIO()
|
55 |
+
img.save(buffer, format='png')
|
56 |
+
|
57 |
+
if not hasattr(img, 'text'):
|
58 |
+
continue
|
59 |
+
|
60 |
+
pose_dict = {
|
61 |
+
'name': img.text['name'], # type: ignore
|
62 |
+
'image': base64.b64encode(buffer.getvalue()).decode('ascii'),
|
63 |
+
'screen': json.loads(img.text['screen']), # type: ignore
|
64 |
+
'camera': json.loads(img.text['camera']), # type: ignore
|
65 |
+
'joints': json.loads(img.text['joints']), # type: ignore
|
66 |
+
}
|
67 |
+
|
68 |
+
yield pose_dict
|
69 |
+
|
70 |
+
def save_pose(data: dict):
|
71 |
+
print(data)
|
72 |
+
name = data['name']
|
73 |
+
screen = data['screen']
|
74 |
+
camera = data['camera']
|
75 |
+
joints = data['joints']
|
76 |
+
|
77 |
+
info = PngImagePlugin.PngInfo()
|
78 |
+
info.add_text('name', name)
|
79 |
+
info.add_text('screen', json.dumps(screen))
|
80 |
+
info.add_text('camera', json.dumps(camera))
|
81 |
+
info.add_text('joints', json.dumps(joints))
|
82 |
+
|
83 |
+
filepath = name2path(name)
|
84 |
+
|
85 |
+
image = Image.open(BytesIO(base64.b64decode(data['image'][len('data:image/png;base64,'):])))
|
86 |
+
unit = max(image.width, image.height)
|
87 |
+
mx, my = (unit - image.width) // 2, (unit - image.height) // 2
|
88 |
+
canvas = Image.new('RGB', (unit, unit), color=(68, 68, 68))
|
89 |
+
canvas.paste(image, (mx, my))
|
90 |
+
image = canvas.resize((canvas.width//4, canvas.height//4))
|
91 |
+
|
92 |
+
image.save(filepath, pnginfo=info)
|
93 |
+
|
94 |
+
def delete_pose(name: str):
|
95 |
+
filepath = name2path(name)
|
96 |
+
os.remove(filepath)
|
97 |
+
|
98 |
+
def load_pose(name: str):
|
99 |
+
filepath = name2path(name)
|
100 |
+
img = Image.open(filepath)
|
101 |
+
|
102 |
+
buffer = BytesIO()
|
103 |
+
img.save(buffer, format='png')
|
104 |
+
|
105 |
+
if not hasattr(img, 'text'):
|
106 |
+
raise ValueError(f'not pose data: {filepath}')
|
107 |
+
|
108 |
+
pose_dict = {
|
109 |
+
'name': img.text['name'], # type: ignore
|
110 |
+
'image': base64.b64encode(buffer.getvalue()).decode('ascii'),
|
111 |
+
'screen': json.loads(img.text['screen']), # type: ignore
|
112 |
+
'camera': json.loads(img.text['camera']), # type: ignore
|
113 |
+
'joints': json.loads(img.text['joints']), # type: ignore
|
114 |
+
}
|
115 |
+
|
116 |
+
return pose_dict
|
117 |
+
def base64_PIL(data:str):
|
118 |
+
return Image.open(BytesIO(base64.b64decode(data)))
|
119 |
+
|
120 |
+
def PIL_base64(data):
|
121 |
+
return base64.b64encode(data.tobytes()).decode('utf-8')
|
122 |
+
|
123 |
+
def resizeImg(image1,image2):
|
124 |
+
width1, height1 = image1.size
|
125 |
+
# 使用图像1的宽高来resize图像2
|
126 |
+
image2_resized = image2.resize((width1, height1))
|
127 |
+
# 返回resize后的图像2
|
128 |
+
return image2_resized
|
129 |
+
|
130 |
+
# def get_img(data):
|
131 |
+
# #执行逻辑
|
132 |
+
# if (data[0]):
|
133 |
+
# bgImgBase64 = data[0]['bgImg'][len('data:image/png;base64,'):]
|
134 |
+
# maskImgBase64 = data[0]['maskImg'][len('data:image/png;base64,'):]
|
135 |
+
# image_cache['bgImgBase64'] = bgImgBase64
|
136 |
+
# image_cache['maskImgBase64'] = maskImgBase64
|
137 |
+
# return 'success'
|
138 |
+
|
139 |
+
def generate_img(data, image_prompt, image_n_prompt):
|
140 |
+
if (data[0]):
|
141 |
+
bg_img = data[0]['bgImg'][len('data:image/png;base64,'):]
|
142 |
+
mask_img_openpose = data[0]['maskImg'][len('data:image/png;base64,'):]
|
143 |
+
print((len(bg_img), len(mask_img_openpose)))
|
144 |
+
print((image_prompt, image_n_prompt))
|
145 |
+
|
146 |
+
maskImg_base64 = image_pose_mask(mask_img_openpose)
|
147 |
+
|
148 |
+
controlnet_img_pil = base64_PIL(mask_img_openpose)
|
149 |
+
bg_img_pil = base64_PIL(bg_img)
|
150 |
+
mask_img_pil = base64_PIL(maskImg_base64)
|
151 |
+
bg_img_pil = resizeImg(mask_img_pil, bg_img_pil)
|
152 |
+
|
153 |
+
img = generate_image(image_prompt, image_n_prompt, controlnet_img_pil, bg_img_pil, mask_img_pil)
|
154 |
+
|
155 |
+
return [img]
|
156 |
+
# return [mask_img_pil]
|
157 |
+
#openpose流程
|
158 |
+
|
159 |
+
return None
|
160 |
+
|
161 |
+
|
162 |
+
def get_image_sketch(image, image_prompt, image_n_prompt):
|
163 |
+
img_origin_numpy = image['image']
|
164 |
+
img_sketch_numpy = image['mask']
|
165 |
+
# print(type(img_origin))
|
166 |
+
# print(type(PIL_base64(Image.fromarray(img_masj))))
|
167 |
+
mask_pil = base64_PIL(image_pose_mask_numpy(img_sketch_numpy))
|
168 |
+
img_origin_pil = Image.fromarray(img_origin_numpy)
|
169 |
+
sketch_pil = Image.fromarray(img_sketch_numpy)
|
170 |
+
img = generate_image_sketch(image_prompt, image_n_prompt, sketch_pil, img_origin_pil, mask_pil)
|
171 |
+
|
172 |
+
return img
|
173 |
+
# return [mask_pil,img_origin_pil,Image.fromarray(img_masj)]
|
css/main.css
ADDED
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#cont {
|
2 |
+
display: flex;
|
3 |
+
flex-flow: column;
|
4 |
+
gap: 0.5em 0;
|
5 |
+
width: max-content;
|
6 |
+
}
|
7 |
+
|
8 |
+
.box {
|
9 |
+
display: block;
|
10 |
+
border: 1px solid gray;
|
11 |
+
padding: 0.5em 0;
|
12 |
+
text-decoration: none;
|
13 |
+
text-align: center;
|
14 |
+
}
|
15 |
+
|
16 |
+
#notation {
|
17 |
+
display: none;
|
18 |
+
position: absolute;
|
19 |
+
color: black;
|
20 |
+
background-color: rgba(255, 255, 255, 0.75);
|
21 |
+
padding: 0.1em 0.25em;
|
22 |
+
pointer-events: none;
|
23 |
+
font-size: small;
|
24 |
+
}
|
25 |
+
|
26 |
+
#notifications {
|
27 |
+
left: 1em;
|
28 |
+
bottom: 0;
|
29 |
+
width: 25%;
|
30 |
+
}
|
31 |
+
|
32 |
+
#notifications .item {
|
33 |
+
padding: 0.5em;
|
34 |
+
border: 1px solid gray;
|
35 |
+
animation: erase 2s ease-out 0.5s forwards;
|
36 |
+
}
|
37 |
+
|
38 |
+
@keyframes erase {
|
39 |
+
100% {
|
40 |
+
opacity: 0;
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
#notifications .success {
|
45 |
+
background-color: #aaccaa;
|
46 |
+
color: #004000;
|
47 |
+
}
|
48 |
+
|
49 |
+
#notifications .info {
|
50 |
+
background-color: white;
|
51 |
+
color: black;
|
52 |
+
}
|
53 |
+
|
54 |
+
#notifications .error {
|
55 |
+
background-color: #ffcccc;
|
56 |
+
color: red;
|
57 |
+
}
|
58 |
+
|
59 |
+
#body_indicator1 {
|
60 |
+
display: none;
|
61 |
+
position: absolute;
|
62 |
+
outline: 1px solid white;
|
63 |
+
pointer-events: none;
|
64 |
+
}
|
65 |
+
|
66 |
+
#body_indicator2 {
|
67 |
+
display: none;
|
68 |
+
position: absolute;
|
69 |
+
outline: 1px solid gray;
|
70 |
+
pointer-events: none;
|
71 |
+
}
|
72 |
+
|
73 |
+
#saved_poses {
|
74 |
+
display: flex;
|
75 |
+
flex-direction: row;
|
76 |
+
gap: 0.25em;
|
77 |
+
font-size: small;
|
78 |
+
}
|
79 |
+
|
80 |
+
#saved_poses > * {
|
81 |
+
margin: 0;
|
82 |
+
outline: 1px solid gray;
|
83 |
+
max-width: 128px;
|
84 |
+
}
|
85 |
+
|
86 |
+
#saved_poses img {
|
87 |
+
max-width: 128px;
|
88 |
+
max-height: 128px;
|
89 |
+
}
|
90 |
+
|
91 |
+
#saved_poses figcaption {
|
92 |
+
padding: 0 0.25em;
|
93 |
+
overflow-wrap: anywhere; /* Opera Android may not be able to interpret `anywhere` keyword. */
|
94 |
+
}
|
95 |
+
|
96 |
+
#saved_poses .close {
|
97 |
+
position: absolute;
|
98 |
+
cursor: pointer;
|
99 |
+
border: 1px solid gray;
|
100 |
+
background-color: white;
|
101 |
+
opacity: 0.5;
|
102 |
+
width: 1.25em;
|
103 |
+
height: 1.25em;
|
104 |
+
text-align: center;
|
105 |
+
vertical-align: middle;
|
106 |
+
margin: 0;
|
107 |
+
font-family: monospace;
|
108 |
+
}
|
109 |
+
|
110 |
+
#saved_poses .close:hover {
|
111 |
+
opacity: 1.0;
|
112 |
+
}
|
113 |
+
|
114 |
+
#saved_poses .close2 {
|
115 |
+
display: none;
|
116 |
+
position: absolute;
|
117 |
+
left: 1.5em;
|
118 |
+
top: 0;
|
119 |
+
}
|
120 |
+
|
121 |
+
#saved_poses .close:hover .close2 {
|
122 |
+
display: block;
|
123 |
+
color: white;
|
124 |
+
pointer-events: none;
|
125 |
+
}
|
generate_img.py
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from diffusers import StableDiffusionControlNetPipeline, ControlNetModel, UniPCMultistepScheduler
|
3 |
+
import torch
|
4 |
+
import numpy as np
|
5 |
+
from pipeline_stable_diffusion_controlnet_inpaint import *
|
6 |
+
from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_controlnet import *
|
7 |
+
import random
|
8 |
+
#model1
|
9 |
+
controlnet = ControlNetModel.from_pretrained("lllyasviel/control_v11p_sd15_openpose", torch_dtype=torch.float16,cache_dir='./models')
|
10 |
+
pipe = StableDiffusionControlNetInpaintPipeline.from_pretrained(
|
11 |
+
"./models/Any-inpainting", controlnet=controlnet, torch_dtype=torch.float16,cache_dir='./models'
|
12 |
+
)
|
13 |
+
|
14 |
+
pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
|
15 |
+
pipe.to('cuda')
|
16 |
+
|
17 |
+
# model2
|
18 |
+
controlnet1 = ControlNetModel.from_pretrained("lllyasviel/control_v11p_sd15_scribble",torch_dtype=torch.float16,cache_dir='./models')
|
19 |
+
|
20 |
+
pipe1 = StableDiffusionControlNetInpaintPipeline.from_pretrained(
|
21 |
+
"./models/Any-inpainting", controlnet=controlnet1, torch_dtype=torch.float16,cache_dir='./models'
|
22 |
+
)
|
23 |
+
|
24 |
+
pipe1.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
|
25 |
+
pipe1.to('cuda')
|
26 |
+
|
27 |
+
def make_inpaint_condition(image, image_mask):
|
28 |
+
image = np.array(image.convert("RGB")).astype(np.float32) / 255.0
|
29 |
+
image_mask = np.array(image_mask.convert("L"))
|
30 |
+
assert image.shape[0:1] == image_mask.shape[0:1], "image and image_mask must have the same image size"
|
31 |
+
image[image_mask > 128] = -1.0 # set as masked pixel
|
32 |
+
image = np.expand_dims(image, 0).transpose(0, 3, 1, 2)
|
33 |
+
image = torch.from_numpy(image)
|
34 |
+
return image
|
35 |
+
|
36 |
+
|
37 |
+
def generate_image(prompt:str, negative_prompt:str, openpose_image, original_image, mask_image):
|
38 |
+
|
39 |
+
a = random.randint(10000,90000)
|
40 |
+
generator = torch.manual_seed(a)
|
41 |
+
# control_image = make_inpaint_condition(original_image, mask_image)
|
42 |
+
# images = [openpose_image, control_image]
|
43 |
+
|
44 |
+
image = pipe(
|
45 |
+
prompt=prompt,
|
46 |
+
# images,
|
47 |
+
image=original_image,
|
48 |
+
control_image=openpose_image,
|
49 |
+
mask_image=mask_image,
|
50 |
+
num_inference_steps=20,
|
51 |
+
generator=generator,
|
52 |
+
negative_prompt=negative_prompt,
|
53 |
+
# controlnet_conditioning_scale=[1.0, 0.8],
|
54 |
+
).images[0]
|
55 |
+
|
56 |
+
return image
|
57 |
+
|
58 |
+
|
59 |
+
def generate_image_sketch(prompt: str, negative_prompt: str, openpose_image, original_image, mask_image):
|
60 |
+
b = random.randint(10000, 90000)
|
61 |
+
generator = torch.manual_seed(b)
|
62 |
+
# control_image = make_inpaint_condition(original_image, mask_image)
|
63 |
+
# images = [openpose_image, control_image]
|
64 |
+
|
65 |
+
image = pipe1(
|
66 |
+
prompt=prompt,
|
67 |
+
# images,
|
68 |
+
image=original_image,
|
69 |
+
control_image=openpose_image,
|
70 |
+
mask_image=mask_image,
|
71 |
+
num_inference_steps=20,
|
72 |
+
generator=generator,
|
73 |
+
negative_prompt=negative_prompt,
|
74 |
+
# controlnet_conditioning_scale=[1.0, 0.8],
|
75 |
+
).images[0]
|
76 |
+
|
77 |
+
return [image]
|
house.mp4
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:1ba5c5749d85848e88cbd570a055608f2b809c75cb9c1258ac14b55dd1a94547
|
3 |
+
size 1360888
|
house.png
ADDED
Git LFS Details
|
image_process.py
ADDED
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# This is a sample Python script.
|
2 |
+
|
3 |
+
# Press ⌃R to execute it or replace it with your code.
|
4 |
+
# Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings.
|
5 |
+
|
6 |
+
import numpy as np
|
7 |
+
import cv2
|
8 |
+
import base64
|
9 |
+
|
10 |
+
|
11 |
+
def cv2_base64(image):
|
12 |
+
base64_str = cv2.imencode('.png',image)[1].tobytes()
|
13 |
+
base64_str = base64.b64encode(base64_str)
|
14 |
+
return base64_str.decode('utf-8')
|
15 |
+
|
16 |
+
def base64_cv2(base64_str):
|
17 |
+
imgString = base64.b64decode(base64_str)
|
18 |
+
nparr = np.frombuffer(imgString,np.uint8)
|
19 |
+
image = cv2.imdecode(nparr,cv2.IMREAD_COLOR)
|
20 |
+
return image
|
21 |
+
|
22 |
+
|
23 |
+
|
24 |
+
def image_pose_mask(imagepath : str):
|
25 |
+
img = base64_cv2(imagepath)
|
26 |
+
|
27 |
+
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
28 |
+
ret, thresh = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY)
|
29 |
+
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
30 |
+
cnt = contours[-1]
|
31 |
+
hull = cv2.convexHull(cnt)
|
32 |
+
length = len(hull)
|
33 |
+
if length > 4:
|
34 |
+
for i in range(length):
|
35 |
+
cv2.line(img, tuple(hull[i][0]), tuple(hull[(i + 1) % length][0]), (255, 255, 255), 2)
|
36 |
+
|
37 |
+
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
38 |
+
|
39 |
+
_, threshold = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY)
|
40 |
+
mask = img.copy()
|
41 |
+
kernel = np.ones((30, 30), dtype=np.uint8)
|
42 |
+
dilated = cv2.dilate(threshold, kernel, 20)
|
43 |
+
dilated = cv2.dilate(dilated, kernel, 20)
|
44 |
+
contours, hierarchy = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
|
45 |
+
valid = len(contours) > 0
|
46 |
+
|
47 |
+
area = []
|
48 |
+
|
49 |
+
for k in range(len(contours)):
|
50 |
+
area.append(cv2.contourArea(contours[k]))
|
51 |
+
max_idx = np.argmax(np.array(area))
|
52 |
+
|
53 |
+
mask2 = cv2.drawContours(mask, contours, max_idx, (255, 255, 255), thickness=-1)
|
54 |
+
img_base64 = cv2_base64(mask2)
|
55 |
+
|
56 |
+
return img_base64
|
57 |
+
|
58 |
+
|
59 |
+
|
60 |
+
def image_pose_mask_numpy(image):
|
61 |
+
img = np.uint8(image)
|
62 |
+
print("shape:" + str(img.shape))
|
63 |
+
|
64 |
+
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
65 |
+
ret, thresh = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY)
|
66 |
+
|
67 |
+
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
68 |
+
cnt = contours[-1]
|
69 |
+
hull = cv2.convexHull(cnt)
|
70 |
+
length = len(hull)
|
71 |
+
if length > 4:
|
72 |
+
for i in range(length):
|
73 |
+
cv2.line(img, tuple(hull[i][0]), tuple(hull[(i + 1) % length][0]), (255, 255, 255), 2)
|
74 |
+
|
75 |
+
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
76 |
+
|
77 |
+
_, threshold = cv2.threshold(gray, 10, 255, cv2.THRESH_BINARY)
|
78 |
+
mask = img.copy()
|
79 |
+
kernel = np.ones((30, 30), dtype=np.uint8)
|
80 |
+
|
81 |
+
dilated = cv2.dilate(threshold, kernel, 20)
|
82 |
+
|
83 |
+
dilated = cv2.dilate(dilated, kernel, 20)
|
84 |
+
contours, hierarchy = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
|
85 |
+
valid = len(contours) > 0
|
86 |
+
|
87 |
+
area = []
|
88 |
+
|
89 |
+
for k in range(len(contours)):
|
90 |
+
area.append(cv2.contourArea(contours[k]))
|
91 |
+
max_idx = np.argmax(np.array(area))
|
92 |
+
|
93 |
+
mask2 = cv2.drawContours(mask, contours, max_idx, (255, 255, 255), thickness=-1)
|
94 |
+
|
95 |
+
img_base64 = cv2_base64(mask2)
|
96 |
+
|
97 |
+
return img_base64
|
98 |
+
|
99 |
+
def image_canny(imagepath:str):
|
100 |
+
|
101 |
+
img = base64_cv2(imagepath)
|
102 |
+
|
103 |
+
image_map = cv2.Canny(img, 100, 200)
|
104 |
+
|
105 |
+
contours, hierarchy = cv2.findContours(image_map, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
106 |
+
cnt = contours[-1]
|
107 |
+
hull = cv2.convexHull(cnt)
|
108 |
+
length = len(hull)
|
109 |
+
if length > 4:
|
110 |
+
for i in range(length):
|
111 |
+
cv2.line(img, tuple(hull[i][0]), tuple(hull[(i + 1) % length][0]), (0, 0, 255), 2)
|
112 |
+
|
113 |
+
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
114 |
+
|
115 |
+
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
|
116 |
+
valid = len(contours) > 0
|
117 |
+
area = []
|
118 |
+
for k in range(len(contours)):
|
119 |
+
area.append(cv2.contourArea(contours[k]))
|
120 |
+
max_idx = np.argmax(np.array(area))
|
121 |
+
|
122 |
+
mask2 = cv2.drawContours(image_map, contours, max_idx, (0, 0, 255), thickness=3)
|
123 |
+
|
124 |
+
img_base64 = cv2_base64(mask2)
|
125 |
+
|
126 |
+
return img_base64
|
127 |
+
|
128 |
+
# Press the green button in the gutter to run the script.
|
129 |
+
if __name__ == '__main__':
|
130 |
+
image_canny(imagepath='download (13).png')
|
131 |
+
|
javascript/lazyload/posex-webui.js
ADDED
@@ -0,0 +1,415 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
async function _import() {
|
2 |
+
if (!globalThis.posex || !globalThis.posex.import) {
|
3 |
+
return await import('posex');
|
4 |
+
} else {
|
5 |
+
return await globalThis.posex.imports.posex();
|
6 |
+
}
|
7 |
+
}
|
8 |
+
const { init, init_3d } = await _import();
|
9 |
+
|
10 |
+
(async function () {
|
11 |
+
let _r = 0;
|
12 |
+
function to_gradio(v) {
|
13 |
+
// force call `change` event on gradio
|
14 |
+
return [v, _r++];
|
15 |
+
}
|
16 |
+
|
17 |
+
function js2py(type, gradio_field, value) {
|
18 |
+
// set `value` to gradio's field
|
19 |
+
// (1) Click gradio's button.
|
20 |
+
// (2) Gradio will fire js callback to retrieve value to be set.
|
21 |
+
// (3) Gradio will fire another js callback to notify the process has been completed.
|
22 |
+
return new Promise(resolve => {
|
23 |
+
const callback_name = `posex-${type}-${gradio_field}`;
|
24 |
+
|
25 |
+
// (2)
|
26 |
+
globalThis[callback_name] = () => {
|
27 |
+
|
28 |
+
delete globalThis[callback_name];
|
29 |
+
|
30 |
+
// (3)
|
31 |
+
const callback_after = callback_name + '_after';
|
32 |
+
globalThis[callback_after] = () => {
|
33 |
+
delete globalThis[callback_after];
|
34 |
+
resolve();
|
35 |
+
};
|
36 |
+
|
37 |
+
return to_gradio(JSON.parse(value));
|
38 |
+
// return to_gradio(value);
|
39 |
+
};
|
40 |
+
|
41 |
+
// (1)
|
42 |
+
gradioApp().querySelector(`#${callback_name}_set`).click();
|
43 |
+
});
|
44 |
+
}
|
45 |
+
|
46 |
+
function py2js(type, pyname, ...args) {
|
47 |
+
// call python's function
|
48 |
+
// (1) Set args to gradio's field
|
49 |
+
// (2) Click gradio's button
|
50 |
+
// (3) JS callback will be kicked with return value from gradio
|
51 |
+
|
52 |
+
// (1)
|
53 |
+
return (args.length == 0 ? Promise.resolve() : js2py(type, pyname + '_args', JSON.stringify(args)))
|
54 |
+
.then(() => {
|
55 |
+
return new Promise(resolve => {
|
56 |
+
const callback_name = `posex-${type}-${pyname}`;
|
57 |
+
// (3)
|
58 |
+
globalThis[callback_name] = value => {
|
59 |
+
delete globalThis[callback_name];
|
60 |
+
resolve(value);
|
61 |
+
}
|
62 |
+
// (2)
|
63 |
+
gradioApp().querySelector(`#${callback_name}_get`).click();
|
64 |
+
});
|
65 |
+
});
|
66 |
+
}
|
67 |
+
|
68 |
+
function reload_poses(json, ui) {
|
69 |
+
const df = document.createDocumentFragment();
|
70 |
+
for (let data of json) {
|
71 |
+
const fig = document.createElement('figure')
|
72 |
+
const img = document.createElement('img');
|
73 |
+
const cap = document.createElement('figcaption');
|
74 |
+
const clo = document.createElement('div');
|
75 |
+
const cloimg = document.createElement('img');
|
76 |
+
const clo2 = document.createElement('span');
|
77 |
+
fig.dataset.poseName = data.name;
|
78 |
+
cap.textContent = data.name;
|
79 |
+
clo.classList.add('close');
|
80 |
+
cloimg.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsSAAALEgHS3X78AAAAG3RFWHRTb2Z0d2FyZQBDZWxzeXMgU3R1ZGlvIFRvb2zBp+F8AAAAxElEQVQ4y82T0REBQRBEX0dAJk4GJwKXgZMBESADIiADJwKXATI4GRBB+1lqKa62+DFV+7E7U6+6e2plm19K/wWQ1AE2QBcobZ9fehVwCb3rWwWShmHwaLsfvW+BAihs71otSJoBc2BuexFBl7anSRlI2gN5OBXQxIpSAB2gCXlcgCzOJGkLkg5ABhyB/B5cqoI1UAb5BbCxPU4CSBqFdda2B1GoE9urVoCkHlCH68N3ZOfzGkNw9dvBZ3Bu+/SHf+GbugG9/4ThhKqF8gAAAABJRU5ErkJggg==';
|
81 |
+
clo2.classList.add('close2');
|
82 |
+
clo2.textContent = 'delete';
|
83 |
+
clo.append(cloimg, clo2);
|
84 |
+
|
85 |
+
img.src = 'data:image/png;base64,' + data.image;
|
86 |
+
img.title = data.name;
|
87 |
+
fig.append(clo, img, cap);
|
88 |
+
|
89 |
+
df.appendChild(fig);
|
90 |
+
}
|
91 |
+
|
92 |
+
ui.saved_poses.innerHTML = '';
|
93 |
+
ui.saved_poses.appendChild(df);
|
94 |
+
}
|
95 |
+
|
96 |
+
function init_ui(type, api) {
|
97 |
+
const $ = x => document.createElement(x);
|
98 |
+
|
99 |
+
const all_reset = $('button');
|
100 |
+
all_reset.innerHTML = '🔄 All Reset';
|
101 |
+
all_reset.classList.add('posex_all_reset', 'posex_box');
|
102 |
+
|
103 |
+
const reset_camera = $('button');
|
104 |
+
reset_camera.innerHTML = '🎥 Reset Camera';
|
105 |
+
reset_camera.classList.add('posex_reset_camera', 'posex_box');
|
106 |
+
|
107 |
+
const reset_pose = $('button');
|
108 |
+
reset_pose.innerHTML = '🧍 Reset Pose';
|
109 |
+
reset_pose.classList.add('posex_reset_pose', 'posex_box');
|
110 |
+
|
111 |
+
const reset_cont = $('div');
|
112 |
+
reset_cont.classList.add('posex_reset_cont');
|
113 |
+
reset_cont.append(reset_camera, reset_pose);
|
114 |
+
|
115 |
+
const canvas = $('canvas');
|
116 |
+
canvas.width = 512;
|
117 |
+
canvas.height = 512;
|
118 |
+
|
119 |
+
const camera_marker = $('div'); camera_marker.textContent = '- Camera';
|
120 |
+
const fixed_roll_label = $('label');
|
121 |
+
const fixed_roll = $('input'); fixed_roll.type = 'checkbox'; fixed_roll.classList.add('posex_fixed_roll', 'posex_camera'); fixed_roll.checked = true;
|
122 |
+
fixed_roll_label.append(fixed_roll, document.createTextNode('Fixed Roll'));
|
123 |
+
|
124 |
+
const img_marker = $('div'); img_marker.textContent = '- Image';
|
125 |
+
const set_img = $('label'); set_img.classList.add('posex_bg');
|
126 |
+
const add_img = $('button'); add_img.classList.add('posex_add_body', 'posex_body'); add_img.innerHTML = '🖼 Add';add_img.onclick = () => img_input.click();
|
127 |
+
const img_input = $('input'); img_input.type = 'file'; img_input.style.display = 'none';
|
128 |
+
set_img.append(add_img, img_input);
|
129 |
+
const reset_img = $('button'); reset_img.classList.add('posex_bg'); reset_img.innerHTML = '❌ Del';
|
130 |
+
const img_cont = $('div'); img_cont.classList.add('posex_bg_cont');
|
131 |
+
img_cont.append(set_img, reset_img);
|
132 |
+
|
133 |
+
const body_marker = $('div'); body_marker.textContent = '- Body';
|
134 |
+
const add_body = $('button'); add_body.classList.add('posex_add_body', 'posex_body'); add_body.innerHTML = '➕ Add';
|
135 |
+
const remove_body = $('button'); remove_body.classList.add('posex_remove_body', 'posex_body'); remove_body.innerHTML = '➖ Remove';
|
136 |
+
const canvas_marker = $('div'); canvas_marker.textContent = '- Image Size';
|
137 |
+
const canvas_width = $('input'); canvas_width.type = 'number'; canvas_width.value = 512; canvas_width.min = 64; canvas_width.classList.add('posex_canvas_width', 'posex_canvas_size');
|
138 |
+
const canvas_height = $('input'); canvas_height.type = 'number'; canvas_height.value = 512; canvas_height.min = 64; canvas_height.classList.add('posex_canvas_height', 'posex_canvas_size');
|
139 |
+
const bg_marker = $('div'); bg_marker.textContent = '- Background';
|
140 |
+
const set_bg = $('label'); set_bg.classList.add('posex_bg');
|
141 |
+
const bg_button = $('button'); bg_button.innerHTML = '🖼 Set'; bg_button.onclick = () => bg_input.click();
|
142 |
+
const bg_input = $('input'); bg_input.type = 'file'; bg_input.style.display = 'none';
|
143 |
+
set_bg.append(bg_button, bg_input);
|
144 |
+
const reset_bg = $('button'); reset_bg.classList.add('posex_bg'); reset_bg.innerHTML = '❌ Del';
|
145 |
+
const bg_cont = $('div'); bg_cont.classList.add('posex_bg_cont');
|
146 |
+
bg_cont.append(set_bg, reset_bg);
|
147 |
+
const joint_marker = $('div'); joint_marker.textContent = '- Joints and Limbs';
|
148 |
+
const limb_width_label = $('label');
|
149 |
+
const limb_width = $('input'); limb_width.type = 'range'; limb_width.min = 1; limb_width.max = 16; limb_width.value = 4; limb_width.classList.add('posex_joints', 'posex_limb_width');
|
150 |
+
limb_width_label.append(limb_width, document.createTextNode('Limb Width'));
|
151 |
+
const elliptic_limbs_label = $('label');
|
152 |
+
const elliptic_limbs = $('input'); elliptic_limbs.type = 'checkbox'; elliptic_limbs.classList.add('posex_joints', 'posex_elliptic_limbs'); elliptic_limbs.checked = true;
|
153 |
+
elliptic_limbs_label.append(elliptic_limbs, document.createTextNode('Elliptic Limbs'));
|
154 |
+
const other_marker = $('div'); other_marker.textContent = '- Others';
|
155 |
+
const low_fps_label = $('label');
|
156 |
+
const low_fps = $('input'); low_fps.type = 'checkbox'; low_fps.classList.add('posex_low_fps', 'posex_others'); low_fps.checked = false;
|
157 |
+
low_fps_label.append(low_fps, document.createTextNode('Low fps'));
|
158 |
+
|
159 |
+
const setting_cont = $('div');
|
160 |
+
setting_cont.classList.add('posex_setting_cont');
|
161 |
+
setting_cont.append(
|
162 |
+
// camera_marker,
|
163 |
+
// fixed_roll_label,
|
164 |
+
// img_marker,
|
165 |
+
// img_cont,
|
166 |
+
all_reset,
|
167 |
+
bg_marker,
|
168 |
+
bg_cont,
|
169 |
+
canvas_marker,
|
170 |
+
canvas_width,
|
171 |
+
canvas_height,
|
172 |
+
body_marker,
|
173 |
+
add_body,
|
174 |
+
remove_body,
|
175 |
+
|
176 |
+
|
177 |
+
// joint_marker,
|
178 |
+
// limb_width_label,
|
179 |
+
// elliptic_limbs_label,
|
180 |
+
// other_marker,
|
181 |
+
// low_fps_label,
|
182 |
+
);
|
183 |
+
|
184 |
+
const canvas_cont = $('div');
|
185 |
+
canvas_cont.classList.add('posex_canvas_cont');
|
186 |
+
canvas_cont.append(
|
187 |
+
canvas,
|
188 |
+
setting_cont,
|
189 |
+
);
|
190 |
+
|
191 |
+
const notation = $('p');
|
192 |
+
notation.classList.add('posex_notation');
|
193 |
+
|
194 |
+
const indicator1 = $('div');
|
195 |
+
indicator1.classList.add('posex_indicator1');
|
196 |
+
|
197 |
+
const indicator2 = $('div');
|
198 |
+
indicator2.classList.add('posex_indicator2');
|
199 |
+
|
200 |
+
const copy = $('button'); copy.classList.add('posex_copy', 'posex_misc', 'posex_box'); copy.innerHTML = '📋 Copy to clipboard';
|
201 |
+
const save = $('button'); save.classList.add('posex_save', 'posex_misc', 'posex_box'); save.innerHTML = '💾 Download image';
|
202 |
+
|
203 |
+
const misc_cont = $('div');
|
204 |
+
misc_cont.classList.add('posex_misc_cont');
|
205 |
+
misc_cont.append(
|
206 |
+
copy,
|
207 |
+
save
|
208 |
+
);
|
209 |
+
|
210 |
+
const save_pose = $('button');
|
211 |
+
save_pose.classList.add('posex_save_pose', 'posex_box');
|
212 |
+
save_pose.innerHTML = '💾🧍 Save Pose';
|
213 |
+
|
214 |
+
const save_pose_callback = async obj => {
|
215 |
+
await py2js(type, 'savepose', obj);
|
216 |
+
const json = await py2js(type, 'allposes')
|
217 |
+
reload_poses(JSON.parse(json), ui);
|
218 |
+
return { result: '', ok: true };
|
219 |
+
};
|
220 |
+
|
221 |
+
const saved_poses = $('div');
|
222 |
+
saved_poses.classList.add('posex_saved_poses');
|
223 |
+
|
224 |
+
saved_poses.addEventListener('click', async e => {
|
225 |
+
const get_name = ele => {
|
226 |
+
while (ele && ele !== document) {
|
227 |
+
if (ele.dataset && ele.dataset.poseName !== undefined)
|
228 |
+
return ele.dataset.poseName;
|
229 |
+
ele = ele.parentNode;
|
230 |
+
}
|
231 |
+
return '';
|
232 |
+
};
|
233 |
+
|
234 |
+
let target = e.target;
|
235 |
+
if (target.tagName === 'IMG') target = target.parentNode;
|
236 |
+
if (target.classList.contains('close2')) target = target.parentNode;
|
237 |
+
if (target.tagName === 'FIGURE') {
|
238 |
+
const name = get_name(target);
|
239 |
+
if (name.length != 0) {
|
240 |
+
const json = await py2js(type, 'loadpose', name);
|
241 |
+
ui.loadPose(JSON.parse(json));
|
242 |
+
}
|
243 |
+
} else if (target.classList.contains('close')) {
|
244 |
+
const name = get_name(target);
|
245 |
+
if (name.length != 0) {
|
246 |
+
await py2js(type, 'delpose', name);
|
247 |
+
const json = await py2js(type, 'allposes')
|
248 |
+
reload_poses(JSON.parse(json), ui);
|
249 |
+
}
|
250 |
+
}
|
251 |
+
}, false);
|
252 |
+
|
253 |
+
const get_imgs = $('button');
|
254 |
+
get_imgs.classList.add('posex_get_imgs', 'posex_box');
|
255 |
+
get_imgs.innerHTML = '💾🧍 get_imgs';
|
256 |
+
|
257 |
+
const get_imgs_callback = async obj => {
|
258 |
+
await py2js(type, 'getimgs', obj);
|
259 |
+
return { result: '', ok: true };
|
260 |
+
};
|
261 |
+
|
262 |
+
const ui = {
|
263 |
+
canvas,
|
264 |
+
notation,
|
265 |
+
indicator1,
|
266 |
+
indicator2,
|
267 |
+
all_reset,
|
268 |
+
reset_camera,
|
269 |
+
reset_pose,
|
270 |
+
fixed_roll,
|
271 |
+
img: img_input,
|
272 |
+
reset_img,
|
273 |
+
add_body,
|
274 |
+
remove_body,
|
275 |
+
canvas_width,
|
276 |
+
canvas_height,
|
277 |
+
bg: bg_input,
|
278 |
+
reset_bg,
|
279 |
+
limb_width,
|
280 |
+
elliptic_limbs,
|
281 |
+
low_fps,
|
282 |
+
save,
|
283 |
+
copy,
|
284 |
+
save_pose,
|
285 |
+
save_pose_callback,
|
286 |
+
saved_poses,
|
287 |
+
get_imgs,
|
288 |
+
get_imgs_callback,
|
289 |
+
};
|
290 |
+
|
291 |
+
const df = document.createDocumentFragment();
|
292 |
+
df.append(
|
293 |
+
// all_reset,
|
294 |
+
// reset_cont,
|
295 |
+
canvas_cont,
|
296 |
+
indicator2,
|
297 |
+
indicator1,
|
298 |
+
notation,
|
299 |
+
// misc_cont,
|
300 |
+
// save_pose,
|
301 |
+
// saved_poses,
|
302 |
+
// get_imgs,
|
303 |
+
);
|
304 |
+
|
305 |
+
return { ui, df };
|
306 |
+
};
|
307 |
+
|
308 |
+
async function init_canvas(
|
309 |
+
type,
|
310 |
+
generate_button,
|
311 |
+
container,
|
312 |
+
api
|
313 |
+
) {
|
314 |
+
container.classList.add('posex_cont');
|
315 |
+
container.innerHTML = '';
|
316 |
+
const { ui, df } = init_ui(type, api);
|
317 |
+
container.appendChild(df);
|
318 |
+
|
319 |
+
ui.container = container;
|
320 |
+
ui.notify = function (str, type) { if (type === 'error') console.error(str); };
|
321 |
+
|
322 |
+
// {
|
323 |
+
// // Send canvas image to ControlNet when button is clicked.
|
324 |
+
// let force = false;
|
325 |
+
// gradioApp().addEventListener('click', async e => {
|
326 |
+
// if (e.target !== generate_button) return;
|
327 |
+
//
|
328 |
+
// if (!enabled.checked) return;
|
329 |
+
//
|
330 |
+
// if (force) {
|
331 |
+
// force = false;
|
332 |
+
// return;
|
333 |
+
// }
|
334 |
+
//
|
335 |
+
// // hook `generate` button to add canvas data
|
336 |
+
// e.preventDefault();
|
337 |
+
// e.stopPropagation();
|
338 |
+
//
|
339 |
+
// const data_url = await ui.getDataURL();
|
340 |
+
// await js2py(type, 'base64', data_url);
|
341 |
+
// force = true;
|
342 |
+
// generate_button.click();
|
343 |
+
// }, true);
|
344 |
+
// }
|
345 |
+
|
346 |
+
// {
|
347 |
+
// // Load saved poses.
|
348 |
+
// const json = await py2js(type, 'allposes')
|
349 |
+
// reload_poses(JSON.parse(json), ui);
|
350 |
+
// }
|
351 |
+
|
352 |
+
//界面加载
|
353 |
+
init(ui);
|
354 |
+
|
355 |
+
//功能js加载
|
356 |
+
const animate = init_3d(ui);
|
357 |
+
|
358 |
+
animate();
|
359 |
+
|
360 |
+
// onUiTabChange(() => {
|
361 |
+
// const tabname = get_uiCurrentTabContent().id;
|
362 |
+
// if (type === 't2i') {
|
363 |
+
// if (0 <= tabname.indexOf('txt2img')) {
|
364 |
+
// ui.play();
|
365 |
+
// } else {
|
366 |
+
// ui.stop();
|
367 |
+
// }
|
368 |
+
// } else if (type === 'i2i') {
|
369 |
+
// if (0 <= tabname.indexOf('img2img')) {
|
370 |
+
// ui.play();
|
371 |
+
// } else {
|
372 |
+
// ui.stop();
|
373 |
+
// }
|
374 |
+
// } else {
|
375 |
+
// ui.stop();
|
376 |
+
// }
|
377 |
+
// });
|
378 |
+
}
|
379 |
+
|
380 |
+
async function init_t2i() {
|
381 |
+
const app = gradioApp();
|
382 |
+
await init_canvas(
|
383 |
+
't2i',
|
384 |
+
app.querySelector('#txt2img_generate'),
|
385 |
+
Array.from(app.querySelectorAll('#posex-t2i-html')).at(-1), // !
|
386 |
+
{
|
387 |
+
load_all_poses: app.querySelector('#posex-t2i-api-all_pose'),
|
388 |
+
delete_pose: app.querySelector('#posex-t2i-api-delete_pose'),
|
389 |
+
}
|
390 |
+
);
|
391 |
+
}
|
392 |
+
|
393 |
+
// async function init_i2i() {
|
394 |
+
// const app = gradioApp();
|
395 |
+
// await init_canvas(
|
396 |
+
// 'i2i',
|
397 |
+
// app.querySelector('#posex-i2i-enabled input[type=checkbox]'),
|
398 |
+
// app.querySelector('#img2img_generate'),
|
399 |
+
// Array.from(app.querySelectorAll('#posex-i2i-html')).at(-1), // !
|
400 |
+
// {
|
401 |
+
// load_all_poses: app.querySelector('#posex-i2i-api-all_pose'),
|
402 |
+
// delete_pose: app.querySelector('#posex-i2i-api-delete_pose'),
|
403 |
+
// }
|
404 |
+
// );
|
405 |
+
// }
|
406 |
+
|
407 |
+
if (!globalThis.posex) globalThis.posex = {};
|
408 |
+
const posex = globalThis.posex;
|
409 |
+
posex.init_t2i = init_t2i;
|
410 |
+
// posex.init_i2i = init_i2i;
|
411 |
+
|
412 |
+
posex.script_loaded = true;
|
413 |
+
document.dispatchEvent(new CustomEvent('posexscriptloaded'));
|
414 |
+
|
415 |
+
})();
|
javascript/posex-webui.js
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
(function () {
|
2 |
+
if (!globalThis.posex) globalThis.posex = {};
|
3 |
+
const posex = globalThis.posex;
|
4 |
+
|
5 |
+
function load(cont) {
|
6 |
+
function load_() {
|
7 |
+
if (posex.script_loading || posex.script_loaded) return;
|
8 |
+
posex.script_loading = true;
|
9 |
+
|
10 |
+
const scripts = cont.textContent.trim().split('\n');
|
11 |
+
const base_path = `/file=${scripts.shift()}/js`;
|
12 |
+
cont.textContent = '';
|
13 |
+
|
14 |
+
const df = document.createDocumentFragment();
|
15 |
+
for (let src of scripts) {
|
16 |
+
console.log(`[Posex] loading ${src}`);
|
17 |
+
const script = document.createElement('script');
|
18 |
+
script.async = true;
|
19 |
+
script.type = 'module';
|
20 |
+
script.src = `file=${src}`;
|
21 |
+
df.appendChild(script);
|
22 |
+
}
|
23 |
+
|
24 |
+
globalThis.posex.import = async () => {
|
25 |
+
const THREE = await import(`${base_path}/three.module.js`);
|
26 |
+
const { TrackballControls } = await import(`${base_path}/TrackballControls.js`);
|
27 |
+
const { DragControls } = await import(`${base_path}/DragControls.js`);
|
28 |
+
const { MeshLine, MeshLineMaterial } = await import(`${base_path}/THREE.MeshLine.Module.min.js`);
|
29 |
+
return { THREE, TrackballControls, DragControls, MeshLine, MeshLineMaterial };
|
30 |
+
};
|
31 |
+
if (!globalThis.posex.imports) globalThis.posex.imports = {};
|
32 |
+
if (!globalThis.posex.imports.three) globalThis.posex.imports.three = async () => await import(`${base_path}/three.module.js`);
|
33 |
+
if (!globalThis.posex.imports.posex) globalThis.posex.imports.posex = async () => await import(`${base_path}/posex.js`);
|
34 |
+
cont.appendChild(df);
|
35 |
+
}
|
36 |
+
|
37 |
+
return posex.script_loaded ? Promise.resolve() : new Promise(resolve => {
|
38 |
+
document.addEventListener('posexscriptloaded', () => resolve(), false);
|
39 |
+
load_();
|
40 |
+
});
|
41 |
+
}
|
42 |
+
|
43 |
+
function lazy(fn, timeout) {
|
44 |
+
if (timeout === undefined) timeout = 500;
|
45 |
+
return new Promise(function callback(resolve) {
|
46 |
+
const result = fn();
|
47 |
+
if (result) {
|
48 |
+
resolve(result);
|
49 |
+
} else {
|
50 |
+
setTimeout(() => callback(resolve), timeout);
|
51 |
+
}
|
52 |
+
});
|
53 |
+
}
|
54 |
+
|
55 |
+
function hook_acc(acc, fn) {
|
56 |
+
const observer = new MutationObserver(list => {
|
57 |
+
for (let mut of list) {
|
58 |
+
if (mut.type === 'childList') {
|
59 |
+
if (mut.addedNodes.length != 0) {
|
60 |
+
// closed -> opened
|
61 |
+
fn();
|
62 |
+
} else {
|
63 |
+
// opened -> closed
|
64 |
+
// do nothing
|
65 |
+
}
|
66 |
+
}
|
67 |
+
}
|
68 |
+
});
|
69 |
+
observer.observe(acc, { childList: true, attributes: false, subtree: false });
|
70 |
+
}
|
71 |
+
|
72 |
+
function launch1(type) {
|
73 |
+
return lazy(() => gradioApp()?.querySelector(`#posex-${type}-tab`)).
|
74 |
+
then(async acc => {
|
75 |
+
const cont = Array.from(acc.querySelectorAll(`#posex-${type}-js`)).at(-1); // !
|
76 |
+
const enabled = acc.querySelector(`#posex-${type}-enabled input[type=checkbox]`);
|
77 |
+
await load(cont);
|
78 |
+
await posex[`init_${type}`]();
|
79 |
+
console.log(`[Posex] ${type} initialized`);
|
80 |
+
});
|
81 |
+
}
|
82 |
+
|
83 |
+
// function launch(type) {
|
84 |
+
// return lazy(() => gradioApp()?.querySelector(`#posex-${type}-accordion`)).
|
85 |
+
// then(acc => hook_acc(acc, async () => {
|
86 |
+
// const cont = Array.from(acc.querySelectorAll(`#posex-${type}-js`)).at(-1); // !
|
87 |
+
// const enabled = acc.querySelector(`#posex-${type}-enabled input[type=checkbox]`);
|
88 |
+
// await load(cont);
|
89 |
+
// if (enabled.checked) {
|
90 |
+
// await posex[`init_${type}`]();
|
91 |
+
// console.log(`[Posex] ${type} initialized`);
|
92 |
+
// } else {
|
93 |
+
// enabled.addEventListener('change', async () => {
|
94 |
+
// await posex[`init_${type}`]();
|
95 |
+
// console.log(`[Posex] ${type} initialized`);
|
96 |
+
// }, { once: true });
|
97 |
+
// }
|
98 |
+
// }));
|
99 |
+
// }
|
100 |
+
|
101 |
+
launch1('t2i');
|
102 |
+
// launch('i2i');
|
103 |
+
|
104 |
+
})();
|
js/DragControls.js
ADDED
@@ -0,0 +1,228 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
async function _import() {
|
2 |
+
if (!globalThis.posex || !globalThis.posex.import) {
|
3 |
+
return await import('three');
|
4 |
+
} else {
|
5 |
+
return await globalThis.posex.imports.three();
|
6 |
+
}
|
7 |
+
}
|
8 |
+
const {
|
9 |
+
EventDispatcher,
|
10 |
+
Matrix4,
|
11 |
+
Plane,
|
12 |
+
Raycaster,
|
13 |
+
Vector2,
|
14 |
+
Vector3
|
15 |
+
} = await _import();
|
16 |
+
|
17 |
+
const _plane = new Plane();
|
18 |
+
const _raycaster = new Raycaster();
|
19 |
+
|
20 |
+
const _pointer = new Vector2();
|
21 |
+
const _offset = new Vector3();
|
22 |
+
const _intersection = new Vector3();
|
23 |
+
const _worldPosition = new Vector3();
|
24 |
+
const _inverseMatrix = new Matrix4();
|
25 |
+
|
26 |
+
class DragControls extends EventDispatcher {
|
27 |
+
|
28 |
+
constructor( _objects, _camera, _domElement ) {
|
29 |
+
|
30 |
+
super();
|
31 |
+
|
32 |
+
_domElement.style.touchAction = 'none'; // disable touch scroll
|
33 |
+
|
34 |
+
let _selected = null, _hovered = null;
|
35 |
+
|
36 |
+
const _intersections = [];
|
37 |
+
|
38 |
+
//
|
39 |
+
|
40 |
+
const scope = this;
|
41 |
+
|
42 |
+
function activate() {
|
43 |
+
|
44 |
+
_domElement.addEventListener( 'pointermove', onPointerMove );
|
45 |
+
_domElement.addEventListener( 'pointerdown', onPointerDown );
|
46 |
+
_domElement.addEventListener( 'pointerup', onPointerCancel );
|
47 |
+
_domElement.addEventListener( 'pointerleave', onPointerCancel );
|
48 |
+
|
49 |
+
}
|
50 |
+
|
51 |
+
function deactivate() {
|
52 |
+
|
53 |
+
_domElement.removeEventListener( 'pointermove', onPointerMove );
|
54 |
+
_domElement.removeEventListener( 'pointerdown', onPointerDown );
|
55 |
+
_domElement.removeEventListener( 'pointerup', onPointerCancel );
|
56 |
+
_domElement.removeEventListener( 'pointerleave', onPointerCancel );
|
57 |
+
|
58 |
+
_domElement.style.cursor = '';
|
59 |
+
|
60 |
+
}
|
61 |
+
|
62 |
+
function dispose() {
|
63 |
+
|
64 |
+
deactivate();
|
65 |
+
|
66 |
+
}
|
67 |
+
|
68 |
+
function getObjects() {
|
69 |
+
|
70 |
+
return _objects;
|
71 |
+
|
72 |
+
}
|
73 |
+
|
74 |
+
function getRaycaster() {
|
75 |
+
|
76 |
+
return _raycaster;
|
77 |
+
|
78 |
+
}
|
79 |
+
|
80 |
+
function onPointerMove( event ) {
|
81 |
+
|
82 |
+
if ( scope.enabled === false ) return;
|
83 |
+
|
84 |
+
updatePointer( event );
|
85 |
+
|
86 |
+
_raycaster.setFromCamera( _pointer, _camera );
|
87 |
+
|
88 |
+
if ( _selected ) {
|
89 |
+
|
90 |
+
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
|
91 |
+
|
92 |
+
_selected.position.copy( _intersection.sub( _offset ).applyMatrix4( _inverseMatrix ) );
|
93 |
+
|
94 |
+
}
|
95 |
+
|
96 |
+
scope.dispatchEvent( { type: 'drag', object: _selected } );
|
97 |
+
|
98 |
+
return;
|
99 |
+
|
100 |
+
}
|
101 |
+
|
102 |
+
// hover support
|
103 |
+
|
104 |
+
if ( event.pointerType === 'mouse' || event.pointerType === 'pen' ) {
|
105 |
+
|
106 |
+
_intersections.length = 0;
|
107 |
+
|
108 |
+
_raycaster.setFromCamera( _pointer, _camera );
|
109 |
+
_raycaster.intersectObjects( _objects, true, _intersections );
|
110 |
+
|
111 |
+
if ( _intersections.length > 0 ) {
|
112 |
+
|
113 |
+
const object = _intersections[ 0 ].object;
|
114 |
+
|
115 |
+
_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( object.matrixWorld ) );
|
116 |
+
|
117 |
+
if ( _hovered !== object && _hovered !== null ) {
|
118 |
+
|
119 |
+
scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
|
120 |
+
|
121 |
+
_domElement.style.cursor = 'auto';
|
122 |
+
_hovered = null;
|
123 |
+
|
124 |
+
}
|
125 |
+
|
126 |
+
if ( _hovered !== object ) {
|
127 |
+
|
128 |
+
scope.dispatchEvent( { type: 'hoveron', object: object } );
|
129 |
+
|
130 |
+
_domElement.style.cursor = 'pointer';
|
131 |
+
_hovered = object;
|
132 |
+
|
133 |
+
}
|
134 |
+
|
135 |
+
} else {
|
136 |
+
|
137 |
+
if ( _hovered !== null ) {
|
138 |
+
|
139 |
+
scope.dispatchEvent( { type: 'hoveroff', object: _hovered } );
|
140 |
+
|
141 |
+
_domElement.style.cursor = 'auto';
|
142 |
+
_hovered = null;
|
143 |
+
|
144 |
+
}
|
145 |
+
|
146 |
+
}
|
147 |
+
|
148 |
+
}
|
149 |
+
|
150 |
+
}
|
151 |
+
|
152 |
+
function onPointerDown( event ) {
|
153 |
+
|
154 |
+
if ( scope.enabled === false ) return;
|
155 |
+
|
156 |
+
updatePointer( event );
|
157 |
+
|
158 |
+
_intersections.length = 0;
|
159 |
+
|
160 |
+
_raycaster.setFromCamera( _pointer, _camera );
|
161 |
+
_raycaster.intersectObjects( _objects, true, _intersections );
|
162 |
+
|
163 |
+
if ( _intersections.length > 0 ) {
|
164 |
+
|
165 |
+
_selected = ( scope.transformGroup === true ) ? _objects[ 0 ] : _intersections[ 0 ].object;
|
166 |
+
|
167 |
+
_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _worldPosition.setFromMatrixPosition( _selected.matrixWorld ) );
|
168 |
+
|
169 |
+
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) {
|
170 |
+
|
171 |
+
_inverseMatrix.copy( _selected.parent.matrixWorld ).invert();
|
172 |
+
_offset.copy( _intersection ).sub( _worldPosition.setFromMatrixPosition( _selected.matrixWorld ) );
|
173 |
+
|
174 |
+
}
|
175 |
+
|
176 |
+
_domElement.style.cursor = 'move';
|
177 |
+
|
178 |
+
scope.dispatchEvent( { type: 'dragstart', object: _selected } );
|
179 |
+
|
180 |
+
}
|
181 |
+
|
182 |
+
|
183 |
+
}
|
184 |
+
|
185 |
+
function onPointerCancel() {
|
186 |
+
|
187 |
+
if ( scope.enabled === false ) return;
|
188 |
+
|
189 |
+
if ( _selected ) {
|
190 |
+
|
191 |
+
scope.dispatchEvent( { type: 'dragend', object: _selected } );
|
192 |
+
|
193 |
+
_selected = null;
|
194 |
+
|
195 |
+
}
|
196 |
+
|
197 |
+
_domElement.style.cursor = _hovered ? 'pointer' : 'auto';
|
198 |
+
|
199 |
+
}
|
200 |
+
|
201 |
+
function updatePointer( event ) {
|
202 |
+
|
203 |
+
const rect = _domElement.getBoundingClientRect();
|
204 |
+
|
205 |
+
_pointer.x = ( event.clientX - rect.left ) / rect.width * 2 - 1;
|
206 |
+
_pointer.y = - ( event.clientY - rect.top ) / rect.height * 2 + 1;
|
207 |
+
|
208 |
+
}
|
209 |
+
|
210 |
+
activate();
|
211 |
+
|
212 |
+
// API
|
213 |
+
|
214 |
+
this.enabled = true;
|
215 |
+
this.transformGroup = false;
|
216 |
+
|
217 |
+
this.activate = activate;
|
218 |
+
this.deactivate = deactivate;
|
219 |
+
this.dispose = dispose;
|
220 |
+
this.getObjects = getObjects;
|
221 |
+
this.getRaycaster = getRaycaster;
|
222 |
+
this.onPointerDown = onPointerDown;
|
223 |
+
|
224 |
+
}
|
225 |
+
|
226 |
+
}
|
227 |
+
|
228 |
+
export { DragControls };
|
js/LICENSE/THREE.MeshLine
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) 2016 Jaume Sanchez
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in all
|
13 |
+
copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21 |
+
SOFTWARE.
|
js/LICENSE/es-module-shims
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
-----------
|
3 |
+
|
4 |
+
Copyright (C) 2018-2021 Guy Bedford
|
5 |
+
|
6 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
7 |
+
|
8 |
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
9 |
+
|
10 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
js/LICENSE/three
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
The MIT License
|
2 |
+
|
3 |
+
Copyright © 2010-2023 three.js authors
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6 |
+
of this software and associated documentation files (the "Software"), to deal
|
7 |
+
in the Software without restriction, including without limitation the rights
|
8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9 |
+
copies of the Software, and to permit persons to whom the Software is
|
10 |
+
furnished to do so, subject to the following conditions:
|
11 |
+
|
12 |
+
The above copyright notice and this permission notice shall be included in
|
13 |
+
all copies or substantial portions of the Software.
|
14 |
+
|
15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21 |
+
THE SOFTWARE.
|
js/THREE.MeshLine.Module.min.js
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Minified by jsDelivr using Terser v5.15.1.
|
3 |
+
* Original file: /npm/[email protected]/src/THREE.MeshLine.Module.js
|
4 |
+
*
|
5 |
+
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
6 |
+
*/
|
7 |
+
async function _import() {
|
8 |
+
if (!globalThis.posex || !globalThis.posex.import) {
|
9 |
+
return await import('three');
|
10 |
+
} else {
|
11 |
+
return await globalThis.posex.imports.three();
|
12 |
+
}
|
13 |
+
}
|
14 |
+
const THREE=await _import();class MeshLine extends THREE.BufferGeometry{constructor(){super(),this.isMeshLine=!0,this.type="MeshLine",this.positions=[],this.previous=[],this.next=[],this.side=[],this.width=[],this.indices_array=[],this.uvs=[],this.counters=[],this._points=[],this._geom=null,this.widthCallback=null,this.matrixWorld=new THREE.Matrix4,Object.defineProperties(this,{geometry:{enumerable:!0,get:function(){return this}},geom:{enumerable:!0,get:function(){return this._geom},set:function(t){this.setGeometry(t,this.widthCallback)}},points:{enumerable:!0,get:function(){return this._points},set:function(t){this.setPoints(t,this.widthCallback)}}})}}function MeshLineRaycast(t,e){var i=new THREE.Matrix4,s=new THREE.Ray,r=new THREE.Sphere,a=new THREE.Vector3,n=this.geometry;if(n.boundingSphere||n.computeBoundingSphere(),r.copy(n.boundingSphere),r.applyMatrix4(this.matrixWorld),!1!==t.ray.intersectSphere(r,a)){i.copy(this.matrixWorld).invert(),s.copy(t.ray).applyMatrix4(i);var o=new THREE.Vector3,u=new THREE.Vector3,h=new THREE.Vector3,l=this instanceof THREE.LineSegments?2:1,p=n.index,c=n.attributes;if(null!==p)for(var f=p.array,v=c.position.array,d=c.width.array,y=0,m=f.length-1;y<m;y+=l){var b=f[y],x=f[y+1];o.fromArray(v,3*b),u.fromArray(v,3*x);var E=void 0!==d[Math.floor(y/3)]?d[Math.floor(y/3)]:1,g=t.params.Line.threshold+this.material.lineWidth*E/2,A=g*g;if(!(s.distanceSqToSegment(o,u,a,h)>A)){a.applyMatrix4(this.matrixWorld);var M=t.ray.origin.distanceTo(a);M<t.near||M>t.far||(e.push({distance:M,point:h.clone().applyMatrix4(this.matrixWorld),index:y,face:null,faceIndex:null,object:this}),y=m)}}}}function memcpy(t,e,i,s,r){var a;if(t=t.subarray||t.slice?t:t.buffer,i=i.subarray||i.slice?i:i.buffer,t=e?t.subarray?t.subarray(e,r&&e+r):t.slice(e,r&&e+r):t,i.set)i.set(t,s);else for(a=0;a<t.length;a++)i[a+s]=t[a];return i}MeshLine.prototype.setMatrixWorld=function(t){this.matrixWorld=t},MeshLine.prototype.setGeometry=function(t,e){this._geometry=t,this.setPoints(t.getAttribute("position").array,e)},MeshLine.prototype.setPoints=function(t,e){if(t instanceof Float32Array||t instanceof Array){if(this._points=t,this.widthCallback=e,this.positions=[],this.counters=[],t.length&&t[0]instanceof THREE.Vector3)for(var i=0;i<t.length;i++){var s=t[i],r=i/t.length;this.positions.push(s.x,s.y,s.z),this.positions.push(s.x,s.y,s.z),this.counters.push(r),this.counters.push(r)}else for(i=0;i<t.length;i+=3){r=i/t.length;this.positions.push(t[i],t[i+1],t[i+2]),this.positions.push(t[i],t[i+1],t[i+2]),this.counters.push(r),this.counters.push(r)}this.process()}else console.error("ERROR: The BufferArray of points is not instancied correctly.")},MeshLine.prototype.raycast=MeshLineRaycast,MeshLine.prototype.compareV3=function(t,e){var i=6*t,s=6*e;return this.positions[i]===this.positions[s]&&this.positions[i+1]===this.positions[s+1]&&this.positions[i+2]===this.positions[s+2]},MeshLine.prototype.copyV3=function(t){var e=6*t;return[this.positions[e],this.positions[e+1],this.positions[e+2]]},MeshLine.prototype.process=function(){var t,e,i=this.positions.length/6;this.previous=[],this.next=[],this.side=[],this.width=[],this.indices_array=[],this.uvs=[],e=this.compareV3(0,i-1)?this.copyV3(i-2):this.copyV3(0),this.previous.push(e[0],e[1],e[2]),this.previous.push(e[0],e[1],e[2]);for(var s=0;s<i;s++){if(this.side.push(1),this.side.push(-1),t=this.widthCallback?this.widthCallback(s/(i-1)):1,this.width.push(t),this.width.push(t),this.uvs.push(s/(i-1),0),this.uvs.push(s/(i-1),1),s<i-1){e=this.copyV3(s),this.previous.push(e[0],e[1],e[2]),this.previous.push(e[0],e[1],e[2]);var r=2*s;this.indices_array.push(r,r+1,r+2),this.indices_array.push(r+2,r+1,r+3)}s>0&&(e=this.copyV3(s),this.next.push(e[0],e[1],e[2]),this.next.push(e[0],e[1],e[2]))}e=this.compareV3(i-1,0)?this.copyV3(1):this.copyV3(i-1),this.next.push(e[0],e[1],e[2]),this.next.push(e[0],e[1],e[2]),this._attributes&&this._attributes.position.count===this.positions.length?(this._attributes.position.copyArray(new Float32Array(this.positions)),this._attributes.position.needsUpdate=!0,this._attributes.previous.copyArray(new Float32Array(this.previous)),this._attributes.previous.needsUpdate=!0,this._attributes.next.copyArray(new Float32Array(this.next)),this._attributes.next.needsUpdate=!0,this._attributes.side.copyArray(new Float32Array(this.side)),this._attributes.side.needsUpdate=!0,this._attributes.width.copyArray(new Float32Array(this.width)),this._attributes.width.needsUpdate=!0,this._attributes.uv.copyArray(new Float32Array(this.uvs)),this._attributes.uv.needsUpdate=!0,this._attributes.index.copyArray(new Uint16Array(this.indices_array)),this._attributes.index.needsUpdate=!0):this._attributes={position:new THREE.BufferAttribute(new Float32Array(this.positions),3),previous:new THREE.BufferAttribute(new Float32Array(this.previous),3),next:new THREE.BufferAttribute(new Float32Array(this.next),3),side:new THREE.BufferAttribute(new Float32Array(this.side),1),width:new THREE.BufferAttribute(new Float32Array(this.width),1),uv:new THREE.BufferAttribute(new Float32Array(this.uvs),2),index:new THREE.BufferAttribute(new Uint16Array(this.indices_array),1),counters:new THREE.BufferAttribute(new Float32Array(this.counters),1)},this.setAttribute("position",this._attributes.position),this.setAttribute("previous",this._attributes.previous),this.setAttribute("next",this._attributes.next),this.setAttribute("side",this._attributes.side),this.setAttribute("width",this._attributes.width),this.setAttribute("uv",this._attributes.uv),this.setAttribute("counters",this._attributes.counters),this.setIndex(this._attributes.index),this.computeBoundingSphere(),this.computeBoundingBox()},MeshLine.prototype.advance=function(t){var e=this._attributes.position.array,i=this._attributes.previous.array,s=this._attributes.next.array,r=e.length;memcpy(e,0,i,0,r),memcpy(e,6,e,0,r-6),e[r-6]=t.x,e[r-5]=t.y,e[r-4]=t.z,e[r-3]=t.x,e[r-2]=t.y,e[r-1]=t.z,memcpy(e,6,s,0,r-6),s[r-6]=t.x,s[r-5]=t.y,s[r-4]=t.z,s[r-3]=t.x,s[r-2]=t.y,s[r-1]=t.z,this._attributes.position.needsUpdate=!0,this._attributes.previous.needsUpdate=!0,this._attributes.next.needsUpdate=!0},THREE.ShaderChunk.meshline_vert=["",THREE.ShaderChunk.logdepthbuf_pars_vertex,THREE.ShaderChunk.fog_pars_vertex,"","attribute vec3 previous;","attribute vec3 next;","attribute float side;","attribute float width;","attribute float counters;","","uniform vec2 resolution;","uniform float lineWidth;","uniform vec3 color;","uniform float opacity;","uniform float sizeAttenuation;","","varying vec2 vUV;","varying vec4 vColor;","varying float vCounters;","","vec2 fix( vec4 i, float aspect ) {",""," vec2 res = i.xy / i.w;"," res.x *= aspect;","\t vCounters = counters;"," return res;","","}","","void main() {",""," float aspect = resolution.x / resolution.y;",""," vColor = vec4( color, opacity );"," vUV = uv;",""," mat4 m = projectionMatrix * modelViewMatrix;"," vec4 finalPosition = m * vec4( position, 1.0 );"," vec4 prevPos = m * vec4( previous, 1.0 );"," vec4 nextPos = m * vec4( next, 1.0 );",""," vec2 currentP = fix( finalPosition, aspect );"," vec2 prevP = fix( prevPos, aspect );"," vec2 nextP = fix( nextPos, aspect );",""," float w = lineWidth * width;",""," vec2 dir;"," if( nextP == currentP ) dir = normalize( currentP - prevP );"," else if( prevP == currentP ) dir = normalize( nextP - currentP );"," else {"," vec2 dir1 = normalize( currentP - prevP );"," vec2 dir2 = normalize( nextP - currentP );"," dir = normalize( dir1 + dir2 );",""," vec2 perp = vec2( -dir1.y, dir1.x );"," vec2 miter = vec2( -dir.y, dir.x );"," //w = clamp( w / dot( miter, perp ), 0., 4. * lineWidth * width );",""," }",""," //vec2 normal = ( cross( vec3( dir, 0. ), vec3( 0., 0., 1. ) ) ).xy;"," vec4 normal = vec4( -dir.y, dir.x, 0., 1. );"," normal.xy *= .5 * w;"," normal *= projectionMatrix;"," if( sizeAttenuation == 0. ) {"," normal.xy *= finalPosition.w;"," normal.xy /= ( vec4( resolution, 0., 1. ) * projectionMatrix ).xy;"," }",""," finalPosition.xy += normal.xy * side;",""," gl_Position = finalPosition;","",THREE.ShaderChunk.logdepthbuf_vertex,THREE.ShaderChunk.fog_vertex&&" vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );",THREE.ShaderChunk.fog_vertex,"}"].join("\n"),THREE.ShaderChunk.meshline_frag=["",THREE.ShaderChunk.fog_pars_fragment,THREE.ShaderChunk.logdepthbuf_pars_fragment,"","uniform sampler2D map;","uniform sampler2D alphaMap;","uniform float useMap;","uniform float useAlphaMap;","uniform float useDash;","uniform float dashArray;","uniform float dashOffset;","uniform float dashRatio;","uniform float visibility;","uniform float alphaTest;","uniform vec2 repeat;","","varying vec2 vUV;","varying vec4 vColor;","varying float vCounters;","","void main() {","",THREE.ShaderChunk.logdepthbuf_fragment,""," vec4 c = vColor;"," if( useMap == 1. ) c *= texture2D( map, vUV * repeat );"," if( useAlphaMap == 1. ) c.a *= texture2D( alphaMap, vUV * repeat ).a;"," if( c.a < alphaTest ) discard;"," if( useDash == 1. ){"," c.a *= ceil(mod(vCounters + dashOffset, dashArray) - (dashArray * dashRatio));"," }"," gl_FragColor = c;"," gl_FragColor.a *= step(vCounters, visibility);","",THREE.ShaderChunk.fog_fragment,"}"].join("\n");class MeshLineMaterial extends THREE.ShaderMaterial{constructor(t){super({uniforms:Object.assign({},THREE.UniformsLib.fog,{lineWidth:{value:1},map:{value:null},useMap:{value:0},alphaMap:{value:null},useAlphaMap:{value:0},color:{value:new THREE.Color(16777215)},opacity:{value:1},resolution:{value:new THREE.Vector2(1,1)},sizeAttenuation:{value:1},dashArray:{value:0},dashOffset:{value:0},dashRatio:{value:.5},useDash:{value:0},visibility:{value:1},alphaTest:{value:0},repeat:{value:new THREE.Vector2(1,1)}}),vertexShader:THREE.ShaderChunk.meshline_vert,fragmentShader:THREE.ShaderChunk.meshline_frag}),this.isMeshLineMaterial=!0,this.type="MeshLineMaterial",Object.defineProperties(this,{lineWidth:{enumerable:!0,get:function(){return this.uniforms.lineWidth.value},set:function(t){this.uniforms.lineWidth.value=t}},map:{enumerable:!0,get:function(){return this.uniforms.map.value},set:function(t){this.uniforms.map.value=t}},useMap:{enumerable:!0,get:function(){return this.uniforms.useMap.value},set:function(t){this.uniforms.useMap.value=t}},alphaMap:{enumerable:!0,get:function(){return this.uniforms.alphaMap.value},set:function(t){this.uniforms.alphaMap.value=t}},useAlphaMap:{enumerable:!0,get:function(){return this.uniforms.useAlphaMap.value},set:function(t){this.uniforms.useAlphaMap.value=t}},color:{enumerable:!0,get:function(){return this.uniforms.color.value},set:function(t){this.uniforms.color.value=t}},opacity:{enumerable:!0,get:function(){return this.uniforms.opacity.value},set:function(t){this.uniforms.opacity.value=t}},resolution:{enumerable:!0,get:function(){return this.uniforms.resolution.value},set:function(t){this.uniforms.resolution.value.copy(t)}},sizeAttenuation:{enumerable:!0,get:function(){return this.uniforms.sizeAttenuation.value},set:function(t){this.uniforms.sizeAttenuation.value=t}},dashArray:{enumerable:!0,get:function(){return this.uniforms.dashArray.value},set:function(t){this.uniforms.dashArray.value=t,this.useDash=0!==t?1:0}},dashOffset:{enumerable:!0,get:function(){return this.uniforms.dashOffset.value},set:function(t){this.uniforms.dashOffset.value=t}},dashRatio:{enumerable:!0,get:function(){return this.uniforms.dashRatio.value},set:function(t){this.uniforms.dashRatio.value=t}},useDash:{enumerable:!0,get:function(){return this.uniforms.useDash.value},set:function(t){this.uniforms.useDash.value=t}},visibility:{enumerable:!0,get:function(){return this.uniforms.visibility.value},set:function(t){this.uniforms.visibility.value=t}},alphaTest:{enumerable:!0,get:function(){return this.uniforms.alphaTest.value},set:function(t){this.uniforms.alphaTest.value=t}},repeat:{enumerable:!0,get:function(){return this.uniforms.repeat.value},set:function(t){this.uniforms.repeat.value.copy(t)}}}),this.setValues(t)}}MeshLineMaterial.prototype.copy=function(t){return THREE.ShaderMaterial.prototype.copy.call(this,t),this.lineWidth=t.lineWidth,this.map=t.map,this.useMap=t.useMap,this.alphaMap=t.alphaMap,this.useAlphaMap=t.useAlphaMap,this.color.copy(t.color),this.opacity=t.opacity,this.resolution.copy(t.resolution),this.sizeAttenuation=t.sizeAttenuation,this.dashArray.copy(t.dashArray),this.dashOffset.copy(t.dashOffset),this.dashRatio.copy(t.dashRatio),this.useDash=t.useDash,this.visibility=t.visibility,this.alphaTest=t.alphaTest,this.repeat.copy(t.repeat),this};export{MeshLine,MeshLineMaterial,MeshLineRaycast};
|
15 |
+
//# sourceMappingURL=/sm/a10f0fbff9ef9e01c8548236b6b20610cf5d5cba1f631d8ebab539add9c04974.map
|
js/TrackballControls.js
ADDED
@@ -0,0 +1,821 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
async function _import() {
|
2 |
+
if (!globalThis.posex || !globalThis.posex.import) {
|
3 |
+
return await import('three');
|
4 |
+
} else {
|
5 |
+
return await globalThis.posex.imports.three();
|
6 |
+
}
|
7 |
+
}
|
8 |
+
const {
|
9 |
+
EventDispatcher,
|
10 |
+
MOUSE,
|
11 |
+
Quaternion,
|
12 |
+
Vector2,
|
13 |
+
Vector3
|
14 |
+
} = await _import();
|
15 |
+
|
16 |
+
const _changeEvent = { type: 'change' };
|
17 |
+
const _startEvent = { type: 'start' };
|
18 |
+
const _endEvent = { type: 'end' };
|
19 |
+
|
20 |
+
class TrackballControls extends EventDispatcher {
|
21 |
+
|
22 |
+
constructor( object, domElement ) {
|
23 |
+
|
24 |
+
super();
|
25 |
+
|
26 |
+
const scope = this;
|
27 |
+
const STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 };
|
28 |
+
|
29 |
+
this.object = object;
|
30 |
+
this.domElement = domElement;
|
31 |
+
this.domElement.style.touchAction = 'none'; // disable touch scroll
|
32 |
+
|
33 |
+
// API
|
34 |
+
|
35 |
+
this.enabled = true;
|
36 |
+
|
37 |
+
this.screen = { left: 0, top: 0, width: 0, height: 0 };
|
38 |
+
|
39 |
+
this.rotateSpeed = 1.0;
|
40 |
+
this.zoomSpeed = 1.2;
|
41 |
+
this.panSpeed = 0.3;
|
42 |
+
|
43 |
+
this.noRotate = false;
|
44 |
+
this.noZoom = false;
|
45 |
+
this.noPan = false;
|
46 |
+
|
47 |
+
this.staticMoving = false;
|
48 |
+
this.dynamicDampingFactor = 0.2;
|
49 |
+
|
50 |
+
this.minDistance = 0;
|
51 |
+
this.maxDistance = Infinity;
|
52 |
+
|
53 |
+
this.keys = [ 'KeyA' /*A*/, 'KeyS' /*S*/, 'KeyD' /*D*/ ];
|
54 |
+
|
55 |
+
this.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN };
|
56 |
+
|
57 |
+
// internals
|
58 |
+
|
59 |
+
this.target = new Vector3();
|
60 |
+
|
61 |
+
const EPS = 0.000001;
|
62 |
+
|
63 |
+
const lastPosition = new Vector3();
|
64 |
+
let lastZoom = 1;
|
65 |
+
|
66 |
+
let _state = STATE.NONE,
|
67 |
+
_keyState = STATE.NONE,
|
68 |
+
|
69 |
+
_touchZoomDistanceStart = 0,
|
70 |
+
_touchZoomDistanceEnd = 0,
|
71 |
+
|
72 |
+
_lastAngle = 0;
|
73 |
+
|
74 |
+
const _eye = new Vector3(),
|
75 |
+
|
76 |
+
_movePrev = new Vector2(),
|
77 |
+
_moveCurr = new Vector2(),
|
78 |
+
|
79 |
+
_lastAxis = new Vector3(),
|
80 |
+
|
81 |
+
_zoomStart = new Vector2(),
|
82 |
+
_zoomEnd = new Vector2(),
|
83 |
+
|
84 |
+
_panStart = new Vector2(),
|
85 |
+
_panEnd = new Vector2(),
|
86 |
+
|
87 |
+
_pointers = [],
|
88 |
+
_pointerPositions = {};
|
89 |
+
|
90 |
+
// for reset
|
91 |
+
|
92 |
+
this.target0 = this.target.clone();
|
93 |
+
this.position0 = this.object.position.clone();
|
94 |
+
this.up0 = this.object.up.clone();
|
95 |
+
this.zoom0 = this.object.zoom;
|
96 |
+
|
97 |
+
// methods
|
98 |
+
|
99 |
+
this.handleResize = function () {
|
100 |
+
|
101 |
+
const box = scope.domElement.getBoundingClientRect();
|
102 |
+
// adjustments come from similar code in the jquery offset() function
|
103 |
+
const d = scope.domElement.ownerDocument.documentElement;
|
104 |
+
scope.screen.left = box.left + window.pageXOffset - d.clientLeft;
|
105 |
+
scope.screen.top = box.top + window.pageYOffset - d.clientTop;
|
106 |
+
scope.screen.width = box.width;
|
107 |
+
scope.screen.height = box.height;
|
108 |
+
|
109 |
+
};
|
110 |
+
|
111 |
+
const getMouseOnScreen = ( function () {
|
112 |
+
|
113 |
+
const vector = new Vector2();
|
114 |
+
|
115 |
+
return function getMouseOnScreen( pageX, pageY ) {
|
116 |
+
|
117 |
+
vector.set(
|
118 |
+
( pageX - scope.screen.left ) / scope.screen.width,
|
119 |
+
( pageY - scope.screen.top ) / scope.screen.height
|
120 |
+
);
|
121 |
+
|
122 |
+
return vector;
|
123 |
+
|
124 |
+
};
|
125 |
+
|
126 |
+
}() );
|
127 |
+
|
128 |
+
const getMouseOnCircle = ( function () {
|
129 |
+
|
130 |
+
const vector = new Vector2();
|
131 |
+
|
132 |
+
return function getMouseOnCircle( pageX, pageY ) {
|
133 |
+
|
134 |
+
vector.set(
|
135 |
+
( ( pageX - scope.screen.width * 0.5 - scope.screen.left ) / ( scope.screen.width * 0.5 ) ),
|
136 |
+
( ( scope.screen.height + 2 * ( scope.screen.top - pageY ) ) / scope.screen.width ) // screen.width intentional
|
137 |
+
);
|
138 |
+
|
139 |
+
return vector;
|
140 |
+
|
141 |
+
};
|
142 |
+
|
143 |
+
}() );
|
144 |
+
|
145 |
+
this.rotateCamera = ( function () {
|
146 |
+
|
147 |
+
const axis = new Vector3(),
|
148 |
+
quaternion = new Quaternion(),
|
149 |
+
eyeDirection = new Vector3(),
|
150 |
+
objectUpDirection = new Vector3(),
|
151 |
+
objectSidewaysDirection = new Vector3(),
|
152 |
+
moveDirection = new Vector3();
|
153 |
+
|
154 |
+
return function rotateCamera() {
|
155 |
+
|
156 |
+
moveDirection.set( _moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0 );
|
157 |
+
let angle = moveDirection.length();
|
158 |
+
|
159 |
+
if ( angle ) {
|
160 |
+
|
161 |
+
_eye.copy( scope.object.position ).sub( scope.target );
|
162 |
+
|
163 |
+
eyeDirection.copy( _eye ).normalize();
|
164 |
+
objectUpDirection.copy( scope.object.up ).normalize();
|
165 |
+
objectSidewaysDirection.crossVectors( objectUpDirection, eyeDirection ).normalize();
|
166 |
+
|
167 |
+
objectUpDirection.setLength( _moveCurr.y - _movePrev.y );
|
168 |
+
objectSidewaysDirection.setLength( _moveCurr.x - _movePrev.x );
|
169 |
+
|
170 |
+
moveDirection.copy( objectUpDirection.add( objectSidewaysDirection ) );
|
171 |
+
|
172 |
+
axis.crossVectors( moveDirection, _eye ).normalize();
|
173 |
+
|
174 |
+
angle *= scope.rotateSpeed;
|
175 |
+
quaternion.setFromAxisAngle( axis, angle );
|
176 |
+
|
177 |
+
_eye.applyQuaternion( quaternion );
|
178 |
+
scope.object.up.applyQuaternion( quaternion );
|
179 |
+
|
180 |
+
_lastAxis.copy( axis );
|
181 |
+
_lastAngle = angle;
|
182 |
+
|
183 |
+
} else if ( ! scope.staticMoving && _lastAngle ) {
|
184 |
+
|
185 |
+
_lastAngle *= Math.sqrt( 1.0 - scope.dynamicDampingFactor );
|
186 |
+
_eye.copy( scope.object.position ).sub( scope.target );
|
187 |
+
quaternion.setFromAxisAngle( _lastAxis, _lastAngle );
|
188 |
+
_eye.applyQuaternion( quaternion );
|
189 |
+
scope.object.up.applyQuaternion( quaternion );
|
190 |
+
|
191 |
+
}
|
192 |
+
|
193 |
+
_movePrev.copy( _moveCurr );
|
194 |
+
|
195 |
+
};
|
196 |
+
|
197 |
+
}() );
|
198 |
+
|
199 |
+
|
200 |
+
this.zoomCamera = function () {
|
201 |
+
|
202 |
+
let factor;
|
203 |
+
|
204 |
+
if ( _state === STATE.TOUCH_ZOOM_PAN ) {
|
205 |
+
|
206 |
+
factor = _touchZoomDistanceStart / _touchZoomDistanceEnd;
|
207 |
+
_touchZoomDistanceStart = _touchZoomDistanceEnd;
|
208 |
+
|
209 |
+
if ( scope.object.isPerspectiveCamera ) {
|
210 |
+
|
211 |
+
_eye.multiplyScalar( factor );
|
212 |
+
|
213 |
+
} else if ( scope.object.isOrthographicCamera ) {
|
214 |
+
|
215 |
+
scope.object.zoom /= factor;
|
216 |
+
scope.object.updateProjectionMatrix();
|
217 |
+
|
218 |
+
} else {
|
219 |
+
|
220 |
+
console.warn( 'THREE.TrackballControls: Unsupported camera type' );
|
221 |
+
|
222 |
+
}
|
223 |
+
|
224 |
+
} else {
|
225 |
+
|
226 |
+
factor = 1.0 + ( _zoomEnd.y - _zoomStart.y ) * scope.zoomSpeed;
|
227 |
+
|
228 |
+
if ( factor !== 1.0 && factor > 0.0 ) {
|
229 |
+
|
230 |
+
if ( scope.object.isPerspectiveCamera ) {
|
231 |
+
|
232 |
+
_eye.multiplyScalar( factor );
|
233 |
+
|
234 |
+
} else if ( scope.object.isOrthographicCamera ) {
|
235 |
+
|
236 |
+
scope.object.zoom /= factor;
|
237 |
+
scope.object.updateProjectionMatrix();
|
238 |
+
|
239 |
+
} else {
|
240 |
+
|
241 |
+
console.warn( 'THREE.TrackballControls: Unsupported camera type' );
|
242 |
+
|
243 |
+
}
|
244 |
+
|
245 |
+
}
|
246 |
+
|
247 |
+
if ( scope.staticMoving ) {
|
248 |
+
|
249 |
+
_zoomStart.copy( _zoomEnd );
|
250 |
+
|
251 |
+
} else {
|
252 |
+
|
253 |
+
_zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;
|
254 |
+
|
255 |
+
}
|
256 |
+
|
257 |
+
}
|
258 |
+
|
259 |
+
};
|
260 |
+
|
261 |
+
this.panCamera = ( function () {
|
262 |
+
|
263 |
+
const mouseChange = new Vector2(),
|
264 |
+
objectUp = new Vector3(),
|
265 |
+
pan = new Vector3();
|
266 |
+
|
267 |
+
return function panCamera() {
|
268 |
+
|
269 |
+
mouseChange.copy( _panEnd ).sub( _panStart );
|
270 |
+
|
271 |
+
if ( mouseChange.lengthSq() ) {
|
272 |
+
|
273 |
+
if ( scope.object.isOrthographicCamera ) {
|
274 |
+
|
275 |
+
const scale_x = ( scope.object.right - scope.object.left ) / scope.object.zoom / scope.domElement.clientWidth;
|
276 |
+
const scale_y = ( scope.object.top - scope.object.bottom ) / scope.object.zoom / scope.domElement.clientWidth;
|
277 |
+
|
278 |
+
mouseChange.x *= scale_x;
|
279 |
+
mouseChange.y *= scale_y;
|
280 |
+
|
281 |
+
}
|
282 |
+
|
283 |
+
mouseChange.multiplyScalar( _eye.length() * scope.panSpeed );
|
284 |
+
|
285 |
+
pan.copy( _eye ).cross( scope.object.up ).setLength( mouseChange.x );
|
286 |
+
pan.add( objectUp.copy( scope.object.up ).setLength( mouseChange.y ) );
|
287 |
+
|
288 |
+
scope.object.position.add( pan );
|
289 |
+
scope.target.add( pan );
|
290 |
+
|
291 |
+
if ( scope.staticMoving ) {
|
292 |
+
|
293 |
+
_panStart.copy( _panEnd );
|
294 |
+
|
295 |
+
} else {
|
296 |
+
|
297 |
+
_panStart.add( mouseChange.subVectors( _panEnd, _panStart ).multiplyScalar( scope.dynamicDampingFactor ) );
|
298 |
+
|
299 |
+
}
|
300 |
+
|
301 |
+
}
|
302 |
+
|
303 |
+
};
|
304 |
+
|
305 |
+
}() );
|
306 |
+
|
307 |
+
this.checkDistances = function () {
|
308 |
+
|
309 |
+
if ( ! scope.noZoom || ! scope.noPan ) {
|
310 |
+
|
311 |
+
if ( _eye.lengthSq() > scope.maxDistance * scope.maxDistance ) {
|
312 |
+
|
313 |
+
scope.object.position.addVectors( scope.target, _eye.setLength( scope.maxDistance ) );
|
314 |
+
_zoomStart.copy( _zoomEnd );
|
315 |
+
|
316 |
+
}
|
317 |
+
|
318 |
+
if ( _eye.lengthSq() < scope.minDistance * scope.minDistance ) {
|
319 |
+
|
320 |
+
scope.object.position.addVectors( scope.target, _eye.setLength( scope.minDistance ) );
|
321 |
+
_zoomStart.copy( _zoomEnd );
|
322 |
+
|
323 |
+
}
|
324 |
+
|
325 |
+
}
|
326 |
+
|
327 |
+
};
|
328 |
+
|
329 |
+
this.update = function () {
|
330 |
+
|
331 |
+
_eye.subVectors( scope.object.position, scope.target );
|
332 |
+
|
333 |
+
if ( ! scope.noRotate ) {
|
334 |
+
|
335 |
+
scope.rotateCamera();
|
336 |
+
|
337 |
+
}
|
338 |
+
|
339 |
+
if ( ! scope.noZoom ) {
|
340 |
+
|
341 |
+
scope.zoomCamera();
|
342 |
+
|
343 |
+
}
|
344 |
+
|
345 |
+
if ( ! scope.noPan ) {
|
346 |
+
|
347 |
+
scope.panCamera();
|
348 |
+
|
349 |
+
}
|
350 |
+
|
351 |
+
scope.object.position.addVectors( scope.target, _eye );
|
352 |
+
|
353 |
+
if ( scope.object.isPerspectiveCamera ) {
|
354 |
+
|
355 |
+
scope.checkDistances();
|
356 |
+
|
357 |
+
scope.object.lookAt( scope.target );
|
358 |
+
|
359 |
+
if ( lastPosition.distanceToSquared( scope.object.position ) > EPS ) {
|
360 |
+
|
361 |
+
scope.dispatchEvent( _changeEvent );
|
362 |
+
|
363 |
+
lastPosition.copy( scope.object.position );
|
364 |
+
|
365 |
+
}
|
366 |
+
|
367 |
+
} else if ( scope.object.isOrthographicCamera ) {
|
368 |
+
|
369 |
+
scope.object.lookAt( scope.target );
|
370 |
+
|
371 |
+
if ( lastPosition.distanceToSquared( scope.object.position ) > EPS || lastZoom !== scope.object.zoom ) {
|
372 |
+
|
373 |
+
scope.dispatchEvent( _changeEvent );
|
374 |
+
|
375 |
+
lastPosition.copy( scope.object.position );
|
376 |
+
lastZoom = scope.object.zoom;
|
377 |
+
|
378 |
+
}
|
379 |
+
|
380 |
+
} else {
|
381 |
+
|
382 |
+
console.warn( 'THREE.TrackballControls: Unsupported camera type' );
|
383 |
+
|
384 |
+
}
|
385 |
+
|
386 |
+
};
|
387 |
+
|
388 |
+
this.reset = function () {
|
389 |
+
|
390 |
+
_state = STATE.NONE;
|
391 |
+
_keyState = STATE.NONE;
|
392 |
+
|
393 |
+
scope.target.copy( scope.target0 );
|
394 |
+
scope.object.position.copy( scope.position0 );
|
395 |
+
scope.object.up.copy( scope.up0 );
|
396 |
+
scope.object.zoom = scope.zoom0;
|
397 |
+
|
398 |
+
scope.object.updateProjectionMatrix();
|
399 |
+
|
400 |
+
_eye.subVectors( scope.object.position, scope.target );
|
401 |
+
|
402 |
+
scope.object.lookAt( scope.target );
|
403 |
+
|
404 |
+
scope.dispatchEvent( _changeEvent );
|
405 |
+
|
406 |
+
lastPosition.copy( scope.object.position );
|
407 |
+
lastZoom = scope.object.zoom;
|
408 |
+
|
409 |
+
};
|
410 |
+
|
411 |
+
// listeners
|
412 |
+
|
413 |
+
function onPointerDown( event ) {
|
414 |
+
|
415 |
+
if ( scope.enabled === false ) return;
|
416 |
+
|
417 |
+
if ( _pointers.length === 0 ) {
|
418 |
+
|
419 |
+
scope.domElement.setPointerCapture( event.pointerId );
|
420 |
+
|
421 |
+
scope.domElement.addEventListener( 'pointermove', onPointerMove );
|
422 |
+
scope.domElement.addEventListener( 'pointerup', onPointerUp );
|
423 |
+
|
424 |
+
}
|
425 |
+
|
426 |
+
//
|
427 |
+
|
428 |
+
addPointer( event );
|
429 |
+
|
430 |
+
if ( event.pointerType === 'touch' ) {
|
431 |
+
|
432 |
+
onTouchStart( event );
|
433 |
+
|
434 |
+
} else {
|
435 |
+
|
436 |
+
onMouseDown( event );
|
437 |
+
|
438 |
+
}
|
439 |
+
|
440 |
+
}
|
441 |
+
|
442 |
+
function onPointerMove( event ) {
|
443 |
+
|
444 |
+
if ( scope.enabled === false ) return;
|
445 |
+
|
446 |
+
if ( event.pointerType === 'touch' ) {
|
447 |
+
|
448 |
+
onTouchMove( event );
|
449 |
+
|
450 |
+
} else {
|
451 |
+
|
452 |
+
onMouseMove( event );
|
453 |
+
|
454 |
+
}
|
455 |
+
|
456 |
+
}
|
457 |
+
|
458 |
+
function onPointerUp( event ) {
|
459 |
+
|
460 |
+
if ( scope.enabled === false ) return;
|
461 |
+
|
462 |
+
if ( event.pointerType === 'touch' ) {
|
463 |
+
|
464 |
+
onTouchEnd( event );
|
465 |
+
|
466 |
+
} else {
|
467 |
+
|
468 |
+
onMouseUp();
|
469 |
+
|
470 |
+
}
|
471 |
+
|
472 |
+
//
|
473 |
+
|
474 |
+
removePointer( event );
|
475 |
+
|
476 |
+
if ( _pointers.length === 0 ) {
|
477 |
+
|
478 |
+
scope.domElement.releasePointerCapture( event.pointerId );
|
479 |
+
|
480 |
+
scope.domElement.removeEventListener( 'pointermove', onPointerMove );
|
481 |
+
scope.domElement.removeEventListener( 'pointerup', onPointerUp );
|
482 |
+
|
483 |
+
}
|
484 |
+
|
485 |
+
|
486 |
+
}
|
487 |
+
|
488 |
+
function onPointerCancel( event ) {
|
489 |
+
|
490 |
+
removePointer( event );
|
491 |
+
|
492 |
+
}
|
493 |
+
|
494 |
+
function keydown( event ) {
|
495 |
+
|
496 |
+
if ( scope.enabled === false ) return;
|
497 |
+
|
498 |
+
window.removeEventListener( 'keydown', keydown );
|
499 |
+
|
500 |
+
if ( _keyState !== STATE.NONE ) {
|
501 |
+
|
502 |
+
return;
|
503 |
+
|
504 |
+
} else if ( event.code === scope.keys[ STATE.ROTATE ] && ! scope.noRotate ) {
|
505 |
+
|
506 |
+
_keyState = STATE.ROTATE;
|
507 |
+
|
508 |
+
} else if ( event.code === scope.keys[ STATE.ZOOM ] && ! scope.noZoom ) {
|
509 |
+
|
510 |
+
_keyState = STATE.ZOOM;
|
511 |
+
|
512 |
+
} else if ( event.code === scope.keys[ STATE.PAN ] && ! scope.noPan ) {
|
513 |
+
|
514 |
+
_keyState = STATE.PAN;
|
515 |
+
|
516 |
+
}
|
517 |
+
|
518 |
+
}
|
519 |
+
|
520 |
+
function keyup() {
|
521 |
+
|
522 |
+
if ( scope.enabled === false ) return;
|
523 |
+
|
524 |
+
_keyState = STATE.NONE;
|
525 |
+
|
526 |
+
window.addEventListener( 'keydown', keydown );
|
527 |
+
|
528 |
+
}
|
529 |
+
|
530 |
+
function onMouseDown( event ) {
|
531 |
+
|
532 |
+
if ( _state === STATE.NONE ) {
|
533 |
+
|
534 |
+
switch ( event.button ) {
|
535 |
+
|
536 |
+
case scope.mouseButtons.LEFT:
|
537 |
+
_state = STATE.ROTATE;
|
538 |
+
break;
|
539 |
+
|
540 |
+
case scope.mouseButtons.MIDDLE:
|
541 |
+
_state = STATE.ZOOM;
|
542 |
+
break;
|
543 |
+
|
544 |
+
case scope.mouseButtons.RIGHT:
|
545 |
+
_state = STATE.PAN;
|
546 |
+
break;
|
547 |
+
|
548 |
+
}
|
549 |
+
|
550 |
+
}
|
551 |
+
|
552 |
+
const state = ( _keyState !== STATE.NONE ) ? _keyState : _state;
|
553 |
+
|
554 |
+
if ( state === STATE.ROTATE && ! scope.noRotate ) {
|
555 |
+
|
556 |
+
_moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) );
|
557 |
+
_movePrev.copy( _moveCurr );
|
558 |
+
|
559 |
+
} else if ( state === STATE.ZOOM && ! scope.noZoom ) {
|
560 |
+
|
561 |
+
_zoomStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
|
562 |
+
_zoomEnd.copy( _zoomStart );
|
563 |
+
|
564 |
+
} else if ( state === STATE.PAN && ! scope.noPan ) {
|
565 |
+
|
566 |
+
_panStart.copy( getMouseOnScreen( event.pageX, event.pageY ) );
|
567 |
+
_panEnd.copy( _panStart );
|
568 |
+
|
569 |
+
}
|
570 |
+
|
571 |
+
scope.dispatchEvent( _startEvent );
|
572 |
+
|
573 |
+
}
|
574 |
+
|
575 |
+
function onMouseMove( event ) {
|
576 |
+
|
577 |
+
const state = ( _keyState !== STATE.NONE ) ? _keyState : _state;
|
578 |
+
|
579 |
+
if ( state === STATE.ROTATE && ! scope.noRotate ) {
|
580 |
+
|
581 |
+
_movePrev.copy( _moveCurr );
|
582 |
+
_moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) );
|
583 |
+
|
584 |
+
} else if ( state === STATE.ZOOM && ! scope.noZoom ) {
|
585 |
+
|
586 |
+
_zoomEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );
|
587 |
+
|
588 |
+
} else if ( state === STATE.PAN && ! scope.noPan ) {
|
589 |
+
|
590 |
+
_panEnd.copy( getMouseOnScreen( event.pageX, event.pageY ) );
|
591 |
+
|
592 |
+
}
|
593 |
+
|
594 |
+
}
|
595 |
+
|
596 |
+
function onMouseUp() {
|
597 |
+
|
598 |
+
_state = STATE.NONE;
|
599 |
+
|
600 |
+
scope.dispatchEvent( _endEvent );
|
601 |
+
|
602 |
+
}
|
603 |
+
|
604 |
+
function onMouseWheel( event ) {
|
605 |
+
|
606 |
+
if ( scope.enabled === false ) return;
|
607 |
+
|
608 |
+
if ( scope.noZoom === true ) return;
|
609 |
+
|
610 |
+
event.preventDefault();
|
611 |
+
|
612 |
+
switch ( event.deltaMode ) {
|
613 |
+
|
614 |
+
case 2:
|
615 |
+
// Zoom in pages
|
616 |
+
_zoomStart.y -= event.deltaY * 0.025;
|
617 |
+
break;
|
618 |
+
|
619 |
+
case 1:
|
620 |
+
// Zoom in lines
|
621 |
+
_zoomStart.y -= event.deltaY * 0.01;
|
622 |
+
break;
|
623 |
+
|
624 |
+
default:
|
625 |
+
// undefined, 0, assume pixels
|
626 |
+
_zoomStart.y -= event.deltaY * 0.00025;
|
627 |
+
break;
|
628 |
+
|
629 |
+
}
|
630 |
+
|
631 |
+
scope.dispatchEvent( _startEvent );
|
632 |
+
scope.dispatchEvent( _endEvent );
|
633 |
+
|
634 |
+
}
|
635 |
+
|
636 |
+
function onTouchStart( event ) {
|
637 |
+
|
638 |
+
trackPointer( event );
|
639 |
+
|
640 |
+
switch ( _pointers.length ) {
|
641 |
+
|
642 |
+
case 1:
|
643 |
+
_state = STATE.TOUCH_ROTATE;
|
644 |
+
_moveCurr.copy( getMouseOnCircle( _pointers[ 0 ].pageX, _pointers[ 0 ].pageY ) );
|
645 |
+
_movePrev.copy( _moveCurr );
|
646 |
+
break;
|
647 |
+
|
648 |
+
default: // 2 or more
|
649 |
+
_state = STATE.TOUCH_ZOOM_PAN;
|
650 |
+
const dx = _pointers[ 0 ].pageX - _pointers[ 1 ].pageX;
|
651 |
+
const dy = _pointers[ 0 ].pageY - _pointers[ 1 ].pageY;
|
652 |
+
_touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
|
653 |
+
|
654 |
+
const x = ( _pointers[ 0 ].pageX + _pointers[ 1 ].pageX ) / 2;
|
655 |
+
const y = ( _pointers[ 0 ].pageY + _pointers[ 1 ].pageY ) / 2;
|
656 |
+
_panStart.copy( getMouseOnScreen( x, y ) );
|
657 |
+
_panEnd.copy( _panStart );
|
658 |
+
break;
|
659 |
+
|
660 |
+
}
|
661 |
+
|
662 |
+
scope.dispatchEvent( _startEvent );
|
663 |
+
|
664 |
+
}
|
665 |
+
|
666 |
+
function onTouchMove( event ) {
|
667 |
+
|
668 |
+
trackPointer( event );
|
669 |
+
|
670 |
+
switch ( _pointers.length ) {
|
671 |
+
|
672 |
+
case 1:
|
673 |
+
_movePrev.copy( _moveCurr );
|
674 |
+
_moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) );
|
675 |
+
break;
|
676 |
+
|
677 |
+
default: // 2 or more
|
678 |
+
|
679 |
+
const position = getSecondPointerPosition( event );
|
680 |
+
|
681 |
+
const dx = event.pageX - position.x;
|
682 |
+
const dy = event.pageY - position.y;
|
683 |
+
_touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy );
|
684 |
+
|
685 |
+
const x = ( event.pageX + position.x ) / 2;
|
686 |
+
const y = ( event.pageY + position.y ) / 2;
|
687 |
+
_panEnd.copy( getMouseOnScreen( x, y ) );
|
688 |
+
break;
|
689 |
+
|
690 |
+
}
|
691 |
+
|
692 |
+
}
|
693 |
+
|
694 |
+
function onTouchEnd( event ) {
|
695 |
+
|
696 |
+
switch ( _pointers.length ) {
|
697 |
+
|
698 |
+
case 0:
|
699 |
+
_state = STATE.NONE;
|
700 |
+
break;
|
701 |
+
|
702 |
+
case 1:
|
703 |
+
_state = STATE.TOUCH_ROTATE;
|
704 |
+
_moveCurr.copy( getMouseOnCircle( event.pageX, event.pageY ) );
|
705 |
+
_movePrev.copy( _moveCurr );
|
706 |
+
break;
|
707 |
+
|
708 |
+
case 2:
|
709 |
+
_state = STATE.TOUCH_ZOOM_PAN;
|
710 |
+
|
711 |
+
for ( let i = 0; i < _pointers.length; i ++ ) {
|
712 |
+
|
713 |
+
if ( _pointers[ i ].pointerId !== event.pointerId ) {
|
714 |
+
|
715 |
+
const position = _pointerPositions[ _pointers[ i ].pointerId ];
|
716 |
+
_moveCurr.copy( getMouseOnCircle( position.x, position.y ) );
|
717 |
+
_movePrev.copy( _moveCurr );
|
718 |
+
break;
|
719 |
+
|
720 |
+
}
|
721 |
+
|
722 |
+
}
|
723 |
+
|
724 |
+
break;
|
725 |
+
|
726 |
+
}
|
727 |
+
|
728 |
+
scope.dispatchEvent( _endEvent );
|
729 |
+
|
730 |
+
}
|
731 |
+
|
732 |
+
function contextmenu( event ) {
|
733 |
+
|
734 |
+
if ( scope.enabled === false ) return;
|
735 |
+
|
736 |
+
event.preventDefault();
|
737 |
+
|
738 |
+
}
|
739 |
+
|
740 |
+
function addPointer( event ) {
|
741 |
+
|
742 |
+
_pointers.push( event );
|
743 |
+
|
744 |
+
}
|
745 |
+
|
746 |
+
function removePointer( event ) {
|
747 |
+
|
748 |
+
delete _pointerPositions[ event.pointerId ];
|
749 |
+
|
750 |
+
for ( let i = 0; i < _pointers.length; i ++ ) {
|
751 |
+
|
752 |
+
if ( _pointers[ i ].pointerId == event.pointerId ) {
|
753 |
+
|
754 |
+
_pointers.splice( i, 1 );
|
755 |
+
return;
|
756 |
+
|
757 |
+
}
|
758 |
+
|
759 |
+
}
|
760 |
+
|
761 |
+
}
|
762 |
+
|
763 |
+
function trackPointer( event ) {
|
764 |
+
|
765 |
+
let position = _pointerPositions[ event.pointerId ];
|
766 |
+
|
767 |
+
if ( position === undefined ) {
|
768 |
+
|
769 |
+
position = new Vector2();
|
770 |
+
_pointerPositions[ event.pointerId ] = position;
|
771 |
+
|
772 |
+
}
|
773 |
+
|
774 |
+
position.set( event.pageX, event.pageY );
|
775 |
+
|
776 |
+
}
|
777 |
+
|
778 |
+
function getSecondPointerPosition( event ) {
|
779 |
+
|
780 |
+
const pointer = ( event.pointerId === _pointers[ 0 ].pointerId ) ? _pointers[ 1 ] : _pointers[ 0 ];
|
781 |
+
|
782 |
+
return _pointerPositions[ pointer.pointerId ];
|
783 |
+
|
784 |
+
}
|
785 |
+
|
786 |
+
this.dispose = function () {
|
787 |
+
|
788 |
+
scope.domElement.removeEventListener( 'contextmenu', contextmenu );
|
789 |
+
|
790 |
+
scope.domElement.removeEventListener( 'pointerdown', onPointerDown );
|
791 |
+
scope.domElement.removeEventListener( 'pointercancel', onPointerCancel );
|
792 |
+
scope.domElement.removeEventListener( 'wheel', onMouseWheel );
|
793 |
+
|
794 |
+
scope.domElement.removeEventListener( 'pointermove', onPointerMove );
|
795 |
+
scope.domElement.removeEventListener( 'pointerup', onPointerUp );
|
796 |
+
|
797 |
+
window.removeEventListener( 'keydown', keydown );
|
798 |
+
window.removeEventListener( 'keyup', keyup );
|
799 |
+
|
800 |
+
};
|
801 |
+
|
802 |
+
this.domElement.addEventListener( 'contextmenu', contextmenu );
|
803 |
+
|
804 |
+
this.domElement.addEventListener( 'pointerdown', onPointerDown );
|
805 |
+
this.domElement.addEventListener( 'pointercancel', onPointerCancel );
|
806 |
+
this.domElement.addEventListener( 'wheel', onMouseWheel, { passive: false } );
|
807 |
+
|
808 |
+
|
809 |
+
window.addEventListener( 'keydown', keydown );
|
810 |
+
window.addEventListener( 'keyup', keyup );
|
811 |
+
|
812 |
+
this.handleResize();
|
813 |
+
|
814 |
+
// force an update at start
|
815 |
+
this.update();
|
816 |
+
|
817 |
+
}
|
818 |
+
|
819 |
+
}
|
820 |
+
|
821 |
+
export { TrackballControls };
|
js/app.js
ADDED
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const POSES = new Map();
|
2 |
+
|
3 |
+
function notify(str, type) {
|
4 |
+
if (type === undefined) type = 'success';
|
5 |
+
|
6 |
+
switch (type) {
|
7 |
+
case 'success': console.log(str); break;
|
8 |
+
case 'info': console.log(str); break;
|
9 |
+
case 'warn': console.warn(str); break;
|
10 |
+
case 'error': console.error(str); break;
|
11 |
+
}
|
12 |
+
|
13 |
+
const p = document.createElement('p');
|
14 |
+
p.textContent = str;
|
15 |
+
p.classList.add('item', type);
|
16 |
+
const cont = document.querySelector('#notifications');
|
17 |
+
cont.appendChild(p);
|
18 |
+
setTimeout(() => cont.removeChild(p), 3000);
|
19 |
+
}
|
20 |
+
|
21 |
+
async function save_pose(obj) {
|
22 |
+
const res = await fetch('/pose/save', {
|
23 |
+
method: 'POST',
|
24 |
+
headers: { 'Content-Type': 'application/json' },
|
25 |
+
body: JSON.stringify(obj),
|
26 |
+
});
|
27 |
+
const result = await res.json();
|
28 |
+
if (result.ok) reload_poses();
|
29 |
+
return result;
|
30 |
+
}
|
31 |
+
|
32 |
+
async function delete_pose(name) {
|
33 |
+
const res = await fetch('/pose/delete', {
|
34 |
+
method: 'POST',
|
35 |
+
headers: { 'Content-Type': 'application/json' },
|
36 |
+
body: JSON.stringify({ name }),
|
37 |
+
});
|
38 |
+
const result = await res.json();
|
39 |
+
notify(result.result, result.ok ? 'success' : 'error');
|
40 |
+
if (result.ok) reload_poses();
|
41 |
+
return result;
|
42 |
+
}
|
43 |
+
|
44 |
+
async function reload_poses() {
|
45 |
+
POSES.clear();
|
46 |
+
|
47 |
+
const res = await fetch('/pose/all');
|
48 |
+
const cont = document.querySelector('#saved_poses');
|
49 |
+
cont.innerHTML = '';
|
50 |
+
const df = document.createDocumentFragment();
|
51 |
+
for (let data of await res.json()) {
|
52 |
+
POSES.set(data.name, data);
|
53 |
+
|
54 |
+
const fig = document.createElement('figure')
|
55 |
+
const img = document.createElement('img');
|
56 |
+
const cap = document.createElement('figcaption');
|
57 |
+
const clo = document.createElement('div');
|
58 |
+
const clo2 = document.createElement('span');
|
59 |
+
fig.dataset.poseName = data.name;
|
60 |
+
cap.textContent = data.name;
|
61 |
+
clo.textContent = 'x';
|
62 |
+
clo.classList.add('close');
|
63 |
+
clo2.classList.add('close2');
|
64 |
+
clo2.textContent = 'delete';
|
65 |
+
clo.appendChild(clo2);
|
66 |
+
|
67 |
+
img.src = 'data:image/png;base64,' + data.image;
|
68 |
+
img.title = data.name;
|
69 |
+
fig.append(clo, img, cap);
|
70 |
+
|
71 |
+
df.appendChild(fig);
|
72 |
+
}
|
73 |
+
cont.appendChild(df);
|
74 |
+
}
|
75 |
+
|
76 |
+
document.addEventListener('DOMContentLoaded', async () => {
|
77 |
+
|
78 |
+
const ui = {
|
79 |
+
container: document.querySelector('#cont'),
|
80 |
+
canvas: document.querySelector('#main_canvas'),
|
81 |
+
notation: document.querySelector('#notation'),
|
82 |
+
indicator1: document.querySelector('#body_indicator1'),
|
83 |
+
indicator2: document.querySelector('#body_indicator2'),
|
84 |
+
all_reset: document.querySelector('#all_reset'),
|
85 |
+
reset_camera: document.querySelector('#reset_camera'),
|
86 |
+
reset_pose: document.querySelector('#reset_pose'),
|
87 |
+
fixed_roll: document.querySelector('#fixed_roll'),
|
88 |
+
add_body: document.querySelector('#add_body'),
|
89 |
+
remove_body: document.querySelector('#remove_body'),
|
90 |
+
canvas_width: document.querySelector('#canvas_width'),
|
91 |
+
canvas_height: document.querySelector('#canvas_height'),
|
92 |
+
bg: document.querySelector('#bg_file'),
|
93 |
+
reset_bg: document.querySelector('#reset_bg'),
|
94 |
+
elliptic_limbs: document.querySelector('#elliptic_limbs'),
|
95 |
+
//joint_radius: document.querySelector('#joint_radius'),
|
96 |
+
limb_width: document.querySelector('#limb_width'),
|
97 |
+
low_fps: document.querySelector('#low_fps'),
|
98 |
+
save: document.querySelector('#save_button'),
|
99 |
+
copy: document.querySelector('#copy_button'),
|
100 |
+
save_pose: document.querySelector('#save_pose'),
|
101 |
+
save_pose_callback: save_pose,
|
102 |
+
notify: notify,
|
103 |
+
};
|
104 |
+
|
105 |
+
document.addEventListener('poseload', e => {
|
106 |
+
const obj = POSES.get(e.detail.name);
|
107 |
+
if (obj) ui.loadPose(obj);
|
108 |
+
}, false);
|
109 |
+
|
110 |
+
const { init, init_3d } = await import('posex');
|
111 |
+
|
112 |
+
init(ui);
|
113 |
+
const animate = init_3d(ui);
|
114 |
+
animate();
|
115 |
+
|
116 |
+
await reload_poses();
|
117 |
+
|
118 |
+
}, false);
|
119 |
+
|
120 |
+
document.addEventListener('DOMContentLoaded', () => {
|
121 |
+
const get_name = ele => {
|
122 |
+
while (ele && ele !== document) {
|
123 |
+
if (ele.dataset && ele.dataset.poseName !== undefined)
|
124 |
+
return ele.dataset.poseName;
|
125 |
+
ele = ele.parentNode;
|
126 |
+
}
|
127 |
+
return '';
|
128 |
+
};
|
129 |
+
|
130 |
+
document.querySelector('#saved_poses').addEventListener('click', e => {
|
131 |
+
let target = e.target;
|
132 |
+
if (target.tagName === 'IMG') target = target.parentNode;
|
133 |
+
if (target.classList.contains('close2')) target = target.parentNode;
|
134 |
+
if (target.tagName === 'FIGURE') {
|
135 |
+
const name = get_name(target);
|
136 |
+
const ev = new CustomEvent('poseload', { bubbles: true, detail: { name } });
|
137 |
+
target.dispatchEvent(ev);
|
138 |
+
} else if (target.classList.contains('close')) {
|
139 |
+
const name = get_name(target);
|
140 |
+
if (name.length != 0) {
|
141 |
+
delete_pose(name);
|
142 |
+
}
|
143 |
+
}
|
144 |
+
}, false);
|
145 |
+
}, false);
|
js/es-module-shims.js
ADDED
@@ -0,0 +1,790 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// https://github.com/guybedford/es-module-shims
|
2 |
+
|
3 |
+
/* ES Module Shims 1.3.6 */
|
4 |
+
(function () {
|
5 |
+
|
6 |
+
const edge = navigator.userAgent.match(/Edge\/\d\d\.\d+$/);
|
7 |
+
|
8 |
+
let baseUrl;
|
9 |
+
|
10 |
+
function createBlob(source, type = 'text/javascript') {
|
11 |
+
return URL.createObjectURL(new Blob([source], { type }));
|
12 |
+
}
|
13 |
+
|
14 |
+
const noop = () => { };
|
15 |
+
|
16 |
+
const baseEl = document.querySelector('base[href]');
|
17 |
+
if (baseEl)
|
18 |
+
baseUrl = baseEl.href;
|
19 |
+
|
20 |
+
if (!baseUrl && typeof location !== 'undefined') {
|
21 |
+
baseUrl = location.href.split('#')[0].split('?')[0];
|
22 |
+
const lastSepIndex = baseUrl.lastIndexOf('/');
|
23 |
+
if (lastSepIndex !== -1)
|
24 |
+
baseUrl = baseUrl.slice(0, lastSepIndex + 1);
|
25 |
+
}
|
26 |
+
|
27 |
+
function isURL(url) {
|
28 |
+
try {
|
29 |
+
new URL(url);
|
30 |
+
return true;
|
31 |
+
}
|
32 |
+
catch {
|
33 |
+
return false;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
const backslashRegEx = /\\/g;
|
38 |
+
function resolveIfNotPlainOrUrl(relUrl, parentUrl) {
|
39 |
+
// strip off any trailing query params or hashes
|
40 |
+
parentUrl = parentUrl && parentUrl.split('#')[0].split('?')[0];
|
41 |
+
if (relUrl.indexOf('\\') !== -1)
|
42 |
+
relUrl = relUrl.replace(backslashRegEx, '/');
|
43 |
+
// protocol-relative
|
44 |
+
if (relUrl[0] === '/' && relUrl[1] === '/') {
|
45 |
+
return parentUrl.slice(0, parentUrl.indexOf(':') + 1) + relUrl;
|
46 |
+
}
|
47 |
+
// relative-url
|
48 |
+
else if (relUrl[0] === '.' && (relUrl[1] === '/' || relUrl[1] === '.' && (relUrl[2] === '/' || relUrl.length === 2 && (relUrl += '/')) ||
|
49 |
+
relUrl.length === 1 && (relUrl += '/')) ||
|
50 |
+
relUrl[0] === '/') {
|
51 |
+
const parentProtocol = parentUrl.slice(0, parentUrl.indexOf(':') + 1);
|
52 |
+
// Disabled, but these cases will give inconsistent results for deep backtracking
|
53 |
+
//if (parentUrl[parentProtocol.length] !== '/')
|
54 |
+
// throw new Error('Cannot resolve');
|
55 |
+
// read pathname from parent URL
|
56 |
+
// pathname taken to be part after leading "/"
|
57 |
+
let pathname;
|
58 |
+
if (parentUrl[parentProtocol.length + 1] === '/') {
|
59 |
+
// resolving to a :// so we need to read out the auth and host
|
60 |
+
if (parentProtocol !== 'file:') {
|
61 |
+
pathname = parentUrl.slice(parentProtocol.length + 2);
|
62 |
+
pathname = pathname.slice(pathname.indexOf('/') + 1);
|
63 |
+
}
|
64 |
+
else {
|
65 |
+
pathname = parentUrl.slice(8);
|
66 |
+
}
|
67 |
+
}
|
68 |
+
else {
|
69 |
+
// resolving to :/ so pathname is the /... part
|
70 |
+
pathname = parentUrl.slice(parentProtocol.length + (parentUrl[parentProtocol.length] === '/'));
|
71 |
+
}
|
72 |
+
|
73 |
+
if (relUrl[0] === '/')
|
74 |
+
return parentUrl.slice(0, parentUrl.length - pathname.length - 1) + relUrl;
|
75 |
+
|
76 |
+
// join together and split for removal of .. and . segments
|
77 |
+
// looping the string instead of anything fancy for perf reasons
|
78 |
+
// '../../../../../z' resolved to 'x/y' is just 'z'
|
79 |
+
const segmented = pathname.slice(0, pathname.lastIndexOf('/') + 1) + relUrl;
|
80 |
+
|
81 |
+
const output = [];
|
82 |
+
let segmentIndex = -1;
|
83 |
+
for (let i = 0; i < segmented.length; i++) {
|
84 |
+
// busy reading a segment - only terminate on '/'
|
85 |
+
if (segmentIndex !== -1) {
|
86 |
+
if (segmented[i] === '/') {
|
87 |
+
output.push(segmented.slice(segmentIndex, i + 1));
|
88 |
+
segmentIndex = -1;
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
// new segment - check if it is relative
|
93 |
+
else if (segmented[i] === '.') {
|
94 |
+
// ../ segment
|
95 |
+
if (segmented[i + 1] === '.' && (segmented[i + 2] === '/' || i + 2 === segmented.length)) {
|
96 |
+
output.pop();
|
97 |
+
i += 2;
|
98 |
+
}
|
99 |
+
// ./ segment
|
100 |
+
else if (segmented[i + 1] === '/' || i + 1 === segmented.length) {
|
101 |
+
i += 1;
|
102 |
+
}
|
103 |
+
else {
|
104 |
+
// the start of a new segment as below
|
105 |
+
segmentIndex = i;
|
106 |
+
}
|
107 |
+
}
|
108 |
+
// it is the start of a new segment
|
109 |
+
else {
|
110 |
+
segmentIndex = i;
|
111 |
+
}
|
112 |
+
}
|
113 |
+
// finish reading out the last segment
|
114 |
+
if (segmentIndex !== -1)
|
115 |
+
output.push(segmented.slice(segmentIndex));
|
116 |
+
return parentUrl.slice(0, parentUrl.length - pathname.length) + output.join('');
|
117 |
+
}
|
118 |
+
}
|
119 |
+
|
120 |
+
/*
|
121 |
+
* Import maps implementation
|
122 |
+
*
|
123 |
+
* To make lookups fast we pre-resolve the entire import map
|
124 |
+
* and then match based on backtracked hash lookups
|
125 |
+
*
|
126 |
+
*/
|
127 |
+
function resolveUrl(relUrl, parentUrl) {
|
128 |
+
return resolveIfNotPlainOrUrl(relUrl, parentUrl) || (relUrl.indexOf(':') !== -1 ? relUrl : resolveIfNotPlainOrUrl('./' + relUrl, parentUrl));
|
129 |
+
}
|
130 |
+
|
131 |
+
function resolveAndComposePackages(packages, outPackages, baseUrl, parentMap) {
|
132 |
+
for (let p in packages) {
|
133 |
+
const resolvedLhs = resolveIfNotPlainOrUrl(p, baseUrl) || p;
|
134 |
+
if (outPackages[resolvedLhs]) {
|
135 |
+
throw new Error(`Dynamic import map rejected: Overrides entry "${resolvedLhs}" from ${outPackages[resolvedLhs]} to ${packages[resolvedLhs]}.`);
|
136 |
+
}
|
137 |
+
let target = packages[p];
|
138 |
+
if (typeof target !== 'string')
|
139 |
+
continue;
|
140 |
+
const mapped = resolveImportMap(parentMap, resolveIfNotPlainOrUrl(target, baseUrl) || target, baseUrl);
|
141 |
+
if (mapped) {
|
142 |
+
outPackages[resolvedLhs] = mapped;
|
143 |
+
continue;
|
144 |
+
}
|
145 |
+
targetWarning(p, packages[p], 'bare specifier did not resolve');
|
146 |
+
}
|
147 |
+
}
|
148 |
+
|
149 |
+
function resolveAndComposeImportMap(json, baseUrl, parentMap) {
|
150 |
+
const outMap = { imports: Object.assign({}, parentMap.imports), scopes: Object.assign({}, parentMap.scopes) };
|
151 |
+
|
152 |
+
if (json.imports)
|
153 |
+
resolveAndComposePackages(json.imports, outMap.imports, baseUrl, parentMap);
|
154 |
+
|
155 |
+
if (json.scopes)
|
156 |
+
for (let s in json.scopes) {
|
157 |
+
const resolvedScope = resolveUrl(s, baseUrl);
|
158 |
+
resolveAndComposePackages(json.scopes[s], outMap.scopes[resolvedScope] || (outMap.scopes[resolvedScope] = {}), baseUrl, parentMap);
|
159 |
+
}
|
160 |
+
|
161 |
+
return outMap;
|
162 |
+
}
|
163 |
+
|
164 |
+
function getMatch(path, matchObj) {
|
165 |
+
if (matchObj[path])
|
166 |
+
return path;
|
167 |
+
let sepIndex = path.length;
|
168 |
+
do {
|
169 |
+
const segment = path.slice(0, sepIndex + 1);
|
170 |
+
if (segment in matchObj)
|
171 |
+
return segment;
|
172 |
+
} while ((sepIndex = path.lastIndexOf('/', sepIndex - 1)) !== -1)
|
173 |
+
}
|
174 |
+
|
175 |
+
function applyPackages(id, packages) {
|
176 |
+
const pkgName = getMatch(id, packages);
|
177 |
+
if (pkgName) {
|
178 |
+
const pkg = packages[pkgName];
|
179 |
+
if (pkg === null) return;
|
180 |
+
if (id.length > pkgName.length && pkg[pkg.length - 1] !== '/')
|
181 |
+
targetWarning(pkgName, pkg, "should have a trailing '/'");
|
182 |
+
else
|
183 |
+
return pkg + id.slice(pkgName.length);
|
184 |
+
}
|
185 |
+
}
|
186 |
+
|
187 |
+
function targetWarning(match, target, msg) {
|
188 |
+
console.warn("Package target " + msg + ", resolving target '" + target + "' for " + match);
|
189 |
+
}
|
190 |
+
|
191 |
+
function resolveImportMap(importMap, resolvedOrPlain, parentUrl) {
|
192 |
+
let scopeUrl = parentUrl && getMatch(parentUrl, importMap.scopes);
|
193 |
+
while (scopeUrl) {
|
194 |
+
const packageResolution = applyPackages(resolvedOrPlain, importMap.scopes[scopeUrl]);
|
195 |
+
if (packageResolution)
|
196 |
+
return packageResolution;
|
197 |
+
scopeUrl = getMatch(scopeUrl.slice(0, scopeUrl.lastIndexOf('/')), importMap.scopes);
|
198 |
+
}
|
199 |
+
return applyPackages(resolvedOrPlain, importMap.imports) || resolvedOrPlain.indexOf(':') !== -1 && resolvedOrPlain;
|
200 |
+
}
|
201 |
+
|
202 |
+
const optionsScript = document.querySelector('script[type=esms-options]');
|
203 |
+
|
204 |
+
const esmsInitOptions = optionsScript ? JSON.parse(optionsScript.innerHTML) : self.esmsInitOptions ? self.esmsInitOptions : {};
|
205 |
+
|
206 |
+
let shimMode = !!esmsInitOptions.shimMode;
|
207 |
+
const resolveHook = globalHook(shimMode && esmsInitOptions.resolve);
|
208 |
+
|
209 |
+
const skip = esmsInitOptions.skip ? new RegExp(esmsInitOptions.skip) : null;
|
210 |
+
|
211 |
+
let nonce = esmsInitOptions.nonce;
|
212 |
+
|
213 |
+
if (!nonce) {
|
214 |
+
const nonceElement = document.querySelector('script[nonce]');
|
215 |
+
if (nonceElement)
|
216 |
+
nonce = nonceElement.nonce || nonceElement.getAttribute('nonce');
|
217 |
+
}
|
218 |
+
|
219 |
+
const onerror = globalHook(esmsInitOptions.onerror || noop);
|
220 |
+
const onpolyfill = globalHook(esmsInitOptions.onpolyfill || noop);
|
221 |
+
|
222 |
+
const { revokeBlobURLs, noLoadEventRetriggers } = esmsInitOptions;
|
223 |
+
|
224 |
+
const fetchHook = esmsInitOptions.fetch ? globalHook(esmsInitOptions.fetch) : fetch;
|
225 |
+
|
226 |
+
function globalHook(name) {
|
227 |
+
return typeof name === 'string' ? self[name] : name;
|
228 |
+
}
|
229 |
+
|
230 |
+
const enable = Array.isArray(esmsInitOptions.polyfillEnable) ? esmsInitOptions.polyfillEnable : [];
|
231 |
+
const cssModulesEnabled = enable.includes('css-modules');
|
232 |
+
const jsonModulesEnabled = enable.includes('json-modules');
|
233 |
+
|
234 |
+
function setShimMode() {
|
235 |
+
shimMode = true;
|
236 |
+
}
|
237 |
+
|
238 |
+
let err;
|
239 |
+
window.addEventListener('error', _err => err = _err);
|
240 |
+
function dynamicImportScript(url, { errUrl = url } = {}) {
|
241 |
+
err = undefined;
|
242 |
+
const src = createBlob(`import*as m from'${url}';self._esmsi=m`);
|
243 |
+
const s = Object.assign(document.createElement('script'), { type: 'module', src });
|
244 |
+
s.setAttribute('nonce', nonce);
|
245 |
+
s.setAttribute('noshim', '');
|
246 |
+
const p = new Promise((resolve, reject) => {
|
247 |
+
// Safari is unique in supporting module script error events
|
248 |
+
s.addEventListener('error', cb);
|
249 |
+
s.addEventListener('load', cb);
|
250 |
+
|
251 |
+
function cb(_err) {
|
252 |
+
document.head.removeChild(s);
|
253 |
+
if (self._esmsi) {
|
254 |
+
resolve(self._esmsi, baseUrl);
|
255 |
+
self._esmsi = undefined;
|
256 |
+
}
|
257 |
+
else {
|
258 |
+
reject(!(_err instanceof Event) && _err || err && err.error || new Error(`Error loading or executing the graph of ${errUrl} (check the console for ${src}).`));
|
259 |
+
err = undefined;
|
260 |
+
}
|
261 |
+
}
|
262 |
+
});
|
263 |
+
document.head.appendChild(s);
|
264 |
+
return p;
|
265 |
+
}
|
266 |
+
|
267 |
+
let dynamicImport = dynamicImportScript;
|
268 |
+
|
269 |
+
const supportsDynamicImportCheck = dynamicImportScript(createBlob('export default u=>import(u)')).then(_dynamicImport => {
|
270 |
+
if (_dynamicImport)
|
271 |
+
dynamicImport = _dynamicImport.default;
|
272 |
+
return !!_dynamicImport;
|
273 |
+
}, noop);
|
274 |
+
|
275 |
+
// support browsers without dynamic import support (eg Firefox 6x)
|
276 |
+
let supportsJsonAssertions = false;
|
277 |
+
let supportsCssAssertions = false;
|
278 |
+
|
279 |
+
let supportsImportMeta = false;
|
280 |
+
let supportsImportMaps = false;
|
281 |
+
|
282 |
+
let supportsDynamicImport = false;
|
283 |
+
|
284 |
+
const featureDetectionPromise = Promise.resolve(supportsDynamicImportCheck).then(_supportsDynamicImport => {
|
285 |
+
if (!_supportsDynamicImport)
|
286 |
+
return;
|
287 |
+
supportsDynamicImport = true;
|
288 |
+
|
289 |
+
return Promise.all([
|
290 |
+
dynamicImport(createBlob('import.meta')).then(() => supportsImportMeta = true, noop),
|
291 |
+
cssModulesEnabled && dynamicImport(createBlob('import"data:text/css,{}"assert{type:"css"}')).then(() => supportsCssAssertions = true, noop),
|
292 |
+
jsonModulesEnabled && dynamicImport(createBlob('import"data:text/json,{}"assert{type:"json"}')).then(() => supportsJsonAssertions = true, noop),
|
293 |
+
new Promise(resolve => {
|
294 |
+
self._$s = v => {
|
295 |
+
document.head.removeChild(iframe);
|
296 |
+
if (v) supportsImportMaps = true;
|
297 |
+
delete self._$s;
|
298 |
+
resolve();
|
299 |
+
};
|
300 |
+
const iframe = document.createElement('iframe');
|
301 |
+
iframe.style.display = 'none';
|
302 |
+
document.head.appendChild(iframe);
|
303 |
+
iframe.src = createBlob(`<script type=importmap nonce="${nonce}">{"imports":{"x":"data:text/javascript,"}}<${''}/script><script nonce="${nonce}">import('x').then(()=>1,()=>0).then(v=>parent._$s(v))<${''}/script>`, 'text/html');
|
304 |
+
})
|
305 |
+
]);
|
306 |
+
});
|
307 |
+
|
308 |
+
let e, r, a, i = 4194304; const s = 1 === new Uint8Array(new Uint16Array([1]).buffer)[0]; let t, f, c$1; function parse(k, l = "@") { if (t = k, f = l, t.length > i || !e) { for (; t.length > i;)i *= 2; r = new ArrayBuffer(4 * i), e = function (e, r, a) { "use asm"; var i = new e.Int8Array(a), s = new e.Int16Array(a), t = new e.Int32Array(a), f = new e.Uint8Array(a), c = new e.Uint16Array(a), n = 816; function b(e) { e = e | 0; var r = 0, a = 0, f = 0, b = 0, l = 0; l = n; n = n + 14336 | 0; b = l; i[589] = 1; s[291] = 0; s[292] = 0; s[293] = -1; t[15] = t[2]; i[590] = 0; t[14] = 0; i[588] = 0; t[16] = l + 10240; t[17] = l + 2048; i[591] = 0; e = (t[3] | 0) + -2 | 0; t[18] = e; r = e + (t[12] << 1) | 0; t[19] = r; e: while (1) { a = e + 2 | 0; t[18] = a; if (e >>> 0 >= r >>> 0) { f = 18; break } r: do { switch (s[a >> 1] | 0) { case 9: case 10: case 11: case 12: case 13: case 32: break; case 101: { if ((((s[292] | 0) == 0 ? R(a) | 0 : 0) ? B(e + 4 | 0, 120, 112, 111, 114, 116) | 0 : 0) ? (u(), (i[589] | 0) == 0) : 0) { f = 9; break e } else f = 17; break } case 105: { if (R(a) | 0 ? B(e + 4 | 0, 109, 112, 111, 114, 116) | 0 : 0) { k(); f = 17; } else f = 17; break } case 59: { f = 17; break } case 47: switch (s[e + 4 >> 1] | 0) { case 47: { G(); break r } case 42: { p(1); break r } default: { f = 16; break e } }default: { f = 16; break e } } } while (0); if ((f | 0) == 17) { f = 0; t[15] = t[18]; } e = t[18] | 0; r = t[19] | 0; } if ((f | 0) == 9) { e = t[18] | 0; t[15] = e; f = 19; } else if ((f | 0) == 16) { i[589] = 0; t[18] = e; f = 19; } else if ((f | 0) == 18) if (!(i[588] | 0)) { e = a; f = 19; } else e = 0; do { if ((f | 0) == 19) { e: while (1) { r = e + 2 | 0; t[18] = r; a = r; if (e >>> 0 >= (t[19] | 0) >>> 0) { f = 75; break } r: do { switch (s[r >> 1] | 0) { case 9: case 10: case 11: case 12: case 13: case 32: break; case 101: { if (((s[292] | 0) == 0 ? R(r) | 0 : 0) ? B(e + 4 | 0, 120, 112, 111, 114, 116) | 0 : 0) { u(); f = 74; } else f = 74; break } case 105: { if (R(r) | 0 ? B(e + 4 | 0, 109, 112, 111, 114, 116) | 0 : 0) { k(); f = 74; } else f = 74; break } case 99: { if ((R(r) | 0 ? z(e + 4 | 0, 108, 97, 115, 115) | 0 : 0) ? Z(s[e + 12 >> 1] | 0) | 0 : 0) { i[591] = 1; f = 74; } else f = 74; break } case 40: { r = t[15] | 0; a = t[17] | 0; f = s[292] | 0; s[292] = f + 1 << 16 >> 16; t[a + ((f & 65535) << 2) >> 2] = r; f = 74; break } case 41: { e = s[292] | 0; if (!(e << 16 >> 16)) { f = 36; break e } f = e + -1 << 16 >> 16; s[292] = f; e = t[11] | 0; if ((e | 0) != 0 ? (t[e + 20 >> 2] | 0) == (t[(t[17] | 0) + ((f & 65535) << 2) >> 2] | 0) : 0) { r = e + 4 | 0; if (!(t[r >> 2] | 0)) t[r >> 2] = a; t[e + 12 >> 2] = a; t[11] = 0; f = 74; } else f = 74; break } case 123: { f = t[15] | 0; a = t[8] | 0; e = f; do { if ((s[f >> 1] | 0) == 41 & (a | 0) != 0 ? (t[a + 4 >> 2] | 0) == (f | 0) : 0) { r = t[9] | 0; t[8] = r; if (!r) { t[4] = 0; break } else { t[r + 28 >> 2] = 0; break } } } while (0); r = s[292] | 0; f = r & 65535; i[b + f >> 0] = i[591] | 0; i[591] = 0; a = t[17] | 0; s[292] = r + 1 << 16 >> 16; t[a + (f << 2) >> 2] = e; f = 74; break } case 125: { e = s[292] | 0; if (!(e << 16 >> 16)) { f = 49; break e } a = e + -1 << 16 >> 16; s[292] = a; r = s[293] | 0; if (e << 16 >> 16 != r << 16 >> 16) if (r << 16 >> 16 != -1 & (a & 65535) < (r & 65535)) { f = 53; break e } else { f = 74; break r } else { a = t[16] | 0; f = (s[291] | 0) + -1 << 16 >> 16; s[291] = f; s[293] = s[a + ((f & 65535) << 1) >> 1] | 0; h(); f = 74; break r } } case 39: { d(39); f = 74; break } case 34: { d(34); f = 74; break } case 47: switch (s[e + 4 >> 1] | 0) { case 47: { G(); break r } case 42: { p(1); break r } default: { r = t[15] | 0; a = s[r >> 1] | 0; a: do { if (!(x(a) | 0)) { switch (a << 16 >> 16) { case 41: if (L(t[(t[17] | 0) + (c[292] << 2) >> 2] | 0) | 0) { f = 71; break a } else { f = 68; break a } case 125: break; default: { f = 68; break a } }e = c[292] | 0; if (!(y(t[(t[17] | 0) + (e << 2) >> 2] | 0) | 0) ? (i[b + e >> 0] | 0) == 0 : 0) f = 68; else f = 71; } else switch (a << 16 >> 16) { case 46: if (((s[r + -2 >> 1] | 0) + -48 & 65535) < 10) { f = 68; break a } else { f = 71; break a } case 43: if ((s[r + -2 >> 1] | 0) == 43) { f = 68; break a } else { f = 71; break a } case 45: if ((s[r + -2 >> 1] | 0) == 45) { f = 68; break a } else { f = 71; break a } default: { f = 71; break a } } } while (0); a: do { if ((f | 0) == 68) { f = 0; if (!(o(r) | 0)) { switch (a << 16 >> 16) { case 0: { f = 71; break a } case 47: break; default: { e = 1; break a } }if (!(i[590] | 0)) e = 1; else f = 71; } else f = 71; } } while (0); if ((f | 0) == 71) { I(); e = 0; } i[590] = e; f = 74; break r } }case 96: { h(); f = 74; break } default: f = 74; } } while (0); if ((f | 0) == 74) { f = 0; t[15] = t[18]; } e = t[18] | 0; } if ((f | 0) == 36) { Y(); e = 0; break } else if ((f | 0) == 49) { Y(); e = 0; break } else if ((f | 0) == 53) { Y(); e = 0; break } else if ((f | 0) == 75) { e = (s[293] | 0) == -1 & (s[292] | 0) == 0 & (i[588] | 0) == 0; break } } } while (0); n = l; return e | 0 } function u() { var e = 0, r = 0, a = 0, f = 0, c = 0, n = 0; c = t[18] | 0; n = c + 12 | 0; t[18] = n; r = w(1) | 0; e = t[18] | 0; if (!((e | 0) == (n | 0) ? !(S(r) | 0) : 0)) f = 3; e: do { if ((f | 0) == 3) { r: do { switch (r << 16 >> 16) { case 100: { J(e, e + 14 | 0); break e } case 97: { t[18] = e + 10; w(1) | 0; e = t[18] | 0; f = 6; break } case 102: { f = 6; break } case 99: { if (z(e + 2 | 0, 108, 97, 115, 115) | 0 ? (a = e + 10 | 0, F(s[a >> 1] | 0) | 0) : 0) { t[18] = a; c = w(1) | 0; n = t[18] | 0; H(c) | 0; J(n, t[18] | 0); t[18] = (t[18] | 0) + -2; break e } e = e + 4 | 0; t[18] = e; f = 13; break } case 108: case 118: { f = 13; break } case 123: { t[18] = e + 2; e = w(1) | 0; a = t[18] | 0; while (1) { if (_(e) | 0) { d(e); e = (t[18] | 0) + 2 | 0; t[18] = e; } else { H(e) | 0; e = t[18] | 0; } w(1) | 0; e = g(a, e) | 0; if (e << 16 >> 16 == 44) { t[18] = (t[18] | 0) + 2; e = w(1) | 0; } r = a; a = t[18] | 0; if (e << 16 >> 16 == 125) { f = 32; break } if ((a | 0) == (r | 0)) { f = 29; break } if (a >>> 0 > (t[19] | 0) >>> 0) { f = 31; break } } if ((f | 0) == 29) { Y(); break e } else if ((f | 0) == 31) { Y(); break e } else if ((f | 0) == 32) { t[18] = a + 2; f = 34; break r } break } case 42: { t[18] = e + 2; w(1) | 0; f = t[18] | 0; g(f, f) | 0; f = 34; break } default: { } } } while (0); if ((f | 0) == 6) { t[18] = e + 16; e = w(1) | 0; if (e << 16 >> 16 == 42) { t[18] = (t[18] | 0) + 2; e = w(1) | 0; } n = t[18] | 0; H(e) | 0; J(n, t[18] | 0); t[18] = (t[18] | 0) + -2; break } else if ((f | 0) == 13) { e = e + 4 | 0; t[18] = e; i[589] = 0; r: while (1) { t[18] = e + 2; n = w(1) | 0; e = t[18] | 0; switch ((H(n) | 0) << 16 >> 16) { case 91: case 123: { f = 15; break r } default: { } }r = t[18] | 0; if ((r | 0) == (e | 0)) break e; J(e, r); switch ((w(1) | 0) << 16 >> 16) { case 61: { f = 19; break r } case 44: break; default: { f = 20; break r } }e = t[18] | 0; } if ((f | 0) == 15) { t[18] = (t[18] | 0) + -2; break } else if ((f | 0) == 19) { t[18] = (t[18] | 0) + -2; break } else if ((f | 0) == 20) { t[18] = (t[18] | 0) + -2; break } } else if ((f | 0) == 34) r = w(1) | 0; e = t[18] | 0; if (r << 16 >> 16 == 102 ? K(e + 2 | 0, 114, 111, 109) | 0 : 0) { t[18] = e + 8; l(c, w(1) | 0); break } t[18] = e + -2; } } while (0); return } function k() { var e = 0, r = 0, a = 0, f = 0, c = 0; c = t[18] | 0; r = c + 12 | 0; t[18] = r; e: do { switch ((w(1) | 0) << 16 >> 16) { case 40: { r = t[17] | 0; a = s[292] | 0; s[292] = a + 1 << 16 >> 16; t[r + ((a & 65535) << 2) >> 2] = c; if ((s[t[15] >> 1] | 0) != 46) { v(c, (t[18] | 0) + 2 | 0, 0, c); t[11] = t[8]; t[18] = (t[18] | 0) + 2; switch ((w(1) | 0) << 16 >> 16) { case 39: { d(39); break } case 34: { d(34); break } default: { t[18] = (t[18] | 0) + -2; break e } }t[18] = (t[18] | 0) + 2; switch ((w(1) | 0) << 16 >> 16) { case 44: { c = t[18] | 0; t[(t[8] | 0) + 4 >> 2] = c; t[18] = c + 2; w(1) | 0; c = t[18] | 0; a = t[8] | 0; t[a + 16 >> 2] = c; i[a + 24 >> 0] = 1; t[18] = c + -2; break e } case 41: { s[292] = (s[292] | 0) + -1 << 16 >> 16; a = t[18] | 0; c = t[8] | 0; t[c + 4 >> 2] = a; t[c + 12 >> 2] = a; i[c + 24 >> 0] = 1; break e } default: { t[18] = (t[18] | 0) + -2; break e } } } break } case 46: { t[18] = (t[18] | 0) + 2; if (((w(1) | 0) << 16 >> 16 == 109 ? (e = t[18] | 0, K(e + 2 | 0, 101, 116, 97) | 0) : 0) ? (s[t[15] >> 1] | 0) != 46 : 0) v(c, c, e + 8 | 0, 2); break } case 42: case 39: case 34: { f = 16; break } case 123: { e = t[18] | 0; if (s[292] | 0) { t[18] = e + -2; break e } while (1) { if (e >>> 0 >= (t[19] | 0) >>> 0) break; e = w(1) | 0; if (!(_(e) | 0)) { if (e << 16 >> 16 == 125) { f = 31; break } } else d(e); e = (t[18] | 0) + 2 | 0; t[18] = e; } if ((f | 0) == 31) t[18] = (t[18] | 0) + 2; w(1) | 0; e = t[18] | 0; if (!(z(e, 102, 114, 111, 109) | 0)) { Y(); break e } t[18] = e + 8; e = w(1) | 0; if (_(e) | 0) { l(c, e); break e } else { Y(); break e } } default: if ((t[18] | 0) != (r | 0)) f = 16; } } while (0); do { if ((f | 0) == 16) { if (s[292] | 0) { t[18] = (t[18] | 0) + -2; break } e = t[19] | 0; r = t[18] | 0; while (1) { if (r >>> 0 >= e >>> 0) { f = 23; break } a = s[r >> 1] | 0; if (_(a) | 0) { f = 21; break } f = r + 2 | 0; t[18] = f; r = f; } if ((f | 0) == 21) { l(c, a); break } else if ((f | 0) == 23) { Y(); break } } } while (0); return } function l(e, r) { e = e | 0; r = r | 0; var a = 0, i = 0; a = (t[18] | 0) + 2 | 0; switch (r << 16 >> 16) { case 39: { d(39); i = 5; break } case 34: { d(34); i = 5; break } default: Y(); }do { if ((i | 0) == 5) { v(e, a, t[18] | 0, 1); t[18] = (t[18] | 0) + 2; i = (w(0) | 0) << 16 >> 16 == 97; r = t[18] | 0; if (i ? B(r + 2 | 0, 115, 115, 101, 114, 116) | 0 : 0) { t[18] = r + 12; if ((w(1) | 0) << 16 >> 16 != 123) { t[18] = r; break } e = t[18] | 0; a = e; e: while (1) { t[18] = a + 2; a = w(1) | 0; switch (a << 16 >> 16) { case 39: { d(39); t[18] = (t[18] | 0) + 2; a = w(1) | 0; break } case 34: { d(34); t[18] = (t[18] | 0) + 2; a = w(1) | 0; break } default: a = H(a) | 0; }if (a << 16 >> 16 != 58) { i = 16; break } t[18] = (t[18] | 0) + 2; switch ((w(1) | 0) << 16 >> 16) { case 39: { d(39); break } case 34: { d(34); break } default: { i = 20; break e } }t[18] = (t[18] | 0) + 2; switch ((w(1) | 0) << 16 >> 16) { case 125: { i = 25; break e } case 44: break; default: { i = 24; break e } }t[18] = (t[18] | 0) + 2; if ((w(1) | 0) << 16 >> 16 == 125) { i = 25; break } a = t[18] | 0; } if ((i | 0) == 16) { t[18] = r; break } else if ((i | 0) == 20) { t[18] = r; break } else if ((i | 0) == 24) { t[18] = r; break } else if ((i | 0) == 25) { i = t[8] | 0; t[i + 16 >> 2] = e; t[i + 12 >> 2] = (t[18] | 0) + 2; break } } t[18] = r + -2; } } while (0); return } function o(e) { e = e | 0; e: do { switch (s[e >> 1] | 0) { case 100: switch (s[e + -2 >> 1] | 0) { case 105: { e = q(e + -4 | 0, 118, 111) | 0; break e } case 108: { e = P(e + -4 | 0, 121, 105, 101) | 0; break e } default: { e = 0; break e } }case 101: { switch (s[e + -2 >> 1] | 0) { case 115: break; case 116: { e = E(e + -4 | 0, 100, 101, 108, 101) | 0; break e } default: { e = 0; break e } }switch (s[e + -4 >> 1] | 0) { case 108: { e = D(e + -6 | 0, 101) | 0; break e } case 97: { e = D(e + -6 | 0, 99) | 0; break e } default: { e = 0; break e } } } case 102: { if ((s[e + -2 >> 1] | 0) == 111 ? (s[e + -4 >> 1] | 0) == 101 : 0) switch (s[e + -6 >> 1] | 0) { case 99: { e = O(e + -8 | 0, 105, 110, 115, 116, 97, 110) | 0; break e } case 112: { e = q(e + -8 | 0, 116, 121) | 0; break e } default: { e = 0; break e } } else e = 0; break } case 110: { e = e + -2 | 0; if (D(e, 105) | 0) e = 1; else e = $(e, 114, 101, 116, 117, 114) | 0; break } case 111: { e = D(e + -2 | 0, 100) | 0; break } case 114: { e = m(e + -2 | 0, 100, 101, 98, 117, 103, 103, 101) | 0; break } case 116: { e = E(e + -2 | 0, 97, 119, 97, 105) | 0; break } case 119: switch (s[e + -2 >> 1] | 0) { case 101: { e = D(e + -4 | 0, 110) | 0; break e } case 111: { e = P(e + -4 | 0, 116, 104, 114) | 0; break e } default: { e = 0; break e } }default: e = 0; } } while (0); return e | 0 } function h() { var e = 0, r = 0, a = 0; r = t[19] | 0; a = t[18] | 0; e: while (1) { e = a + 2 | 0; if (a >>> 0 >= r >>> 0) { r = 8; break } switch (s[e >> 1] | 0) { case 96: { r = 9; break e } case 36: { if ((s[a + 4 >> 1] | 0) == 123) { r = 6; break e } break } case 92: { e = a + 4 | 0; break } default: { } }a = e; } if ((r | 0) == 6) { t[18] = a + 4; e = s[293] | 0; r = t[16] | 0; a = s[291] | 0; s[291] = a + 1 << 16 >> 16; s[r + ((a & 65535) << 1) >> 1] = e; a = (s[292] | 0) + 1 << 16 >> 16; s[292] = a; s[293] = a; } else if ((r | 0) == 8) { t[18] = e; Y(); } else if ((r | 0) == 9) t[18] = e; return } function w(e) { e = e | 0; var r = 0, a = 0, i = 0; a = t[18] | 0; e: do { r = s[a >> 1] | 0; r: do { if (r << 16 >> 16 != 47) if (e) if (Z(r) | 0) break; else break e; else if (Q(r) | 0) break; else break e; else switch (s[a + 2 >> 1] | 0) { case 47: { G(); break r } case 42: { p(e); break r } default: { r = 47; break e } } } while (0); i = t[18] | 0; a = i + 2 | 0; t[18] = a; } while (i >>> 0 < (t[19] | 0) >>> 0); return r | 0 } function d(e) { e = e | 0; var r = 0, a = 0, i = 0, f = 0; f = t[19] | 0; r = t[18] | 0; while (1) { i = r + 2 | 0; if (r >>> 0 >= f >>> 0) { r = 9; break } a = s[i >> 1] | 0; if (a << 16 >> 16 == e << 16 >> 16) { r = 10; break } if (a << 16 >> 16 == 92) { a = r + 4 | 0; if ((s[a >> 1] | 0) == 13) { r = r + 6 | 0; r = (s[r >> 1] | 0) == 10 ? r : a; } else r = a; } else if (ae(a) | 0) { r = 9; break } else r = i; } if ((r | 0) == 9) { t[18] = i; Y(); } else if ((r | 0) == 10) t[18] = i; return } function v(e, r, a, s) { e = e | 0; r = r | 0; a = a | 0; s = s | 0; var f = 0, c = 0; f = t[13] | 0; t[13] = f + 32; c = t[8] | 0; t[((c | 0) == 0 ? 16 : c + 28 | 0) >> 2] = f; t[9] = c; t[8] = f; t[f + 8 >> 2] = e; do { if (2 != (s | 0)) if (1 == (s | 0)) { t[f + 12 >> 2] = a + 2; break } else { t[f + 12 >> 2] = t[3]; break } else t[f + 12 >> 2] = a; } while (0); t[f >> 2] = r; t[f + 4 >> 2] = a; t[f + 16 >> 2] = 0; t[f + 20 >> 2] = s; i[f + 24 >> 0] = 1 == (s | 0) & 1; t[f + 28 >> 2] = 0; return } function A() { var e = 0, r = 0, a = 0; a = t[19] | 0; r = t[18] | 0; e: while (1) { e = r + 2 | 0; if (r >>> 0 >= a >>> 0) { r = 6; break } switch (s[e >> 1] | 0) { case 13: case 10: { r = 6; break e } case 93: { r = 7; break e } case 92: { e = r + 4 | 0; break } default: { } }r = e; } if ((r | 0) == 6) { t[18] = e; Y(); e = 0; } else if ((r | 0) == 7) { t[18] = e; e = 93; } return e | 0 } function C(e, r, a, i, t, f, c, n) { e = e | 0; r = r | 0; a = a | 0; i = i | 0; t = t | 0; f = f | 0; c = c | 0; n = n | 0; if ((((((s[e + 12 >> 1] | 0) == n << 16 >> 16 ? (s[e + 10 >> 1] | 0) == c << 16 >> 16 : 0) ? (s[e + 8 >> 1] | 0) == f << 16 >> 16 : 0) ? (s[e + 6 >> 1] | 0) == t << 16 >> 16 : 0) ? (s[e + 4 >> 1] | 0) == i << 16 >> 16 : 0) ? (s[e + 2 >> 1] | 0) == a << 16 >> 16 : 0) r = (s[e >> 1] | 0) == r << 16 >> 16; else r = 0; return r | 0 } function y(e) { e = e | 0; switch (s[e >> 1] | 0) { case 62: { e = (s[e + -2 >> 1] | 0) == 61; break } case 41: case 59: { e = 1; break } case 104: { e = E(e + -2 | 0, 99, 97, 116, 99) | 0; break } case 121: { e = O(e + -2 | 0, 102, 105, 110, 97, 108, 108) | 0; break } case 101: { e = P(e + -2 | 0, 101, 108, 115) | 0; break } default: e = 0; }return e | 0 } function g(e, r) { e = e | 0; r = r | 0; var a = 0, i = 0; a = t[18] | 0; i = s[a >> 1] | 0; if (i << 16 >> 16 == 97) { t[18] = a + 4; a = w(1) | 0; e = t[18] | 0; if (_(a) | 0) { d(a); r = (t[18] | 0) + 2 | 0; t[18] = r; } else { H(a) | 0; r = t[18] | 0; } i = w(1) | 0; a = t[18] | 0; } if ((a | 0) != (e | 0)) J(e, r); return i | 0 } function I() { var e = 0, r = 0, a = 0; e: while (1) { e = t[18] | 0; r = e + 2 | 0; t[18] = r; if (e >>> 0 >= (t[19] | 0) >>> 0) { a = 7; break } switch (s[r >> 1] | 0) { case 13: case 10: { a = 7; break e } case 47: break e; case 91: { A() | 0; break } case 92: { t[18] = e + 4; break } default: { } } } if ((a | 0) == 7) Y(); return } function p(e) { e = e | 0; var r = 0, a = 0, i = 0, f = 0, c = 0; f = (t[18] | 0) + 2 | 0; t[18] = f; a = t[19] | 0; while (1) { r = f + 2 | 0; if (f >>> 0 >= a >>> 0) break; i = s[r >> 1] | 0; if (!e ? ae(i) | 0 : 0) break; if (i << 16 >> 16 == 42 ? (s[f + 4 >> 1] | 0) == 47 : 0) { c = 8; break } f = r; } if ((c | 0) == 8) { t[18] = r; r = f + 4 | 0; } t[18] = r; return } function U(e, r, a, i, t, f, c) { e = e | 0; r = r | 0; a = a | 0; i = i | 0; t = t | 0; f = f | 0; c = c | 0; if (((((s[e + 10 >> 1] | 0) == c << 16 >> 16 ? (s[e + 8 >> 1] | 0) == f << 16 >> 16 : 0) ? (s[e + 6 >> 1] | 0) == t << 16 >> 16 : 0) ? (s[e + 4 >> 1] | 0) == i << 16 >> 16 : 0) ? (s[e + 2 >> 1] | 0) == a << 16 >> 16 : 0) r = (s[e >> 1] | 0) == r << 16 >> 16; else r = 0; return r | 0 } function m(e, r, a, i, f, c, n, b) { e = e | 0; r = r | 0; a = a | 0; i = i | 0; f = f | 0; c = c | 0; n = n | 0; b = b | 0; var u = 0, k = 0; k = e + -12 | 0; u = t[3] | 0; if (k >>> 0 >= u >>> 0 ? C(k, r, a, i, f, c, n, b) | 0 : 0) if ((k | 0) == (u | 0)) u = 1; else u = F(s[e + -14 >> 1] | 0) | 0; else u = 0; return u | 0 } function S(e) { e = e | 0; e: do { switch (e << 16 >> 16) { case 38: case 37: case 33: { e = 1; break } default: if ((e & -8) << 16 >> 16 == 40 | (e + -58 & 65535) < 6) e = 1; else { switch (e << 16 >> 16) { case 91: case 93: case 94: { e = 1; break e } default: { } }e = (e + -123 & 65535) < 4; } } } while (0); return e | 0 } function x(e) { e = e | 0; e: do { switch (e << 16 >> 16) { case 38: case 37: case 33: break; default: if (!((e + -58 & 65535) < 6 | (e + -40 & 65535) < 7 & e << 16 >> 16 != 41)) { switch (e << 16 >> 16) { case 91: case 94: break e; default: { } }return e << 16 >> 16 != 125 & (e + -123 & 65535) < 4 | 0 } } } while (0); return 1 } function O(e, r, a, i, f, c, n) { e = e | 0; r = r | 0; a = a | 0; i = i | 0; f = f | 0; c = c | 0; n = n | 0; var b = 0, u = 0; u = e + -10 | 0; b = t[3] | 0; if (u >>> 0 >= b >>> 0 ? U(u, r, a, i, f, c, n) | 0 : 0) if ((u | 0) == (b | 0)) b = 1; else b = F(s[e + -12 >> 1] | 0) | 0; else b = 0; return b | 0 } function $(e, r, a, i, f, c) { e = e | 0; r = r | 0; a = a | 0; i = i | 0; f = f | 0; c = c | 0; var n = 0, b = 0; b = e + -8 | 0; n = t[3] | 0; if (b >>> 0 >= n >>> 0 ? B(b, r, a, i, f, c) | 0 : 0) if ((b | 0) == (n | 0)) n = 1; else n = F(s[e + -10 >> 1] | 0) | 0; else n = 0; return n | 0 } function j(e) { e = e | 0; var r = 0, a = 0, i = 0, f = 0; a = n; n = n + 16 | 0; i = a; t[i >> 2] = 0; t[12] = e; r = t[3] | 0; f = r + (e << 1) | 0; e = f + 2 | 0; s[f >> 1] = 0; t[i >> 2] = e; t[13] = e; t[4] = 0; t[8] = 0; t[6] = 0; t[5] = 0; t[10] = 0; t[7] = 0; n = a; return r | 0 } function B(e, r, a, i, t, f) { e = e | 0; r = r | 0; a = a | 0; i = i | 0; t = t | 0; f = f | 0; if ((((s[e + 8 >> 1] | 0) == f << 16 >> 16 ? (s[e + 6 >> 1] | 0) == t << 16 >> 16 : 0) ? (s[e + 4 >> 1] | 0) == i << 16 >> 16 : 0) ? (s[e + 2 >> 1] | 0) == a << 16 >> 16 : 0) r = (s[e >> 1] | 0) == r << 16 >> 16; else r = 0; return r | 0 } function E(e, r, a, i, f) { e = e | 0; r = r | 0; a = a | 0; i = i | 0; f = f | 0; var c = 0, n = 0; n = e + -6 | 0; c = t[3] | 0; if (n >>> 0 >= c >>> 0 ? z(n, r, a, i, f) | 0 : 0) if ((n | 0) == (c | 0)) c = 1; else c = F(s[e + -8 >> 1] | 0) | 0; else c = 0; return c | 0 } function P(e, r, a, i) { e = e | 0; r = r | 0; a = a | 0; i = i | 0; var f = 0, c = 0; c = e + -4 | 0; f = t[3] | 0; if (c >>> 0 >= f >>> 0 ? K(c, r, a, i) | 0 : 0) if ((c | 0) == (f | 0)) f = 1; else f = F(s[e + -6 >> 1] | 0) | 0; else f = 0; return f | 0 } function q(e, r, a) { e = e | 0; r = r | 0; a = a | 0; var i = 0, f = 0; f = e + -2 | 0; i = t[3] | 0; if (f >>> 0 >= i >>> 0 ? N(f, r, a) | 0 : 0) if ((f | 0) == (i | 0)) i = 1; else i = F(s[e + -4 >> 1] | 0) | 0; else i = 0; return i | 0 } function z(e, r, a, i, t) { e = e | 0; r = r | 0; a = a | 0; i = i | 0; t = t | 0; if (((s[e + 6 >> 1] | 0) == t << 16 >> 16 ? (s[e + 4 >> 1] | 0) == i << 16 >> 16 : 0) ? (s[e + 2 >> 1] | 0) == a << 16 >> 16 : 0) r = (s[e >> 1] | 0) == r << 16 >> 16; else r = 0; return r | 0 } function D(e, r) { e = e | 0; r = r | 0; var a = 0; a = t[3] | 0; if (a >>> 0 <= e >>> 0 ? (s[e >> 1] | 0) == r << 16 >> 16 : 0) if ((a | 0) == (e | 0)) a = 1; else a = F(s[e + -2 >> 1] | 0) | 0; else a = 0; return a | 0 } function F(e) { e = e | 0; e: do { if ((e + -9 & 65535) < 5) e = 1; else { switch (e << 16 >> 16) { case 32: case 160: { e = 1; break e } default: { } }e = e << 16 >> 16 != 46 & (S(e) | 0); } } while (0); return e | 0 } function G() { var e = 0, r = 0, a = 0; e = t[19] | 0; a = t[18] | 0; e: while (1) { r = a + 2 | 0; if (a >>> 0 >= e >>> 0) break; switch (s[r >> 1] | 0) { case 13: case 10: break e; default: a = r; } } t[18] = r; return } function H(e) { e = e | 0; while (1) { if (Z(e) | 0) break; if (S(e) | 0) break; e = (t[18] | 0) + 2 | 0; t[18] = e; e = s[e >> 1] | 0; if (!(e << 16 >> 16)) { e = 0; break } } return e | 0 } function J(e, r) { e = e | 0; r = r | 0; var a = 0, i = 0; a = t[13] | 0; t[13] = a + 12; i = t[10] | 0; t[((i | 0) == 0 ? 20 : i + 8 | 0) >> 2] = a; t[10] = a; t[a >> 2] = e; t[a + 4 >> 2] = r; t[a + 8 >> 2] = 0; return } function K(e, r, a, i) { e = e | 0; r = r | 0; a = a | 0; i = i | 0; if ((s[e + 4 >> 1] | 0) == i << 16 >> 16 ? (s[e + 2 >> 1] | 0) == a << 16 >> 16 : 0) r = (s[e >> 1] | 0) == r << 16 >> 16; else r = 0; return r | 0 } function L(e) { e = e | 0; if (!($(e, 119, 104, 105, 108, 101) | 0) ? !(P(e, 102, 111, 114) | 0) : 0) e = q(e, 105, 102) | 0; else e = 1; return e | 0 } function M() { var e = 0; e = t[(t[6] | 0) + 20 >> 2] | 0; switch (e | 0) { case 1: { e = -1; break } case 2: { e = -2; break } default: e = e - (t[3] | 0) >> 1; }return e | 0 } function N(e, r, a) { e = e | 0; r = r | 0; a = a | 0; if ((s[e + 2 >> 1] | 0) == a << 16 >> 16) r = (s[e >> 1] | 0) == r << 16 >> 16; else r = 0; return r | 0 } function Q(e) { e = e | 0; switch (e << 16 >> 16) { case 160: case 32: case 12: case 11: case 9: { e = 1; break } default: e = 0; }return e | 0 } function R(e) { e = e | 0; if ((t[3] | 0) == (e | 0)) e = 1; else e = F(s[e + -2 >> 1] | 0) | 0; return e | 0 } function T() { var e = 0; e = t[(t[6] | 0) + 16 >> 2] | 0; if (!e) e = -1; else e = e - (t[3] | 0) >> 1; return e | 0 } function V() { var e = 0; e = t[6] | 0; e = t[((e | 0) == 0 ? 16 : e + 28 | 0) >> 2] | 0; t[6] = e; return (e | 0) != 0 | 0 } function W() { var e = 0; e = t[7] | 0; e = t[((e | 0) == 0 ? 20 : e + 8 | 0) >> 2] | 0; t[7] = e; return (e | 0) != 0 | 0 } function X(e) { e = e | 0; var r = 0; r = n; n = n + e | 0; n = n + 15 & -16; return r | 0 } function Y() { i[588] = 1; t[14] = (t[18] | 0) - (t[3] | 0) >> 1; t[18] = (t[19] | 0) + 2; return } function Z(e) { e = e | 0; return (e | 128) << 16 >> 16 == 160 | (e + -9 & 65535) < 5 | 0 } function _(e) { e = e | 0; return e << 16 >> 16 == 39 | e << 16 >> 16 == 34 | 0 } function ee() { return (t[(t[6] | 0) + 12 >> 2] | 0) - (t[3] | 0) >> 1 | 0 } function re() { return (t[(t[6] | 0) + 8 >> 2] | 0) - (t[3] | 0) >> 1 | 0 } function ae(e) { e = e | 0; return e << 16 >> 16 == 13 | e << 16 >> 16 == 10 | 0 } function ie() { return (t[(t[6] | 0) + 4 >> 2] | 0) - (t[3] | 0) >> 1 | 0 } function se() { return (t[(t[7] | 0) + 4 >> 2] | 0) - (t[3] | 0) >> 1 | 0 } function te() { return (t[t[6] >> 2] | 0) - (t[3] | 0) >> 1 | 0 } function fe() { return (t[t[7] >> 2] | 0) - (t[3] | 0) >> 1 | 0 } function ce() { return f[(t[6] | 0) + 24 >> 0] | 0 | 0 } function ne(e) { e = e | 0; t[3] = e; return } function be() { return (i[589] | 0) != 0 | 0 } function ue() { return t[14] | 0 } return { ai: T, e: ue, ee: se, es: fe, f: be, id: M, ie: ie, ip: ce, is: te, p: b, re: W, ri: V, sa: j, se: ee, ses: ne, ss: re, sta: X } }({ Int8Array: Int8Array, Int16Array: Int16Array, Int32Array: Int32Array, Uint8Array: Uint8Array, Uint16Array: Uint16Array }, {}, r), a = e.sta(2 * i); } const o = t.length + 1; e.ses(a), e.sa(o - 1), (s ? b : n)(t, new Uint16Array(r, a, o)), e.p() || (c$1 = e.e(), h()); const w = [], d = []; for (; e.ri();) { const r = e.is(), a = e.ie(), i = e.ai(), s = e.id(), f = e.ss(), c = e.se(); let n; e.ip() && (n = u(-1 === s ? r : r + 1, t.charCodeAt(-1 === s ? r - 1 : r))), w.push({ n: n, s: r, e: a, ss: f, se: c, d: s, a: i }); } for (; e.re();) { const r = e.es(), a = t.charCodeAt(r); d.push(34 === a || 39 === a ? u(r + 1, a) : t.slice(e.es(), e.ee())); } return [w, d, !!e.f()] } function n(e, r) { const a = e.length; let i = 0; for (; i < a;) { const a = e.charCodeAt(i); r[i++] = (255 & a) << 8 | a >>> 8; } } function b(e, r) { const a = e.length; let i = 0; for (; i < a;)r[i] = e.charCodeAt(i++); } function u(e, r) { c$1 = e; let a = "", i = c$1; for (; ;) { c$1 >= t.length && h(); const e = t.charCodeAt(c$1); if (e === r) break; 92 === e ? (a += t.slice(i, c$1), a += k(), i = c$1) : (8232 === e || 8233 === e || o(e) && h(), ++c$1); } return a += t.slice(i, c$1++), a } function k() { let e = t.charCodeAt(++c$1); switch (++c$1, e) { case 110: return "\n"; case 114: return "\r"; case 120: return String.fromCharCode(l(2)); case 117: return function () { let e; 123 === t.charCodeAt(c$1) ? (++c$1, e = l(t.indexOf("}", c$1) - c$1), ++c$1, e > 1114111 && h()) : e = l(4); return e <= 65535 ? String.fromCharCode(e) : (e -= 65536, String.fromCharCode(55296 + (e >> 10), 56320 + (1023 & e))) }(); case 116: return "\t"; case 98: return "\b"; case 118: return "\v"; case 102: return "\f"; case 13: 10 === t.charCodeAt(c$1) && ++c$1; case 10: return ""; case 56: case 57: h(); default: if (e >= 48 && e <= 55) { let r = t.substr(c$1 - 1, 3).match(/^[0-7]+/)[0], a = parseInt(r, 8); return a > 255 && (r = r.slice(0, -1), a = parseInt(r, 8)), c$1 += r.length - 1, e = t.charCodeAt(c$1), "0" === r && 56 !== e && 57 !== e || h(), String.fromCharCode(a) } return o(e) ? "" : String.fromCharCode(e) } } function l(e) { const r = c$1; let a = 0, i = 0; for (let r = 0; r < e; ++r, ++c$1) { let e, s = t.charCodeAt(c$1); if (95 !== s) { if (s >= 97) e = s - 97 + 10; else if (s >= 65) e = s - 65 + 10; else { if (!(s >= 48 && s <= 57)) break; e = s - 48; } if (e >= 16) break; i = s, a = 16 * a + e; } else 95 !== i && 0 !== r || h(), i = s; } return 95 !== i && c$1 - r === e || h(), a } function o(e) { return 13 === e || 10 === e } function h() { throw Object.assign(new Error(`Parse error ${f}:${t.slice(0, c$1).split("\n").length}:${c$1 - t.lastIndexOf("\n", c$1 - 1)}`), { idx: c$1 }) }
|
309 |
+
|
310 |
+
async function defaultResolve(id, parentUrl) {
|
311 |
+
return resolveImportMap(importMap, resolveIfNotPlainOrUrl(id, parentUrl) || id, parentUrl);
|
312 |
+
}
|
313 |
+
|
314 |
+
async function _resolve(id, parentUrl) {
|
315 |
+
const urlResolved = resolveIfNotPlainOrUrl(id, parentUrl);
|
316 |
+
return {
|
317 |
+
r: resolveImportMap(importMap, urlResolved || id, parentUrl),
|
318 |
+
// b = bare specifier
|
319 |
+
b: !urlResolved && !isURL(id)
|
320 |
+
};
|
321 |
+
}
|
322 |
+
|
323 |
+
const resolve = resolveHook ? async (id, parentUrl) => ({ r: await resolveHook(id, parentUrl, defaultResolve), b: false }) : _resolve;
|
324 |
+
|
325 |
+
let id = 0;
|
326 |
+
const registry = {};
|
327 |
+
|
328 |
+
async function loadAll(load, seen) {
|
329 |
+
if (load.b || seen[load.u])
|
330 |
+
return;
|
331 |
+
seen[load.u] = 1;
|
332 |
+
await load.L;
|
333 |
+
await Promise.all(load.d.map(dep => loadAll(dep, seen)));
|
334 |
+
if (!load.n)
|
335 |
+
load.n = load.d.some(dep => dep.n);
|
336 |
+
}
|
337 |
+
|
338 |
+
let importMap = { imports: {}, scopes: {} };
|
339 |
+
let importMapSrcOrLazy = false;
|
340 |
+
let baselinePassthrough;
|
341 |
+
|
342 |
+
const initPromise = featureDetectionPromise.then(() => {
|
343 |
+
// shim mode is determined on initialization, no late shim mode
|
344 |
+
if (!shimMode) {
|
345 |
+
let seenScript = false;
|
346 |
+
for (const script of document.querySelectorAll('script[type="module-shim"],script[type="importmap-shim"],script[type="module"],script[type="importmap"]')) {
|
347 |
+
if (!seenScript && script.type === 'module')
|
348 |
+
seenScript = true;
|
349 |
+
if (script.type.endsWith('-shim')) {
|
350 |
+
setShimMode();
|
351 |
+
break;
|
352 |
+
}
|
353 |
+
if (seenScript && script.type === 'importmap') {
|
354 |
+
importMapSrcOrLazy = true;
|
355 |
+
break;
|
356 |
+
}
|
357 |
+
}
|
358 |
+
}
|
359 |
+
baselinePassthrough = supportsDynamicImport && supportsImportMeta && supportsImportMaps && (!jsonModulesEnabled || supportsJsonAssertions) && (!cssModulesEnabled || supportsCssAssertions) && !importMapSrcOrLazy && !false;
|
360 |
+
if (!baselinePassthrough) onpolyfill();
|
361 |
+
if (shimMode || !baselinePassthrough) {
|
362 |
+
new MutationObserver(mutations => {
|
363 |
+
for (const mutation of mutations) {
|
364 |
+
if (mutation.type !== 'childList') continue;
|
365 |
+
for (const node of mutation.addedNodes) {
|
366 |
+
if (node.tagName === 'SCRIPT') {
|
367 |
+
if (!shimMode && node.type === 'module' || shimMode && node.type === 'module-shim')
|
368 |
+
processScript(node);
|
369 |
+
if (!shimMode && node.type === 'importmap' || shimMode && node.type === 'importmap-shim')
|
370 |
+
processImportMap(node);
|
371 |
+
}
|
372 |
+
else if (node.tagName === 'LINK' && node.rel === 'modulepreload')
|
373 |
+
processPreload(node);
|
374 |
+
}
|
375 |
+
}
|
376 |
+
}).observe(document, { childList: true, subtree: true });
|
377 |
+
processImportMaps();
|
378 |
+
processScriptsAndPreloads();
|
379 |
+
return undefined;
|
380 |
+
}
|
381 |
+
});
|
382 |
+
let importMapPromise = initPromise;
|
383 |
+
|
384 |
+
let acceptingImportMaps = true;
|
385 |
+
async function topLevelLoad(url, fetchOpts, source, nativelyLoaded, lastStaticLoadPromise) {
|
386 |
+
if (!shimMode)
|
387 |
+
acceptingImportMaps = false;
|
388 |
+
await importMapPromise;
|
389 |
+
// early analysis opt-out - no need to even fetch if we have feature support
|
390 |
+
if (!shimMode && baselinePassthrough) {
|
391 |
+
// for polyfill case, only dynamic import needs a return value here, and dynamic import will never pass nativelyLoaded
|
392 |
+
if (nativelyLoaded)
|
393 |
+
return null;
|
394 |
+
await lastStaticLoadPromise;
|
395 |
+
return dynamicImport(source ? createBlob(source) : url, { errUrl: url || source });
|
396 |
+
}
|
397 |
+
const load = getOrCreateLoad(url, fetchOpts, source);
|
398 |
+
const seen = {};
|
399 |
+
await loadAll(load, seen);
|
400 |
+
lastLoad = undefined;
|
401 |
+
resolveDeps(load, seen);
|
402 |
+
await lastStaticLoadPromise;
|
403 |
+
if (source && !shimMode && !load.n && !false) {
|
404 |
+
const module = await dynamicImport(createBlob(source), { errUrl: source });
|
405 |
+
if (revokeBlobURLs) revokeObjectURLs(Object.keys(seen));
|
406 |
+
return module;
|
407 |
+
}
|
408 |
+
const module = await dynamicImport(!shimMode && !load.n && nativelyLoaded ? load.u : load.b, { errUrl: load.u });
|
409 |
+
// if the top-level load is a shell, run its update function
|
410 |
+
if (load.s)
|
411 |
+
(await dynamicImport(load.s)).u$_(module);
|
412 |
+
if (revokeBlobURLs) revokeObjectURLs(Object.keys(seen));
|
413 |
+
// when tla is supported, this should return the tla promise as an actual handle
|
414 |
+
// so readystate can still correspond to the sync subgraph exec completions
|
415 |
+
return module;
|
416 |
+
}
|
417 |
+
|
418 |
+
function revokeObjectURLs(registryKeys) {
|
419 |
+
let batch = 0;
|
420 |
+
const keysLength = registryKeys.length;
|
421 |
+
const schedule = self.requestIdleCallback ? self.requestIdleCallback : self.requestAnimationFrame;
|
422 |
+
schedule(cleanup);
|
423 |
+
function cleanup() {
|
424 |
+
const batchStartIndex = batch * 100;
|
425 |
+
if (batchStartIndex > keysLength) return
|
426 |
+
for (const key of registryKeys.slice(batchStartIndex, batchStartIndex + 100)) {
|
427 |
+
const load = registry[key];
|
428 |
+
if (load) URL.revokeObjectURL(load.b);
|
429 |
+
}
|
430 |
+
batch++;
|
431 |
+
schedule(cleanup);
|
432 |
+
}
|
433 |
+
}
|
434 |
+
|
435 |
+
async function importShim(id, parentUrl = baseUrl, _assertion) {
|
436 |
+
// needed for shim check
|
437 |
+
await initPromise;
|
438 |
+
if (acceptingImportMaps || shimMode || !baselinePassthrough) {
|
439 |
+
processImportMaps();
|
440 |
+
if (!shimMode)
|
441 |
+
acceptingImportMaps = false;
|
442 |
+
}
|
443 |
+
await importMapPromise;
|
444 |
+
return topLevelLoad((await resolve(id, parentUrl)).r || throwUnresolved(id, parentUrl), { credentials: 'same-origin' });
|
445 |
+
}
|
446 |
+
|
447 |
+
self.importShim = importShim;
|
448 |
+
|
449 |
+
if (shimMode) {
|
450 |
+
importShim.getImportMap = () => JSON.parse(JSON.stringify(importMap));
|
451 |
+
}
|
452 |
+
|
453 |
+
const meta = {};
|
454 |
+
|
455 |
+
async function importMetaResolve(id, parentUrl = this.url) {
|
456 |
+
return (await resolve(id, `${parentUrl}`)).r || throwUnresolved(id, parentUrl);
|
457 |
+
}
|
458 |
+
|
459 |
+
self._esmsm = meta;
|
460 |
+
|
461 |
+
function urlJsString(url) {
|
462 |
+
return `'${url.replace(/'/g, "\\'")}'`;
|
463 |
+
}
|
464 |
+
|
465 |
+
let lastLoad;
|
466 |
+
function resolveDeps(load, seen) {
|
467 |
+
if (load.b || !seen[load.u])
|
468 |
+
return;
|
469 |
+
seen[load.u] = 0;
|
470 |
+
|
471 |
+
for (const dep of load.d)
|
472 |
+
resolveDeps(dep, seen);
|
473 |
+
|
474 |
+
const [imports] = load.a;
|
475 |
+
|
476 |
+
// "execution"
|
477 |
+
const source = load.S;
|
478 |
+
|
479 |
+
// edge doesnt execute sibling in order, so we fix this up by ensuring all previous executions are explicit dependencies
|
480 |
+
let resolvedSource = edge && lastLoad ? `import '${lastLoad}';` : '';
|
481 |
+
|
482 |
+
if (!imports.length) {
|
483 |
+
resolvedSource += source;
|
484 |
+
}
|
485 |
+
else {
|
486 |
+
// once all deps have loaded we can inline the dependency resolution blobs
|
487 |
+
// and define this blob
|
488 |
+
let lastIndex = 0, depIndex = 0;
|
489 |
+
for (const { s: start, se: end, d: dynamicImportIndex } of imports) {
|
490 |
+
// dependency source replacements
|
491 |
+
if (dynamicImportIndex === -1) {
|
492 |
+
const depLoad = load.d[depIndex++];
|
493 |
+
let blobUrl = depLoad.b;
|
494 |
+
if (!blobUrl) {
|
495 |
+
// circular shell creation
|
496 |
+
if (!(blobUrl = depLoad.s)) {
|
497 |
+
blobUrl = depLoad.s = createBlob(`export function u$_(m){${depLoad.a[1].map(
|
498 |
+
name => name === 'default' ? `$_default=m.default` : `${name}=m.${name}`
|
499 |
+
).join(',')
|
500 |
+
}}${depLoad.a[1].map(name =>
|
501 |
+
name === 'default' ? `let $_default;export{$_default as default}` : `export let ${name}`
|
502 |
+
).join(';')
|
503 |
+
}\n//# sourceURL=${depLoad.r}?cycle`);
|
504 |
+
}
|
505 |
+
}
|
506 |
+
// circular shell execution
|
507 |
+
else if (depLoad.s) {
|
508 |
+
resolvedSource += `${source.slice(lastIndex, start - 1)}/*${source.slice(start - 1, end)}*/${urlJsString(blobUrl)};import*as m$_${depIndex} from'${depLoad.b}';import{u$_ as u$_${depIndex}}from'${depLoad.s}';u$_${depIndex}(m$_${depIndex})`;
|
509 |
+
lastIndex = end;
|
510 |
+
depLoad.s = undefined;
|
511 |
+
continue;
|
512 |
+
}
|
513 |
+
resolvedSource += `${source.slice(lastIndex, start - 1)}/*${source.slice(start - 1, end)}*/${urlJsString(blobUrl)}`;
|
514 |
+
lastIndex = end;
|
515 |
+
}
|
516 |
+
// import.meta
|
517 |
+
else if (dynamicImportIndex === -2) {
|
518 |
+
meta[load.r] = { url: load.r, resolve: importMetaResolve };
|
519 |
+
resolvedSource += `${source.slice(lastIndex, start)}self._esmsm[${urlJsString(load.r)}]`;
|
520 |
+
lastIndex = end;
|
521 |
+
}
|
522 |
+
// dynamic import
|
523 |
+
else {
|
524 |
+
resolvedSource += `${source.slice(lastIndex, dynamicImportIndex + 6)}Shim(${source.slice(start, end)}, ${load.r && urlJsString(load.r)}`;
|
525 |
+
lastIndex = end;
|
526 |
+
}
|
527 |
+
}
|
528 |
+
|
529 |
+
resolvedSource += source.slice(lastIndex);
|
530 |
+
}
|
531 |
+
|
532 |
+
// ; and // trailer support added for Ruby 7 source maps compatibility
|
533 |
+
let hasSourceURL = false;
|
534 |
+
resolvedSource = resolvedSource.replace(sourceMapURLRegEx, (match, isMapping, url) => (hasSourceURL = !isMapping, match.replace(url, () => new URL(url, load.r))));
|
535 |
+
if (!hasSourceURL)
|
536 |
+
resolvedSource += '\n//# sourceURL=' + load.r;
|
537 |
+
|
538 |
+
load.b = lastLoad = createBlob(resolvedSource);
|
539 |
+
load.S = undefined;
|
540 |
+
}
|
541 |
+
|
542 |
+
const sourceMapURLRegEx = /\n\/\/# source(Mapping)?URL=([^\n]+)\s*((;|\/\/[^#][^\n]*)\s*)*$/;
|
543 |
+
|
544 |
+
const jsContentType = /^(text|application)\/(x-)?javascript(;|$)/;
|
545 |
+
const jsonContentType = /^(text|application)\/json(;|$)/;
|
546 |
+
const cssContentType = /^(text|application)\/css(;|$)/;
|
547 |
+
const wasmContentType = /^application\/wasm(;|$)/;
|
548 |
+
|
549 |
+
const cssUrlRegEx = /url\(\s*(?:(["'])((?:\\.|[^\n\\"'])+)\1|((?:\\.|[^\s,"'()\\])+))\s*\)/g;
|
550 |
+
|
551 |
+
// restrict in-flight fetches to a pool of 100
|
552 |
+
let p = [];
|
553 |
+
let c = 0;
|
554 |
+
function pushFetchPool() {
|
555 |
+
if (++c > 100)
|
556 |
+
return new Promise(r => p.push(r));
|
557 |
+
}
|
558 |
+
function popFetchPool() {
|
559 |
+
c--;
|
560 |
+
if (p.length)
|
561 |
+
p.shift()();
|
562 |
+
}
|
563 |
+
|
564 |
+
async function doFetch(url, fetchOpts) {
|
565 |
+
const poolQueue = pushFetchPool();
|
566 |
+
if (poolQueue) await poolQueue;
|
567 |
+
try {
|
568 |
+
var res = await fetchHook(url, fetchOpts);
|
569 |
+
}
|
570 |
+
finally {
|
571 |
+
popFetchPool();
|
572 |
+
}
|
573 |
+
if (!res.ok)
|
574 |
+
throw new Error(`${res.status} ${res.statusText} ${res.url}`);
|
575 |
+
const contentType = res.headers.get('content-type');
|
576 |
+
if (jsContentType.test(contentType))
|
577 |
+
return { r: res.url, s: await res.text(), t: 'js' };
|
578 |
+
else if (jsonContentType.test(contentType))
|
579 |
+
return { r: res.url, s: `export default ${await res.text()}`, t: 'json' };
|
580 |
+
else if (cssContentType.test(contentType))
|
581 |
+
return {
|
582 |
+
r: res.url, s: `var s=new CSSStyleSheet();s.replaceSync(${JSON.stringify((await res.text()).replace(cssUrlRegEx, (_match, quotes, relUrl1, relUrl2) => `url(${quotes}${resolveUrl(relUrl1 || relUrl2, url)}${quotes})`))
|
583 |
+
});export default s;`, t: 'css'
|
584 |
+
};
|
585 |
+
else if (wasmContentType.test(contentType))
|
586 |
+
throw new Error('WASM modules not supported');
|
587 |
+
else
|
588 |
+
throw new Error(`Unknown Content-Type "${contentType}"`);
|
589 |
+
}
|
590 |
+
|
591 |
+
function getOrCreateLoad(url, fetchOpts, source) {
|
592 |
+
let load = registry[url];
|
593 |
+
if (load)
|
594 |
+
return load;
|
595 |
+
|
596 |
+
load = registry[url] = {
|
597 |
+
// url
|
598 |
+
u: url,
|
599 |
+
// response url
|
600 |
+
r: undefined,
|
601 |
+
// fetchPromise
|
602 |
+
f: undefined,
|
603 |
+
// source
|
604 |
+
S: undefined,
|
605 |
+
// linkPromise
|
606 |
+
L: undefined,
|
607 |
+
// analysis
|
608 |
+
a: undefined,
|
609 |
+
// deps
|
610 |
+
d: undefined,
|
611 |
+
// blobUrl
|
612 |
+
b: undefined,
|
613 |
+
// shellUrl
|
614 |
+
s: undefined,
|
615 |
+
// needsShim
|
616 |
+
n: false,
|
617 |
+
// type
|
618 |
+
t: null
|
619 |
+
};
|
620 |
+
|
621 |
+
load.f = (async () => {
|
622 |
+
if (!source) {
|
623 |
+
// preload fetch options override fetch options (race)
|
624 |
+
let t;
|
625 |
+
({ r: load.r, s: source, t } = await (fetchCache[url] || doFetch(url, fetchOpts)));
|
626 |
+
if (t && !shimMode) {
|
627 |
+
if (t === 'css' && !cssModulesEnabled || t === 'json' && !jsonModulesEnabled)
|
628 |
+
throw new Error(`${t}-modules require <script type="esms-options">{ "polyfillEnable": ["${t}-modules"] }<${''}/script>`);
|
629 |
+
if (t === 'css' && !supportsCssAssertions || t === 'json' && !supportsJsonAssertions)
|
630 |
+
load.n = true;
|
631 |
+
}
|
632 |
+
}
|
633 |
+
try {
|
634 |
+
load.a = parse(source, load.u);
|
635 |
+
}
|
636 |
+
catch (e) {
|
637 |
+
console.warn(e);
|
638 |
+
load.a = [[], []];
|
639 |
+
}
|
640 |
+
load.S = source;
|
641 |
+
return load;
|
642 |
+
})();
|
643 |
+
|
644 |
+
load.L = load.f.then(async () => {
|
645 |
+
let childFetchOpts = fetchOpts;
|
646 |
+
load.d = (await Promise.all(load.a[0].map(async ({ n, d }) => {
|
647 |
+
if (d >= 0 && !supportsDynamicImport || d === 2 && !supportsImportMeta)
|
648 |
+
load.n = true;
|
649 |
+
if (!n) return;
|
650 |
+
const { r, b } = await resolve(n, load.r || load.u);
|
651 |
+
if (b && (!supportsImportMaps || importMapSrcOrLazy))
|
652 |
+
load.n = true;
|
653 |
+
if (d !== -1) return;
|
654 |
+
if (!r)
|
655 |
+
throwUnresolved(n, load.r || load.u);
|
656 |
+
if (skip && skip.test(r)) return { b: r };
|
657 |
+
if (childFetchOpts.integrity)
|
658 |
+
childFetchOpts = Object.assign({}, childFetchOpts, { integrity: undefined });
|
659 |
+
return getOrCreateLoad(r, childFetchOpts).f;
|
660 |
+
}))).filter(l => l);
|
661 |
+
});
|
662 |
+
|
663 |
+
return load;
|
664 |
+
}
|
665 |
+
|
666 |
+
function processScriptsAndPreloads() {
|
667 |
+
for (const script of document.querySelectorAll(shimMode ? 'script[type="module-shim"]' : 'script[type="module"]'))
|
668 |
+
processScript(script);
|
669 |
+
for (const link of document.querySelectorAll('link[rel="modulepreload"]'))
|
670 |
+
processPreload(link);
|
671 |
+
}
|
672 |
+
|
673 |
+
function processImportMaps() {
|
674 |
+
for (const script of document.querySelectorAll(shimMode ? 'script[type="importmap-shim"]' : 'script[type="importmap"]'))
|
675 |
+
processImportMap(script);
|
676 |
+
}
|
677 |
+
|
678 |
+
function getFetchOpts(script) {
|
679 |
+
const fetchOpts = {};
|
680 |
+
if (script.integrity)
|
681 |
+
fetchOpts.integrity = script.integrity;
|
682 |
+
if (script.referrerpolicy)
|
683 |
+
fetchOpts.referrerPolicy = script.referrerpolicy;
|
684 |
+
if (script.crossorigin === 'use-credentials')
|
685 |
+
fetchOpts.credentials = 'include';
|
686 |
+
else if (script.crossorigin === 'anonymous')
|
687 |
+
fetchOpts.credentials = 'omit';
|
688 |
+
else
|
689 |
+
fetchOpts.credentials = 'same-origin';
|
690 |
+
return fetchOpts;
|
691 |
+
}
|
692 |
+
|
693 |
+
let lastStaticLoadPromise = Promise.resolve();
|
694 |
+
|
695 |
+
let domContentLoadedCnt = 1;
|
696 |
+
function domContentLoadedCheck() {
|
697 |
+
if (--domContentLoadedCnt === 0 && !noLoadEventRetriggers)
|
698 |
+
document.dispatchEvent(new Event('DOMContentLoaded'));
|
699 |
+
}
|
700 |
+
// this should always trigger because we assume es-module-shims is itself a domcontentloaded requirement
|
701 |
+
document.addEventListener('DOMContentLoaded', async () => {
|
702 |
+
await initPromise;
|
703 |
+
domContentLoadedCheck();
|
704 |
+
if (shimMode || !baselinePassthrough) {
|
705 |
+
processImportMaps();
|
706 |
+
processScriptsAndPreloads();
|
707 |
+
}
|
708 |
+
});
|
709 |
+
|
710 |
+
let readyStateCompleteCnt = 1;
|
711 |
+
if (document.readyState === 'complete') {
|
712 |
+
readyStateCompleteCheck();
|
713 |
+
}
|
714 |
+
else {
|
715 |
+
document.addEventListener('readystatechange', async () => {
|
716 |
+
processImportMaps();
|
717 |
+
await initPromise;
|
718 |
+
readyStateCompleteCheck();
|
719 |
+
});
|
720 |
+
}
|
721 |
+
function readyStateCompleteCheck() {
|
722 |
+
if (--readyStateCompleteCnt === 0 && !noLoadEventRetriggers)
|
723 |
+
document.dispatchEvent(new Event('readystatechange'));
|
724 |
+
}
|
725 |
+
|
726 |
+
function processImportMap(script) {
|
727 |
+
if (script.ep) // ep marker = script processed
|
728 |
+
return;
|
729 |
+
// empty inline scripts sometimes show before domready
|
730 |
+
if (!script.src && !script.innerHTML)
|
731 |
+
return;
|
732 |
+
script.ep = true;
|
733 |
+
// we dont currently support multiple, external or dynamic imports maps in polyfill mode to match native
|
734 |
+
if (script.src) {
|
735 |
+
if (!shimMode)
|
736 |
+
return;
|
737 |
+
importMapSrcOrLazy = true;
|
738 |
+
}
|
739 |
+
if (acceptingImportMaps) {
|
740 |
+
importMapPromise = importMapPromise
|
741 |
+
.then(async () => {
|
742 |
+
importMap = resolveAndComposeImportMap(script.src ? await (await fetchHook(script.src)).json() : JSON.parse(script.innerHTML), script.src || baseUrl, importMap);
|
743 |
+
})
|
744 |
+
.catch(error => setTimeout(() => { throw error }));
|
745 |
+
if (!shimMode)
|
746 |
+
acceptingImportMaps = false;
|
747 |
+
}
|
748 |
+
}
|
749 |
+
|
750 |
+
function processScript(script) {
|
751 |
+
if (script.ep) // ep marker = script processed
|
752 |
+
return;
|
753 |
+
if (script.getAttribute('noshim') !== null)
|
754 |
+
return;
|
755 |
+
// empty inline scripts sometimes show before domready
|
756 |
+
if (!script.src && !script.innerHTML)
|
757 |
+
return;
|
758 |
+
script.ep = true;
|
759 |
+
// does this load block readystate complete
|
760 |
+
const isReadyScript = readyStateCompleteCnt > 0;
|
761 |
+
// does this load block DOMContentLoaded
|
762 |
+
const isDomContentLoadedScript = domContentLoadedCnt > 0;
|
763 |
+
if (isReadyScript) readyStateCompleteCnt++;
|
764 |
+
if (isDomContentLoadedScript) domContentLoadedCnt++;
|
765 |
+
const blocks = script.getAttribute('async') === null && isReadyScript;
|
766 |
+
const loadPromise = topLevelLoad(script.src || `${baseUrl}?${id++}`, getFetchOpts(script), !script.src && script.innerHTML, !shimMode, blocks && lastStaticLoadPromise).catch(e => {
|
767 |
+
setTimeout(() => { throw e });
|
768 |
+
onerror(e);
|
769 |
+
});
|
770 |
+
if (blocks)
|
771 |
+
lastStaticLoadPromise = loadPromise.then(readyStateCompleteCheck);
|
772 |
+
if (isDomContentLoadedScript)
|
773 |
+
loadPromise.then(domContentLoadedCheck);
|
774 |
+
}
|
775 |
+
|
776 |
+
const fetchCache = {};
|
777 |
+
function processPreload(link) {
|
778 |
+
if (link.ep) // ep marker = processed
|
779 |
+
return;
|
780 |
+
link.ep = true;
|
781 |
+
if (fetchCache[link.href])
|
782 |
+
return;
|
783 |
+
fetchCache[link.href] = doFetch(link.href, getFetchOpts(link));
|
784 |
+
}
|
785 |
+
|
786 |
+
function throwUnresolved(id, parentUrl) {
|
787 |
+
throw Error("Unable to resolve specifier '" + id + (parentUrl ? "' from " + parentUrl : "'"));
|
788 |
+
}
|
789 |
+
|
790 |
+
})();
|
js/posex.js
ADDED
@@ -0,0 +1,945 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
async function _import() {
|
2 |
+
if (!globalThis.posex || !globalThis.posex.import) {
|
3 |
+
const THREE = await import('three');
|
4 |
+
const { TrackballControls } = await import('three-trackballcontrols');
|
5 |
+
const { DragControls } = await import('three-dragcontrols');
|
6 |
+
const { MeshLine, MeshLineMaterial } = await import('three-meshline');
|
7 |
+
return { THREE, TrackballControls, DragControls, MeshLine, MeshLineMaterial };
|
8 |
+
} else {
|
9 |
+
return await globalThis.posex.import();
|
10 |
+
}
|
11 |
+
}
|
12 |
+
const { THREE, TrackballControls, DragControls, MeshLine, MeshLineMaterial } = await _import();
|
13 |
+
|
14 |
+
const JOINT_RADIUS = 4.0;
|
15 |
+
const LIMB_SIZE = 4.0;
|
16 |
+
const LIMB_N = 64;
|
17 |
+
|
18 |
+
const joint_names = [
|
19 |
+
'nose',
|
20 |
+
'neck',
|
21 |
+
'right shoulder',
|
22 |
+
'right elbow',
|
23 |
+
'right wrist',
|
24 |
+
'left shoulder',
|
25 |
+
'left elbow',
|
26 |
+
'left wrist',
|
27 |
+
'right hip',
|
28 |
+
'right knee',
|
29 |
+
'right ancle',
|
30 |
+
'left hip',
|
31 |
+
'left knee',
|
32 |
+
'left ancle',
|
33 |
+
'right eye',
|
34 |
+
'left eye',
|
35 |
+
'right ear',
|
36 |
+
'left ear'
|
37 |
+
];
|
38 |
+
|
39 |
+
const joint_colors = [
|
40 |
+
// r g b
|
41 |
+
[255, 0, 0], // 0: nose
|
42 |
+
[255, 85, 0], // 1: neck
|
43 |
+
[255, 170, 0], // 2: right shoulder
|
44 |
+
[255, 255, 0], // 3: right elbow
|
45 |
+
[170, 255, 0], // 4: right wrist
|
46 |
+
[85, 255, 0], // 5: left shoulder
|
47 |
+
[0, 255, 0], // 6: left elbow
|
48 |
+
[0, 255, 85], // 7: left wrist
|
49 |
+
[0, 255, 170], // 8: right hip
|
50 |
+
[0, 255, 255], // 9: right knee
|
51 |
+
[0, 170, 255], // 10: right ancle
|
52 |
+
[0, 85, 255], // 11: left hip
|
53 |
+
[0, 0, 255], // 12: left knee
|
54 |
+
[85, 0, 255], // 13: left ancle
|
55 |
+
[170, 0, 255], // 14: right eye
|
56 |
+
[255, 0, 255], // 15: left eye
|
57 |
+
[255, 0, 170], // 16: right ear
|
58 |
+
[255, 0, 85] // 17: left ear
|
59 |
+
];
|
60 |
+
|
61 |
+
const limb_pairs = [
|
62 |
+
[1, 2], // 0: right shoulder
|
63 |
+
[1, 5], // 1: left shoulder
|
64 |
+
[2, 3], // 2: right upper arm
|
65 |
+
[3, 4], // 3: right forearm
|
66 |
+
[5, 6], // 4: left upper arm
|
67 |
+
[6, 7], // 5: left forearm
|
68 |
+
[1, 8], // 6: right hip
|
69 |
+
[8, 9], // 7: right upper leg
|
70 |
+
[9, 10], // 8: right lower leg
|
71 |
+
[1, 11], // 9: left hip
|
72 |
+
[11, 12], // 10: left upper leg
|
73 |
+
[12, 13], // 11: left lower leg
|
74 |
+
[1, 0], // 12: neck
|
75 |
+
[0, 14], // 13: right eye
|
76 |
+
[14, 16], // 14: right ear
|
77 |
+
[0, 15], // 15: left eye
|
78 |
+
[15, 17], // 16: left ear
|
79 |
+
];
|
80 |
+
|
81 |
+
const standard_pose = [
|
82 |
+
// x y z ∈ [0,1]
|
83 |
+
[0.500, 0.820, 0.000], // 0: nose
|
84 |
+
[0.500, 0.750, 0.000], // 1: neck
|
85 |
+
[0.416, 0.750, 0.000], // 2: right shoulder
|
86 |
+
[0.305, 0.750, 0.000], // 3: right elbow
|
87 |
+
[0.188, 0.750, 0.000], // 4: right wrist
|
88 |
+
[0.584, 0.750, 0.000], // 5: left shoulder
|
89 |
+
[0.695, 0.750, 0.000], // 6: left elbow
|
90 |
+
[0.812, 0.750, 0.000], // 7: left wrist
|
91 |
+
[0.447, 0.511, 0.000], // 8: right hip
|
92 |
+
[0.453, 0.295, 0.000], // 9: right knee
|
93 |
+
[0.445, 0.109, 0.000], // 10: right ancle
|
94 |
+
[0.553, 0.511, 0.000], // 11: left hip
|
95 |
+
[0.547, 0.295, 0.000], // 12: left knee
|
96 |
+
[0.555, 0.109, 0.000], // 13: left ancle
|
97 |
+
[0.480, 0.848, 0.000], // 14: right eye
|
98 |
+
[0.520, 0.848, 0.000], // 15: left eye
|
99 |
+
[0.450, 0.834, 0.000], // 16: right ear
|
100 |
+
[0.550, 0.834, 0.000] // 17: left ear
|
101 |
+
]
|
102 |
+
|
103 |
+
for (let xyz of standard_pose) {
|
104 |
+
xyz[0] = xyz[0] - 0.5; // [0,1] -> [-0.5,0.5]
|
105 |
+
xyz[1] = xyz[1] - 0.5; // [0,1] -> [-0.5,0.5]
|
106 |
+
//xyz[2] = xyz[2] * 2 - 1.0;
|
107 |
+
}
|
108 |
+
|
109 |
+
function create_body(unit, x0, y0, z0) {
|
110 |
+
const joints = [];
|
111 |
+
const limbs = [];
|
112 |
+
|
113 |
+
for (let i = 0; i < standard_pose.length; ++i) {
|
114 |
+
const [x, y, z] = standard_pose[i];
|
115 |
+
const [r, g, b] = joint_colors[i];
|
116 |
+
const color = (r << 16) | (g << 8) | (b << 0);
|
117 |
+
const geom = new THREE.SphereGeometry(JOINT_RADIUS, 32, 32);
|
118 |
+
const mat = new THREE.MeshBasicMaterial({ color: color });
|
119 |
+
const joint = new THREE.Mesh(geom, mat);
|
120 |
+
joint.name = joint_names[i];
|
121 |
+
joint.position.x = x * unit + x0;
|
122 |
+
joint.position.y = y * unit + y0;
|
123 |
+
joint.position.z = z + z0;
|
124 |
+
joint.dirty = true; // update limbs in next frame
|
125 |
+
joints.push(joint);
|
126 |
+
}
|
127 |
+
|
128 |
+
for (let i = 0; i < limb_pairs.length; ++i) {
|
129 |
+
const [r, g, b] = joint_colors[i];
|
130 |
+
const color = (r << 16) | (g << 8) | (b << 0);
|
131 |
+
const line = new MeshLine();
|
132 |
+
const mat = new MeshLineMaterial({ color: color, opacity: 0.6, transparent: true });
|
133 |
+
limbs.push(new THREE.Mesh(line, mat));
|
134 |
+
}
|
135 |
+
|
136 |
+
return [joints, limbs];
|
137 |
+
}
|
138 |
+
|
139 |
+
function init_3d(ui) {
|
140 |
+
const
|
141 |
+
container = ui.container,
|
142 |
+
canvas = ui.canvas,
|
143 |
+
notation = ui.notation,
|
144 |
+
indicator1 = ui.indicator1,
|
145 |
+
indicator2 = ui.indicator2,
|
146 |
+
width = () => canvas.width,
|
147 |
+
height = () => canvas.height,
|
148 |
+
unit = () => Math.min(width(), height()),
|
149 |
+
unit_max = () => Math.max(width(), height());
|
150 |
+
|
151 |
+
canvas.addEventListener('contextmenu', e => {
|
152 |
+
e.preventDefault();
|
153 |
+
}, false);
|
154 |
+
|
155 |
+
const scene = new THREE.Scene();
|
156 |
+
const default_bg = () => new THREE.Color(0x000000);
|
157 |
+
scene.background = default_bg();
|
158 |
+
const camera = new THREE.OrthographicCamera(width() / -2, width() / 2, height() / 2, height() / -2, 1, width() * 4);
|
159 |
+
camera.fixed_roll = ui.fixed_roll ? !!ui.fixed_roll.checked : false;
|
160 |
+
camera.position.z = unit_max() * 2;
|
161 |
+
|
162 |
+
const renderer = new THREE.WebGLRenderer({
|
163 |
+
canvas: canvas,
|
164 |
+
antialias: true,
|
165 |
+
alpha: true,
|
166 |
+
preserveDrawingBuffer: true,
|
167 |
+
});
|
168 |
+
renderer.setSize(width(), height());
|
169 |
+
|
170 |
+
let bg_backup = new Map();
|
171 |
+
function set_bg(image_path, dont_dispose) {
|
172 |
+
const old_tex = scene.background;
|
173 |
+
if (dont_dispose === false) {
|
174 |
+
bg_backup.clear();
|
175 |
+
}
|
176 |
+
if (image_path === null) {
|
177 |
+
scene.background = default_bg();
|
178 |
+
if (old_tex && old_tex.dispose && !dont_dispose) old_tex.dispose();
|
179 |
+
return;
|
180 |
+
}
|
181 |
+
if (!(image_path.isTexture || image_path.isColor)) {
|
182 |
+
bg_backup.set('image64', image_path);
|
183 |
+
}
|
184 |
+
const tex = (image_path.isTexture || image_path.isColor) ? image_path : new THREE.TextureLoader().load(image_path);
|
185 |
+
scene.background = tex;
|
186 |
+
if (old_tex && old_tex.dispose && !dont_dispose) old_tex.dispose();
|
187 |
+
}
|
188 |
+
|
189 |
+
const images = new Map();
|
190 |
+
const object_to_img = new Map();
|
191 |
+
|
192 |
+
function set_img(name, image_path , img_width, img_length) {
|
193 |
+
remove_img(name);
|
194 |
+
let geometry = new THREE.PlaneGeometry(img_width, img_length);
|
195 |
+
let plan_texture = new THREE.TextureLoader().load(image_path)
|
196 |
+
let material = new THREE.MeshBasicMaterial({//贴图通过材质添加给几何体
|
197 |
+
map: plan_texture,//给纹理属性map赋值
|
198 |
+
side: THREE.DoubleSide,//两面可见
|
199 |
+
});
|
200 |
+
let rect = new THREE.Mesh(geometry, material);
|
201 |
+
const group_img = new THREE.Group();
|
202 |
+
|
203 |
+
const dispose = () => {
|
204 |
+
scene.remove(group_img);
|
205 |
+
};
|
206 |
+
|
207 |
+
|
208 |
+
const image = {
|
209 |
+
name,
|
210 |
+
group_img,
|
211 |
+
img_width,
|
212 |
+
img_length,
|
213 |
+
rect,
|
214 |
+
dispose,
|
215 |
+
};
|
216 |
+
group_img.add(rect);
|
217 |
+
object_to_img.set(group_img, image);
|
218 |
+
|
219 |
+
images.set(name, image);
|
220 |
+
scene.add(group_img);
|
221 |
+
|
222 |
+
return image;
|
223 |
+
}
|
224 |
+
|
225 |
+
let image_num = 0;
|
226 |
+
if (ui.img) {
|
227 |
+
ui.img.addEventListener('change', e => {
|
228 |
+
const files = ui.img.files;
|
229 |
+
if (files.length != 0) {
|
230 |
+
const file = files[0];
|
231 |
+
const r = new FileReader();
|
232 |
+
r.onload = () => set_img(`img_${image_num}`,r.result,30,30);
|
233 |
+
r.readAsDataURL(file);
|
234 |
+
}
|
235 |
+
ui.img.value = '';
|
236 |
+
}, false);
|
237 |
+
}
|
238 |
+
|
239 |
+
if (ui.reset_img)
|
240 |
+
ui.reset_img.addEventListener('click', () => {
|
241 |
+
if (images.size <= 0) {
|
242 |
+
ui.notify('No image is not allowed.', 'error');
|
243 |
+
return;
|
244 |
+
}
|
245 |
+
remove_img("img_0");
|
246 |
+
}, false);
|
247 |
+
|
248 |
+
const remove_img = name => {
|
249 |
+
if (!images.get(name)) return;
|
250 |
+
images.get(name).dispose();
|
251 |
+
images.delete(name);
|
252 |
+
};
|
253 |
+
|
254 |
+
|
255 |
+
const bodies = new Map();
|
256 |
+
let selected_body = null;
|
257 |
+
let touched_body = null;
|
258 |
+
const touchable_objects = [];
|
259 |
+
const touchable_bodies = [];
|
260 |
+
const object_to_body = new Map();
|
261 |
+
|
262 |
+
function remove(mesh) {
|
263 |
+
if (mesh instanceof Array) {
|
264 |
+
for (let m of mesh) remove(m);
|
265 |
+
} else {
|
266 |
+
mesh.material.dispose();
|
267 |
+
mesh.geometry.dispose();
|
268 |
+
object_to_body.delete(mesh);
|
269 |
+
}
|
270 |
+
};
|
271 |
+
const add_body = (name, x0, y0, z0) => {
|
272 |
+
remove_body(name);
|
273 |
+
const [joints, limbs] = create_body(unit(), x0, y0, z0);
|
274 |
+
const group = new THREE.Group(); // for DragControls
|
275 |
+
|
276 |
+
const dispose = () => {
|
277 |
+
for (let joint of joints) {
|
278 |
+
array_remove(touchable_objects, joint);
|
279 |
+
remove(joint);
|
280 |
+
}
|
281 |
+
for (let limb of limbs) {
|
282 |
+
remove(limb);
|
283 |
+
scene.remove(limb);
|
284 |
+
}
|
285 |
+
array_remove(touchable_bodies, group);
|
286 |
+
scene.remove(group);
|
287 |
+
};
|
288 |
+
|
289 |
+
const reset = (dx, dy, dz) => {
|
290 |
+
if (dx === undefined) dx = x0;
|
291 |
+
if (dy === undefined) dy = y0;
|
292 |
+
if (dz === undefined) dz = z0;
|
293 |
+
for (let i = 0; i < standard_pose.length; ++i) {
|
294 |
+
const [x, y, z] = standard_pose[i];
|
295 |
+
joints[i].position.set(x * unit() + dx, y * unit() + dy, z + dz);
|
296 |
+
joints[i].dirty = true;
|
297 |
+
}
|
298 |
+
group.position.set(0, 0, 0);
|
299 |
+
body.dirty = true;
|
300 |
+
};
|
301 |
+
|
302 |
+
const body = {
|
303 |
+
name,
|
304 |
+
group,
|
305 |
+
joints,
|
306 |
+
limbs,
|
307 |
+
x0, y0, z0,
|
308 |
+
dispose,
|
309 |
+
reset,
|
310 |
+
dirty: true, // update limbs in next frame
|
311 |
+
};
|
312 |
+
|
313 |
+
for (let joint of joints) {
|
314 |
+
touchable_objects.push(joint);
|
315 |
+
object_to_body.set(joint, body);
|
316 |
+
group.add(joint);
|
317 |
+
}
|
318 |
+
for (let limb of limbs) {
|
319 |
+
scene.add(limb);
|
320 |
+
object_to_body.set(limb, body);
|
321 |
+
}
|
322 |
+
object_to_body.set(group, body);
|
323 |
+
|
324 |
+
bodies.set(name, body);
|
325 |
+
scene.add(group);
|
326 |
+
touchable_bodies.push(group);
|
327 |
+
|
328 |
+
return body;
|
329 |
+
};
|
330 |
+
|
331 |
+
const remove_body = name => {
|
332 |
+
if (!bodies.get(name)) return;
|
333 |
+
bodies.get(name).dispose();
|
334 |
+
bodies.delete(name);
|
335 |
+
};
|
336 |
+
|
337 |
+
const get_body_rect = body => {
|
338 |
+
const v = new THREE.Vector3();
|
339 |
+
let xmin = Infinity, xmax = -Infinity, ymin = Infinity, ymax = -Infinity;
|
340 |
+
for (let joint of body.joints) {
|
341 |
+
const wpos = joint.getWorldPosition(v);
|
342 |
+
const spos = wpos.project(camera);
|
343 |
+
if (spos.x < xmin) xmin = spos.x;
|
344 |
+
if (xmax < spos.x) xmax = spos.x;
|
345 |
+
if (spos.y < ymin) ymin = spos.y;
|
346 |
+
if (ymax < spos.y) ymax = spos.y;
|
347 |
+
}
|
348 |
+
return [xmin, ymin, xmax, ymax];
|
349 |
+
};
|
350 |
+
|
351 |
+
// const default_body = add_body('defualt', 0, 0, 0);
|
352 |
+
|
353 |
+
const controls = new TrackballControls(camera, renderer.domElement);
|
354 |
+
const dragger_joint = new DragControls(touchable_objects, camera, renderer.domElement);
|
355 |
+
const dragger_body = new DragControls([], camera, renderer.domElement);
|
356 |
+
dragger_body.transformGroup = true;
|
357 |
+
|
358 |
+
dragger_joint.addEventListener('dragstart', () => { controls.enabled = false; });
|
359 |
+
dragger_joint.addEventListener('dragend', () => { controls.enabled = true; });
|
360 |
+
dragger_joint.addEventListener('drag', e => {
|
361 |
+
e.object.dirty = true;
|
362 |
+
object_to_body.get(e.object).dirty = true;
|
363 |
+
});
|
364 |
+
|
365 |
+
dragger_body.addEventListener('dragstart', () => { controls.enabled = false; });
|
366 |
+
dragger_body.addEventListener('dragend', () => { controls.enabled = true; });
|
367 |
+
dragger_body.addEventListener('drag', e => {
|
368 |
+
const body = object_to_body.get(e.object);
|
369 |
+
body.dirty = true;
|
370 |
+
for (let i = 0; i < body.joints.length; ++i) {
|
371 |
+
body.joints[i].dirty = true;
|
372 |
+
}
|
373 |
+
});
|
374 |
+
|
375 |
+
renderer.domElement.addEventListener('pointerdown', e => {
|
376 |
+
dragger_joint.enabled = e.button === 0;
|
377 |
+
dragger_body.enabled = e.button === 2;
|
378 |
+
}, true);
|
379 |
+
|
380 |
+
const rc = new THREE.Raycaster();
|
381 |
+
const m = new THREE.Vector2();
|
382 |
+
renderer.domElement.addEventListener('pointermove', e => {
|
383 |
+
e.preventDefault();
|
384 |
+
m.x = (e.offsetX / width()) * 2 - 1;
|
385 |
+
m.y = (1 - e.offsetY / height()) * 2 - 1;
|
386 |
+
rc.setFromCamera(m, camera);
|
387 |
+
const touched = rc.intersectObjects(touchable_objects);
|
388 |
+
|
389 |
+
// show label
|
390 |
+
if (touched.length != 0) {
|
391 |
+
const [dx, dy] = get_relative_offset(renderer.domElement, container);
|
392 |
+
notation.textContent = touched[0].object.name;
|
393 |
+
notation.style.left = `${e.offsetX + dx}px`;
|
394 |
+
notation.style.top = `${e.offsetY + dy - 32}px`;
|
395 |
+
notation.style.display = 'block';
|
396 |
+
} else {
|
397 |
+
notation.textContent = '';
|
398 |
+
notation.style.display = 'none';
|
399 |
+
}
|
400 |
+
|
401 |
+
// show temporary selection
|
402 |
+
if (touched.length != 0) {
|
403 |
+
touched_body = object_to_body.get(touched[0].object);
|
404 |
+
} else {
|
405 |
+
touched_body = null;
|
406 |
+
}
|
407 |
+
}, false);
|
408 |
+
|
409 |
+
renderer.domElement.addEventListener('pointerdown', e => {
|
410 |
+
e.preventDefault();
|
411 |
+
m.x = (e.offsetX / width()) * 2 - 1;
|
412 |
+
m.y = (1 - e.offsetY / height()) * 2 - 1;
|
413 |
+
rc.setFromCamera(m, camera);
|
414 |
+
const touched = rc.intersectObjects(touchable_objects);
|
415 |
+
|
416 |
+
// show selection
|
417 |
+
if (touched.length != 0) {
|
418 |
+
selected_body = object_to_body.get(touched[0].object);
|
419 |
+
const objs = dragger_body.getObjects();
|
420 |
+
objs.length = 0;
|
421 |
+
objs.push(selected_body.group);
|
422 |
+
dragger_body.onPointerDown(e);
|
423 |
+
} else {
|
424 |
+
selected_body = null;
|
425 |
+
dragger_body.getObjects().length = 0;
|
426 |
+
}
|
427 |
+
}, false);
|
428 |
+
|
429 |
+
if (ui.all_reset)
|
430 |
+
ui.all_reset.addEventListener('click', () => {
|
431 |
+
touched_body = null;
|
432 |
+
selected_body = null;
|
433 |
+
camera.position.set(0, 0, unit_max() * 2);
|
434 |
+
camera.rotation.set(0, 0, 0);
|
435 |
+
controls.reset();
|
436 |
+
for (let name of Array.from(bodies.keys()).slice(1)) {
|
437 |
+
remove_body(name);
|
438 |
+
}
|
439 |
+
for (let body of bodies.values()) {
|
440 |
+
body.reset(0, 0, 0);
|
441 |
+
}
|
442 |
+
}, false);
|
443 |
+
|
444 |
+
if (ui.reset_camera)
|
445 |
+
ui.reset_camera.addEventListener('click', () => {
|
446 |
+
camera.position.set(0, 0, unit_max() * 2);
|
447 |
+
camera.rotation.set(0, 0, 0);
|
448 |
+
controls.reset();
|
449 |
+
}, false);
|
450 |
+
|
451 |
+
if (ui.reset_pose)
|
452 |
+
ui.reset_pose.addEventListener('click', () => {
|
453 |
+
if (selected_body) {
|
454 |
+
selected_body.reset();
|
455 |
+
} else {
|
456 |
+
for (let [name, body] of bodies) {
|
457 |
+
body.reset();
|
458 |
+
}
|
459 |
+
}
|
460 |
+
}, false);
|
461 |
+
|
462 |
+
if (ui.fixed_roll)
|
463 |
+
ui.fixed_roll.addEventListener('change', () => {
|
464 |
+
camera.fixed_roll = !!ui.fixed_roll.checked;
|
465 |
+
}, false);
|
466 |
+
|
467 |
+
let body_num = 1;
|
468 |
+
if (ui.add_body)
|
469 |
+
ui.add_body.addEventListener('click', () => {
|
470 |
+
if (bodies.size < 1) {
|
471 |
+
add_body('defualt', 0, 0, 0);
|
472 |
+
} else {
|
473 |
+
const last_body = selected_body ?? Array.from(bodies.values()).at(-1);
|
474 |
+
const base = last_body.joints[0].getWorldPosition(new THREE.Vector3());
|
475 |
+
const
|
476 |
+
dx = base.x - standard_pose[0][0] * unit(),
|
477 |
+
dy = base.y - standard_pose[0][1] * unit(),
|
478 |
+
dz = base.z - standard_pose[0][2];
|
479 |
+
add_body(`body_${body_num++}`, dx + 32, dy, dz);
|
480 |
+
}
|
481 |
+
}, false);
|
482 |
+
|
483 |
+
if (ui.remove_body)
|
484 |
+
ui.remove_body.addEventListener('click', () => {
|
485 |
+
if (!selected_body) {
|
486 |
+
ui.notify('No body is selected.', 'error');
|
487 |
+
return;
|
488 |
+
}
|
489 |
+
if (bodies.size <= 0) {
|
490 |
+
ui.notify('No body is not allowed.', 'error');
|
491 |
+
return;
|
492 |
+
}
|
493 |
+
remove_body(selected_body.name);
|
494 |
+
touched_body = null;
|
495 |
+
selected_body = null;
|
496 |
+
}, false);
|
497 |
+
|
498 |
+
const get_client_boundary = body => {
|
499 |
+
let [xmin, ymin, xmax, ymax] = get_body_rect(body);
|
500 |
+
|
501 |
+
// [-1,1] -> [0,width]
|
502 |
+
xmin = (xmin + 1) * width() / 2;
|
503 |
+
xmax = (xmax + 1) * width() / 2;
|
504 |
+
ymin = height() - (ymin + 1) * height() / 2;
|
505 |
+
ymax = height() - (ymax + 1) * height() / 2;
|
506 |
+
[ymin, ymax] = [ymax, ymin];
|
507 |
+
|
508 |
+
// add margin
|
509 |
+
xmin = xmin - 5 + renderer.domElement.offsetLeft;
|
510 |
+
xmax = xmax + 5 + renderer.domElement.offsetLeft;
|
511 |
+
ymin = ymin - 5 + renderer.domElement.offsetTop;
|
512 |
+
ymax = ymax + 5 + renderer.domElement.offsetTop;
|
513 |
+
|
514 |
+
return [xmin, ymin, xmax, ymax];
|
515 |
+
}
|
516 |
+
|
517 |
+
const size_change = (w, h) => {
|
518 |
+
if (w < 64 || h < 64) return;
|
519 |
+
canvas.width = w;
|
520 |
+
canvas.height = h;
|
521 |
+
renderer.setSize(w, h);
|
522 |
+
// update camera
|
523 |
+
camera.left = w / -2;
|
524 |
+
camera.right = w / 2;
|
525 |
+
camera.top = h / 2;
|
526 |
+
camera.bottom = h / -2;
|
527 |
+
camera.near = 1;
|
528 |
+
camera.far = w * 4;
|
529 |
+
camera.position.z = unit_max() * 2;
|
530 |
+
camera.updateProjectionMatrix();
|
531 |
+
controls.handleResize();
|
532 |
+
};
|
533 |
+
|
534 |
+
const width_input = ui.canvas_width, height_input = ui.canvas_height;
|
535 |
+
if (width_input && height_input) {
|
536 |
+
width_input.addEventListener('change', () => {
|
537 |
+
const w = +width_input.value;
|
538 |
+
const h = +height_input.value;
|
539 |
+
size_change(w, h);
|
540 |
+
}, false);
|
541 |
+
height_input.addEventListener('change', () => {
|
542 |
+
const w = +width_input.value;
|
543 |
+
const h = +height_input.value;
|
544 |
+
size_change(w, h);
|
545 |
+
}, false);
|
546 |
+
}
|
547 |
+
|
548 |
+
if (ui.bg)
|
549 |
+
ui.bg.addEventListener('change', e => {
|
550 |
+
const files = ui.bg.files;
|
551 |
+
if (files.length != 0) {
|
552 |
+
const file = files[0];
|
553 |
+
const r = new FileReader();
|
554 |
+
r.onload = () => set_bg(r.result);
|
555 |
+
r.readAsDataURL(file);
|
556 |
+
}
|
557 |
+
ui.bg.value = '';
|
558 |
+
}, false);
|
559 |
+
|
560 |
+
if (ui.reset_bg)
|
561 |
+
ui.reset_bg.addEventListener('click', () => set_bg(null), false);
|
562 |
+
|
563 |
+
function get_pose_dict(obj3d) {
|
564 |
+
return {
|
565 |
+
position: obj3d.position.toArray(),
|
566 |
+
rotation: obj3d.rotation.toArray(),
|
567 |
+
scale: obj3d.scale.toArray(),
|
568 |
+
up: obj3d.up.toArray(),
|
569 |
+
};
|
570 |
+
}
|
571 |
+
|
572 |
+
function set_pose_dict(obj3d, dict) {
|
573 |
+
obj3d.position.set(...dict.position);
|
574 |
+
obj3d.rotation.set(...dict.rotation);
|
575 |
+
obj3d.scale.set(...dict.scale);
|
576 |
+
obj3d.up.set(...dict.up);
|
577 |
+
}
|
578 |
+
|
579 |
+
if (ui.save_pose && ui.save_pose_callback)
|
580 |
+
ui.save_pose.addEventListener('click', async () => {
|
581 |
+
const name = prompt('Input pose name.');
|
582 |
+
if (name === undefined || name === null || name === '') return;
|
583 |
+
|
584 |
+
const screen = {
|
585 |
+
width: width(),
|
586 |
+
height: height(),
|
587 |
+
}
|
588 |
+
|
589 |
+
const camera_ = get_pose_dict(camera);
|
590 |
+
camera_.zoom = camera.zoom;
|
591 |
+
|
592 |
+
const joints = [];
|
593 |
+
for (let [name, body] of bodies) {
|
594 |
+
joints.push({
|
595 |
+
name,
|
596 |
+
joints: body.joints.map(j => get_pose_dict(j)),
|
597 |
+
group: get_pose_dict(body.group),
|
598 |
+
x0: body.x0,
|
599 |
+
y0: body.y0,
|
600 |
+
z0: body.z0,
|
601 |
+
});
|
602 |
+
}
|
603 |
+
|
604 |
+
const image = await ui.getDataURL();
|
605 |
+
|
606 |
+
const data = { name, image, screen, camera: camera_, joints };
|
607 |
+
const result = await ui.save_pose_callback(data);
|
608 |
+
ui.notify(result.result, result.ok ? 'success' : 'error');
|
609 |
+
}, false);
|
610 |
+
|
611 |
+
|
612 |
+
if (ui.get_imgs_callback()) {
|
613 |
+
gradioApp().querySelector(`#posex-t2i-generate`).addEventListener('click', async () => {
|
614 |
+
//搜集参数
|
615 |
+
const bgImg = bg_backup.get("image64") === "" ? "" : bg_backup.get("image64");
|
616 |
+
console.log(`bgImgsize:${bgImg.length}`);
|
617 |
+
const maskImg = await ui.getDataURL();
|
618 |
+
console.log(`maskImg:${maskImg.length}`);
|
619 |
+
const data = { bgImg, maskImg };
|
620 |
+
const result = await ui.get_imgs_callback(data);
|
621 |
+
ui.notify(result.result, result.ok ? 'success' : 'error');
|
622 |
+
}, false)
|
623 |
+
// ui.get_imgs.addEventListener('click', async () => {
|
624 |
+
// //搜集参数
|
625 |
+
// const bgImg = bg_backup.get("image64") === "" ? "" : bg_backup.get("image64");
|
626 |
+
// console.log(`bgImgsize:${bgImg.length}`);
|
627 |
+
// const maskImg = await ui.getDataURL();
|
628 |
+
// console.log(`maskImg:${maskImg.length}`);
|
629 |
+
// const data = { bgImg, maskImg };
|
630 |
+
// const result = await ui.get_imgs_callback(data);
|
631 |
+
// ui.notify(result.result, result.ok ? 'success' : 'error');
|
632 |
+
// }, false)
|
633 |
+
}
|
634 |
+
|
635 |
+
const onAnimateEndOneshot = [];
|
636 |
+
|
637 |
+
// joint and limb update
|
638 |
+
let elliptic_limbs = ui.elliptic_limbs ? !!ui.elliptic_limbs.checked : true;
|
639 |
+
//let joint_size_m = ui.joint_radius ? +ui.joint_radius.value / JOINT_RADIUS : 1.0;
|
640 |
+
let limb_size_m = ui.limb_width ? +ui.limb_width.value / LIMB_SIZE : 1.0;
|
641 |
+
if (ui.elliptic_limbs)
|
642 |
+
ui.elliptic_limbs.addEventListener('change', () => {
|
643 |
+
const b = !!ui.elliptic_limbs.checked;
|
644 |
+
if (elliptic_limbs !== b) {
|
645 |
+
elliptic_limbs = b;
|
646 |
+
for (let body of bodies.values()) {
|
647 |
+
body.dirty = true;
|
648 |
+
for (let i = 0; i < body.joints.length; ++i) {
|
649 |
+
body.joints[i].dirty = true;
|
650 |
+
}
|
651 |
+
}
|
652 |
+
}
|
653 |
+
}, false);
|
654 |
+
|
655 |
+
//if (ui.joint_radius)
|
656 |
+
// ui.joint_radius.addEventListener('input', () => {
|
657 |
+
// const new_val = +ui.joint_radius.value / JOINT_RADIUS;
|
658 |
+
// if (joint_size_m !== new_val) {
|
659 |
+
// joint_size_m = new_val;
|
660 |
+
// for (let body of bodies.values()) {
|
661 |
+
// body.dirty = true;
|
662 |
+
// for (let i = 0; i < body.joints.length; ++i) {
|
663 |
+
// body.joints[i].dirty = true;
|
664 |
+
// }
|
665 |
+
// }
|
666 |
+
// }
|
667 |
+
// }, false);
|
668 |
+
|
669 |
+
if (ui.limb_width)
|
670 |
+
ui.limb_width.addEventListener('input', () => {
|
671 |
+
const new_val = +ui.limb_width.value / LIMB_SIZE;
|
672 |
+
if (limb_size_m !== new_val) {
|
673 |
+
limb_size_m = new_val;
|
674 |
+
for (let body of bodies.values()) {
|
675 |
+
body.dirty = true;
|
676 |
+
for (let i = 0; i < body.joints.length; ++i) {
|
677 |
+
body.joints[i].dirty = true;
|
678 |
+
}
|
679 |
+
}
|
680 |
+
}
|
681 |
+
}, false);
|
682 |
+
|
683 |
+
const limb_vecs = Array.from(Array(LIMB_N)).map(x => new THREE.Vector3());
|
684 |
+
function elliptic_limb_width(p) {
|
685 |
+
// draw limb ellipse
|
686 |
+
// x^2 / a^2 + y^2 / b^2 = 1
|
687 |
+
// a := half of distance between two joints
|
688 |
+
// b := 2 * LIMB_SIZE / camera.zoom
|
689 |
+
// {a(2p-1)}^2 / a^2 + y^2 / b^2 = 1
|
690 |
+
// y^2 = b^2 { 1 - (2p-1)^2 }
|
691 |
+
const b = 2 * LIMB_SIZE * limb_size_m / camera.zoom;
|
692 |
+
const pp = 2 * p - 1;
|
693 |
+
return b * Math.sqrt(1 - pp * pp);
|
694 |
+
}
|
695 |
+
function stick_limb_width(p) {
|
696 |
+
// half width of ellipse
|
697 |
+
return LIMB_SIZE * limb_size_m / camera.zoom;
|
698 |
+
}
|
699 |
+
function create_limb(mesh, from, to) {
|
700 |
+
const s0 = limb_vecs[0];
|
701 |
+
const s1 = limb_vecs[LIMB_N - 1];
|
702 |
+
from.getWorldPosition(s0);
|
703 |
+
to.getWorldPosition(s1);
|
704 |
+
const N = LIMB_N - 1;
|
705 |
+
for (let i = 1; i < limb_vecs.length - 1; ++i) {
|
706 |
+
limb_vecs[i].lerpVectors(s0, s1, i / N);
|
707 |
+
}
|
708 |
+
mesh.geometry.setPoints(limb_vecs, elliptic_limbs ? elliptic_limb_width : stick_limb_width);
|
709 |
+
}
|
710 |
+
|
711 |
+
let low_fps = ui.low_fps ? !!ui.low_fps.checked : false;
|
712 |
+
if (ui.low_fps)
|
713 |
+
ui.low_fps.addEventListener('change', () => {
|
714 |
+
low_fps = !!ui.low_fps.checked;
|
715 |
+
}, false);
|
716 |
+
|
717 |
+
let last_zoom = camera.zoom;
|
718 |
+
let running = true;
|
719 |
+
//const frames = [0,0,0,0,0,0,0,0,0,0], frame_index = 0;
|
720 |
+
let last_tick = globalThis.performance.now();
|
721 |
+
const animate = () => {
|
722 |
+
const t0 = globalThis.performance.now();
|
723 |
+
//frames[(frame_index++)%frames.length] = t0 - last_tick;
|
724 |
+
//last_tick = t0;
|
725 |
+
//console.log(frames.reduce((acc, cur) => acc + cur) / frames.length);
|
726 |
+
|
727 |
+
requestAnimationFrame(animate);
|
728 |
+
if (!running) return;
|
729 |
+
|
730 |
+
if (controls.enabled) {
|
731 |
+
if (controls.screen.width === 0 && controls.screen.height === 0) {
|
732 |
+
controls.handleResize();
|
733 |
+
}
|
734 |
+
}
|
735 |
+
controls.update();
|
736 |
+
|
737 |
+
if (low_fps && t0 - last_tick < 30) return; // nearly 30fps
|
738 |
+
last_tick = t0;
|
739 |
+
|
740 |
+
for (let [name, body] of bodies) {
|
741 |
+
const { joints, limbs, group } = body;
|
742 |
+
|
743 |
+
// update joint size
|
744 |
+
for (let joint of joints) {
|
745 |
+
joint.scale.setScalar(1 / camera.zoom);
|
746 |
+
}
|
747 |
+
|
748 |
+
// show limbs
|
749 |
+
const zoom_changed = last_zoom !== camera.zoom;
|
750 |
+
if (body.dirty || zoom_changed) {
|
751 |
+
for (let i = 0; i < limb_pairs.length; ++i) {
|
752 |
+
const [from_index, to_index] = limb_pairs[i];
|
753 |
+
const [from, to] = [joints[from_index], joints[to_index]];
|
754 |
+
if (from.dirty || to.dirty || zoom_changed) {
|
755 |
+
create_limb(limbs[i], from, to);
|
756 |
+
}
|
757 |
+
}
|
758 |
+
|
759 |
+
for (let i = 0; i < joints.length; ++i) {
|
760 |
+
joints[i].dirty = false;
|
761 |
+
}
|
762 |
+
body.dirty = false;
|
763 |
+
}
|
764 |
+
}
|
765 |
+
|
766 |
+
last_zoom = camera.zoom;
|
767 |
+
|
768 |
+
// show selection
|
769 |
+
if (touched_body) {
|
770 |
+
let [xmin, ymin, xmax, ymax] = get_client_boundary(touched_body);
|
771 |
+
const st = indicator2.style;
|
772 |
+
st.display = 'block';
|
773 |
+
st.left = `${xmin}px`;
|
774 |
+
st.top = `${ymin}px`;
|
775 |
+
st.width = `${xmax - xmin}px`;
|
776 |
+
st.height = `${ymax - ymin}px`;
|
777 |
+
} else {
|
778 |
+
indicator2.style.display = 'none';
|
779 |
+
}
|
780 |
+
|
781 |
+
if (selected_body) {
|
782 |
+
let [xmin, ymin, xmax, ymax] = get_client_boundary(selected_body);
|
783 |
+
const st = indicator1.style;
|
784 |
+
st.display = 'block';
|
785 |
+
st.left = `${xmin}px`;
|
786 |
+
st.top = `${ymin}px`;
|
787 |
+
st.width = `${xmax - xmin}px`;
|
788 |
+
st.height = `${ymax - ymin}px`;
|
789 |
+
} else {
|
790 |
+
indicator1.style.display = 'none';
|
791 |
+
}
|
792 |
+
|
793 |
+
if (camera.fixed_roll) camera.up.set(0, 1, 0);
|
794 |
+
renderer.render(scene, camera);
|
795 |
+
|
796 |
+
for (let fn of onAnimateEndOneshot) {
|
797 |
+
fn();
|
798 |
+
}
|
799 |
+
onAnimateEndOneshot.length = 0;
|
800 |
+
};
|
801 |
+
|
802 |
+
ui.loadPose = function (data) {
|
803 |
+
selected_body = null;
|
804 |
+
touched_body = null;
|
805 |
+
touchable_objects.length = 0;
|
806 |
+
touchable_bodies.length = 0;
|
807 |
+
object_to_body.clear();
|
808 |
+
for (let name of bodies.keys()) {
|
809 |
+
remove_body(name);
|
810 |
+
}
|
811 |
+
|
812 |
+
// screen
|
813 |
+
size_change(data.screen.width, data.screen.height);
|
814 |
+
if (width_input) width_input.value = data.screen.width;
|
815 |
+
if (height_input) height_input.value = data.screen.height;
|
816 |
+
|
817 |
+
// camera
|
818 |
+
set_pose_dict(camera, data.camera);
|
819 |
+
camera.zoom = data.camera.zoom;
|
820 |
+
camera.updateProjectionMatrix();
|
821 |
+
|
822 |
+
// bodies
|
823 |
+
|
824 |
+
// update `body_num`
|
825 |
+
const body_names = data.joints.map(x => {
|
826 |
+
const m = /^body_(\d+)$/.exec(x.name);
|
827 |
+
return m ? +m[1] : -1;
|
828 |
+
}).filter(x => 0 <= x);
|
829 |
+
if (body_names.length == 0) {
|
830 |
+
body_num = 0;
|
831 |
+
} else {
|
832 |
+
body_num = Math.max(...body_names) + 1;
|
833 |
+
}
|
834 |
+
|
835 |
+
for (let dict of data.joints) {
|
836 |
+
const body = add_body(dict.name, dict.x0, dict.y0, dict.z0);
|
837 |
+
for (let i = 0, e = Math.min(body.joints.length, dict.joints.length); i < e; ++i) {
|
838 |
+
set_pose_dict(body.joints[i], dict.joints[i]);
|
839 |
+
}
|
840 |
+
set_pose_dict(body.group, dict.group);
|
841 |
+
}
|
842 |
+
};
|
843 |
+
|
844 |
+
ui.getDataURL = async function () {
|
845 |
+
const pr = new Promise(resolve => {
|
846 |
+
const current_bg = scene.background;
|
847 |
+
set_bg(null, true);
|
848 |
+
onAnimateEndOneshot.push(() => {
|
849 |
+
resolve(renderer.domElement.toDataURL('image/png'));
|
850 |
+
set_bg(current_bg);
|
851 |
+
});
|
852 |
+
});
|
853 |
+
return await pr;
|
854 |
+
};
|
855 |
+
|
856 |
+
ui.getBlob = async function () {
|
857 |
+
const pr = new Promise(resolve => {
|
858 |
+
const current_bg = scene.background;
|
859 |
+
set_bg(null, true);
|
860 |
+
onAnimateEndOneshot.push(() => {
|
861 |
+
renderer.domElement.toBlob(blob => {
|
862 |
+
resolve(blob);
|
863 |
+
set_bg(current_bg);
|
864 |
+
});
|
865 |
+
});
|
866 |
+
});
|
867 |
+
return await pr;
|
868 |
+
};
|
869 |
+
|
870 |
+
ui.stop = function () {
|
871 |
+
running = false;
|
872 |
+
dragger_joint.deactivate();
|
873 |
+
dragger_joint.enabled = false;
|
874 |
+
dragger_body.deactivate();
|
875 |
+
dragger_body.enabled = false;
|
876 |
+
controls.enabled = false;
|
877 |
+
};
|
878 |
+
|
879 |
+
ui.play = function () {
|
880 |
+
running = true;
|
881 |
+
dragger_joint.activate();
|
882 |
+
dragger_joint.enabled = true;
|
883 |
+
dragger_body.activate();
|
884 |
+
dragger_body.enabled = true;
|
885 |
+
controls.enabled = true;
|
886 |
+
controls.handleResize();
|
887 |
+
};
|
888 |
+
|
889 |
+
return animate;
|
890 |
+
}
|
891 |
+
|
892 |
+
function init(ui) {
|
893 |
+
if (ui.save)
|
894 |
+
ui.save.addEventListener('click', async () => {
|
895 |
+
const a = document.createElement('a');
|
896 |
+
if (ui.getDataURL) {
|
897 |
+
a.href = await ui.getDataURL('image/png');
|
898 |
+
} else {
|
899 |
+
a.href = ui.canvas.toDataURL('image/png');
|
900 |
+
}
|
901 |
+
a.download = 'download.png';
|
902 |
+
a.click();
|
903 |
+
ui.notify('save success');
|
904 |
+
}, false);
|
905 |
+
|
906 |
+
if (ui.copy)
|
907 |
+
ui.copy.addEventListener('click', async () => {
|
908 |
+
if (globalThis.ClipboardItem === undefined) {
|
909 |
+
alert('`ClipboardItem` is not defined. If you are in Firefox, change about:config -> dom.events.asyncClipboard.clipboardItem to `true`.')
|
910 |
+
return;
|
911 |
+
}
|
912 |
+
|
913 |
+
async function get_blob() {
|
914 |
+
if (ui.getBlob) {
|
915 |
+
return await ui.getBlob();
|
916 |
+
} else {
|
917 |
+
return await new Promise(resolve => ui.canvas.toBlob(blob => resolve(blob)));
|
918 |
+
}
|
919 |
+
}
|
920 |
+
try {
|
921 |
+
const blob = await get_blob();
|
922 |
+
const data = new ClipboardItem({ [blob.type]: blob });
|
923 |
+
navigator.clipboard.write([data]);
|
924 |
+
ui.notify('copy success');
|
925 |
+
} catch (e) {
|
926 |
+
ui.notify(`failed to copy data: ${e.message}`, 'error');
|
927 |
+
}
|
928 |
+
}, false);
|
929 |
+
}
|
930 |
+
|
931 |
+
function array_remove(array, item) {
|
932 |
+
let index = array.indexOf(item);
|
933 |
+
while (0 <= index) {
|
934 |
+
array.splice(index, 1);
|
935 |
+
index = array.indexOf(item);
|
936 |
+
}
|
937 |
+
}
|
938 |
+
|
939 |
+
function get_relative_offset(target, origin) {
|
940 |
+
const r0 = origin.getBoundingClientRect();
|
941 |
+
const r1 = target.getBoundingClientRect();
|
942 |
+
return [r1.left - r0.left, r1.top - r0.top];
|
943 |
+
}
|
944 |
+
|
945 |
+
export { init, init_3d };
|
js/three.module.js
ADDED
The diff for this file is too large to render.
See raw diff
|
|
person.png
ADDED
Git LFS Details
|
person_control.mp4
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:8014b6a3f11441bc6c203ad6ff602d70c6b8c446d890de77e620f2339c378818
|
3 |
+
size 2792964
|
pipeline_stable_diffusion_controlnet_inpaint.py
ADDED
@@ -0,0 +1,521 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright 2023 The HuggingFace Team. All rights reserved.
|
2 |
+
#
|
3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4 |
+
# you may not use this file except in compliance with the License.
|
5 |
+
# You may obtain a copy of the License at
|
6 |
+
#
|
7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8 |
+
#
|
9 |
+
# Unless required by applicable law or agreed to in writing, software
|
10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12 |
+
# See the License for the specific language governing permissions and
|
13 |
+
# limitations under the License.
|
14 |
+
|
15 |
+
import torch
|
16 |
+
import PIL.Image
|
17 |
+
import numpy as np
|
18 |
+
|
19 |
+
from diffusers.pipelines.stable_diffusion.pipeline_stable_diffusion_controlnet import *
|
20 |
+
|
21 |
+
EXAMPLE_DOC_STRING = """
|
22 |
+
Examples:
|
23 |
+
```py
|
24 |
+
>>> # !pip install opencv-python transformers accelerate
|
25 |
+
>>> from diffusers import StableDiffusionControlNetInpaintPipeline, ControlNetModel, UniPCMultistepScheduler
|
26 |
+
>>> from diffusers.utils import load_image
|
27 |
+
>>> import numpy as np
|
28 |
+
>>> import torch
|
29 |
+
|
30 |
+
>>> import cv2
|
31 |
+
>>> from PIL import Image
|
32 |
+
>>> # download an image
|
33 |
+
>>> image = load_image(
|
34 |
+
... "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo.png"
|
35 |
+
... )
|
36 |
+
>>> image = np.array(image)
|
37 |
+
>>> mask_image = load_image(
|
38 |
+
... "https://raw.githubusercontent.com/CompVis/latent-diffusion/main/data/inpainting_examples/overture-creations-5sI6fQgYIuo_mask.png"
|
39 |
+
... )
|
40 |
+
>>> mask_image = np.array(mask_image)
|
41 |
+
>>> # get canny image
|
42 |
+
>>> canny_image = cv2.Canny(image, 100, 200)
|
43 |
+
>>> canny_image = canny_image[:, :, None]
|
44 |
+
>>> canny_image = np.concatenate([canny_image, canny_image, canny_image], axis=2)
|
45 |
+
>>> canny_image = Image.fromarray(canny_image)
|
46 |
+
|
47 |
+
>>> # load control net and stable diffusion v1-5
|
48 |
+
>>> controlnet = ControlNetModel.from_pretrained("lllyasviel/sd-controlnet-canny", torch_dtype=torch.float16)
|
49 |
+
>>> pipe = StableDiffusionControlNetInpaintPipeline.from_pretrained(
|
50 |
+
... "runwayml/stable-diffusion-inpainting", controlnet=controlnet, torch_dtype=torch.float16
|
51 |
+
... )
|
52 |
+
|
53 |
+
>>> # speed up diffusion process with faster scheduler and memory optimization
|
54 |
+
>>> pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config)
|
55 |
+
>>> # remove following line if xformers is not installed
|
56 |
+
>>> pipe.enable_xformers_memory_efficient_attention()
|
57 |
+
|
58 |
+
>>> pipe.enable_model_cpu_offload()
|
59 |
+
|
60 |
+
>>> # generate image
|
61 |
+
>>> generator = torch.manual_seed(0)
|
62 |
+
>>> image = pipe(
|
63 |
+
... "futuristic-looking doggo",
|
64 |
+
... num_inference_steps=20,
|
65 |
+
... generator=generator,
|
66 |
+
... image=image,
|
67 |
+
... control_image=canny_image,
|
68 |
+
... mask_image=mask_image
|
69 |
+
... ).images[0]
|
70 |
+
```
|
71 |
+
"""
|
72 |
+
|
73 |
+
|
74 |
+
def prepare_mask_and_masked_image(image, mask):
|
75 |
+
"""
|
76 |
+
Prepares a pair (image, mask) to be consumed by the Stable Diffusion pipeline. This means that those inputs will be
|
77 |
+
converted to ``torch.Tensor`` with shapes ``batch x channels x height x width`` where ``channels`` is ``3`` for the
|
78 |
+
``image`` and ``1`` for the ``mask``.
|
79 |
+
The ``image`` will be converted to ``torch.float32`` and normalized to be in ``[-1, 1]``. The ``mask`` will be
|
80 |
+
binarized (``mask > 0.5``) and cast to ``torch.float32`` too.
|
81 |
+
Args:
|
82 |
+
image (Union[np.array, PIL.Image, torch.Tensor]): The image to inpaint.
|
83 |
+
It can be a ``PIL.Image``, or a ``height x width x 3`` ``np.array`` or a ``channels x height x width``
|
84 |
+
``torch.Tensor`` or a ``batch x channels x height x width`` ``torch.Tensor``.
|
85 |
+
mask (_type_): The mask to apply to the image, i.e. regions to inpaint.
|
86 |
+
It can be a ``PIL.Image``, or a ``height x width`` ``np.array`` or a ``1 x height x width``
|
87 |
+
``torch.Tensor`` or a ``batch x 1 x height x width`` ``torch.Tensor``.
|
88 |
+
Raises:
|
89 |
+
ValueError: ``torch.Tensor`` images should be in the ``[-1, 1]`` range. ValueError: ``torch.Tensor`` mask
|
90 |
+
should be in the ``[0, 1]`` range. ValueError: ``mask`` and ``image`` should have the same spatial dimensions.
|
91 |
+
TypeError: ``mask`` is a ``torch.Tensor`` but ``image`` is not
|
92 |
+
(ot the other way around).
|
93 |
+
Returns:
|
94 |
+
tuple[torch.Tensor]: The pair (mask, masked_image) as ``torch.Tensor`` with 4
|
95 |
+
dimensions: ``batch x channels x height x width``.
|
96 |
+
"""
|
97 |
+
if isinstance(image, torch.Tensor):
|
98 |
+
if not isinstance(mask, torch.Tensor):
|
99 |
+
raise TypeError(f"`image` is a torch.Tensor but `mask` (type: {type(mask)} is not")
|
100 |
+
|
101 |
+
# Batch single image
|
102 |
+
if image.ndim == 3:
|
103 |
+
assert image.shape[0] == 3, "Image outside a batch should be of shape (3, H, W)"
|
104 |
+
image = image.unsqueeze(0)
|
105 |
+
|
106 |
+
# Batch and add channel dim for single mask
|
107 |
+
if mask.ndim == 2:
|
108 |
+
mask = mask.unsqueeze(0).unsqueeze(0)
|
109 |
+
|
110 |
+
# Batch single mask or add channel dim
|
111 |
+
if mask.ndim == 3:
|
112 |
+
# Single batched mask, no channel dim or single mask not batched but channel dim
|
113 |
+
if mask.shape[0] == 1:
|
114 |
+
mask = mask.unsqueeze(0)
|
115 |
+
|
116 |
+
# Batched masks no channel dim
|
117 |
+
else:
|
118 |
+
mask = mask.unsqueeze(1)
|
119 |
+
|
120 |
+
assert image.ndim == 4 and mask.ndim == 4, "Image and Mask must have 4 dimensions"
|
121 |
+
assert image.shape[-2:] == mask.shape[-2:], "Image and Mask must have the same spatial dimensions"
|
122 |
+
assert image.shape[0] == mask.shape[0], "Image and Mask must have the same batch size"
|
123 |
+
|
124 |
+
# Check image is in [-1, 1]
|
125 |
+
if image.min() < -1 or image.max() > 1:
|
126 |
+
raise ValueError("Image should be in [-1, 1] range")
|
127 |
+
|
128 |
+
# Check mask is in [0, 1]
|
129 |
+
if mask.min() < 0 or mask.max() > 1:
|
130 |
+
raise ValueError("Mask should be in [0, 1] range")
|
131 |
+
|
132 |
+
# Binarize mask
|
133 |
+
mask[mask < 0.5] = 0
|
134 |
+
mask[mask >= 0.5] = 1
|
135 |
+
|
136 |
+
# Image as float32
|
137 |
+
image = image.to(dtype=torch.float32)
|
138 |
+
elif isinstance(mask, torch.Tensor):
|
139 |
+
raise TypeError(f"`mask` is a torch.Tensor but `image` (type: {type(image)} is not")
|
140 |
+
else:
|
141 |
+
# preprocess image
|
142 |
+
if isinstance(image, (PIL.Image.Image, np.ndarray)):
|
143 |
+
image = [image]
|
144 |
+
|
145 |
+
if isinstance(image, list) and isinstance(image[0], PIL.Image.Image):
|
146 |
+
image = [np.array(i.convert("RGB"))[None, :] for i in image]
|
147 |
+
image = np.concatenate(image, axis=0)
|
148 |
+
elif isinstance(image, list) and isinstance(image[0], np.ndarray):
|
149 |
+
image = np.concatenate([i[None, :] for i in image], axis=0)
|
150 |
+
|
151 |
+
image = image.transpose(0, 3, 1, 2)
|
152 |
+
image = torch.from_numpy(image).to(dtype=torch.float32) / 127.5 - 1.0
|
153 |
+
|
154 |
+
# preprocess mask
|
155 |
+
if isinstance(mask, (PIL.Image.Image, np.ndarray)):
|
156 |
+
mask = [mask]
|
157 |
+
|
158 |
+
if isinstance(mask, list) and isinstance(mask[0], PIL.Image.Image):
|
159 |
+
mask = np.concatenate([np.array(m.convert("L"))[None, None, :] for m in mask], axis=0)
|
160 |
+
mask = mask.astype(np.float32) / 255.0
|
161 |
+
elif isinstance(mask, list) and isinstance(mask[0], np.ndarray):
|
162 |
+
mask = np.concatenate([m[None, None, :] for m in mask], axis=0)
|
163 |
+
|
164 |
+
mask[mask < 0.5] = 0
|
165 |
+
mask[mask >= 0.5] = 1
|
166 |
+
mask = torch.from_numpy(mask)
|
167 |
+
|
168 |
+
masked_image = image * (mask < 0.5)
|
169 |
+
|
170 |
+
return mask, masked_image
|
171 |
+
|
172 |
+
class StableDiffusionControlNetInpaintPipeline(StableDiffusionControlNetPipeline):
|
173 |
+
r"""
|
174 |
+
Pipeline for text-guided image inpainting using Stable Diffusion with ControlNet guidance.
|
175 |
+
|
176 |
+
This model inherits from [`StableDiffusionControlNetPipeline`]. Check the superclass documentation for the generic methods the
|
177 |
+
library implements for all the pipelines (such as downloading or saving, running on a particular device, etc.)
|
178 |
+
|
179 |
+
Args:
|
180 |
+
vae ([`AutoencoderKL`]):
|
181 |
+
Variational Auto-Encoder (VAE) Model to encode and decode images to and from latent representations.
|
182 |
+
text_encoder ([`CLIPTextModel`]):
|
183 |
+
Frozen text-encoder. Stable Diffusion uses the text portion of
|
184 |
+
[CLIP](https://huggingface.co/docs/transformers/model_doc/clip#transformers.CLIPTextModel), specifically
|
185 |
+
the [clip-vit-large-patch14](https://huggingface.co/openai/clip-vit-large-patch14) variant.
|
186 |
+
tokenizer (`CLIPTokenizer`):
|
187 |
+
Tokenizer of class
|
188 |
+
[CLIPTokenizer](https://huggingface.co/docs/transformers/v4.21.0/en/model_doc/clip#transformers.CLIPTokenizer).
|
189 |
+
unet ([`UNet2DConditionModel`]): Conditional U-Net architecture to denoise the encoded image latents.
|
190 |
+
controlnet ([`ControlNetModel`]):
|
191 |
+
Provides additional conditioning to the unet during the denoising process
|
192 |
+
scheduler ([`SchedulerMixin`]):
|
193 |
+
A scheduler to be used in combination with `unet` to denoise the encoded image latents. Can be one of
|
194 |
+
[`DDIMScheduler`], [`LMSDiscreteScheduler`], or [`PNDMScheduler`].
|
195 |
+
safety_checker ([`StableDiffusionSafetyChecker`]):
|
196 |
+
Classification module that estimates whether generated images could be considered offensive or harmful.
|
197 |
+
Please, refer to the [model card](https://huggingface.co/runwayml/stable-diffusion-v1-5) for details.
|
198 |
+
feature_extractor ([`CLIPFeatureExtractor`]):
|
199 |
+
Model that extracts features from generated images to be used as inputs for the `safety_checker`.
|
200 |
+
"""
|
201 |
+
|
202 |
+
def prepare_mask_latents(
|
203 |
+
self, mask, masked_image, batch_size, height, width, dtype, device, generator, do_classifier_free_guidance
|
204 |
+
):
|
205 |
+
# resize the mask to latents shape as we concatenate the mask to the latents
|
206 |
+
# we do that before converting to dtype to avoid breaking in case we're using cpu_offload
|
207 |
+
# and half precision
|
208 |
+
mask = torch.nn.functional.interpolate(
|
209 |
+
mask, size=(height // self.vae_scale_factor, width // self.vae_scale_factor)
|
210 |
+
)
|
211 |
+
mask = mask.to(device=device, dtype=dtype)
|
212 |
+
|
213 |
+
masked_image = masked_image.to(device=device, dtype=dtype)
|
214 |
+
|
215 |
+
# encode the mask image into latents space so we can concatenate it to the latents
|
216 |
+
if isinstance(generator, list):
|
217 |
+
masked_image_latents = [
|
218 |
+
self.vae.encode(masked_image[i : i + 1]).latent_dist.sample(generator=generator[i])
|
219 |
+
for i in range(batch_size)
|
220 |
+
]
|
221 |
+
masked_image_latents = torch.cat(masked_image_latents, dim=0)
|
222 |
+
else:
|
223 |
+
masked_image_latents = self.vae.encode(masked_image).latent_dist.sample(generator=generator)
|
224 |
+
masked_image_latents = self.vae.config.scaling_factor * masked_image_latents
|
225 |
+
|
226 |
+
# duplicate mask and masked_image_latents for each generation per prompt, using mps friendly method
|
227 |
+
if mask.shape[0] < batch_size:
|
228 |
+
if not batch_size % mask.shape[0] == 0:
|
229 |
+
raise ValueError(
|
230 |
+
"The passed mask and the required batch size don't match. Masks are supposed to be duplicated to"
|
231 |
+
f" a total batch size of {batch_size}, but {mask.shape[0]} masks were passed. Make sure the number"
|
232 |
+
" of masks that you pass is divisible by the total requested batch size."
|
233 |
+
)
|
234 |
+
mask = mask.repeat(batch_size // mask.shape[0], 1, 1, 1)
|
235 |
+
if masked_image_latents.shape[0] < batch_size:
|
236 |
+
if not batch_size % masked_image_latents.shape[0] == 0:
|
237 |
+
raise ValueError(
|
238 |
+
"The passed images and the required batch size don't match. Images are supposed to be duplicated"
|
239 |
+
f" to a total batch size of {batch_size}, but {masked_image_latents.shape[0]} images were passed."
|
240 |
+
" Make sure the number of images that you pass is divisible by the total requested batch size."
|
241 |
+
)
|
242 |
+
masked_image_latents = masked_image_latents.repeat(batch_size // masked_image_latents.shape[0], 1, 1, 1)
|
243 |
+
|
244 |
+
mask = torch.cat([mask] * 2) if do_classifier_free_guidance else mask
|
245 |
+
masked_image_latents = (
|
246 |
+
torch.cat([masked_image_latents] * 2) if do_classifier_free_guidance else masked_image_latents
|
247 |
+
)
|
248 |
+
|
249 |
+
# aligning device to prevent device errors when concating it with the latent model input
|
250 |
+
masked_image_latents = masked_image_latents.to(device=device, dtype=dtype)
|
251 |
+
return mask, masked_image_latents
|
252 |
+
|
253 |
+
@torch.no_grad()
|
254 |
+
@replace_example_docstring(EXAMPLE_DOC_STRING)
|
255 |
+
def __call__(
|
256 |
+
self,
|
257 |
+
prompt: Union[str, List[str]] = None,
|
258 |
+
image: Union[torch.FloatTensor, PIL.Image.Image] = None,
|
259 |
+
control_image: Union[torch.FloatTensor, PIL.Image.Image, List[torch.FloatTensor], List[PIL.Image.Image]] = None,
|
260 |
+
mask_image: Union[torch.FloatTensor, PIL.Image.Image] = None,
|
261 |
+
height: Optional[int] = None,
|
262 |
+
width: Optional[int] = None,
|
263 |
+
num_inference_steps: int = 50,
|
264 |
+
guidance_scale: float = 7.5,
|
265 |
+
negative_prompt: Optional[Union[str, List[str]]] = None,
|
266 |
+
num_images_per_prompt: Optional[int] = 1,
|
267 |
+
eta: float = 0.0,
|
268 |
+
generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
|
269 |
+
latents: Optional[torch.FloatTensor] = None,
|
270 |
+
prompt_embeds: Optional[torch.FloatTensor] = None,
|
271 |
+
negative_prompt_embeds: Optional[torch.FloatTensor] = None,
|
272 |
+
output_type: Optional[str] = "pil",
|
273 |
+
return_dict: bool = True,
|
274 |
+
callback: Optional[Callable[[int, int, torch.FloatTensor], None]] = None,
|
275 |
+
callback_steps: int = 1,
|
276 |
+
cross_attention_kwargs: Optional[Dict[str, Any]] = None,
|
277 |
+
controlnet_conditioning_scale: float = 1.0,
|
278 |
+
):
|
279 |
+
r"""
|
280 |
+
Function invoked when calling the pipeline for generation.
|
281 |
+
Args:
|
282 |
+
prompt (`str` or `List[str]`, *optional*):
|
283 |
+
The prompt or prompts to guide the image generation. If not defined, one has to pass `prompt_embeds`.
|
284 |
+
instead.
|
285 |
+
image (`PIL.Image.Image`):
|
286 |
+
`Image`, or tensor representing an image batch which will be inpainted, *i.e.* parts of the image will
|
287 |
+
be masked out with `mask_image` and repainted according to `prompt`.
|
288 |
+
control_image (`torch.FloatTensor`, `PIL.Image.Image`, `List[torch.FloatTensor]` or `List[PIL.Image.Image]`):
|
289 |
+
The ControlNet input condition. ControlNet uses this input condition to generate guidance to Unet. If
|
290 |
+
the type is specified as `Torch.FloatTensor`, it is passed to ControlNet as is. PIL.Image.Image` can
|
291 |
+
also be accepted as an image. The control image is automatically resized to fit the output image.
|
292 |
+
mask_image (`PIL.Image.Image`):
|
293 |
+
`Image`, or tensor representing an image batch, to mask `image`. White pixels in the mask will be
|
294 |
+
repainted, while black pixels will be preserved. If `mask_image` is a PIL image, it will be converted
|
295 |
+
to a single channel (luminance) before use. If it's a tensor, it should contain one color channel (L)
|
296 |
+
instead of 3, so the expected shape would be `(B, H, W, 1)`.
|
297 |
+
height (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):
|
298 |
+
The height in pixels of the generated image.
|
299 |
+
width (`int`, *optional*, defaults to self.unet.config.sample_size * self.vae_scale_factor):
|
300 |
+
The width in pixels of the generated image.
|
301 |
+
num_inference_steps (`int`, *optional*, defaults to 50):
|
302 |
+
The number of denoising steps. More denoising steps usually lead to a higher quality image at the
|
303 |
+
expense of slower inference.
|
304 |
+
guidance_scale (`float`, *optional*, defaults to 7.5):
|
305 |
+
Guidance scale as defined in [Classifier-Free Diffusion Guidance](https://arxiv.org/abs/2207.12598).
|
306 |
+
`guidance_scale` is defined as `w` of equation 2. of [Imagen
|
307 |
+
Paper](https://arxiv.org/pdf/2205.11487.pdf). Guidance scale is enabled by setting `guidance_scale >
|
308 |
+
1`. Higher guidance scale encourages to generate images that are closely linked to the text `prompt`,
|
309 |
+
usually at the expense of lower image quality.
|
310 |
+
negative_prompt (`str` or `List[str]`, *optional*):
|
311 |
+
The prompt or prompts not to guide the image generation. If not defined, one has to pass
|
312 |
+
`negative_prompt_embeds`. instead. If not defined, one has to pass `negative_prompt_embeds`. instead.
|
313 |
+
Ignored when not using guidance (i.e., ignored if `guidance_scale` is less than `1`).
|
314 |
+
num_images_per_prompt (`int`, *optional*, defaults to 1):
|
315 |
+
The number of images to generate per prompt.
|
316 |
+
eta (`float`, *optional*, defaults to 0.0):
|
317 |
+
Corresponds to parameter eta (η) in the DDIM paper: https://arxiv.org/abs/2010.02502. Only applies to
|
318 |
+
[`schedulers.DDIMScheduler`], will be ignored for others.
|
319 |
+
generator (`torch.Generator` or `List[torch.Generator]`, *optional*):
|
320 |
+
One or a list of [torch generator(s)](https://pytorch.org/docs/stable/generated/torch.Generator.html)
|
321 |
+
to make generation deterministic.
|
322 |
+
latents (`torch.FloatTensor`, *optional*):
|
323 |
+
Pre-generated noisy latents, sampled from a Gaussian distribution, to be used as inputs for image
|
324 |
+
generation. Can be used to tweak the same generation with different prompts. If not provided, a latents
|
325 |
+
tensor will ge generated by sampling using the supplied random `generator`.
|
326 |
+
prompt_embeds (`torch.FloatTensor`, *optional*):
|
327 |
+
Pre-generated text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt weighting. If not
|
328 |
+
provided, text embeddings will be generated from `prompt` input argument.
|
329 |
+
negative_prompt_embeds (`torch.FloatTensor`, *optional*):
|
330 |
+
Pre-generated negative text embeddings. Can be used to easily tweak text inputs, *e.g.* prompt
|
331 |
+
weighting. If not provided, negative_prompt_embeds will be generated from `negative_prompt` input
|
332 |
+
argument.
|
333 |
+
output_type (`str`, *optional*, defaults to `"pil"`):
|
334 |
+
The output format of the generate image. Choose between
|
335 |
+
[PIL](https://pillow.readthedocs.io/en/stable/): `PIL.Image.Image` or `np.array`.
|
336 |
+
return_dict (`bool`, *optional*, defaults to `True`):
|
337 |
+
Whether or not to return a [`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] instead of a
|
338 |
+
plain tuple.
|
339 |
+
callback (`Callable`, *optional*):
|
340 |
+
A function that will be called every `callback_steps` steps during inference. The function will be
|
341 |
+
called with the following arguments: `callback(step: int, timestep: int, latents: torch.FloatTensor)`.
|
342 |
+
callback_steps (`int`, *optional*, defaults to 1):
|
343 |
+
The frequency at which the `callback` function will be called. If not specified, the callback will be
|
344 |
+
called at every step.
|
345 |
+
cross_attention_kwargs (`dict`, *optional*):
|
346 |
+
A kwargs dictionary that if specified is passed along to the `AttnProcessor` as defined under
|
347 |
+
`self.processor` in
|
348 |
+
[diffusers.cross_attention](https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/cross_attention.py).
|
349 |
+
controlnet_conditioning_scale (`float`, *optional*, defaults to 1.0):
|
350 |
+
The outputs of the controlnet are multiplied by `controlnet_conditioning_scale` before they are added
|
351 |
+
to the residual in the original unet.
|
352 |
+
Examples:
|
353 |
+
Returns:
|
354 |
+
[`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] or `tuple`:
|
355 |
+
[`~pipelines.stable_diffusion.StableDiffusionPipelineOutput`] if `return_dict` is True, otherwise a `tuple.
|
356 |
+
When returning a tuple, the first element is a list with the generated images, and the second element is a
|
357 |
+
list of `bool`s denoting whether the corresponding generated image likely represents "not-safe-for-work"
|
358 |
+
(nsfw) content, according to the `safety_checker`.
|
359 |
+
"""
|
360 |
+
# 0. Default height and width to unet
|
361 |
+
height, width = self._default_height_width(height, width, control_image)
|
362 |
+
|
363 |
+
# 1. Check inputs. Raise error if not correct
|
364 |
+
self.check_inputs(
|
365 |
+
prompt, control_image, height, width, callback_steps, negative_prompt, prompt_embeds, negative_prompt_embeds
|
366 |
+
)
|
367 |
+
|
368 |
+
# 2. Define call parameters
|
369 |
+
if prompt is not None and isinstance(prompt, str):
|
370 |
+
batch_size = 1
|
371 |
+
elif prompt is not None and isinstance(prompt, list):
|
372 |
+
batch_size = len(prompt)
|
373 |
+
else:
|
374 |
+
batch_size = prompt_embeds.shape[0]
|
375 |
+
|
376 |
+
device = self._execution_device
|
377 |
+
# here `guidance_scale` is defined analog to the guidance weight `w` of equation (2)
|
378 |
+
# of the Imagen paper: https://arxiv.org/pdf/2205.11487.pdf . `guidance_scale = 1`
|
379 |
+
# corresponds to doing no classifier free guidance.
|
380 |
+
do_classifier_free_guidance = guidance_scale > 1.0
|
381 |
+
|
382 |
+
# 3. Encode input prompt
|
383 |
+
prompt_embeds = self._encode_prompt(
|
384 |
+
prompt,
|
385 |
+
device,
|
386 |
+
num_images_per_prompt,
|
387 |
+
do_classifier_free_guidance,
|
388 |
+
negative_prompt,
|
389 |
+
prompt_embeds=prompt_embeds,
|
390 |
+
negative_prompt_embeds=negative_prompt_embeds,
|
391 |
+
)
|
392 |
+
|
393 |
+
# 4. Prepare image
|
394 |
+
control_image = self.prepare_image(
|
395 |
+
control_image,
|
396 |
+
width,
|
397 |
+
height,
|
398 |
+
batch_size * num_images_per_prompt,
|
399 |
+
num_images_per_prompt,
|
400 |
+
device,
|
401 |
+
self.controlnet.dtype,
|
402 |
+
)
|
403 |
+
|
404 |
+
if do_classifier_free_guidance:
|
405 |
+
control_image = torch.cat([control_image] * 2)
|
406 |
+
|
407 |
+
# 5. Prepare timesteps
|
408 |
+
self.scheduler.set_timesteps(num_inference_steps, device=device)
|
409 |
+
timesteps = self.scheduler.timesteps
|
410 |
+
|
411 |
+
# 6. Prepare latent variables
|
412 |
+
num_channels_latents = self.controlnet.config.in_channels
|
413 |
+
latents = self.prepare_latents(
|
414 |
+
batch_size * num_images_per_prompt,
|
415 |
+
num_channels_latents,
|
416 |
+
height,
|
417 |
+
width,
|
418 |
+
prompt_embeds.dtype,
|
419 |
+
device,
|
420 |
+
generator,
|
421 |
+
latents,
|
422 |
+
)
|
423 |
+
|
424 |
+
# EXTRA: prepare mask latents
|
425 |
+
mask, masked_image = prepare_mask_and_masked_image(image, mask_image)
|
426 |
+
mask, masked_image_latents = self.prepare_mask_latents(
|
427 |
+
mask,
|
428 |
+
masked_image,
|
429 |
+
batch_size * num_images_per_prompt,
|
430 |
+
height,
|
431 |
+
width,
|
432 |
+
prompt_embeds.dtype,
|
433 |
+
device,
|
434 |
+
generator,
|
435 |
+
do_classifier_free_guidance,
|
436 |
+
)
|
437 |
+
|
438 |
+
# 7. Prepare extra step kwargs. TODO: Logic should ideally just be moved out of the pipeline
|
439 |
+
extra_step_kwargs = self.prepare_extra_step_kwargs(generator, eta)
|
440 |
+
|
441 |
+
# 8. Denoising loop
|
442 |
+
num_warmup_steps = len(timesteps) - num_inference_steps * self.scheduler.order
|
443 |
+
with self.progress_bar(total=num_inference_steps) as progress_bar:
|
444 |
+
for i, t in enumerate(timesteps):
|
445 |
+
# expand the latents if we are doing classifier free guidance
|
446 |
+
latent_model_input = torch.cat([latents] * 2) if do_classifier_free_guidance else latents
|
447 |
+
latent_model_input = self.scheduler.scale_model_input(latent_model_input, t)
|
448 |
+
|
449 |
+
down_block_res_samples, mid_block_res_sample = self.controlnet(
|
450 |
+
latent_model_input,
|
451 |
+
t,
|
452 |
+
encoder_hidden_states=prompt_embeds,
|
453 |
+
controlnet_cond=control_image,
|
454 |
+
return_dict=False,
|
455 |
+
)
|
456 |
+
|
457 |
+
down_block_res_samples = [
|
458 |
+
down_block_res_sample * controlnet_conditioning_scale
|
459 |
+
for down_block_res_sample in down_block_res_samples
|
460 |
+
]
|
461 |
+
mid_block_res_sample *= controlnet_conditioning_scale
|
462 |
+
|
463 |
+
# predict the noise residual
|
464 |
+
latent_model_input = torch.cat([latent_model_input, mask, masked_image_latents], dim=1)
|
465 |
+
noise_pred = self.unet(
|
466 |
+
latent_model_input,
|
467 |
+
t,
|
468 |
+
encoder_hidden_states=prompt_embeds,
|
469 |
+
cross_attention_kwargs=cross_attention_kwargs,
|
470 |
+
down_block_additional_residuals=down_block_res_samples,
|
471 |
+
mid_block_additional_residual=mid_block_res_sample,
|
472 |
+
).sample
|
473 |
+
|
474 |
+
# perform guidance
|
475 |
+
if do_classifier_free_guidance:
|
476 |
+
noise_pred_uncond, noise_pred_text = noise_pred.chunk(2)
|
477 |
+
noise_pred = noise_pred_uncond + guidance_scale * (noise_pred_text - noise_pred_uncond)
|
478 |
+
|
479 |
+
# compute the previous noisy sample x_t -> x_t-1
|
480 |
+
latents = self.scheduler.step(noise_pred, t, latents, **extra_step_kwargs).prev_sample
|
481 |
+
|
482 |
+
# call the callback, if provided
|
483 |
+
if i == len(timesteps) - 1 or ((i + 1) > num_warmup_steps and (i + 1) % self.scheduler.order == 0):
|
484 |
+
progress_bar.update()
|
485 |
+
if callback is not None and i % callback_steps == 0:
|
486 |
+
callback(i, t, latents)
|
487 |
+
|
488 |
+
# If we do sequential model offloading, let's offload unet and controlnet
|
489 |
+
# manually for max memory savings
|
490 |
+
if hasattr(self, "final_offload_hook") and self.final_offload_hook is not None:
|
491 |
+
self.unet.to("cpu")
|
492 |
+
self.controlnet.to("cpu")
|
493 |
+
torch.cuda.empty_cache()
|
494 |
+
|
495 |
+
if output_type == "latent":
|
496 |
+
image = latents
|
497 |
+
has_nsfw_concept = None
|
498 |
+
elif output_type == "pil":
|
499 |
+
# 8. Post-processing
|
500 |
+
image = self.decode_latents(latents)
|
501 |
+
|
502 |
+
# 9. Run safety checker
|
503 |
+
image, has_nsfw_concept = self.run_safety_checker(image, device, prompt_embeds.dtype)
|
504 |
+
|
505 |
+
# 10. Convert to PIL
|
506 |
+
image = self.numpy_to_pil(image)
|
507 |
+
else:
|
508 |
+
# 8. Post-processing
|
509 |
+
image = self.decode_latents(latents)
|
510 |
+
|
511 |
+
# 9. Run safety checker
|
512 |
+
image, has_nsfw_concept = self.run_safety_checker(image, device, prompt_embeds.dtype)
|
513 |
+
|
514 |
+
# Offload last model to CPU
|
515 |
+
if hasattr(self, "final_offload_hook") and self.final_offload_hook is not None:
|
516 |
+
self.final_offload_hook.offload()
|
517 |
+
|
518 |
+
if not return_dict:
|
519 |
+
return (image, has_nsfw_concept)
|
520 |
+
|
521 |
+
return StableDiffusionPipelineOutput(images=image, nsfw_content_detected=has_nsfw_concept)
|
requirements.txt
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
accelerate==0.18.0
|
2 |
+
aiofiles==23.1.0
|
3 |
+
aiohttp==3.8.4
|
4 |
+
diffusers==0.16.1
|
5 |
+
einops==0.6.1
|
6 |
+
gradio==3.28.3
|
7 |
+
gradio_client==0.1.4
|
8 |
+
huggingface-hub==0.14.1
|
9 |
+
idna==3.4
|
10 |
+
importlib-metadata==6.6.0
|
11 |
+
kiwisolver==1.4.4
|
12 |
+
lightning-utilities==0.8.0
|
13 |
+
matplotlib==3.7.1
|
14 |
+
numpy==1.24.3
|
15 |
+
open-clip-torch==2.19.0
|
16 |
+
opencv-python==4.7.0.72
|
17 |
+
Pillow==9.5.0
|
18 |
+
pytorch-lightning==2.0.2
|
19 |
+
safetensors==0.3.1
|
20 |
+
torch==2.0.0
|
21 |
+
torchmetrics==0.11.4
|
22 |
+
torchvision==0.15.1
|
23 |
+
transformers==4.28.1
|
script.js
ADDED
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
function gradioApp() {
|
2 |
+
const elems = document.getElementsByTagName('gradio-app')
|
3 |
+
const elem = elems.length == 0 ? document : elems[0]
|
4 |
+
|
5 |
+
if (elem !== document) elem.getElementById = function(id){ return document.getElementById(id) }
|
6 |
+
return elem.shadowRoot ? elem.shadowRoot : elem
|
7 |
+
}
|
8 |
+
|
9 |
+
function get_uiCurrentTab() {
|
10 |
+
return gradioApp().querySelector('#tabs button:not(.border-transparent)')
|
11 |
+
}
|
12 |
+
|
13 |
+
function get_uiCurrentTabContent() {
|
14 |
+
return gradioApp().querySelector('.tabitem[id^=tab_]:not([style*="display: none"])')
|
15 |
+
}
|
16 |
+
|
17 |
+
uiUpdateCallbacks = []
|
18 |
+
uiLoadedCallbacks = []
|
19 |
+
uiTabChangeCallbacks = []
|
20 |
+
optionsChangedCallbacks = []
|
21 |
+
let uiCurrentTab = null
|
22 |
+
|
23 |
+
function onUiUpdate(callback){
|
24 |
+
uiUpdateCallbacks.push(callback)
|
25 |
+
}
|
26 |
+
function onUiLoaded(callback){
|
27 |
+
uiLoadedCallbacks.push(callback)
|
28 |
+
}
|
29 |
+
function onUiTabChange(callback){
|
30 |
+
uiTabChangeCallbacks.push(callback)
|
31 |
+
}
|
32 |
+
function onOptionsChanged(callback){
|
33 |
+
optionsChangedCallbacks.push(callback)
|
34 |
+
}
|
35 |
+
|
36 |
+
function runCallback(x, m){
|
37 |
+
try {
|
38 |
+
x(m)
|
39 |
+
} catch (e) {
|
40 |
+
(console.error || console.log).call(console, e.message, e);
|
41 |
+
}
|
42 |
+
}
|
43 |
+
function executeCallbacks(queue, m) {
|
44 |
+
queue.forEach(function(x){runCallback(x, m)})
|
45 |
+
}
|
46 |
+
|
47 |
+
var executedOnLoaded = false;
|
48 |
+
|
49 |
+
document.addEventListener("DOMContentLoaded", function() {
|
50 |
+
var mutationObserver = new MutationObserver(function(m){
|
51 |
+
if(!executedOnLoaded && gradioApp().querySelector('#txt2img_prompt')){
|
52 |
+
executedOnLoaded = true;
|
53 |
+
executeCallbacks(uiLoadedCallbacks);
|
54 |
+
}
|
55 |
+
|
56 |
+
executeCallbacks(uiUpdateCallbacks, m);
|
57 |
+
const newTab = get_uiCurrentTab();
|
58 |
+
if ( newTab && ( newTab !== uiCurrentTab ) ) {
|
59 |
+
uiCurrentTab = newTab;
|
60 |
+
executeCallbacks(uiTabChangeCallbacks);
|
61 |
+
}
|
62 |
+
});
|
63 |
+
mutationObserver.observe( gradioApp(), { childList:true, subtree:true })
|
64 |
+
});
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Add a ctrl+enter as a shortcut to start a generation
|
68 |
+
*/
|
69 |
+
document.addEventListener('keydown', function(e) {
|
70 |
+
var handled = false;
|
71 |
+
if (e.key !== undefined) {
|
72 |
+
if((e.key == "Enter" && (e.metaKey || e.ctrlKey || e.altKey))) handled = true;
|
73 |
+
} else if (e.keyCode !== undefined) {
|
74 |
+
if((e.keyCode == 13 && (e.metaKey || e.ctrlKey || e.altKey))) handled = true;
|
75 |
+
}
|
76 |
+
if (handled) {
|
77 |
+
button = get_uiCurrentTabContent().querySelector('button[id$=_generate]');
|
78 |
+
if (button) {
|
79 |
+
button.click();
|
80 |
+
}
|
81 |
+
e.preventDefault();
|
82 |
+
}
|
83 |
+
})
|
84 |
+
|
85 |
+
/**
|
86 |
+
* checks that a UI element is not in another hidden element or tab content
|
87 |
+
*/
|
88 |
+
function uiElementIsVisible(el) {
|
89 |
+
let isVisible = !el.closest('.\\!hidden');
|
90 |
+
if ( ! isVisible ) {
|
91 |
+
return false;
|
92 |
+
}
|
93 |
+
|
94 |
+
while( isVisible = el.closest('.tabitem')?.style.display !== 'none' ) {
|
95 |
+
if ( ! isVisible ) {
|
96 |
+
return false;
|
97 |
+
} else if ( el.parentElement ) {
|
98 |
+
el = el.parentElement
|
99 |
+
} else {
|
100 |
+
break;
|
101 |
+
}
|
102 |
+
}
|
103 |
+
return isVisible;
|
104 |
+
}
|
style.css
ADDED
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
* CSS for WebUI
|
3 |
+
**/
|
4 |
+
|
5 |
+
.posex_cont {
|
6 |
+
display: flex;
|
7 |
+
flex-flow: column;
|
8 |
+
gap: 0.5em 0;
|
9 |
+
width: max-content;
|
10 |
+
overflow: auto !important;
|
11 |
+
max-width: 100%;
|
12 |
+
}
|
13 |
+
|
14 |
+
.posex_cont input[type=checkbox] {
|
15 |
+
appearance: auto;
|
16 |
+
}
|
17 |
+
|
18 |
+
.posex_reset_cont {
|
19 |
+
display: flex;
|
20 |
+
flex-direction: row;
|
21 |
+
gap: 0 0.5em;
|
22 |
+
}
|
23 |
+
|
24 |
+
.posex_box {
|
25 |
+
display: block;
|
26 |
+
border: 1px solid gray;
|
27 |
+
padding: 0.5em 0;
|
28 |
+
text-decoration: none;
|
29 |
+
text-align: center;
|
30 |
+
}
|
31 |
+
|
32 |
+
.posex_reset_cont .posex_box {
|
33 |
+
flex: 1 1 0;
|
34 |
+
}
|
35 |
+
|
36 |
+
.posex_canvas_cont {
|
37 |
+
display: flex;
|
38 |
+
flex-direction: row;
|
39 |
+
}
|
40 |
+
|
41 |
+
.posex_canvas_size {
|
42 |
+
background-color: transparent !important;
|
43 |
+
}
|
44 |
+
|
45 |
+
.posex_setting_cont {
|
46 |
+
margin-left: 1em;
|
47 |
+
display: flex;
|
48 |
+
flex-direction: column;
|
49 |
+
gap: 0.25em;
|
50 |
+
}
|
51 |
+
|
52 |
+
.posex_body {
|
53 |
+
width: max-content;
|
54 |
+
min-width: 100%;
|
55 |
+
text-align: left;
|
56 |
+
border: 1px solid gray;
|
57 |
+
padding: 0.5em;
|
58 |
+
}
|
59 |
+
|
60 |
+
.posex_bg_cont {
|
61 |
+
display: flex;
|
62 |
+
flex-direction: row;
|
63 |
+
gap: 0 0.25em;
|
64 |
+
}
|
65 |
+
|
66 |
+
.posex_bg {
|
67 |
+
flex: 0 0 0;
|
68 |
+
border: 1px solid gray;
|
69 |
+
padding: 0.25em 1em;
|
70 |
+
min-width: 5em;
|
71 |
+
}
|
72 |
+
|
73 |
+
.posex_notation {
|
74 |
+
display: none;
|
75 |
+
position: absolute;
|
76 |
+
color: black;
|
77 |
+
background-color: rgba(255, 255, 255, 0.75);
|
78 |
+
padding: 0.1em 0.25em;
|
79 |
+
pointer-events: none;
|
80 |
+
font-size: small;
|
81 |
+
}
|
82 |
+
|
83 |
+
.posex_indicator1 {
|
84 |
+
display: none;
|
85 |
+
position: absolute;
|
86 |
+
outline: 1px solid white;
|
87 |
+
pointer-events: none;
|
88 |
+
}
|
89 |
+
|
90 |
+
.posex_indicator2 {
|
91 |
+
display: none;
|
92 |
+
position: absolute;
|
93 |
+
outline: 1px solid gray;
|
94 |
+
pointer-events: none;
|
95 |
+
}
|
96 |
+
|
97 |
+
.posex_misc_cont {
|
98 |
+
display: flex;
|
99 |
+
flex-flow: row;
|
100 |
+
gap: 0 0.5em;
|
101 |
+
}
|
102 |
+
|
103 |
+
.posex_misc {
|
104 |
+
flex: 1 1 0;
|
105 |
+
}
|
106 |
+
|
107 |
+
.posex_saved_poses {
|
108 |
+
display: flex;
|
109 |
+
flex-direction: row;
|
110 |
+
gap: 0.25em;
|
111 |
+
font-size: small;
|
112 |
+
}
|
113 |
+
|
114 |
+
.posex_saved_poses > * {
|
115 |
+
margin: 0;
|
116 |
+
outline: 1px solid gray;
|
117 |
+
max-width: 128px;
|
118 |
+
}
|
119 |
+
|
120 |
+
.posex_saved_poses img {
|
121 |
+
max-width: 128px;
|
122 |
+
max-height: 128px;
|
123 |
+
}
|
124 |
+
|
125 |
+
.posex_saved_poses figcaption {
|
126 |
+
padding: 0 0.25em;
|
127 |
+
overflow-wrap: anywhere; /* Opera Android may not be able to interpret `anywhere` keyword. */
|
128 |
+
}
|
129 |
+
|
130 |
+
.posex_saved_poses .close {
|
131 |
+
position: absolute;
|
132 |
+
cursor: pointer;
|
133 |
+
background-color: white;
|
134 |
+
opacity: 0.5 !important;
|
135 |
+
width: 16px;
|
136 |
+
height: 16px;
|
137 |
+
text-align: center;
|
138 |
+
vertical-align: middle;
|
139 |
+
margin: 0;
|
140 |
+
padding: 0;
|
141 |
+
font-family: monospace;
|
142 |
+
}
|
143 |
+
|
144 |
+
.posex_saved_poses .close:hover {
|
145 |
+
opacity: 1.0 !important;
|
146 |
+
}
|
147 |
+
|
148 |
+
.posex_saved_poses .close2 {
|
149 |
+
display: none;
|
150 |
+
position: absolute;
|
151 |
+
left: 1.5em;
|
152 |
+
top: 0;
|
153 |
+
}
|
154 |
+
|
155 |
+
.posex_saved_poses .close:hover .close2 {
|
156 |
+
display: block;
|
157 |
+
color: white;
|
158 |
+
pointer-events: none;
|
159 |
+
}
|