@combos-fun/plugin-renderer-filter 0.0.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/agent-skill.md +36 -0
- package/combos-plugin.json +11 -0
- package/dist/plugin-renderer-filter.cjs.js +287 -0
- package/dist/plugin-renderer-filter.cjs.js.map +1 -0
- package/dist/plugin-renderer-filter.cjs.prod.js +1 -0
- package/dist/plugin-renderer-filter.d.ts +56 -0
- package/dist/plugin-renderer-filter.esm.js +284 -0
- package/dist/plugin-renderer-filter.esm.js.map +1 -0
- package/index.js +7 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# @combos-fun/plugin-renderer-filter
|
|
2
|
+
|
|
3
|
+
@combos-fun/plugin-renderer-filter — part of the Combos Fun engine monorepo.
|
|
4
|
+
|
|
5
|
+
Keywords: `filter`, `shader`, `blur`, `color-matrix`, `2d`.
|
|
6
|
+
|
|
7
|
+
## Documentation
|
|
8
|
+
|
|
9
|
+
- Per-package agent / developer notes: [`agent-skill.md`](./agent-skill.md)
|
|
10
|
+
- Machine-readable manifest: [`combos-plugin.json`](./combos-plugin.json)
|
|
11
|
+
|
|
12
|
+
When consumed from npm:
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import manifest from '@combos-fun/plugin-renderer-filter/plugin-manifest';
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## License
|
|
19
|
+
|
|
20
|
+
Internal workspace package, part of the Combos Fun engine monorepo.
|
package/agent-skill.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# `@combos-fun/plugin-renderer-filter` — Agent notes
|
|
2
|
+
|
|
3
|
+
Read only to apply blur, color matrix, noise, displacement, or custom GLSL to an existing GameObject container.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import {
|
|
7
|
+
Filter,
|
|
8
|
+
FilterSystem,
|
|
9
|
+
type FilterParams,
|
|
10
|
+
type FilterEffectParams,
|
|
11
|
+
type FilterEffectType,
|
|
12
|
+
type FilterUniformValue,
|
|
13
|
+
} from '@combos-fun/plugin-renderer-filter';
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`Filter.componentName = 'Filter'`. `FilterSystem.systemName` and its string
|
|
17
|
+
lookup key are **`'FilterSystem'`**, not `'Filter'`; constructor lookup remains
|
|
18
|
+
preferred.
|
|
19
|
+
|
|
20
|
+
`FilterParams` has `enabled?: boolean` (default `true`) and `effects?: FilterEffectParams[]` (default `[]`). `enabled: false` clears `container.filters` without discarding the built effects.
|
|
21
|
+
|
|
22
|
+
| Effect `type` | Fields and defaults |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `blur` (also the default type) | `strength` default `8`, `quality` default `4` |
|
|
25
|
+
| `colorMatrix` | `brightness`, `contrast`, `saturate`, `hue`, `grayscale` |
|
|
26
|
+
| `noise` | `noise` default `0.5`, optional `seed` |
|
|
27
|
+
| `displacement` | required IMAGE name `map`, `scale` default `20` |
|
|
28
|
+
| `shader` | required SHADER name `resource`, optional `uniforms` |
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
go.addComponent(new Filter({
|
|
32
|
+
effects: [{ type: 'blur', strength: 8 }],
|
|
33
|
+
}));
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Shader `resource` is a registered SHADER name, not inline GLSL or a URL. Fragment source is required; omitted vertex source uses the built-in Pixi v8 filter vertex. Uniform values accept numbers, booleans, or numeric arrays; `time` and `uTime` are advanced in seconds every renderer update. Custom fragments should sample `uTexture` at `vTextureCoord`.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@combos-fun/plugin-renderer-filter",
|
|
3
|
+
"pluginId": "renderer-filter",
|
|
4
|
+
"category": "rendering",
|
|
5
|
+
"dimension": "2d",
|
|
6
|
+
"isCore": false,
|
|
7
|
+
"keywords": ["filter", "shader", "blur", "color-matrix", "2d"],
|
|
8
|
+
"agentSkill": "./agent-skill.md",
|
|
9
|
+
"requires": ["@combos-fun/engine", "@combos-fun/plugin-renderer"],
|
|
10
|
+
"exports": ["Filter", "FilterSystem"]
|
|
11
|
+
}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var tslib = require('tslib');
|
|
4
|
+
var engine = require('@combos-fun/engine');
|
|
5
|
+
var inspectorDecorator = require('@combos-fun/inspector-decorator');
|
|
6
|
+
var pluginRenderer = require('@combos-fun/plugin-renderer');
|
|
7
|
+
var pixi_js = require('pixi.js');
|
|
8
|
+
|
|
9
|
+
class Filter extends engine.Component {
|
|
10
|
+
constructor() {
|
|
11
|
+
super(...arguments);
|
|
12
|
+
this.enabled = true;
|
|
13
|
+
this.effects = [];
|
|
14
|
+
}
|
|
15
|
+
static { this.componentName = 'Filter'; }
|
|
16
|
+
init(obj) {
|
|
17
|
+
if (!obj)
|
|
18
|
+
return;
|
|
19
|
+
Object.assign(this, obj);
|
|
20
|
+
if (obj.effects)
|
|
21
|
+
this.effects = obj.effects;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
tslib.__decorate([
|
|
25
|
+
inspectorDecorator.Field({
|
|
26
|
+
type: 'boolean',
|
|
27
|
+
group: 'Filter',
|
|
28
|
+
label: 'enabled',
|
|
29
|
+
description: 'Apply effects to this GameObject.',
|
|
30
|
+
editor: 'toggle',
|
|
31
|
+
})
|
|
32
|
+
], Filter.prototype, "enabled", void 0);
|
|
33
|
+
|
|
34
|
+
async function loadShaderSource(name) {
|
|
35
|
+
const trimmed = String(name ?? '').trim();
|
|
36
|
+
if (!trimmed) {
|
|
37
|
+
throw new Error('SHADER resource name is required');
|
|
38
|
+
}
|
|
39
|
+
const res = await engine.resource.getResource(trimmed);
|
|
40
|
+
if (!res?.name) {
|
|
41
|
+
throw new Error(`Unknown resource "${trimmed}"; register RESOURCE_TYPE.SHADER first`);
|
|
42
|
+
}
|
|
43
|
+
const vertex = typeof res.data?.vertex === 'string'
|
|
44
|
+
? res.data.vertex
|
|
45
|
+
: typeof res.instance?.vertex === 'string' ? res.instance.vertex : '';
|
|
46
|
+
const fragment = typeof res.data?.fragment === 'string'
|
|
47
|
+
? res.data.fragment
|
|
48
|
+
: typeof res.instance?.fragment === 'string' ? res.instance.fragment : '';
|
|
49
|
+
if (!fragment) {
|
|
50
|
+
throw new Error(`SHADER "${trimmed}" missing fragment`);
|
|
51
|
+
}
|
|
52
|
+
return { vertex, fragment };
|
|
53
|
+
}
|
|
54
|
+
const DEFAULT_FILTER_VERTEX = `in vec2 aPosition;
|
|
55
|
+
out vec2 vTextureCoord;
|
|
56
|
+
|
|
57
|
+
uniform vec4 uInputSize;
|
|
58
|
+
uniform vec4 uOutputFrame;
|
|
59
|
+
uniform vec4 uOutputTexture;
|
|
60
|
+
|
|
61
|
+
vec4 filterVertexPosition(void) {
|
|
62
|
+
vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;
|
|
63
|
+
position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;
|
|
64
|
+
position.y = position.y * (2.0 * uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;
|
|
65
|
+
return vec4(position, 0.0, 1.0);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
vec2 filterTextureCoord(void) {
|
|
69
|
+
return aPosition * (uOutputFrame.zw * uInputSize.zw);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
void main(void) {
|
|
73
|
+
gl_Position = filterVertexPosition();
|
|
74
|
+
vTextureCoord = filterTextureCoord();
|
|
75
|
+
}
|
|
76
|
+
`;
|
|
77
|
+
function pixiUniformType(value) {
|
|
78
|
+
if (typeof value === 'boolean' || typeof value === 'number')
|
|
79
|
+
return 'f32';
|
|
80
|
+
const n = value.length;
|
|
81
|
+
if (n === 2)
|
|
82
|
+
return 'vec2<f32>';
|
|
83
|
+
if (n === 3)
|
|
84
|
+
return 'vec3<f32>';
|
|
85
|
+
if (n === 4)
|
|
86
|
+
return 'vec4<f32>';
|
|
87
|
+
if (n === 9)
|
|
88
|
+
return 'mat3x3<f32>';
|
|
89
|
+
if (n === 16)
|
|
90
|
+
return 'mat4x4<f32>';
|
|
91
|
+
return 'f32';
|
|
92
|
+
}
|
|
93
|
+
function pixiUniformValue(value) {
|
|
94
|
+
if (typeof value === 'boolean')
|
|
95
|
+
return value ? 1 : 0;
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let FilterSystem = class FilterSystem extends pluginRenderer.Renderer {
|
|
100
|
+
constructor() {
|
|
101
|
+
super(...arguments);
|
|
102
|
+
this.name = 'FilterSystem';
|
|
103
|
+
this.entries = new Map();
|
|
104
|
+
this.deltaSeconds = 1 / 60;
|
|
105
|
+
}
|
|
106
|
+
static { this.systemName = 'FilterSystem'; }
|
|
107
|
+
update(e) {
|
|
108
|
+
this.deltaSeconds = (e?.deltaTime ?? 16.67) / 1000;
|
|
109
|
+
super.update(e);
|
|
110
|
+
}
|
|
111
|
+
init() {
|
|
112
|
+
this.renderSystem = this.game.getSystem(pluginRenderer.RendererSystem);
|
|
113
|
+
this.renderSystem.rendererManager.register(this);
|
|
114
|
+
this.containerManager = this.renderSystem.containerManager;
|
|
115
|
+
}
|
|
116
|
+
componentChanged(changed) {
|
|
117
|
+
if (changed.componentName !== 'Filter')
|
|
118
|
+
return;
|
|
119
|
+
if (changed.type === engine.OBSERVER_TYPE.REMOVE) {
|
|
120
|
+
this.clear(changed.gameObject.id);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (changed.type === engine.OBSERVER_TYPE.CHANGE && changed.prop?.prop?.[0] === 'enabled') {
|
|
124
|
+
this.applyEnabled(changed.gameObject, changed.component);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
this.mount(changed.gameObject, changed.component);
|
|
128
|
+
}
|
|
129
|
+
rendererUpdate(gameObject) {
|
|
130
|
+
const component = gameObject.getComponent(Filter);
|
|
131
|
+
if (!component?.enabled)
|
|
132
|
+
return;
|
|
133
|
+
const entry = this.entries.get(gameObject.id);
|
|
134
|
+
if (!entry?.shaderUniforms.length)
|
|
135
|
+
return;
|
|
136
|
+
entry.time += this.deltaSeconds;
|
|
137
|
+
for (const { filter, keys } of entry.shaderUniforms) {
|
|
138
|
+
const group = filter.resources?.combosUniforms;
|
|
139
|
+
if (!group?.uniforms)
|
|
140
|
+
continue;
|
|
141
|
+
for (const key of keys) {
|
|
142
|
+
if (key === 'time' || key === 'uTime') {
|
|
143
|
+
group.uniforms[key] = entry.time;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
applyEnabled(gameObject, component) {
|
|
149
|
+
const container = this.containerManager.getContainer(gameObject.id);
|
|
150
|
+
if (!container)
|
|
151
|
+
return;
|
|
152
|
+
const entry = this.entries.get(gameObject.id);
|
|
153
|
+
container.filters = component.enabled && entry ? entry.filters : [];
|
|
154
|
+
}
|
|
155
|
+
async mount(gameObject, component) {
|
|
156
|
+
const asyncId = this.increaseAsyncId(gameObject.id);
|
|
157
|
+
const built = await this.buildFilters(component.effects || []);
|
|
158
|
+
if (!this.validateAsyncId(gameObject.id, asyncId)) {
|
|
159
|
+
this.destroyFilters(built.filters);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
this.clear(gameObject.id, false);
|
|
163
|
+
this.entries.set(gameObject.id, { ...built, time: 0 });
|
|
164
|
+
this.applyEnabled(gameObject, component);
|
|
165
|
+
}
|
|
166
|
+
async buildFilters(effects) {
|
|
167
|
+
const filters = [];
|
|
168
|
+
const shaderUniforms = [];
|
|
169
|
+
for (const effect of effects) {
|
|
170
|
+
const type = effect.type || 'blur';
|
|
171
|
+
if (type === 'blur') {
|
|
172
|
+
filters.push(new pixi_js.BlurFilter({
|
|
173
|
+
strength: effect.strength ?? 8,
|
|
174
|
+
quality: effect.quality ?? 4,
|
|
175
|
+
}));
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (type === 'colorMatrix') {
|
|
179
|
+
const matrix = new pixi_js.ColorMatrixFilter();
|
|
180
|
+
if (effect.brightness != null)
|
|
181
|
+
matrix.brightness(effect.brightness, false);
|
|
182
|
+
if (effect.contrast != null)
|
|
183
|
+
matrix.contrast(effect.contrast, true);
|
|
184
|
+
if (effect.saturate != null)
|
|
185
|
+
matrix.saturate(effect.saturate, true);
|
|
186
|
+
if (effect.hue != null)
|
|
187
|
+
matrix.hue(effect.hue, true);
|
|
188
|
+
if (effect.grayscale)
|
|
189
|
+
matrix.greyscale(0.33, true);
|
|
190
|
+
filters.push(matrix);
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
if (type === 'noise') {
|
|
194
|
+
filters.push(new pixi_js.NoiseFilter({
|
|
195
|
+
noise: effect.noise ?? 0.5,
|
|
196
|
+
seed: effect.seed,
|
|
197
|
+
}));
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (type === 'displacement') {
|
|
201
|
+
filters.push(await this.createDisplacement(effect));
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (type === 'shader') {
|
|
205
|
+
const { filter, keys } = await this.createShader(effect);
|
|
206
|
+
filters.push(filter);
|
|
207
|
+
if (keys.length)
|
|
208
|
+
shaderUniforms.push({ filter, keys });
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
throw new Error(`Unknown Filter effect type: ${type}`);
|
|
212
|
+
}
|
|
213
|
+
return { filters, shaderUniforms };
|
|
214
|
+
}
|
|
215
|
+
async createDisplacement(effect) {
|
|
216
|
+
const mapName = String(effect.map ?? '').trim();
|
|
217
|
+
if (!mapName) {
|
|
218
|
+
throw new Error('displacement Filter requires map (IMAGE resource name)');
|
|
219
|
+
}
|
|
220
|
+
const res = await engine.resource.getResource(mapName);
|
|
221
|
+
const image = res?.data?.image;
|
|
222
|
+
if (!image) {
|
|
223
|
+
throw new Error(`displacement map "${mapName}" has no image data`);
|
|
224
|
+
}
|
|
225
|
+
const sprite = new pixi_js.Sprite(pixi_js.Texture.from(image));
|
|
226
|
+
return new pixi_js.DisplacementFilter({
|
|
227
|
+
sprite,
|
|
228
|
+
scale: effect.scale ?? 20,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
async createShader(effect) {
|
|
232
|
+
const source = await loadShaderSource(effect.resource || '');
|
|
233
|
+
const uniforms = effect.uniforms || {};
|
|
234
|
+
const keys = Object.keys(uniforms);
|
|
235
|
+
const resources = {};
|
|
236
|
+
if (keys.length) {
|
|
237
|
+
const group = {};
|
|
238
|
+
for (const [key, raw] of Object.entries(uniforms)) {
|
|
239
|
+
group[key] = {
|
|
240
|
+
value: pixiUniformValue(raw),
|
|
241
|
+
type: pixiUniformType(raw),
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
resources.combosUniforms = group;
|
|
245
|
+
}
|
|
246
|
+
const filter = pixi_js.Filter.from({
|
|
247
|
+
gl: {
|
|
248
|
+
vertex: source.vertex || DEFAULT_FILTER_VERTEX,
|
|
249
|
+
fragment: source.fragment,
|
|
250
|
+
},
|
|
251
|
+
resources,
|
|
252
|
+
});
|
|
253
|
+
return { filter, keys };
|
|
254
|
+
}
|
|
255
|
+
clear(id, resetContainer = true) {
|
|
256
|
+
const entry = this.entries.get(id);
|
|
257
|
+
if (entry) {
|
|
258
|
+
this.destroyFilters(entry.filters);
|
|
259
|
+
this.entries.delete(id);
|
|
260
|
+
}
|
|
261
|
+
if (resetContainer) {
|
|
262
|
+
const container = this.containerManager.getContainer(id);
|
|
263
|
+
if (container)
|
|
264
|
+
container.filters = [];
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
destroyFilters(filters) {
|
|
268
|
+
for (const filter of filters) {
|
|
269
|
+
filter.destroy?.();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
onDestroy() {
|
|
273
|
+
for (const id of [...this.entries.keys()]) {
|
|
274
|
+
this.clear(id);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
FilterSystem = tslib.__decorate([
|
|
279
|
+
engine.decorators.componentObserver({
|
|
280
|
+
Filter: ['enabled', { prop: ['effects'], deep: true }],
|
|
281
|
+
})
|
|
282
|
+
], FilterSystem);
|
|
283
|
+
var FilterSystem_default = FilterSystem;
|
|
284
|
+
|
|
285
|
+
exports.Filter = Filter;
|
|
286
|
+
exports.FilterSystem = FilterSystem_default;
|
|
287
|
+
//# sourceMappingURL=plugin-renderer-filter.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-renderer-filter.cjs.js","sources":["../lib/component.ts","../lib/shaderSource.ts","../lib/system.ts"],"sourcesContent":["import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\n\nexport type FilterEffectType = 'blur' | 'colorMatrix' | 'noise' | 'displacement' | 'shader';\n\nexport type FilterUniformValue = number | boolean | number[];\n\nexport interface FilterEffectParams {\n type?: FilterEffectType | string;\n strength?: number;\n quality?: number;\n brightness?: number;\n contrast?: number;\n saturate?: number;\n hue?: number;\n grayscale?: boolean;\n noise?: number;\n seed?: number;\n map?: string;\n scale?: number;\n resource?: string;\n uniforms?: Record<string, FilterUniformValue>;\n}\n\nexport interface FilterParams {\n enabled?: boolean;\n effects?: FilterEffectParams[];\n}\n\nexport default class Filter extends Component<FilterParams> {\n static componentName: string = 'Filter';\n\n @Field({\n type: 'boolean',\n group: 'Filter',\n label: 'enabled',\n description: 'Apply effects to this GameObject.',\n editor: 'toggle',\n })\n enabled: boolean = true;\n\n effects: FilterEffectParams[] = [];\n\n init(obj?: FilterParams) {\n if (!obj) return;\n Object.assign(this, obj);\n if (obj.effects) this.effects = obj.effects;\n }\n}\n","import { resource } from '@combos-fun/engine';\n\nexport async function loadShaderSource(name: string): Promise<{ vertex: string; fragment: string }> {\n const trimmed = String(name ?? '').trim();\n if (!trimmed) {\n throw new Error('SHADER resource name is required');\n }\n const res = await resource.getResource(trimmed);\n if (!res?.name) {\n throw new Error(`Unknown resource \"${trimmed}\"; register RESOURCE_TYPE.SHADER first`);\n }\n const vertex = typeof res.data?.vertex === 'string'\n ? res.data.vertex\n : typeof res.instance?.vertex === 'string' ? res.instance.vertex : '';\n const fragment = typeof res.data?.fragment === 'string'\n ? res.data.fragment\n : typeof res.instance?.fragment === 'string' ? res.instance.fragment : '';\n if (!fragment) {\n throw new Error(`SHADER \"${trimmed}\" missing fragment`);\n }\n return { vertex, fragment };\n}\n\nexport const DEFAULT_FILTER_VERTEX = `in vec2 aPosition;\nout vec2 vTextureCoord;\n\nuniform vec4 uInputSize;\nuniform vec4 uOutputFrame;\nuniform vec4 uOutputTexture;\n\nvec4 filterVertexPosition(void) {\n vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;\n position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0 * uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;\n return vec4(position, 0.0, 1.0);\n}\n\nvec2 filterTextureCoord(void) {\n return aPosition * (uOutputFrame.zw * uInputSize.zw);\n}\n\nvoid main(void) {\n gl_Position = filterVertexPosition();\n vTextureCoord = filterTextureCoord();\n}\n`;\n\nexport function pixiUniformType(value: number | boolean | number[]): string {\n if (typeof value === 'boolean' || typeof value === 'number') return 'f32';\n const n = value.length;\n if (n === 2) return 'vec2<f32>';\n if (n === 3) return 'vec3<f32>';\n if (n === 4) return 'vec4<f32>';\n if (n === 9) return 'mat3x3<f32>';\n if (n === 16) return 'mat4x4<f32>';\n return 'f32';\n}\n\nexport function pixiUniformValue(value: number | boolean | number[]): number | number[] {\n if (typeof value === 'boolean') return value ? 1 : 0;\n return value;\n}\n","import { decorators, resource, ComponentChanged, OBSERVER_TYPE, GameObject, UpdateParams } from '@combos-fun/engine';\nimport { Renderer, RendererManager, ContainerManager, RendererSystem } from '@combos-fun/plugin-renderer';\nimport {\n Filter as PixiFilter,\n BlurFilter,\n ColorMatrixFilter,\n NoiseFilter,\n DisplacementFilter,\n Sprite,\n Texture,\n} from 'pixi.js';\nimport FilterComponent from './component';\nimport type { FilterEffectParams, FilterUniformValue } from './component';\nimport {\n DEFAULT_FILTER_VERTEX,\n loadShaderSource,\n pixiUniformType,\n pixiUniformValue,\n} from './shaderSource';\n\ninterface FilterEntry {\n filters: PixiFilter[];\n shaderUniforms: Array<{ filter: PixiFilter; keys: string[] }>;\n time: number;\n}\n\n@decorators.componentObserver({\n Filter: ['enabled', { prop: ['effects'], deep: true }],\n})\nexport default class FilterSystem extends Renderer {\n static systemName = 'FilterSystem';\n name: string = 'FilterSystem';\n renderSystem: RendererSystem;\n rendererManager: RendererManager;\n containerManager: ContainerManager;\n private entries: Map<number, FilterEntry> = new Map();\n private deltaSeconds = 1 / 60;\n\n override update(e?: UpdateParams) {\n this.deltaSeconds = (e?.deltaTime ?? 16.67) / 1000;\n super.update(e);\n }\n\n init() {\n this.renderSystem = this.game.getSystem(RendererSystem) as RendererSystem;\n this.renderSystem.rendererManager.register(this);\n this.containerManager = this.renderSystem.containerManager;\n }\n\n componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Filter') return;\n if (changed.type === OBSERVER_TYPE.REMOVE) {\n this.clear(changed.gameObject.id);\n return;\n }\n if (changed.type === OBSERVER_TYPE.CHANGE && changed.prop?.prop?.[0] === 'enabled') {\n this.applyEnabled(changed.gameObject, changed.component as FilterComponent);\n return;\n }\n this.mount(changed.gameObject, changed.component as FilterComponent);\n }\n\n rendererUpdate(gameObject: GameObject) {\n const component = gameObject.getComponent(FilterComponent) as FilterComponent;\n if (!component?.enabled) return;\n const entry = this.entries.get(gameObject.id);\n if (!entry?.shaderUniforms.length) return;\n entry.time += this.deltaSeconds;\n for (const { filter, keys } of entry.shaderUniforms) {\n const group = filter.resources?.combosUniforms;\n if (!group?.uniforms) continue;\n for (const key of keys) {\n if (key === 'time' || key === 'uTime') {\n group.uniforms[key] = entry.time;\n }\n }\n }\n }\n\n private applyEnabled(gameObject: GameObject, component: FilterComponent) {\n const container = this.containerManager.getContainer(gameObject.id);\n if (!container) return;\n const entry = this.entries.get(gameObject.id);\n container.filters = component.enabled && entry ? entry.filters : [];\n }\n\n private async mount(gameObject: GameObject, component: FilterComponent) {\n const asyncId = this.increaseAsyncId(gameObject.id);\n const built = await this.buildFilters(component.effects || []);\n if (!this.validateAsyncId(gameObject.id, asyncId)) {\n this.destroyFilters(built.filters);\n return;\n }\n this.clear(gameObject.id, false);\n this.entries.set(gameObject.id, { ...built, time: 0 });\n this.applyEnabled(gameObject, component);\n }\n\n private async buildFilters(effects: FilterEffectParams[]): Promise<Omit<FilterEntry, 'time'>> {\n const filters: PixiFilter[] = [];\n const shaderUniforms: FilterEntry['shaderUniforms'] = [];\n for (const effect of effects) {\n const type = effect.type || 'blur';\n if (type === 'blur') {\n filters.push(new BlurFilter({\n strength: effect.strength ?? 8,\n quality: effect.quality ?? 4,\n }));\n continue;\n }\n if (type === 'colorMatrix') {\n const matrix = new ColorMatrixFilter();\n if (effect.brightness != null) matrix.brightness(effect.brightness, false);\n if (effect.contrast != null) matrix.contrast(effect.contrast, true);\n if (effect.saturate != null) matrix.saturate(effect.saturate, true);\n if (effect.hue != null) matrix.hue(effect.hue, true);\n if (effect.grayscale) matrix.greyscale(0.33, true);\n filters.push(matrix);\n continue;\n }\n if (type === 'noise') {\n filters.push(new NoiseFilter({\n noise: effect.noise ?? 0.5,\n seed: effect.seed,\n }));\n continue;\n }\n if (type === 'displacement') {\n filters.push(await this.createDisplacement(effect));\n continue;\n }\n if (type === 'shader') {\n const { filter, keys } = await this.createShader(effect);\n filters.push(filter);\n if (keys.length) shaderUniforms.push({ filter, keys });\n continue;\n }\n throw new Error(`Unknown Filter effect type: ${type}`);\n }\n return { filters, shaderUniforms };\n }\n\n private async createDisplacement(effect: FilterEffectParams): Promise<DisplacementFilter> {\n const mapName = String(effect.map ?? '').trim();\n if (!mapName) {\n throw new Error('displacement Filter requires map (IMAGE resource name)');\n }\n const res = await resource.getResource(mapName);\n const image = res?.data?.image as HTMLImageElement | undefined;\n if (!image) {\n throw new Error(`displacement map \"${mapName}\" has no image data`);\n }\n const sprite = new Sprite(Texture.from(image));\n return new DisplacementFilter({\n sprite,\n scale: effect.scale ?? 20,\n });\n }\n\n private async createShader(effect: FilterEffectParams): Promise<{ filter: PixiFilter; keys: string[] }> {\n const source = await loadShaderSource(effect.resource || '');\n const uniforms = effect.uniforms || {};\n const keys = Object.keys(uniforms);\n const resources: Record<string, Record<string, { value: number | number[]; type: string }>> = {};\n if (keys.length) {\n const group: Record<string, { value: number | number[]; type: string }> = {};\n for (const [key, raw] of Object.entries(uniforms)) {\n group[key] = {\n value: pixiUniformValue(raw as FilterUniformValue),\n type: pixiUniformType(raw as FilterUniformValue),\n };\n }\n resources.combosUniforms = group;\n }\n const filter = PixiFilter.from({\n gl: {\n vertex: source.vertex || DEFAULT_FILTER_VERTEX,\n fragment: source.fragment,\n },\n resources,\n });\n return { filter, keys };\n }\n\n private clear(id: number, resetContainer = true) {\n const entry = this.entries.get(id);\n if (entry) {\n this.destroyFilters(entry.filters);\n this.entries.delete(id);\n }\n if (resetContainer) {\n const container = this.containerManager.getContainer(id);\n if (container) container.filters = [];\n }\n }\n\n private destroyFilters(filters: PixiFilter[]) {\n for (const filter of filters) {\n filter.destroy?.();\n }\n }\n\n onDestroy() {\n for (const id of [...this.entries.keys()]) {\n this.clear(id);\n }\n }\n}\n"],"names":["Component","__decorate","Field","resource","Renderer","RendererSystem","OBSERVER_TYPE","FilterComponent","BlurFilter","ColorMatrixFilter","NoiseFilter","Sprite","Texture","DisplacementFilter","PixiFilter","decorators"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var e=require("tslib"),t=require("@combos-fun/engine"),r=require("@combos-fun/inspector-decorator"),n=require("@combos-fun/plugin-renderer"),s=require("pixi.js");class i extends t.Component{constructor(){super(...arguments),this.enabled=!0,this.effects=[]}static{this.componentName="Filter"}init(e){e&&(Object.assign(this,e),e.effects&&(this.effects=e.effects))}}e.__decorate([r.Field({type:"boolean",group:"Filter",label:"enabled",description:"Apply effects to this GameObject.",editor:"toggle"})],i.prototype,"enabled",void 0);function o(e){if("boolean"==typeof e||"number"==typeof e)return"f32";const t=e.length;return 2===t?"vec2<f32>":3===t?"vec3<f32>":4===t?"vec4<f32>":9===t?"mat3x3<f32>":16===t?"mat4x4<f32>":"f32"}function a(e){return"boolean"==typeof e?e?1:0:e}let c=class extends n.Renderer{constructor(){super(...arguments),this.name="FilterSystem",this.entries=new Map,this.deltaSeconds=1/60}static{this.systemName="FilterSystem"}update(e){this.deltaSeconds=(e?.deltaTime??16.67)/1e3,super.update(e)}init(){this.renderSystem=this.game.getSystem(n.RendererSystem),this.renderSystem.rendererManager.register(this),this.containerManager=this.renderSystem.containerManager}componentChanged(e){"Filter"===e.componentName&&(e.type!==t.OBSERVER_TYPE.REMOVE?e.type!==t.OBSERVER_TYPE.CHANGE||"enabled"!==e.prop?.prop?.[0]?this.mount(e.gameObject,e.component):this.applyEnabled(e.gameObject,e.component):this.clear(e.gameObject.id))}rendererUpdate(e){const t=e.getComponent(i);if(!t?.enabled)return;const r=this.entries.get(e.id);if(r?.shaderUniforms.length){r.time+=this.deltaSeconds;for(const{filter:e,keys:t}of r.shaderUniforms){const n=e.resources?.combosUniforms;if(n?.uniforms)for(const e of t)"time"!==e&&"uTime"!==e||(n.uniforms[e]=r.time)}}}applyEnabled(e,t){const r=this.containerManager.getContainer(e.id);if(!r)return;const n=this.entries.get(e.id);r.filters=t.enabled&&n?n.filters:[]}async mount(e,t){const r=this.increaseAsyncId(e.id),n=await this.buildFilters(t.effects||[]);this.validateAsyncId(e.id,r)?(this.clear(e.id,!1),this.entries.set(e.id,{...n,time:0}),this.applyEnabled(e,t)):this.destroyFilters(n.filters)}async buildFilters(e){const t=[],r=[];for(const n of e){const e=n.type||"blur";if("blur"!==e){if("colorMatrix"===e){const e=new s.ColorMatrixFilter;null!=n.brightness&&e.brightness(n.brightness,!1),null!=n.contrast&&e.contrast(n.contrast,!0),null!=n.saturate&&e.saturate(n.saturate,!0),null!=n.hue&&e.hue(n.hue,!0),n.grayscale&&e.greyscale(.33,!0),t.push(e);continue}if("noise"!==e){if("displacement"!==e){if("shader"===e){const{filter:e,keys:s}=await this.createShader(n);t.push(e),s.length&&r.push({filter:e,keys:s});continue}throw new Error(`Unknown Filter effect type: ${e}`)}t.push(await this.createDisplacement(n))}else t.push(new s.NoiseFilter({noise:n.noise??.5,seed:n.seed}))}else t.push(new s.BlurFilter({strength:n.strength??8,quality:n.quality??4}))}return{filters:t,shaderUniforms:r}}async createDisplacement(e){const r=String(e.map??"").trim();if(!r)throw new Error("displacement Filter requires map (IMAGE resource name)");const n=await t.resource.getResource(r),i=n?.data?.image;if(!i)throw new Error(`displacement map "${r}" has no image data`);const o=new s.Sprite(s.Texture.from(i));return new s.DisplacementFilter({sprite:o,scale:e.scale??20})}async createShader(e){const r=await async function(e){const r=String(e??"").trim();if(!r)throw new Error("SHADER resource name is required");const n=await t.resource.getResource(r);if(!n?.name)throw new Error(`Unknown resource "${r}"; register RESOURCE_TYPE.SHADER first`);const s="string"==typeof n.data?.vertex?n.data.vertex:"string"==typeof n.instance?.vertex?n.instance.vertex:"",i="string"==typeof n.data?.fragment?n.data.fragment:"string"==typeof n.instance?.fragment?n.instance.fragment:"";if(!i)throw new Error(`SHADER "${r}" missing fragment`);return{vertex:s,fragment:i}}(e.resource||""),n=e.uniforms||{},i=Object.keys(n),c={};if(i.length){const e={};for(const[t,r]of Object.entries(n))e[t]={value:a(r),type:o(r)};c.combosUniforms=e}return{filter:s.Filter.from({gl:{vertex:r.vertex||"in vec2 aPosition;\nout vec2 vTextureCoord;\n\nuniform vec4 uInputSize;\nuniform vec4 uOutputFrame;\nuniform vec4 uOutputTexture;\n\nvec4 filterVertexPosition(void) {\n vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;\n position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0 * uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;\n return vec4(position, 0.0, 1.0);\n}\n\nvec2 filterTextureCoord(void) {\n return aPosition * (uOutputFrame.zw * uInputSize.zw);\n}\n\nvoid main(void) {\n gl_Position = filterVertexPosition();\n vTextureCoord = filterTextureCoord();\n}\n",fragment:r.fragment},resources:c}),keys:i}}clear(e,t=!0){const r=this.entries.get(e);if(r&&(this.destroyFilters(r.filters),this.entries.delete(e)),t){const t=this.containerManager.getContainer(e);t&&(t.filters=[])}}destroyFilters(e){for(const t of e)t.destroy?.()}onDestroy(){for(const e of[...this.entries.keys()])this.clear(e)}};c=e.__decorate([t.decorators.componentObserver({Filter:["enabled",{prop:["effects"],deep:!0}]})],c);var u=c;exports.Filter=i,exports.FilterSystem=u;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Component, UpdateParams, ComponentChanged, GameObject } from '@combos-fun/engine';
|
|
2
|
+
import { Renderer, RendererSystem, RendererManager, ContainerManager } from '@combos-fun/plugin-renderer';
|
|
3
|
+
|
|
4
|
+
type FilterEffectType = 'blur' | 'colorMatrix' | 'noise' | 'displacement' | 'shader';
|
|
5
|
+
type FilterUniformValue = number | boolean | number[];
|
|
6
|
+
interface FilterEffectParams {
|
|
7
|
+
type?: FilterEffectType | string;
|
|
8
|
+
strength?: number;
|
|
9
|
+
quality?: number;
|
|
10
|
+
brightness?: number;
|
|
11
|
+
contrast?: number;
|
|
12
|
+
saturate?: number;
|
|
13
|
+
hue?: number;
|
|
14
|
+
grayscale?: boolean;
|
|
15
|
+
noise?: number;
|
|
16
|
+
seed?: number;
|
|
17
|
+
map?: string;
|
|
18
|
+
scale?: number;
|
|
19
|
+
resource?: string;
|
|
20
|
+
uniforms?: Record<string, FilterUniformValue>;
|
|
21
|
+
}
|
|
22
|
+
interface FilterParams {
|
|
23
|
+
enabled?: boolean;
|
|
24
|
+
effects?: FilterEffectParams[];
|
|
25
|
+
}
|
|
26
|
+
declare class Filter extends Component<FilterParams> {
|
|
27
|
+
static componentName: string;
|
|
28
|
+
enabled: boolean;
|
|
29
|
+
effects: FilterEffectParams[];
|
|
30
|
+
init(obj?: FilterParams): void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
declare class FilterSystem extends Renderer {
|
|
34
|
+
static systemName: string;
|
|
35
|
+
name: string;
|
|
36
|
+
renderSystem: RendererSystem;
|
|
37
|
+
rendererManager: RendererManager;
|
|
38
|
+
containerManager: ContainerManager;
|
|
39
|
+
private entries;
|
|
40
|
+
private deltaSeconds;
|
|
41
|
+
update(e?: UpdateParams): void;
|
|
42
|
+
init(): void;
|
|
43
|
+
componentChanged(changed: ComponentChanged): void;
|
|
44
|
+
rendererUpdate(gameObject: GameObject): void;
|
|
45
|
+
private applyEnabled;
|
|
46
|
+
private mount;
|
|
47
|
+
private buildFilters;
|
|
48
|
+
private createDisplacement;
|
|
49
|
+
private createShader;
|
|
50
|
+
private clear;
|
|
51
|
+
private destroyFilters;
|
|
52
|
+
onDestroy(): void;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { Filter, FilterSystem };
|
|
56
|
+
export type { FilterEffectParams, FilterEffectType, FilterParams, FilterUniformValue };
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { __decorate } from 'tslib';
|
|
2
|
+
import { Component, resource, OBSERVER_TYPE, decorators } from '@combos-fun/engine';
|
|
3
|
+
import { Field } from '@combos-fun/inspector-decorator';
|
|
4
|
+
import { Renderer, RendererSystem } from '@combos-fun/plugin-renderer';
|
|
5
|
+
import { BlurFilter, ColorMatrixFilter, NoiseFilter, Sprite, Texture, DisplacementFilter, Filter as Filter$1 } from 'pixi.js';
|
|
6
|
+
|
|
7
|
+
class Filter extends Component {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(...arguments);
|
|
10
|
+
this.enabled = true;
|
|
11
|
+
this.effects = [];
|
|
12
|
+
}
|
|
13
|
+
static { this.componentName = 'Filter'; }
|
|
14
|
+
init(obj) {
|
|
15
|
+
if (!obj)
|
|
16
|
+
return;
|
|
17
|
+
Object.assign(this, obj);
|
|
18
|
+
if (obj.effects)
|
|
19
|
+
this.effects = obj.effects;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
__decorate([
|
|
23
|
+
Field({
|
|
24
|
+
type: 'boolean',
|
|
25
|
+
group: 'Filter',
|
|
26
|
+
label: 'enabled',
|
|
27
|
+
description: 'Apply effects to this GameObject.',
|
|
28
|
+
editor: 'toggle',
|
|
29
|
+
})
|
|
30
|
+
], Filter.prototype, "enabled", void 0);
|
|
31
|
+
|
|
32
|
+
async function loadShaderSource(name) {
|
|
33
|
+
const trimmed = String(name ?? '').trim();
|
|
34
|
+
if (!trimmed) {
|
|
35
|
+
throw new Error('SHADER resource name is required');
|
|
36
|
+
}
|
|
37
|
+
const res = await resource.getResource(trimmed);
|
|
38
|
+
if (!res?.name) {
|
|
39
|
+
throw new Error(`Unknown resource "${trimmed}"; register RESOURCE_TYPE.SHADER first`);
|
|
40
|
+
}
|
|
41
|
+
const vertex = typeof res.data?.vertex === 'string'
|
|
42
|
+
? res.data.vertex
|
|
43
|
+
: typeof res.instance?.vertex === 'string' ? res.instance.vertex : '';
|
|
44
|
+
const fragment = typeof res.data?.fragment === 'string'
|
|
45
|
+
? res.data.fragment
|
|
46
|
+
: typeof res.instance?.fragment === 'string' ? res.instance.fragment : '';
|
|
47
|
+
if (!fragment) {
|
|
48
|
+
throw new Error(`SHADER "${trimmed}" missing fragment`);
|
|
49
|
+
}
|
|
50
|
+
return { vertex, fragment };
|
|
51
|
+
}
|
|
52
|
+
const DEFAULT_FILTER_VERTEX = `in vec2 aPosition;
|
|
53
|
+
out vec2 vTextureCoord;
|
|
54
|
+
|
|
55
|
+
uniform vec4 uInputSize;
|
|
56
|
+
uniform vec4 uOutputFrame;
|
|
57
|
+
uniform vec4 uOutputTexture;
|
|
58
|
+
|
|
59
|
+
vec4 filterVertexPosition(void) {
|
|
60
|
+
vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;
|
|
61
|
+
position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;
|
|
62
|
+
position.y = position.y * (2.0 * uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;
|
|
63
|
+
return vec4(position, 0.0, 1.0);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
vec2 filterTextureCoord(void) {
|
|
67
|
+
return aPosition * (uOutputFrame.zw * uInputSize.zw);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
void main(void) {
|
|
71
|
+
gl_Position = filterVertexPosition();
|
|
72
|
+
vTextureCoord = filterTextureCoord();
|
|
73
|
+
}
|
|
74
|
+
`;
|
|
75
|
+
function pixiUniformType(value) {
|
|
76
|
+
if (typeof value === 'boolean' || typeof value === 'number')
|
|
77
|
+
return 'f32';
|
|
78
|
+
const n = value.length;
|
|
79
|
+
if (n === 2)
|
|
80
|
+
return 'vec2<f32>';
|
|
81
|
+
if (n === 3)
|
|
82
|
+
return 'vec3<f32>';
|
|
83
|
+
if (n === 4)
|
|
84
|
+
return 'vec4<f32>';
|
|
85
|
+
if (n === 9)
|
|
86
|
+
return 'mat3x3<f32>';
|
|
87
|
+
if (n === 16)
|
|
88
|
+
return 'mat4x4<f32>';
|
|
89
|
+
return 'f32';
|
|
90
|
+
}
|
|
91
|
+
function pixiUniformValue(value) {
|
|
92
|
+
if (typeof value === 'boolean')
|
|
93
|
+
return value ? 1 : 0;
|
|
94
|
+
return value;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let FilterSystem = class FilterSystem extends Renderer {
|
|
98
|
+
constructor() {
|
|
99
|
+
super(...arguments);
|
|
100
|
+
this.name = 'FilterSystem';
|
|
101
|
+
this.entries = new Map();
|
|
102
|
+
this.deltaSeconds = 1 / 60;
|
|
103
|
+
}
|
|
104
|
+
static { this.systemName = 'FilterSystem'; }
|
|
105
|
+
update(e) {
|
|
106
|
+
this.deltaSeconds = (e?.deltaTime ?? 16.67) / 1000;
|
|
107
|
+
super.update(e);
|
|
108
|
+
}
|
|
109
|
+
init() {
|
|
110
|
+
this.renderSystem = this.game.getSystem(RendererSystem);
|
|
111
|
+
this.renderSystem.rendererManager.register(this);
|
|
112
|
+
this.containerManager = this.renderSystem.containerManager;
|
|
113
|
+
}
|
|
114
|
+
componentChanged(changed) {
|
|
115
|
+
if (changed.componentName !== 'Filter')
|
|
116
|
+
return;
|
|
117
|
+
if (changed.type === OBSERVER_TYPE.REMOVE) {
|
|
118
|
+
this.clear(changed.gameObject.id);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (changed.type === OBSERVER_TYPE.CHANGE && changed.prop?.prop?.[0] === 'enabled') {
|
|
122
|
+
this.applyEnabled(changed.gameObject, changed.component);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
this.mount(changed.gameObject, changed.component);
|
|
126
|
+
}
|
|
127
|
+
rendererUpdate(gameObject) {
|
|
128
|
+
const component = gameObject.getComponent(Filter);
|
|
129
|
+
if (!component?.enabled)
|
|
130
|
+
return;
|
|
131
|
+
const entry = this.entries.get(gameObject.id);
|
|
132
|
+
if (!entry?.shaderUniforms.length)
|
|
133
|
+
return;
|
|
134
|
+
entry.time += this.deltaSeconds;
|
|
135
|
+
for (const { filter, keys } of entry.shaderUniforms) {
|
|
136
|
+
const group = filter.resources?.combosUniforms;
|
|
137
|
+
if (!group?.uniforms)
|
|
138
|
+
continue;
|
|
139
|
+
for (const key of keys) {
|
|
140
|
+
if (key === 'time' || key === 'uTime') {
|
|
141
|
+
group.uniforms[key] = entry.time;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
applyEnabled(gameObject, component) {
|
|
147
|
+
const container = this.containerManager.getContainer(gameObject.id);
|
|
148
|
+
if (!container)
|
|
149
|
+
return;
|
|
150
|
+
const entry = this.entries.get(gameObject.id);
|
|
151
|
+
container.filters = component.enabled && entry ? entry.filters : [];
|
|
152
|
+
}
|
|
153
|
+
async mount(gameObject, component) {
|
|
154
|
+
const asyncId = this.increaseAsyncId(gameObject.id);
|
|
155
|
+
const built = await this.buildFilters(component.effects || []);
|
|
156
|
+
if (!this.validateAsyncId(gameObject.id, asyncId)) {
|
|
157
|
+
this.destroyFilters(built.filters);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
this.clear(gameObject.id, false);
|
|
161
|
+
this.entries.set(gameObject.id, { ...built, time: 0 });
|
|
162
|
+
this.applyEnabled(gameObject, component);
|
|
163
|
+
}
|
|
164
|
+
async buildFilters(effects) {
|
|
165
|
+
const filters = [];
|
|
166
|
+
const shaderUniforms = [];
|
|
167
|
+
for (const effect of effects) {
|
|
168
|
+
const type = effect.type || 'blur';
|
|
169
|
+
if (type === 'blur') {
|
|
170
|
+
filters.push(new BlurFilter({
|
|
171
|
+
strength: effect.strength ?? 8,
|
|
172
|
+
quality: effect.quality ?? 4,
|
|
173
|
+
}));
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (type === 'colorMatrix') {
|
|
177
|
+
const matrix = new ColorMatrixFilter();
|
|
178
|
+
if (effect.brightness != null)
|
|
179
|
+
matrix.brightness(effect.brightness, false);
|
|
180
|
+
if (effect.contrast != null)
|
|
181
|
+
matrix.contrast(effect.contrast, true);
|
|
182
|
+
if (effect.saturate != null)
|
|
183
|
+
matrix.saturate(effect.saturate, true);
|
|
184
|
+
if (effect.hue != null)
|
|
185
|
+
matrix.hue(effect.hue, true);
|
|
186
|
+
if (effect.grayscale)
|
|
187
|
+
matrix.greyscale(0.33, true);
|
|
188
|
+
filters.push(matrix);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (type === 'noise') {
|
|
192
|
+
filters.push(new NoiseFilter({
|
|
193
|
+
noise: effect.noise ?? 0.5,
|
|
194
|
+
seed: effect.seed,
|
|
195
|
+
}));
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (type === 'displacement') {
|
|
199
|
+
filters.push(await this.createDisplacement(effect));
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (type === 'shader') {
|
|
203
|
+
const { filter, keys } = await this.createShader(effect);
|
|
204
|
+
filters.push(filter);
|
|
205
|
+
if (keys.length)
|
|
206
|
+
shaderUniforms.push({ filter, keys });
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
throw new Error(`Unknown Filter effect type: ${type}`);
|
|
210
|
+
}
|
|
211
|
+
return { filters, shaderUniforms };
|
|
212
|
+
}
|
|
213
|
+
async createDisplacement(effect) {
|
|
214
|
+
const mapName = String(effect.map ?? '').trim();
|
|
215
|
+
if (!mapName) {
|
|
216
|
+
throw new Error('displacement Filter requires map (IMAGE resource name)');
|
|
217
|
+
}
|
|
218
|
+
const res = await resource.getResource(mapName);
|
|
219
|
+
const image = res?.data?.image;
|
|
220
|
+
if (!image) {
|
|
221
|
+
throw new Error(`displacement map "${mapName}" has no image data`);
|
|
222
|
+
}
|
|
223
|
+
const sprite = new Sprite(Texture.from(image));
|
|
224
|
+
return new DisplacementFilter({
|
|
225
|
+
sprite,
|
|
226
|
+
scale: effect.scale ?? 20,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
async createShader(effect) {
|
|
230
|
+
const source = await loadShaderSource(effect.resource || '');
|
|
231
|
+
const uniforms = effect.uniforms || {};
|
|
232
|
+
const keys = Object.keys(uniforms);
|
|
233
|
+
const resources = {};
|
|
234
|
+
if (keys.length) {
|
|
235
|
+
const group = {};
|
|
236
|
+
for (const [key, raw] of Object.entries(uniforms)) {
|
|
237
|
+
group[key] = {
|
|
238
|
+
value: pixiUniformValue(raw),
|
|
239
|
+
type: pixiUniformType(raw),
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
resources.combosUniforms = group;
|
|
243
|
+
}
|
|
244
|
+
const filter = Filter$1.from({
|
|
245
|
+
gl: {
|
|
246
|
+
vertex: source.vertex || DEFAULT_FILTER_VERTEX,
|
|
247
|
+
fragment: source.fragment,
|
|
248
|
+
},
|
|
249
|
+
resources,
|
|
250
|
+
});
|
|
251
|
+
return { filter, keys };
|
|
252
|
+
}
|
|
253
|
+
clear(id, resetContainer = true) {
|
|
254
|
+
const entry = this.entries.get(id);
|
|
255
|
+
if (entry) {
|
|
256
|
+
this.destroyFilters(entry.filters);
|
|
257
|
+
this.entries.delete(id);
|
|
258
|
+
}
|
|
259
|
+
if (resetContainer) {
|
|
260
|
+
const container = this.containerManager.getContainer(id);
|
|
261
|
+
if (container)
|
|
262
|
+
container.filters = [];
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
destroyFilters(filters) {
|
|
266
|
+
for (const filter of filters) {
|
|
267
|
+
filter.destroy?.();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
onDestroy() {
|
|
271
|
+
for (const id of [...this.entries.keys()]) {
|
|
272
|
+
this.clear(id);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
FilterSystem = __decorate([
|
|
277
|
+
decorators.componentObserver({
|
|
278
|
+
Filter: ['enabled', { prop: ['effects'], deep: true }],
|
|
279
|
+
})
|
|
280
|
+
], FilterSystem);
|
|
281
|
+
var FilterSystem_default = FilterSystem;
|
|
282
|
+
|
|
283
|
+
export { Filter, FilterSystem_default as FilterSystem };
|
|
284
|
+
//# sourceMappingURL=plugin-renderer-filter.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-renderer-filter.esm.js","sources":["../lib/component.ts","../lib/shaderSource.ts","../lib/system.ts"],"sourcesContent":["import { Component } from '@combos-fun/engine';\nimport { Field } from '@combos-fun/inspector-decorator';\n\nexport type FilterEffectType = 'blur' | 'colorMatrix' | 'noise' | 'displacement' | 'shader';\n\nexport type FilterUniformValue = number | boolean | number[];\n\nexport interface FilterEffectParams {\n type?: FilterEffectType | string;\n strength?: number;\n quality?: number;\n brightness?: number;\n contrast?: number;\n saturate?: number;\n hue?: number;\n grayscale?: boolean;\n noise?: number;\n seed?: number;\n map?: string;\n scale?: number;\n resource?: string;\n uniforms?: Record<string, FilterUniformValue>;\n}\n\nexport interface FilterParams {\n enabled?: boolean;\n effects?: FilterEffectParams[];\n}\n\nexport default class Filter extends Component<FilterParams> {\n static componentName: string = 'Filter';\n\n @Field({\n type: 'boolean',\n group: 'Filter',\n label: 'enabled',\n description: 'Apply effects to this GameObject.',\n editor: 'toggle',\n })\n enabled: boolean = true;\n\n effects: FilterEffectParams[] = [];\n\n init(obj?: FilterParams) {\n if (!obj) return;\n Object.assign(this, obj);\n if (obj.effects) this.effects = obj.effects;\n }\n}\n","import { resource } from '@combos-fun/engine';\n\nexport async function loadShaderSource(name: string): Promise<{ vertex: string; fragment: string }> {\n const trimmed = String(name ?? '').trim();\n if (!trimmed) {\n throw new Error('SHADER resource name is required');\n }\n const res = await resource.getResource(trimmed);\n if (!res?.name) {\n throw new Error(`Unknown resource \"${trimmed}\"; register RESOURCE_TYPE.SHADER first`);\n }\n const vertex = typeof res.data?.vertex === 'string'\n ? res.data.vertex\n : typeof res.instance?.vertex === 'string' ? res.instance.vertex : '';\n const fragment = typeof res.data?.fragment === 'string'\n ? res.data.fragment\n : typeof res.instance?.fragment === 'string' ? res.instance.fragment : '';\n if (!fragment) {\n throw new Error(`SHADER \"${trimmed}\" missing fragment`);\n }\n return { vertex, fragment };\n}\n\nexport const DEFAULT_FILTER_VERTEX = `in vec2 aPosition;\nout vec2 vTextureCoord;\n\nuniform vec4 uInputSize;\nuniform vec4 uOutputFrame;\nuniform vec4 uOutputTexture;\n\nvec4 filterVertexPosition(void) {\n vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;\n position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;\n position.y = position.y * (2.0 * uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;\n return vec4(position, 0.0, 1.0);\n}\n\nvec2 filterTextureCoord(void) {\n return aPosition * (uOutputFrame.zw * uInputSize.zw);\n}\n\nvoid main(void) {\n gl_Position = filterVertexPosition();\n vTextureCoord = filterTextureCoord();\n}\n`;\n\nexport function pixiUniformType(value: number | boolean | number[]): string {\n if (typeof value === 'boolean' || typeof value === 'number') return 'f32';\n const n = value.length;\n if (n === 2) return 'vec2<f32>';\n if (n === 3) return 'vec3<f32>';\n if (n === 4) return 'vec4<f32>';\n if (n === 9) return 'mat3x3<f32>';\n if (n === 16) return 'mat4x4<f32>';\n return 'f32';\n}\n\nexport function pixiUniformValue(value: number | boolean | number[]): number | number[] {\n if (typeof value === 'boolean') return value ? 1 : 0;\n return value;\n}\n","import { decorators, resource, ComponentChanged, OBSERVER_TYPE, GameObject, UpdateParams } from '@combos-fun/engine';\nimport { Renderer, RendererManager, ContainerManager, RendererSystem } from '@combos-fun/plugin-renderer';\nimport {\n Filter as PixiFilter,\n BlurFilter,\n ColorMatrixFilter,\n NoiseFilter,\n DisplacementFilter,\n Sprite,\n Texture,\n} from 'pixi.js';\nimport FilterComponent from './component';\nimport type { FilterEffectParams, FilterUniformValue } from './component';\nimport {\n DEFAULT_FILTER_VERTEX,\n loadShaderSource,\n pixiUniformType,\n pixiUniformValue,\n} from './shaderSource';\n\ninterface FilterEntry {\n filters: PixiFilter[];\n shaderUniforms: Array<{ filter: PixiFilter; keys: string[] }>;\n time: number;\n}\n\n@decorators.componentObserver({\n Filter: ['enabled', { prop: ['effects'], deep: true }],\n})\nexport default class FilterSystem extends Renderer {\n static systemName = 'FilterSystem';\n name: string = 'FilterSystem';\n renderSystem: RendererSystem;\n rendererManager: RendererManager;\n containerManager: ContainerManager;\n private entries: Map<number, FilterEntry> = new Map();\n private deltaSeconds = 1 / 60;\n\n override update(e?: UpdateParams) {\n this.deltaSeconds = (e?.deltaTime ?? 16.67) / 1000;\n super.update(e);\n }\n\n init() {\n this.renderSystem = this.game.getSystem(RendererSystem) as RendererSystem;\n this.renderSystem.rendererManager.register(this);\n this.containerManager = this.renderSystem.containerManager;\n }\n\n componentChanged(changed: ComponentChanged) {\n if (changed.componentName !== 'Filter') return;\n if (changed.type === OBSERVER_TYPE.REMOVE) {\n this.clear(changed.gameObject.id);\n return;\n }\n if (changed.type === OBSERVER_TYPE.CHANGE && changed.prop?.prop?.[0] === 'enabled') {\n this.applyEnabled(changed.gameObject, changed.component as FilterComponent);\n return;\n }\n this.mount(changed.gameObject, changed.component as FilterComponent);\n }\n\n rendererUpdate(gameObject: GameObject) {\n const component = gameObject.getComponent(FilterComponent) as FilterComponent;\n if (!component?.enabled) return;\n const entry = this.entries.get(gameObject.id);\n if (!entry?.shaderUniforms.length) return;\n entry.time += this.deltaSeconds;\n for (const { filter, keys } of entry.shaderUniforms) {\n const group = filter.resources?.combosUniforms;\n if (!group?.uniforms) continue;\n for (const key of keys) {\n if (key === 'time' || key === 'uTime') {\n group.uniforms[key] = entry.time;\n }\n }\n }\n }\n\n private applyEnabled(gameObject: GameObject, component: FilterComponent) {\n const container = this.containerManager.getContainer(gameObject.id);\n if (!container) return;\n const entry = this.entries.get(gameObject.id);\n container.filters = component.enabled && entry ? entry.filters : [];\n }\n\n private async mount(gameObject: GameObject, component: FilterComponent) {\n const asyncId = this.increaseAsyncId(gameObject.id);\n const built = await this.buildFilters(component.effects || []);\n if (!this.validateAsyncId(gameObject.id, asyncId)) {\n this.destroyFilters(built.filters);\n return;\n }\n this.clear(gameObject.id, false);\n this.entries.set(gameObject.id, { ...built, time: 0 });\n this.applyEnabled(gameObject, component);\n }\n\n private async buildFilters(effects: FilterEffectParams[]): Promise<Omit<FilterEntry, 'time'>> {\n const filters: PixiFilter[] = [];\n const shaderUniforms: FilterEntry['shaderUniforms'] = [];\n for (const effect of effects) {\n const type = effect.type || 'blur';\n if (type === 'blur') {\n filters.push(new BlurFilter({\n strength: effect.strength ?? 8,\n quality: effect.quality ?? 4,\n }));\n continue;\n }\n if (type === 'colorMatrix') {\n const matrix = new ColorMatrixFilter();\n if (effect.brightness != null) matrix.brightness(effect.brightness, false);\n if (effect.contrast != null) matrix.contrast(effect.contrast, true);\n if (effect.saturate != null) matrix.saturate(effect.saturate, true);\n if (effect.hue != null) matrix.hue(effect.hue, true);\n if (effect.grayscale) matrix.greyscale(0.33, true);\n filters.push(matrix);\n continue;\n }\n if (type === 'noise') {\n filters.push(new NoiseFilter({\n noise: effect.noise ?? 0.5,\n seed: effect.seed,\n }));\n continue;\n }\n if (type === 'displacement') {\n filters.push(await this.createDisplacement(effect));\n continue;\n }\n if (type === 'shader') {\n const { filter, keys } = await this.createShader(effect);\n filters.push(filter);\n if (keys.length) shaderUniforms.push({ filter, keys });\n continue;\n }\n throw new Error(`Unknown Filter effect type: ${type}`);\n }\n return { filters, shaderUniforms };\n }\n\n private async createDisplacement(effect: FilterEffectParams): Promise<DisplacementFilter> {\n const mapName = String(effect.map ?? '').trim();\n if (!mapName) {\n throw new Error('displacement Filter requires map (IMAGE resource name)');\n }\n const res = await resource.getResource(mapName);\n const image = res?.data?.image as HTMLImageElement | undefined;\n if (!image) {\n throw new Error(`displacement map \"${mapName}\" has no image data`);\n }\n const sprite = new Sprite(Texture.from(image));\n return new DisplacementFilter({\n sprite,\n scale: effect.scale ?? 20,\n });\n }\n\n private async createShader(effect: FilterEffectParams): Promise<{ filter: PixiFilter; keys: string[] }> {\n const source = await loadShaderSource(effect.resource || '');\n const uniforms = effect.uniforms || {};\n const keys = Object.keys(uniforms);\n const resources: Record<string, Record<string, { value: number | number[]; type: string }>> = {};\n if (keys.length) {\n const group: Record<string, { value: number | number[]; type: string }> = {};\n for (const [key, raw] of Object.entries(uniforms)) {\n group[key] = {\n value: pixiUniformValue(raw as FilterUniformValue),\n type: pixiUniformType(raw as FilterUniformValue),\n };\n }\n resources.combosUniforms = group;\n }\n const filter = PixiFilter.from({\n gl: {\n vertex: source.vertex || DEFAULT_FILTER_VERTEX,\n fragment: source.fragment,\n },\n resources,\n });\n return { filter, keys };\n }\n\n private clear(id: number, resetContainer = true) {\n const entry = this.entries.get(id);\n if (entry) {\n this.destroyFilters(entry.filters);\n this.entries.delete(id);\n }\n if (resetContainer) {\n const container = this.containerManager.getContainer(id);\n if (container) container.filters = [];\n }\n }\n\n private destroyFilters(filters: PixiFilter[]) {\n for (const filter of filters) {\n filter.destroy?.();\n }\n }\n\n onDestroy() {\n for (const id of [...this.entries.keys()]) {\n this.clear(id);\n }\n }\n}\n"],"names":["FilterComponent","PixiFilter"],"mappings":"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"}
|
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@combos-fun/plugin-renderer-filter",
|
|
3
|
+
"version": "0.0.46",
|
|
4
|
+
"description": "Pixi filters and custom 2D shaders",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"module": "dist/plugin-renderer-filter.esm.js",
|
|
7
|
+
"bundle": "CombosFun.plugin.renderer.filter",
|
|
8
|
+
"unpkg": "dist/CombosFun.plugin.renderer.filter.min.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"dist",
|
|
12
|
+
"agent-skill.md",
|
|
13
|
+
"combos-plugin.json"
|
|
14
|
+
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./dist/plugin-renderer-filter.esm.js",
|
|
18
|
+
"require": "./index.js",
|
|
19
|
+
"types": "./dist/plugin-renderer-filter.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./plugin-manifest": "./combos-plugin.json",
|
|
22
|
+
"./agent-skill": "./agent-skill.md"
|
|
23
|
+
},
|
|
24
|
+
"combos": {
|
|
25
|
+
"pluginManifest": "./combos-plugin.json"
|
|
26
|
+
},
|
|
27
|
+
"types": "dist/plugin-renderer-filter.d.ts",
|
|
28
|
+
"keywords": [
|
|
29
|
+
"combos-fun",
|
|
30
|
+
"filter",
|
|
31
|
+
"shader",
|
|
32
|
+
"blur",
|
|
33
|
+
"color-matrix",
|
|
34
|
+
"2d"
|
|
35
|
+
],
|
|
36
|
+
"author": "sun668 <q947692259@gmail.com>",
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"pixi.js": "^8.18.1",
|
|
39
|
+
"@combos-fun/inspector-decorator": "0.0.46",
|
|
40
|
+
"@combos-fun/plugin-renderer": "0.0.46",
|
|
41
|
+
"@combos-fun/engine": "0.0.46"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "node ../../scripts/build-package.mjs"
|
|
45
|
+
}
|
|
46
|
+
}
|