hirol commited on
Commit
a637d5e
1 Parent(s): e08094e

Upload 27 files

Browse files
.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: ControlnetOverMask
3
  emoji: 🌖
4
- colorFrom: pink
5
  colorTo: blue
6
  sdk: gradio
7
- sdk_version: 3.28.3
8
  app_file: app.py
9
  pinned: false
10
  license: mit
 
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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

  • SHA256: 687911aeb3c787c9be63e0cc356b17bbf1655b3315028334f800898fcb417e9b
  • Pointer size: 132 Bytes
  • Size of remote file: 1.34 MB
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 = '&#x1f504; All Reset';
101
+ all_reset.classList.add('posex_all_reset', 'posex_box');
102
+
103
+ const reset_camera = $('button');
104
+ reset_camera.innerHTML = '&#x1f3a5; Reset Camera';
105
+ reset_camera.classList.add('posex_reset_camera', 'posex_box');
106
+
107
+ const reset_pose = $('button');
108
+ reset_pose.innerHTML = '&#x1f9cd; 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 = '&#x1f5bc; 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 = '&#x274c; 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 = '&#x2795; Add';
135
+ const remove_body = $('button'); remove_body.classList.add('posex_remove_body', 'posex_body'); remove_body.innerHTML = '&#x2796; 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 = '&#x1f5bc; 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 = '&#x274c; 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 = '&#x1f4cb; Copy to clipboard';
201
+ const save = $('button'); save.classList.add('posex_save', 'posex_misc', 'posex_box'); save.innerHTML = '&#x1f4be; 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 = '&#x1f4be;&#x1f9cd; 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 = '&#x1f4be;&#x1f9cd; 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

  • SHA256: 1fbf58b0e6fa7a2a9094c7402ee5c2edaa6f550df5601b82806b0a5540d1a518
  • Pointer size: 132 Bytes
  • Size of remote file: 2.88 MB
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
+ }