chgnhyk 0.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
chgnhyk-0.0.0/PKG-INFO ADDED
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.4
2
+ Name: chgnhyk
3
+ Version: 0.0.0
4
+ Summary: visual and audio engine of chgnhyk
5
+ Requires-Python: >=3.9.0
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: moderngl
8
+ Requires-Dist: numpy
9
+ Requires-Dist: pillow
10
+ Requires-Dist: opencv-python
11
+ Requires-Dist: csoundengine
12
+ Requires-Dist: moviepy
13
+ Requires-Dist: svgpathtools
14
+ Requires-Dist: trimesh
15
+ Requires-Dist: pyrr
16
+ Requires-Dist: noise
17
+ Requires-Dist: moderngl_window
File without changes
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "chgnhyk"
7
+ version = "0.0.0"
8
+ description = "visual and audio engine of chgnhyk"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9.0"
11
+ dependencies = [
12
+ "moderngl",
13
+ "numpy",
14
+ "pillow",
15
+ "opencv-python",
16
+ "csoundengine",
17
+ "moviepy",
18
+ "svgpathtools",
19
+ "trimesh",
20
+ "pyrr",
21
+ "noise",
22
+ "moderngl_window"
23
+ ]
24
+
25
+ [tool.setuptools]
26
+ package-dir = {"" = "src"}
27
+
28
+ [tool.setuptools.packages.find]
29
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,114 @@
1
+ import math
2
+ import random
3
+
4
+ class AreaCell:
5
+ def __init__(self, x, y, idx):
6
+ self.filled = False
7
+ self.x = x
8
+ self.y = y
9
+ self.idx = idx
10
+ #seed(0)
11
+ pass
12
+
13
+ class AreaPicker:
14
+ def __init__(self, w:int, h:int, seed:int=0):
15
+ self.reset(w, h, seed)
16
+ self.min_w = 0
17
+
18
+
19
+ def reset(self, w:int, h:int, seed:int=0):
20
+ self.rects = []
21
+ self.depleted = False
22
+ self.seed = seed
23
+ random.seed(self.seed)
24
+ self.setGrid(w, h)
25
+
26
+
27
+ def setGrid(self, w:int, h:int):
28
+ self.gw = w
29
+ self.gh = h
30
+ self.cells = []
31
+ self.pool = []
32
+ for x in range(self.gw):
33
+ for y in range(self.gh):
34
+ idx = x + y * self.gw
35
+ self.cells.append(AreaCell(x, y, idx))
36
+ self.pool.append(idx)
37
+
38
+ def pickArea(self):
39
+ if len(self.pool) == 0:
40
+ self.depleted = True
41
+ return
42
+
43
+ pck_idx = random.randint(0, len(self.pool)-1)
44
+ pck_idx = self.pool[pck_idx]
45
+
46
+ pck_y_idx = math.floor(pck_idx/self.gw)
47
+ pck_x_idx = pck_idx % self.gw
48
+
49
+ x_dir = -1 if random.random() > 0.5 else 1
50
+ y_dir = -1 if random.random() > 0.5 else 1
51
+ avail_w = 0
52
+ avail_h = self.gh
53
+
54
+ x = pck_x_idx
55
+ while 0 <= x < self.gw:
56
+ xidx = x + pck_y_idx * self.gw
57
+ col_avail_h = 0
58
+ y = pck_y_idx
59
+ while 0 <= y < self.gh:
60
+ yidx = x + y * self.gw
61
+ if self.cells[yidx].filled:
62
+ break
63
+ col_avail_h += 1
64
+ y += y_dir
65
+
66
+ avail_h = min(avail_h, col_avail_h)
67
+ if self.cells[xidx].filled:
68
+ break
69
+ avail_w += 1
70
+ x += x_dir
71
+
72
+ # TODO --> need to think about this
73
+ # if avail_w < self.min_w and avail_h < self.min_w:
74
+ # self.cells[pck_idx].filled = True
75
+ # if pck_idx in self.pool:
76
+ # self.pool.remove(pck_idx)
77
+ # return
78
+
79
+ if avail_w > self.min_w:
80
+ rw = random.randint(self.min_w, avail_w-1)
81
+ else:
82
+ rw = max(0, min(self.min_w, avail_w-1))
83
+
84
+ if avail_h > self.min_w:
85
+ rh = random.randint(self.min_w, avail_h-1)
86
+ else:
87
+ rh = max(0, min(self.min_w, avail_h-1))
88
+
89
+ x_strt = pck_x_idx if (x_dir == 1) else pck_x_idx-rw
90
+ x_end = pck_x_idx+rw if (x_dir == 1) else pck_x_idx
91
+ y_strt = pck_y_idx if (y_dir == 1) else pck_y_idx-rh
92
+ y_end = pck_y_idx+rh if (y_dir == 1) else pck_y_idx
93
+
94
+ #print(x_strt, x_end, y_strt, y_end, x_dir, y_dir)
95
+
96
+ for x in range(x_strt, x_end+1, 1):
97
+ for y in range(y_strt, y_end+1, 1):
98
+ idx = x + y * self.gw
99
+
100
+ self.cells[idx].filled = True
101
+ if idx in self.pool:
102
+ self.pool.remove(idx)
103
+
104
+ self.rects.append({
105
+ "x": x_strt,
106
+ "y": y_strt,
107
+ "w": abs(x_end-x_strt)+1,
108
+ "h": abs(y_end-y_strt)+1
109
+ })
110
+
111
+ if len(self.pool) == 0:
112
+ self.depleted = True
113
+
114
+
@@ -0,0 +1,93 @@
1
+ import math
2
+
3
+ def clamp(x, min_val, max_val):
4
+ return max(min(x, max_val), min_val)
5
+
6
+ def rotate(x,y,a):
7
+ return (math.cos(a)*x-math.sin(a)*y, math.sin(a)*x+math.cos(a)*y)
8
+
9
+ def fract(x):
10
+ return x-math.floor(x)
11
+
12
+ def smoothstep(mi, mx, v):
13
+ x = max(0, min(1, (v-mi)/(mx-mi)))
14
+ return x*x*(3 - 2*x)
15
+
16
+ def normalize(x, y):
17
+ vl = math.sqrt(x*x+y*y)
18
+ if vl < 1e-6:
19
+ return (0.0, 0.0)
20
+ else:
21
+ return (x/vl, y/vl)
22
+
23
+ def get_dist(x1,y1,x2,y2):
24
+ dx = x2-x1
25
+ dy = y2-y1
26
+ return math.sqrt(dx*dx+dy*dy)
27
+
28
+ def get_angle(v1:tuple,v2:tuple):
29
+ dot = v1[0]*v2[0]+v1[1]*v2[1]
30
+ crss = v1[0]*v2[1]-v1[1]*v2[0]
31
+
32
+ dot = clamp(dot, -1.0, 1.0)
33
+
34
+ if abs(dot - 1.0) < 1e-6 and abs(crss) < 1e-6:
35
+ return 0.0
36
+ else:
37
+ angle = math.atan2(crss,dot)
38
+ return angle
39
+
40
+ class Arm2D:
41
+ def __init__(self, num, l, ease = 1.0, angle = 0.0):
42
+ self.L = l
43
+ self.angles = []
44
+ self.positions = []
45
+ self.sx = 0
46
+ self.sy = 0
47
+
48
+ self.ease = ease
49
+
50
+ self.num = num
51
+ for i in range(self.num):
52
+ if i == 0:
53
+ self.angles.append(math.pi * 0.5 + angle)
54
+ else:
55
+ self.angles.append(0.0)
56
+ self.positions.append((0.0,0.0))
57
+
58
+
59
+ def get_arm_pos(self):
60
+ data = []
61
+ data = self.positions.copy()
62
+ self.update_arms()
63
+ data.append((self.ex,self.ey))
64
+ # print(len(data))
65
+ return data
66
+
67
+ def update_arms(self):
68
+ _sx = self.sx
69
+ _sy = self.sy
70
+ _a = 0
71
+ for i in range(self.num):
72
+ _a += self.angles[i]
73
+ self.positions[i] = (_sx,_sy)
74
+ _sx = _sx + math.cos(_a) * self.L
75
+ _sy = _sy + math.sin(_a) * self.L
76
+
77
+ self.ex = _sx
78
+ self.ey = _sy
79
+
80
+ def set_target(self, tx, ty):
81
+ self.update_arms()
82
+
83
+ for i in range(self.num-1,-1,-1):
84
+ jx = self.positions[i][0]
85
+ jy = self.positions[i][1]
86
+
87
+ jd = normalize(self.ex-jx, self.ey-jy)
88
+ d = normalize(tx-jx, ty-jy)
89
+
90
+ angle = get_angle(jd, d)
91
+ self.angles[i] += angle * self.ease
92
+
93
+ self.update_arms()
@@ -0,0 +1,116 @@
1
+ import math
2
+
3
+ class Cmplx:
4
+ def __init__(self, a, b):
5
+ self.re = a
6
+ self.im = b
7
+ pass
8
+
9
+ def add(self, c):
10
+ self.re += c.re
11
+ self.im += c.im
12
+
13
+ def mult(self, c):
14
+ _re = self.re * c.re - self.im * c.im
15
+ _im = self.re * c.im + self.im * c.re
16
+ return Cmplx(_re, _im)
17
+
18
+ def DFT(x:iter, w, h, compress=0):
19
+
20
+ X = []
21
+ N = len(x)
22
+ for i in range(N):
23
+ x[i] = Cmplx(x[i][0]-w*0.5,x[i][1]-h*0.5)
24
+
25
+ for k in range(N):
26
+ _sum = Cmplx(0, 0)
27
+ for n in range (N):
28
+ phi = (math.pi * 2 * k * n) / N
29
+ c = Cmplx(math.cos(phi), -math.sin(phi))
30
+ _sum.add(x[n].mult(c))
31
+ _sum.re = _sum.re / N
32
+ _sum.im = _sum.im / N
33
+
34
+ #freq = k
35
+ freq = k if k <= N//2 else k - N
36
+ amp = math.sqrt(_sum.re * _sum.re + _sum.im * _sum.im)
37
+ phase = math.atan2(_sum.im, _sum.re)
38
+
39
+ X.append({
40
+ "re": _sum.re,
41
+ "im": _sum.im,
42
+ "freq": freq,
43
+ "amp": amp,
44
+ "phase": phase
45
+ })
46
+
47
+ if compress > 0 and compress < len(x):
48
+ X.sort(key=lambda c: c["amp"], reverse=True)
49
+ X = X[:compress]
50
+
51
+ return X
52
+
53
+ def MixF(X1, X2, t):
54
+ X = []
55
+ for i in range(len(X1)):
56
+ re1 = X1[i]["re"]
57
+ im1 = X1[i]["im"]
58
+
59
+ re2 = X2[i]["re"]
60
+ im2 = X2[i]["im"]
61
+
62
+ re = (1.0-t)*re1 + t*re2
63
+ im = (1.0-t)*im1 + t*im2
64
+ X.append({
65
+ "re": re,
66
+ "im": im,
67
+ "freq": X1[i]["freq"]
68
+ })
69
+ return X
70
+
71
+ def MixSortedF(X1, X2, t):
72
+ X = []
73
+
74
+ # Build lookup tables by frequency
75
+ A = {c["freq"]: c for c in X1}
76
+ B = {c["freq"]: c for c in X2}
77
+
78
+ # Union of all frequencies
79
+ freqs = set(A.keys()) | set(B.keys())
80
+
81
+ for k in freqs:
82
+ c1 = A.get(k)
83
+ c2 = B.get(k)
84
+
85
+ # Zero-fill if missing
86
+ re1 = c1["re"] if c1 else 0.0
87
+ im1 = c1["im"] if c1 else 0.0
88
+
89
+ re2 = c2["re"] if c2 else 0.0
90
+ im2 = c2["im"] if c2 else 0.0
91
+
92
+ # Linear interpolation
93
+ re = (1.0 - t) * re1 + t * re2
94
+ im = (1.0 - t) * im1 + t * im2
95
+
96
+ X.append({
97
+ "re": re,
98
+ "im": im,
99
+ "freq": k
100
+ })
101
+
102
+ return X
103
+
104
+ def epiCycle(x, y, timer, rotation, fourier:iter):
105
+ _x = x
106
+ _y = y
107
+ for i in range(len(fourier)):
108
+ re = fourier[i]["re"]
109
+ im = fourier[i]["im"]
110
+ freq = fourier[i]["freq"] #i if i <= len(fourier)//2 else i - len(fourier)
111
+ radius = math.sqrt(re * re + im * im)
112
+ phase = math.atan2(im, re)
113
+ _x += radius * math.cos(freq * timer + phase + rotation)
114
+ _y += radius * math.sin(freq * timer + phase + rotation)
115
+
116
+ return (_x,_y)
@@ -0,0 +1,245 @@
1
+ import numpy as np
2
+ from PIL import Image
3
+ import moderngl
4
+ from pyrr import Matrix44
5
+ import math
6
+ from typing import Union
7
+ from .utils import FakeUniform, EXT_MAP
8
+ from pathlib import Path
9
+
10
+ def particle(i, num):
11
+
12
+ x = np.random.uniform(-0.5, 0.5)
13
+ y = np.random.uniform(-0.5, 0.5)
14
+ z = 1 #np.random.uniform(-1.0, 1.0)
15
+
16
+ r = np.random.uniform(0.0, 1.0)
17
+ g = np.random.uniform(0.0, 1.0)
18
+ b = np.random.uniform(0.0, 1.0)
19
+ return [x, y, z, r, g, b]
20
+
21
+
22
+
23
+ class ParticlesFBO:
24
+
25
+ quad_vertex_shader = '''
26
+ #version 330
27
+ in vec2 in_vert;
28
+ in vec2 in_uv;
29
+ out vec2 UV;
30
+ void main() {
31
+ gl_Position = vec4(in_vert, 0.0, 1.0);
32
+ UV = in_uv;
33
+ }
34
+ '''
35
+ copier_fragment_shader = '''
36
+ #version 330
37
+ out vec4 outputColor;
38
+ in vec2 UV;
39
+
40
+ uniform sampler2D copy_target;
41
+
42
+ void main()
43
+ {
44
+ vec4 copy = texture(copy_target,UV);
45
+ outputColor = copy;
46
+ }
47
+ '''
48
+
49
+ def __init__(self, ctx, size, vertex_shader, fragment_shader, transform_shader, enable_backbuffer = False, rest_time = 0.0, num = 10000, particle_func = None):
50
+ self.ctx = ctx
51
+ self.size = size
52
+ self.enable_backbuffer = enable_backbuffer
53
+
54
+ self.texture = self.ctx.texture(self.size, components=4, dtype="f4")
55
+ self.fbo = self.ctx.framebuffer(self.texture)
56
+ self.prog = self.ctx.program(
57
+ vertex_shader=vertex_shader, fragment_shader=fragment_shader)
58
+
59
+ vertex_data = np.array([
60
+ # x, y, z, u, v
61
+ -1.0, -1.0, 0.0, 0.0, 0.0,
62
+ +1.0, -1.0, 0.0, 1.0, 0.0,
63
+ -1.0, +1.0, 0.0, 0.0, 1.0,
64
+ +1.0, +1.0, 0.0, 1.0, 1.0,
65
+ ]).astype(np.float32)
66
+
67
+ content = [(
68
+ self.ctx.buffer(vertex_data),
69
+ '3f 2f',
70
+ 'in_vert', 'in_uv'
71
+ )]
72
+
73
+ self.transform_prog = self.ctx.program(
74
+ vertex_shader = transform_shader,
75
+ varyings = ['out_pos', 'out_col'])
76
+
77
+ self.particle_number = num
78
+
79
+ self.particle_func = particle_func
80
+
81
+ if callable(self.particle_func):
82
+ particles = np.array([self.particle_func(i, self.particle_number) for i in range(self.particle_number)], dtype='f4')
83
+ else:
84
+ particles = np.array([particle(i, self.particle_number) for i in range(self.particle_number)], dtype='f4')
85
+
86
+ self.vbo1 = self.ctx.buffer(particles.tobytes())
87
+ self.vbo2 = self.ctx.buffer(reserve=self.vbo1.size)
88
+
89
+ self.vao1 = self.ctx.vertex_array(self.transform_prog, [(self.vbo1, '3f 3f', 'in_pos', 'in_col')])
90
+ self.vao2 = self.ctx.vertex_array(self.transform_prog, [(self.vbo2, '3f 3f', 'in_pos', 'in_col')])
91
+ self.render_vao = self.ctx.vertex_array(self.prog, [(self.vbo1, '3f 3f', 'in_vert', 'in_col')])
92
+
93
+ self.aspect_ratio = self.size[0] / self.size[1]
94
+ self.mvp = self.prog.get('Mvp', FakeUniform())
95
+ self.campos = self.transform_prog.get('CAMPOS', FakeUniform())
96
+ self.real_cam = self.prog.get('CAMPOS', FakeUniform())
97
+ self.time = self.prog.get('time', FakeUniform())
98
+ self.resolution = self.prog.get('resolution', FakeUniform())
99
+
100
+ if self.resolution:
101
+ self.set_uniform("resolution", self.size)
102
+ else:
103
+ print(f'unable to set resolution uniform {self.resolution}')
104
+
105
+ if self.enable_backbuffer == True:
106
+ self.bck_texture = self.ctx.texture(
107
+ self.size, components=4, dtype="f4")
108
+ self.bck_fbo = self.ctx.framebuffer(self.bck_texture)
109
+ self.bck_prog = self.ctx.program(
110
+ vertex_shader=self.quad_vertex_shader, fragment_shader=self.copier_fragment_shader)
111
+ self.bck_vao = self.ctx.vertex_array(self.bck_prog, content)
112
+
113
+ self.backbuffer_uniform = self.prog.get(
114
+ 'backbuffer', FakeUniform())
115
+ self.copy_target_uniform = self.bck_prog.get(
116
+ 'copy_target', FakeUniform())
117
+ else:
118
+ self.bck_fbo = None
119
+
120
+ self.textures = {}
121
+ self.texture_uniforms = {}
122
+ self.textures_ = {}
123
+ self.texture_uniforms_ = {}
124
+
125
+
126
+ self.proj = Matrix44.perspective_projection(45.0, self.aspect_ratio, 0.1, 1000.0)
127
+ self.lookat = Matrix44.look_at(
128
+ (0.0, 0.0, 3.0),
129
+ (0.0, 0.0, 0.0),
130
+ (0.0, 1.0, 0.0),
131
+ )
132
+ self.set_cam((0.0, 0.0, 3.0))
133
+
134
+ self.clear_col = (0.0,0.0,0.0)
135
+
136
+ def set_clear_col(self, col:tuple = (0.0,0.0,0.0)):
137
+ self.clear_col = col
138
+
139
+ def release_all(self):
140
+ if hasattr(self, 'bck_texture'):
141
+ self.bck_texture.release()
142
+ for (name, texture) in self.textures.items():
143
+ self.textures[name].release()
144
+ self.textures_[name].release()
145
+ self.texture.release()
146
+
147
+ def set_uniform(self, name, value):
148
+ uniform = self.prog.get(name, FakeUniform())
149
+ uniform.value = value
150
+
151
+ uniform = self.transform_prog.get(name, FakeUniform())
152
+ uniform.value = value
153
+
154
+ def set_texture_uniform_from_path(self, path, name, id):
155
+ im = Image.open(path)
156
+ im_WIDTH, im_HEIGHT, im_DATA = im.size[0], im.size[1], im.convert(
157
+ 'RGBA').tobytes("raw", "RGBA", 0, -1)
158
+ texture = self.ctx.texture(
159
+ (im.size[0], im.size[1]), components=4, data=im_DATA)
160
+ self.set_texture_uniform(texture, name, id)
161
+
162
+ def set_texture_uniform(self, texture, name, id):
163
+ if name not in self.textures:
164
+ self.texture_uniforms[name] = self.prog.get(name, FakeUniform())
165
+ self.textures[name] = texture
166
+
167
+ self.texture_uniforms_[name] = self.transform_prog.get(name, FakeUniform())
168
+ self.textures_[name] = texture
169
+ self.texture_uniforms[name].value = id
170
+ self.texture_uniforms_[name].value = id
171
+
172
+ def clear(self):
173
+ self.fbo.clear()
174
+ if self.bck_fbo:
175
+ self.bck_fbo.clear()
176
+
177
+ def extract_img(self, path: Union[str, Path], format='png', quality=100):
178
+ path_format = Path(path).suffix.lower().lstrip(".")
179
+ path_format = EXT_MAP.get(path_format)
180
+ if format != path_format:
181
+ format = path_format
182
+
183
+ if format == 'jpeg':
184
+ image = Image.frombytes('RGB', self.size, self.fbo.read(components=3))
185
+ else:
186
+ image = Image.frombytes('RGBA', self.size, self.fbo.read(components=4))
187
+ image = image.transpose(Image.FLIP_TOP_BOTTOM)
188
+ image.save(str(path), format=format, quality=quality)
189
+
190
+ def extract_np_img(self) -> np.ndarray:
191
+ img_buf = self.fbo.read()
192
+ img_width = self.fbo.size[0]
193
+ img_height = self.fbo.size[1]
194
+ img = np.frombuffer(img_buf, np.uint8).reshape(img_height, img_width, 3)[::-1]
195
+ return img
196
+
197
+ # def extract_vao(self, path, format='jpeg'):
198
+ # image = Image.frombytes('LA', (self.particle_number, self.particle_number), self.vbo1.read(size=-1,offset=2))
199
+ # image = image.transpose(Image.FLIP_TOP_BOTTOM)
200
+ # image.save(path, format=format)
201
+
202
+ def set_cam(self, _campos, _lookat = (0,0,0), _up = (0,1,0)):
203
+ self.campos.value = _campos
204
+ self.real_cam.value = _campos
205
+ self.lookat = Matrix44.look_at(
206
+ _campos,
207
+ _lookat,
208
+ _up,
209
+ )
210
+ self.mvp.write((self.proj * self.lookat).astype('f4'))
211
+
212
+ def render(self):
213
+ self.fbo.use()
214
+
215
+ self.fbo.clear(*self.clear_col)
216
+ self.ctx.enable(moderngl.PROGRAM_POINT_SIZE)
217
+ self.ctx.enable(moderngl.BLEND)
218
+ #self.ctx.enable(moderngl.DEPTH_TEST)
219
+ self.ctx.blend_equation = moderngl.FUNC_ADD, moderngl.MAX
220
+
221
+ for (name, texture) in self.textures.items():
222
+ # print(name, texture, self.texture_uniforms[name].value)
223
+ textureid = self.texture_uniforms[name].value
224
+ self.textures[name].use(textureid)
225
+ self.texture_uniforms[name].value = textureid
226
+
227
+ textureid_ = self.texture_uniforms_[name].value
228
+ self.textures_[name].use(textureid_)
229
+ self.texture_uniforms_[name].value = textureid_
230
+
231
+ if self.enable_backbuffer == True:
232
+ self.bck_texture.use(1)
233
+ self.backbuffer_uniform.value = 1
234
+
235
+ self.vao1.transform(self.vbo2, moderngl.POINTS, self.particle_number)
236
+ self.ctx.copy_buffer(self.vbo1, self.vbo2)
237
+ self.render_vao.render(moderngl.POINTS, self.particle_number)
238
+
239
+ if self.enable_backbuffer == True:
240
+ self.bck_fbo.use()
241
+
242
+ self.texture.use(0)
243
+ self.copy_target_uniform.value = 0
244
+
245
+ self.bck_vao.render(moderngl.TRIANGLE_STRIP)