dacha 0.17.0 → 0.17.2

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.
Files changed (44) hide show
  1. package/build/contrib/components/index.d.ts +11 -20
  2. package/build/contrib/components/index.js +2 -1
  3. package/build/contrib/components/mesh/index.d.ts +107 -0
  4. package/build/contrib/components/mesh/index.js +115 -0
  5. package/build/contrib/systems/behavior-system/system.js +1 -1
  6. package/build/contrib/systems/index.d.ts +1 -1
  7. package/build/contrib/systems/index.js +1 -1
  8. package/build/contrib/systems/renderer/actor-render-tree.d.ts +5 -3
  9. package/build/contrib/systems/renderer/actor-render-tree.js +4 -2
  10. package/build/contrib/systems/renderer/assets/index.d.ts +3 -1
  11. package/build/contrib/systems/renderer/assets/index.js +21 -24
  12. package/build/contrib/systems/renderer/assets/utils.js +5 -0
  13. package/build/contrib/systems/renderer/builders/index.d.ts +1 -0
  14. package/build/contrib/systems/renderer/builders/index.js +1 -0
  15. package/build/contrib/systems/renderer/builders/mesh-builder/consts.d.ts +2 -0
  16. package/build/contrib/systems/renderer/builders/mesh-builder/consts.js +2 -0
  17. package/build/contrib/systems/renderer/builders/mesh-builder/index.d.ts +22 -0
  18. package/build/contrib/systems/renderer/builders/mesh-builder/index.js +114 -0
  19. package/build/contrib/systems/renderer/builders/sprite-builder/index.d.ts +1 -4
  20. package/build/contrib/systems/renderer/builders/sprite-builder/index.js +7 -56
  21. package/build/contrib/systems/renderer/builders/texture-array-store/index.d.ts +13 -0
  22. package/build/contrib/systems/renderer/builders/texture-array-store/index.js +61 -0
  23. package/build/contrib/systems/renderer/builders/{sprite-builder → texture-array-store}/utils.d.ts +3 -2
  24. package/build/contrib/systems/renderer/builders/{sprite-builder → texture-array-store}/utils.js +3 -3
  25. package/build/contrib/systems/renderer/consts.js +2 -0
  26. package/build/contrib/systems/renderer/filters/filter-effect.d.ts +14 -0
  27. package/build/contrib/systems/renderer/filters/filter-effect.js +3 -0
  28. package/build/contrib/systems/renderer/filters/index.d.ts +21 -0
  29. package/build/contrib/systems/renderer/filters/index.js +64 -0
  30. package/build/contrib/systems/renderer/index.d.ts +2 -0
  31. package/build/contrib/systems/renderer/index.js +2 -0
  32. package/build/contrib/systems/renderer/material/consts.d.ts +2 -0
  33. package/build/contrib/systems/renderer/material/consts.js +36 -0
  34. package/build/contrib/systems/renderer/material/index.d.ts +20 -0
  35. package/build/contrib/systems/renderer/material/index.js +94 -0
  36. package/build/contrib/systems/renderer/material/shader.d.ts +25 -0
  37. package/build/contrib/systems/renderer/material/shader.js +3 -0
  38. package/build/contrib/systems/renderer/renderer.d.ts +6 -2
  39. package/build/contrib/systems/renderer/renderer.js +27 -3
  40. package/build/contrib/systems/renderer/service/index.d.ts +38 -1
  41. package/build/contrib/systems/renderer/service/index.js +44 -1
  42. package/build/contrib/systems/renderer/types.d.ts +10 -0
  43. package/build/types/global.d.ts +12 -0
  44. package/package.json +3 -3
@@ -1,26 +1,16 @@
1
- import { Texture, Sprite as PixiSprite, TilingSprite, } from 'pixi.js';
1
+ import { Texture, Sprite as PixiSprite, TilingSprite } from 'pixi.js';
2
2
  import { BLEND_MODE_MAPPING } from '../../consts';
3
3
  import { Sprite } from '../../../../components/sprite';
4
- import { CacheStore } from '../../../../../engine/data-lib';
5
- import { getTextureSource, getTextureArray } from './utils';
4
+ import { TextureArrayStore } from '../texture-array-store';
6
5
  export class SpriteBuilder {
7
6
  assets;
8
- textureSourceMap;
9
- textureArrayMap;
7
+ textureArrayStore;
10
8
  constructor({ assets }) {
11
9
  this.assets = assets;
12
- this.textureSourceMap = new CacheStore();
13
- this.textureArrayMap = new CacheStore();
10
+ this.textureArrayStore = new TextureArrayStore(assets);
14
11
  }
15
12
  destroy(sprite) {
16
- const textureSourceKey = sprite.renderData?.textureSourceKey;
17
- const textureArrayKey = sprite.renderData?.textureArrayKey;
18
- if (textureSourceKey) {
19
- this.textureSourceMap.release(textureSourceKey, true);
20
- }
21
- if (textureArrayKey) {
22
- this.textureArrayMap.release(textureArrayKey, true);
23
- }
13
+ this.textureArrayStore.removeTextureArray(sprite);
24
14
  sprite.renderData?.view.destroy();
25
15
  sprite.renderData = undefined;
26
16
  }
@@ -61,11 +51,11 @@ export class SpriteBuilder {
61
51
  if (this.assets.get(sprite) &&
62
52
  (sprite.src !== meta.src || sprite.slice !== meta.slice)) {
63
53
  view.label = sprite.src;
64
- this.updateTextureArray(sprite);
54
+ this.textureArrayStore.updateTextureArray(sprite);
65
55
  meta.src = sprite.src;
66
56
  meta.slice = sprite.slice;
67
57
  }
68
- const textureArray = this.getTextureArray(sprite);
58
+ const textureArray = this.textureArrayStore.getTextureArray(sprite);
69
59
  const texture = textureArray?.[sprite.currentFrame ?? 0];
70
60
  view.texture = texture ?? Texture.WHITE;
71
61
  const scaleX = sprite.flipX ? -1 : 1;
@@ -89,43 +79,4 @@ export class SpriteBuilder {
89
79
  meta.height = sprite.height;
90
80
  }
91
81
  }
92
- updateTextureArray(sprite) {
93
- const oldTextureSourceKey = sprite.renderData.textureSourceKey;
94
- const oldTextureArrayKey = sprite.renderData.textureArrayKey;
95
- if (oldTextureSourceKey) {
96
- this.textureSourceMap.release(oldTextureSourceKey, true);
97
- }
98
- if (oldTextureArrayKey) {
99
- this.textureArrayMap.release(oldTextureArrayKey, true);
100
- }
101
- sprite.renderData.textureSourceKey = sprite.src;
102
- sprite.renderData.textureArrayKey = `${sprite.slice}_${sprite.renderData.textureSourceKey}`;
103
- const textureSourceKey = sprite.renderData.textureSourceKey;
104
- const textureArrayKey = sprite.renderData.textureArrayKey;
105
- if (this.textureArrayMap.has(textureArrayKey)) {
106
- this.textureArrayMap.retain(textureArrayKey);
107
- this.textureSourceMap.retain(textureSourceKey);
108
- return;
109
- }
110
- if (this.textureSourceMap.has(textureSourceKey)) {
111
- const textureSource = this.textureSourceMap.get(textureSourceKey);
112
- const textureArray = getTextureArray(textureSource, sprite);
113
- this.textureArrayMap.add(textureArrayKey, textureArray);
114
- this.textureArrayMap.retain(textureArrayKey);
115
- this.textureSourceMap.retain(textureSourceKey);
116
- }
117
- const image = this.assets.get(sprite);
118
- if (!image) {
119
- return undefined;
120
- }
121
- const textureSource = getTextureSource(image);
122
- const textureArray = getTextureArray(textureSource, sprite);
123
- this.textureSourceMap.add(textureSourceKey, textureSource);
124
- this.textureArrayMap.add(textureArrayKey, textureArray);
125
- this.textureArrayMap.retain(textureArrayKey);
126
- this.textureSourceMap.retain(textureSourceKey);
127
- }
128
- getTextureArray(sprite) {
129
- return this.textureArrayMap.get(sprite.renderData.textureArrayKey);
130
- }
131
82
  }
@@ -0,0 +1,13 @@
1
+ import { Texture } from 'pixi.js';
2
+ import type { Assets } from '../../assets';
3
+ import { Sprite } from '../../../../components/sprite';
4
+ import { Mesh } from '../../../../components/mesh';
5
+ export declare class TextureArrayStore {
6
+ private assets;
7
+ private textureSourceMap;
8
+ private textureArrayMap;
9
+ constructor(assets: Assets);
10
+ updateTextureArray(component: Sprite | Mesh): void;
11
+ removeTextureArray(component: Sprite | Mesh): void;
12
+ getTextureArray(component: Sprite | Mesh): Texture[] | undefined;
13
+ }
@@ -0,0 +1,61 @@
1
+ import { CacheStore } from '../../../../../engine/data-lib';
2
+ import { getTextureSource, getTextureArray } from './utils';
3
+ export class TextureArrayStore {
4
+ assets;
5
+ textureSourceMap;
6
+ textureArrayMap;
7
+ constructor(assets) {
8
+ this.assets = assets;
9
+ this.textureSourceMap = new CacheStore();
10
+ this.textureArrayMap = new CacheStore();
11
+ }
12
+ updateTextureArray(component) {
13
+ const oldTextureSourceKey = component.renderData.textureSourceKey;
14
+ const oldTextureArrayKey = component.renderData.textureArrayKey;
15
+ if (oldTextureSourceKey) {
16
+ this.textureSourceMap.release(oldTextureSourceKey, true);
17
+ }
18
+ if (oldTextureArrayKey) {
19
+ this.textureArrayMap.release(oldTextureArrayKey, true);
20
+ }
21
+ component.renderData.textureSourceKey = component.src;
22
+ component.renderData.textureArrayKey = `${component.slice}_${component.renderData.textureSourceKey}`;
23
+ const textureSourceKey = component.renderData.textureSourceKey;
24
+ const textureArrayKey = component.renderData.textureArrayKey;
25
+ if (this.textureArrayMap.has(textureArrayKey)) {
26
+ this.textureArrayMap.retain(textureArrayKey);
27
+ this.textureSourceMap.retain(textureSourceKey);
28
+ return;
29
+ }
30
+ if (this.textureSourceMap.has(textureSourceKey)) {
31
+ const textureSource = this.textureSourceMap.get(textureSourceKey);
32
+ const textureArray = getTextureArray(textureSource, component);
33
+ this.textureArrayMap.add(textureArrayKey, textureArray);
34
+ this.textureArrayMap.retain(textureArrayKey);
35
+ this.textureSourceMap.retain(textureSourceKey);
36
+ }
37
+ const image = this.assets.get(component);
38
+ if (!image) {
39
+ return undefined;
40
+ }
41
+ const textureSource = getTextureSource(image);
42
+ const textureArray = getTextureArray(textureSource, component);
43
+ this.textureSourceMap.add(textureSourceKey, textureSource);
44
+ this.textureArrayMap.add(textureArrayKey, textureArray);
45
+ this.textureArrayMap.retain(textureArrayKey);
46
+ this.textureSourceMap.retain(textureSourceKey);
47
+ }
48
+ removeTextureArray(component) {
49
+ const textureSourceKey = component.renderData?.textureSourceKey;
50
+ const textureArrayKey = component.renderData?.textureArrayKey;
51
+ if (textureSourceKey) {
52
+ this.textureSourceMap.release(textureSourceKey, true);
53
+ }
54
+ if (textureArrayKey) {
55
+ this.textureArrayMap.release(textureArrayKey, true);
56
+ }
57
+ }
58
+ getTextureArray(component) {
59
+ return this.textureArrayMap.get(component.renderData.textureArrayKey);
60
+ }
61
+ }
@@ -1,4 +1,5 @@
1
1
  import { Texture, TextureSource } from 'pixi.js';
2
- import { Sprite } from '../../../../components/sprite';
3
2
  export declare const getTextureSource: (image: HTMLImageElement) => TextureSource;
4
- export declare const getTextureArray: (textureSource: TextureSource, sprite: Sprite) => Texture[];
3
+ export declare const getTextureArray: (textureSource: TextureSource, component: {
4
+ slice: number;
5
+ }) => Texture[];
@@ -3,11 +3,11 @@ export const getTextureSource = (image) => TextureSource.from({
3
3
  resource: image,
4
4
  scaleMode: 'nearest',
5
5
  });
6
- export const getTextureArray = (textureSource, sprite) => {
6
+ export const getTextureArray = (textureSource, component) => {
7
7
  const textures = [];
8
- const frameWidth = Math.max(textureSource.width / sprite.slice, 1);
8
+ const frameWidth = Math.max(textureSource.width / component.slice, 1);
9
9
  const frameHeight = Math.max(textureSource.height, 1);
10
- for (let i = 0; i < sprite.slice; i += 1) {
10
+ for (let i = 0; i < component.slice; i += 1) {
11
11
  const rectangle = new Rectangle(i * frameWidth, 0, frameWidth, frameHeight);
12
12
  const texture = new Texture({ source: textureSource, frame: rectangle });
13
13
  textures.push(texture);
@@ -2,6 +2,7 @@ import { Sprite } from '../../components/sprite';
2
2
  import { Shape } from '../../components/shape';
3
3
  import { PixiView } from '../../components/pixi-view';
4
4
  import { BitmapText } from '../../components/bitmap-text';
5
+ import { Mesh } from '../../components/mesh';
5
6
  export const BLEND_MODE_MAPPING = {
6
7
  normal: 'normal',
7
8
  addition: 'add',
@@ -19,4 +20,5 @@ export const VIEW_COMPONENTS = [
19
20
  Shape,
20
21
  PixiView,
21
22
  BitmapText,
23
+ Mesh,
22
24
  ];
@@ -0,0 +1,14 @@
1
+ import type { Filter } from 'pixi.js';
2
+ import type { Constructor } from '../../../../types/utils';
3
+ export interface FilterEffectConfig {
4
+ name: string;
5
+ options: Record<string, unknown>;
6
+ }
7
+ export declare abstract class FilterEffect {
8
+ static behaviorName: string;
9
+ abstract create(options: unknown): Filter;
10
+ update?(filter: Filter, options: unknown, elapsedTime: number): void;
11
+ }
12
+ export type FilterEffectConstructor = Constructor<FilterEffect> & {
13
+ behaviorName: string;
14
+ };
@@ -0,0 +1,3 @@
1
+ export class FilterEffect {
2
+ static behaviorName;
3
+ }
@@ -0,0 +1,21 @@
1
+ import { type Application } from 'pixi.js';
2
+ import type { Time } from '../types';
3
+ import type { FilterEffectConstructor, FilterEffectConfig } from './filter-effect';
4
+ export interface FiltersSystemOptions {
5
+ application: Application;
6
+ time: Time;
7
+ availableFilterEffects?: FilterEffectConstructor[];
8
+ filterEffects?: FilterEffectConfig[];
9
+ }
10
+ export declare class FilterSystem {
11
+ private application;
12
+ private time;
13
+ private effects;
14
+ private filtersMap;
15
+ constructor({ application, time, availableFilterEffects, filterEffects, }: FiltersSystemOptions);
16
+ clear(): void;
17
+ addEffect(config: FilterEffectConfig): void;
18
+ removeEffect(config: FilterEffectConfig): void;
19
+ getEffects(): FilterEffectConfig[];
20
+ update(): void;
21
+ }
@@ -0,0 +1,64 @@
1
+ import { Filter } from 'pixi.js';
2
+ export class FilterSystem {
3
+ application;
4
+ time;
5
+ effects;
6
+ filtersMap;
7
+ constructor({ application, time, availableFilterEffects = [], filterEffects = [], }) {
8
+ Filter.defaultOptions.resolution = window.devicePixelRatio;
9
+ this.application = application;
10
+ this.effects = availableFilterEffects.reduce((acc, FilterEffect) => {
11
+ if (FilterEffect.behaviorName === undefined) {
12
+ throw new Error(`Missing behaviorName field for "${FilterEffect.name}" FilterEffect class.`);
13
+ }
14
+ if (acc[FilterEffect.behaviorName] !== undefined) {
15
+ console.warn(`FilterEffect "${FilterEffect.behaviorName}" already exists and will be overridden.`);
16
+ }
17
+ acc[FilterEffect.behaviorName] = new FilterEffect();
18
+ return acc;
19
+ }, {});
20
+ this.time = time;
21
+ this.filtersMap = new Map();
22
+ filterEffects.forEach((effect) => this.addEffect(effect));
23
+ }
24
+ clear() {
25
+ this.filtersMap.clear();
26
+ this.application.stage.filters = null;
27
+ }
28
+ addEffect(config) {
29
+ const effect = this.effects[config.name];
30
+ if (!effect) {
31
+ throw new Error(`Filter effect not found: ${config.name}`);
32
+ }
33
+ const filter = effect.create(config.options);
34
+ filter.__dacha = { meta: { name: config.name } };
35
+ this.filtersMap.set(config, filter);
36
+ const currentFilters = this.application.stage.filters ?? [];
37
+ this.application.stage.filters = [...currentFilters, filter];
38
+ }
39
+ removeEffect(config) {
40
+ const filter = this.filtersMap.get(config);
41
+ if (!filter) {
42
+ return;
43
+ }
44
+ this.filtersMap.delete(config);
45
+ const currentFilters = this.application.stage.filters ?? [];
46
+ const nextFilters = currentFilters.filter((entry) => entry !== filter);
47
+ this.application.stage.filters = nextFilters.length ? nextFilters : null;
48
+ }
49
+ getEffects() {
50
+ return Array.from(this.filtersMap.keys());
51
+ }
52
+ update() {
53
+ this.filtersMap.forEach((filter, config) => {
54
+ const meta = filter.__dacha.meta;
55
+ if (config.name !== meta.name) {
56
+ this.removeEffect(config);
57
+ this.addEffect(config);
58
+ }
59
+ });
60
+ this.filtersMap.forEach((filter, config) => {
61
+ this.effects[config.name]?.update?.(filter, config.options, this.time.elapsed);
62
+ });
63
+ }
64
+ }
@@ -1,2 +1,4 @@
1
1
  export { Renderer } from './renderer';
2
2
  export { RendererService } from './service';
3
+ export { FilterEffect } from './filters/filter-effect';
4
+ export { Shader } from './material/shader';
@@ -1,2 +1,4 @@
1
1
  export { Renderer } from './renderer';
2
2
  export { RendererService } from './service';
3
+ export { FilterEffect } from './filters/filter-effect';
4
+ export { Shader } from './material/shader';
@@ -0,0 +1,2 @@
1
+ export declare const DEFAULT_VERTEX_SHADER = "\n precision mediump float;\n\n attribute vec2 aPosition;\n attribute vec2 aUV;\n\n uniform mat3 uProjectionMatrix;\n uniform mat3 uWorldTransformMatrix;\n uniform mat3 uTransformMatrix;\n\n varying vec2 vUV;\n\n void main() {\n vUV = aUV;\n\n mat3 mvp = uProjectionMatrix * uWorldTransformMatrix * uTransformMatrix;\n vec3 pos = mvp * vec3(aPosition, 1.0);\n gl_Position = vec4(pos.xy, 0.0, 1.0);\n }\n";
2
+ export declare const DEFAULT_FRAGMENT_SHADER = "\n precision mediump float;\n\n varying vec2 vUV;\n\n uniform sampler2D uSampler;\n uniform vec3 uTint;\n uniform float uAlpha;\n\n void main() {\n vec4 color = texture2D(uSampler, vUV);\n color.rgb *= uTint;\n color *= uAlpha;\n gl_FragColor = color;\n }\n";
@@ -0,0 +1,36 @@
1
+ export const DEFAULT_VERTEX_SHADER = `
2
+ precision mediump float;
3
+
4
+ attribute vec2 aPosition;
5
+ attribute vec2 aUV;
6
+
7
+ uniform mat3 uProjectionMatrix;
8
+ uniform mat3 uWorldTransformMatrix;
9
+ uniform mat3 uTransformMatrix;
10
+
11
+ varying vec2 vUV;
12
+
13
+ void main() {
14
+ vUV = aUV;
15
+
16
+ mat3 mvp = uProjectionMatrix * uWorldTransformMatrix * uTransformMatrix;
17
+ vec3 pos = mvp * vec3(aPosition, 1.0);
18
+ gl_Position = vec4(pos.xy, 0.0, 1.0);
19
+ }
20
+ `;
21
+ export const DEFAULT_FRAGMENT_SHADER = `
22
+ precision mediump float;
23
+
24
+ varying vec2 vUV;
25
+
26
+ uniform sampler2D uSampler;
27
+ uniform vec3 uTint;
28
+ uniform float uAlpha;
29
+
30
+ void main() {
31
+ vec4 color = texture2D(uSampler, vUV);
32
+ color.rgb *= uTint;
33
+ color *= uAlpha;
34
+ gl_FragColor = color;
35
+ }
36
+ `;
@@ -0,0 +1,20 @@
1
+ import type { ViewComponent, Time } from '../types';
2
+ import type { ShaderConstructor, MaterialConfig } from './shader';
3
+ interface MaterialSystemOptions {
4
+ shaders?: ShaderConstructor[];
5
+ time: Time;
6
+ }
7
+ type MaterialViewComponent = ViewComponent & {
8
+ material?: MaterialConfig;
9
+ };
10
+ export declare class MaterialSystem {
11
+ private time;
12
+ private shaderBuilders;
13
+ private currentVersion;
14
+ constructor({ time, shaders }: MaterialSystemOptions);
15
+ private createShader;
16
+ destroyShader(component: MaterialViewComponent): void;
17
+ updateShader(component: MaterialViewComponent): void;
18
+ reloadShaders(shaders: ShaderConstructor[]): void;
19
+ }
20
+ export {};
@@ -0,0 +1,94 @@
1
+ import { Shader as PixiShader, Color, Texture, } from 'pixi.js';
2
+ import { DEFAULT_FRAGMENT_SHADER, DEFAULT_VERTEX_SHADER } from './consts';
3
+ const createShaderBuilders = (shaders) => {
4
+ return shaders.reduce((acc, MaterialClass) => {
5
+ if (MaterialClass.behaviorName === undefined) {
6
+ throw new Error(`Missing behaviorName field for "${MaterialClass.name}" Shader class.`);
7
+ }
8
+ if (acc[MaterialClass.behaviorName] !== undefined) {
9
+ console.warn(`Material "${MaterialClass.behaviorName}" already exists and will be overridden.`);
10
+ }
11
+ acc[MaterialClass.behaviorName] = new MaterialClass();
12
+ return acc;
13
+ }, {});
14
+ };
15
+ export class MaterialSystem {
16
+ time;
17
+ shaderBuilders;
18
+ currentVersion;
19
+ constructor({ time, shaders = [] }) {
20
+ this.time = time;
21
+ this.shaderBuilders = createShaderBuilders(shaders);
22
+ this.currentVersion = 0;
23
+ }
24
+ createShader(config) {
25
+ const builder = config ? this.shaderBuilders[config.name] : undefined;
26
+ const shader = PixiShader.from({
27
+ gl: {
28
+ vertex: (config && builder?.vertex(config.options)) ?? DEFAULT_VERTEX_SHADER,
29
+ fragment: (config && builder?.fragment(config.options)) ??
30
+ DEFAULT_FRAGMENT_SHADER,
31
+ },
32
+ resources: {
33
+ uSampler: Texture.WHITE,
34
+ uniformsGroup: {
35
+ uTime: { value: 0.0, type: 'f32' },
36
+ uTint: { value: [1.0, 1.0, 1.0], type: 'vec3<f32>' },
37
+ uAlpha: { value: 1.0, type: 'f32' },
38
+ uTextureSize: { value: [0.0, 0.0], type: 'vec2<f32>' },
39
+ ...(config && builder?.uniforms?.(config.options)),
40
+ },
41
+ },
42
+ });
43
+ shader.__dacha = { version: this.currentVersion, meta: {} };
44
+ return shader;
45
+ }
46
+ destroyShader(component) {
47
+ const view = component.renderData.view;
48
+ if (view.shader) {
49
+ view.shader.destroy();
50
+ }
51
+ }
52
+ updateShader(component) {
53
+ const view = component.renderData.view;
54
+ const material = component.material;
55
+ const builder = material ? this.shaderBuilders[material.name] : undefined;
56
+ const shaderKey = (material && builder?.shaderKey?.(material.name, material.options)) ??
57
+ component.material?.name ??
58
+ null;
59
+ if (!view.shader ||
60
+ shaderKey !== view.shader.__dacha.meta.materialShaderKey ||
61
+ this.currentVersion !== view.shader.__dacha.version) {
62
+ this.destroyShader(component);
63
+ view.shader = this.createShader(component.material);
64
+ view.shader.__dacha.meta.materialShaderKey = shaderKey;
65
+ }
66
+ const meta = view.shader.__dacha.meta;
67
+ if (meta.materialSampler !== view.texture.source) {
68
+ meta.materialSampler = view.texture.source;
69
+ view.shader.resources.uSampler = view.texture.source;
70
+ }
71
+ view.shader.resources.uniformsGroup.uniforms.uTime = this.time.elapsed;
72
+ view.shader.resources.uniformsGroup.uniforms.uAlpha =
73
+ view.getGlobalAlpha(true);
74
+ const tint = view.getGlobalTint(true);
75
+ if (meta.materialTint !== tint) {
76
+ meta.materialTint = tint;
77
+ view.shader.resources.uniformsGroup.uniforms.uTint = Color.shared
78
+ .setValue(tint)
79
+ .toRgbArray([]);
80
+ }
81
+ view.shader.resources.uniformsGroup.uniforms.uTextureSize[0] =
82
+ view.texture.source.width;
83
+ view.shader.resources.uniformsGroup.uniforms.uTextureSize[1] =
84
+ view.texture.source.height;
85
+ if (!material || !builder) {
86
+ return;
87
+ }
88
+ builder.updateUniforms?.(view.shader.resources.uniformsGroup.uniforms, material.options);
89
+ }
90
+ reloadShaders(shaders) {
91
+ this.shaderBuilders = createShaderBuilders(shaders);
92
+ this.currentVersion += 1;
93
+ }
94
+ }
@@ -0,0 +1,25 @@
1
+ import type { Constructor } from '../../../../types/utils';
2
+ export interface MaterialConfig {
3
+ name: string;
4
+ options: Record<string, unknown>;
5
+ }
6
+ type ShaderUniformType = 'f32' | 'i32' | 'vec2<f32>' | 'vec3<f32>' | 'vec4<f32>' | 'mat2x2<f32>' | 'mat3x3<f32>' | 'mat4x4<f32>' | 'mat3x2<f32>' | 'mat4x2<f32>' | 'mat2x3<f32>' | 'mat4x3<f32>' | 'mat2x4<f32>' | 'mat3x4<f32>' | 'vec2<i32>' | 'vec3<i32>' | 'vec4<i32>';
7
+ type ShaderUniformValue = number | boolean | number[] | boolean[] | Float32Array | Int32Array | Uint32Array;
8
+ interface ShaderUniform {
9
+ value: ShaderUniformValue;
10
+ type: ShaderUniformType;
11
+ }
12
+ export type ShaderUniformDefinitions = Record<string, ShaderUniform>;
13
+ export type ShaderUniforms = Record<string, ShaderUniformValue>;
14
+ export declare abstract class Shader {
15
+ static behaviorName: string;
16
+ shaderKey?(name: string, options: unknown): string;
17
+ abstract vertex(options: unknown): string;
18
+ abstract fragment(options: unknown): string;
19
+ uniforms?(options: unknown): ShaderUniformDefinitions;
20
+ updateUniforms?(uniforms: ShaderUniforms, options: unknown): void;
21
+ }
22
+ export type ShaderConstructor = Constructor<Shader> & {
23
+ behaviorName: string;
24
+ };
25
+ export {};
@@ -0,0 +1,3 @@
1
+ export class Shader {
2
+ static behaviorName;
3
+ }
@@ -1,4 +1,4 @@
1
- import { WorldSystem, type WorldSystemOptions } from '../../../engine/system';
1
+ import { WorldSystem, type WorldSystemOptions, type UpdateOptions } from '../../../engine/system';
2
2
  import { type Scene } from '../../../engine/scene';
3
3
  /**
4
4
  * Renderer system that manages 2D graphics rendering using PIXI.js under the hood
@@ -17,6 +17,10 @@ export declare class Renderer extends WorldSystem {
17
17
  private cameraService;
18
18
  private assets;
19
19
  private actorRenderTree?;
20
+ private filterSystem;
21
+ private materialSystem;
22
+ private resources?;
23
+ private time;
20
24
  constructor(options: WorldSystemOptions);
21
25
  onWorldLoad(): Promise<void>;
22
26
  onWorldDestroy(): void;
@@ -25,5 +29,5 @@ export declare class Renderer extends WorldSystem {
25
29
  onSceneExit(): void;
26
30
  onSceneDestroy(scene: Scene): void;
27
31
  private updateCamera;
28
- update(): void;
32
+ update(options: UpdateOptions): void;
29
33
  }
@@ -1,5 +1,5 @@
1
1
  import { Application, Container, Color, RenderLayer, } from 'pixi.js';
2
- import { WorldSystem } from '../../../engine/system';
2
+ import { WorldSystem, } from '../../../engine/system';
3
3
  import { Transform } from '../../components/transform';
4
4
  import { Camera } from '../../components/camera';
5
5
  import { CameraService } from '../camera-system';
@@ -9,6 +9,8 @@ import { composeSort, createSortByLayer, sortByYAxis, sortByXAxis, } from './sor
9
9
  import { parseSortingLayers } from './sort/utils';
10
10
  import { Assets } from './assets';
11
11
  import { ActorRenderTree } from './actor-render-tree';
12
+ import { FilterSystem } from './filters';
13
+ import { MaterialSystem } from './material';
12
14
  import { SORTING_ORDER_MAPPING } from './consts';
13
15
  /**
14
16
  * Renderer system that manages 2D graphics rendering using PIXI.js under the hood
@@ -27,11 +29,16 @@ export class Renderer extends WorldSystem {
27
29
  cameraService;
28
30
  assets;
29
31
  actorRenderTree;
32
+ filterSystem;
33
+ materialSystem;
34
+ resources;
35
+ time;
30
36
  constructor(options) {
31
37
  super();
32
- const { globalOptions, windowNodeId, backgroundColor, templateCollection, world, } = options;
38
+ const { globalOptions, windowNodeId, backgroundColor, templateCollection, world, resources, filterEffects, } = options;
33
39
  this.backgroundColor = new Color(backgroundColor);
34
40
  this.window = getWindowNode(windowNodeId);
41
+ this.resources = resources;
35
42
  const sorting = globalOptions.sorting;
36
43
  const sortingOrder = SORTING_ORDER_MAPPING[sorting?.order ?? 'bottomRight'];
37
44
  const parsedSortingLayers = parseSortingLayers(sorting?.layers);
@@ -48,12 +55,25 @@ export class Renderer extends WorldSystem {
48
55
  this.application = new Application();
49
56
  this.worldContainer = new Container();
50
57
  this.assets = new Assets({ templateCollection });
58
+ this.time = { elapsed: 0 };
59
+ this.materialSystem = new MaterialSystem({
60
+ shaders: this.resources?.shaders,
61
+ time: this.time,
62
+ });
63
+ this.filterSystem = new FilterSystem({
64
+ application: this.application,
65
+ time: this.time,
66
+ filterEffects,
67
+ availableFilterEffects: this.resources?.filterEffects,
68
+ });
51
69
  this.cameraService = world.getService(CameraService);
52
70
  world.addService(new RendererService({
53
71
  application: this.application,
54
72
  worldContainer: this.worldContainer,
55
73
  getViewEntries: () => this.actorRenderTree?.viewEntries,
56
74
  sortFn: this.sortFn,
75
+ filterSystem: this.filterSystem,
76
+ materialSystem: this.materialSystem,
57
77
  }));
58
78
  }
59
79
  async onWorldLoad() {
@@ -77,6 +97,7 @@ export class Renderer extends WorldSystem {
77
97
  };
78
98
  }
79
99
  onWorldDestroy() {
100
+ this.filterSystem.clear();
80
101
  this.window.removeChild(this.application.canvas);
81
102
  this.application.destroy();
82
103
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -92,6 +113,7 @@ export class Renderer extends WorldSystem {
92
113
  worldContainer: this.worldContainer,
93
114
  assets: this.assets,
94
115
  sortingLayers: this.sortingLayers,
116
+ materialSystem: this.materialSystem,
95
117
  });
96
118
  }
97
119
  onSceneExit() {
@@ -113,9 +135,11 @@ export class Renderer extends WorldSystem {
113
135
  this.worldContainer.position.set(this.application.renderer.width / 2, this.application.renderer.height / 2);
114
136
  this.worldContainer.pivot.set(x, y);
115
137
  }
116
- update() {
138
+ update(options) {
139
+ this.time.elapsed += options.deltaTime / 1000;
117
140
  this.updateCamera();
118
141
  this.actorRenderTree?.update();
142
+ this.filterSystem.update();
119
143
  this.application.renderer.render({ container: this.application.stage });
120
144
  }
121
145
  }