@planara/core 1.2.4 → 1.3.0

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 CHANGED
@@ -1,4 +1,5 @@
1
1
  ![build](https://github.com/planara/planara-core/actions/workflows/build.yml/badge.svg)
2
+ ![deploy](https://github.com/planara/planara-core/actions/workflows/deploy.yml/badge.svg)
2
3
 
3
4
  ## Planara Core
4
5
 
@@ -20,4 +21,4 @@
20
21
 
21
22
  - Покраска объектов (через материалы или vertex colors).
22
23
 
23
- - Отображение сетки и осей (Grid и Axes Helper).
24
+ - Отображение сетки и осей (Grid и Axes Helper).
@@ -1 +1 @@
1
- {"version":3,"file":"editor-renderer.d.ts","sourceRoot":"","sources":["../../src/core/editor-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,8CAA8C;IAC9C,OAAO,CAAC,KAAK,CAAS;IAEtB;;;;OAIG;gBACS,MAAM,EAAE,iBAAiB;IAgBrC;;OAEG;IACH,SAAS,CAAC,MAAM;CAIjB"}
1
+ {"version":3,"file":"editor-renderer.d.ts","sourceRoot":"","sources":["../../src/core/editor-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,8CAA8C;IAC9C,OAAO,CAAC,KAAK,CAAS;IAEtB;;;;OAIG;gBACgB,MAAM,EAAE,iBAAiB;IAgB5C;;OAEG;IACH,SAAS,CAAC,MAAM;CAIjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"preview-renderer.d.ts","sourceRoot":"","sources":["../../src/core/preview-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,QAAQ;IAC3C,8CAA8C;IAC9C,OAAO,CAAC,KAAK,CAAS;IAEtB;;;OAGG;gBACS,MAAM,EAAE,iBAAiB;IAcrC;;OAEG;IACH,SAAS,CAAC,MAAM;CAIjB"}
1
+ {"version":3,"file":"preview-renderer.d.ts","sourceRoot":"","sources":["../../src/core/preview-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC;;;;GAIG;AACH,qBAAa,eAAgB,SAAQ,QAAQ;IAC3C,8CAA8C;IAC9C,OAAO,CAAC,KAAK,CAAS;IAEtB;;;OAGG;gBACS,MAAM,EAAE,iBAAiB;IAerC;;OAEG;IACH,SAAS,CAAC,MAAM;CAIjB"}
@@ -1,22 +1,24 @@
1
- import { Renderer as OGLRenderer, Camera, Transform } from 'ogl';
1
+ import { Renderer as OGLRenderer, Camera, Transform, Mesh, Geometry, Program } from 'ogl';
2
+ import { Figure } from '@planara/types';
2
3
  /**
3
4
  * Абстрактный базовый класс рендерера для работы с WebGL через OGL.
4
5
  * Отвечает за инициализацию сцены, камеры и цикла рендеринга.
5
6
  */
6
7
  export declare abstract class Renderer {
7
8
  /** Экземпляр рендерера OGL */
8
- gl: OGLRenderer;
9
+ protected gl: OGLRenderer;
9
10
  /** Корневой объект сцены */
10
- scene: Transform;
11
+ protected scene: Transform;
11
12
  /** Камера для сцены */
12
- camera: Camera;
13
+ protected camera: Camera;
13
14
  /** HTML-элемент canvas, на котором рендерится сцена */
14
15
  protected canvas: HTMLCanvasElement;
16
+ protected program: Program;
15
17
  /**
16
18
  * Конструктор рендерера
17
19
  * @param canvas - HTMLCanvasElement для рендеринга
18
20
  */
19
- constructor(canvas: HTMLCanvasElement);
21
+ protected constructor(canvas: HTMLCanvasElement);
20
22
  /**
21
23
  * Обновляет размер рендерера и камеры при изменении размеров canvas.
22
24
  */
@@ -24,14 +26,19 @@ export declare abstract class Renderer {
24
26
  /**
25
27
  * Выполняет рендеринг сцены с текущей камерой.
26
28
  */
27
- render(): void;
29
+ protected render(): void;
30
+ /**
31
+ * Метод для обновления логики рендерера.
32
+ */
33
+ protected update(): void;
28
34
  /**
29
35
  * Запускает основной цикл рендеринга.
30
36
  */
31
37
  loop(): void;
32
38
  /**
33
- * Метод для обновления логики рендерера.
39
+ * Публичный метод для добавления фигуры.
40
+ * @param figure Данные фигуры: position, normal, uv
34
41
  */
35
- protected update(): void;
42
+ addFigure(figure: Figure): Mesh<Geometry, Program>;
36
43
  }
37
44
  //# sourceMappingURL=renderer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/core/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAEjE;;;GAGG;AACH,8BAAsB,QAAQ;IAC5B,8BAA8B;IACvB,EAAE,EAAE,WAAW,CAAC;IAEvB,4BAA4B;IACrB,KAAK,EAAE,SAAS,CAAC;IAExB,uBAAuB;IAChB,MAAM,EAAE,MAAM,CAAC;IAEtB,uDAAuD;IACvD,SAAS,CAAC,MAAM,EAAE,iBAAiB,CAAC;IAEpC;;;OAGG;gBACS,MAAM,EAAE,iBAAiB;IAarC;;OAEG;IACH,MAAM;IAKN;;OAEG;IACH,MAAM;IAIN;;OAEG;IACH,IAAI;IAMJ;;OAEG;IACH,SAAS,CAAC,MAAM,IAAI,IAAI;CACzB"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/core/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,OAAO,EAAE,MAAM,KAAK,CAAC;AAE/F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE7C;;;GAGG;AACH,8BAAsB,QAAQ;IAC5B,8BAA8B;IAC9B,SAAS,CAAC,EAAE,EAAE,WAAW,CAAC;IAE1B,4BAA4B;IAC5B,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC;IAE3B,uBAAuB;IACvB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IAEzB,uDAAuD;IACvD,SAAS,CAAC,MAAM,EAAE,iBAAiB,CAAC;IAEpC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC;IAE3B;;;OAGG;IACH,SAAS,aAAa,MAAM,EAAE,iBAAiB;IAyB/C;;OAEG;IACI,MAAM;IAUb;;OAEG;IACH,SAAS,CAAC,MAAM;IAIhB;;OAEG;IACH,SAAS,CAAC,MAAM,IAAI,IAAI;IAExB;;OAEG;IACI,IAAI;IAMX;;;OAGG;IACI,SAAS,CAAC,MAAM,EAAE,MAAM;CAkBhC"}
package/dist/index.cjs.js CHANGED
@@ -1,2 +1,33 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("ogl");class h{gl;scene;camera;canvas;constructor(e){this.canvas=e,this.gl=new n.Renderer({canvas:e}),this.gl.setSize(e.clientWidth,e.clientHeight),this.gl.gl.clearColor(1,1,1,1),this.scene=new n.Transform,this.camera=new n.Camera(this.gl.gl,{fov:45}),this.camera.position.set(1,1,7),this.camera.lookAt([0,0,0])}resize(){this.gl.setSize(this.canvas.clientWidth,this.canvas.clientHeight),this.camera.perspective({aspect:this.canvas.width/this.canvas.height})}render(){this.gl.render({scene:this.scene,camera:this.camera})}loop(){this.update(),this.render(),requestAnimationFrame(this.loop.bind(this))}update(){}}class d extends h{orbit;constructor(e){super(e);const t=new n.GridHelper(this.gl.gl,{size:10,divisions:10});t.position.y=-.001,t.setParent(this.scene),new n.AxesHelper(this.gl.gl,{size:6,symmetric:!0}).setParent(this.scene),this.orbit=new n.Orbit(this.camera)}update(){this.orbit?.update()}}class v extends h{orbit;constructor(e){super(e),this.orbit=new n.Orbit(this.camera,{target:new n.Vec3(0,0,0),minPolarAngle:Math.PI/2,maxPolarAngle:Math.PI/2,enableRotate:!0,enableZoom:!1,enablePan:!1})}update(){this.orbit?.update()}}class g{type;position;normal;uv;material;constructor(e){this.type=e.type,this.position=e.position,this.normal=e.normal??[],this.uv=e.uv??[],this.material=e.material}}var u=(s=>(s[s.Cube=0]="Cube",s[s.Sphere=1]="Sphere",s[s.Plane=2]="Plane",s[s.Cylinder=3]="Cylinder",s[s.Custom=4]="Custom",s))(u||{});class b{positions=[];normals=[];uvs=[];tmpPositions=[];tmpNormals=[];tmpUVs=[];parse(e){const t=e.split(`
2
- `);for(const a of t){if(!a.trim()||a.startsWith("#"))continue;const i=a.trim().split(/\s+/);switch(i[0]){case"v":this.tmpPositions.push(i.slice(1).map(Number));break;case"vn":this.tmpNormals.push(i.slice(1).map(Number));break;case"vt":this.tmpUVs.push(i.slice(1).map(Number));break;case"f":this.processFaceLine(i);break}}const o={type:u.Custom,position:this.positions,...this.normals.length>0&&{normal:this.normals},...this.uvs.length>0&&{uv:this.uvs}};return new g(o)}processFaceLine(e){for(let t=1;t<e.length;t++){const o=e[t];if(!o)continue;const[a,i,l]=o.split("/"),c=a?parseInt(a,10):void 0,p=i?parseInt(i,10):void 0,m=l?parseInt(l,10):void 0;if(c!==void 0){const r=this.tmpPositions[c-1];r&&this.positions.push(...r)}if(p!==void 0){const r=this.tmpUVs[p-1];r&&this.uvs.push(...r)}if(m!==void 0){const r=this.tmpNormals[m-1];r&&this.normals.push(...r)}}}}exports.EditorRenderer=d;exports.ObjLoader=b;exports.PreviewRenderer=v;exports.Renderer=h;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("ogl");function p(t){const e=`
2
+ attribute vec3 position;
3
+ attribute vec3 normal;
4
+ attribute vec2 uv;
5
+
6
+ uniform mat4 modelViewMatrix;
7
+ uniform mat4 projectionMatrix;
8
+ uniform mat3 normalMatrix;
9
+
10
+ varying vec3 vNormal;
11
+ varying vec2 vUv;
12
+
13
+ void main() {
14
+ vUv = uv;
15
+ vNormal = normalize(normalMatrix * normal);
16
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
17
+ }
18
+ `,i=`
19
+ precision highp float;
20
+
21
+ uniform sampler2D tMap;
22
+ varying vec3 vNormal;
23
+ varying vec2 vUv;
24
+
25
+ void main() {
26
+ vec3 tex = texture2D(tMap, vUv).rgb;
27
+ vec3 light = normalize(vec3(0.5, 1.0, -0.3));
28
+ float shading = dot(normalize(vNormal), light) * 0.15;
29
+ gl_FragColor.rgb = tex + shading;
30
+ gl_FragColor.a = 1.0;
31
+ }
32
+ `,r=new s.Texture(t);return new s.Program(t,{vertex:e,fragment:i,uniforms:{tMap:{value:r}}})}class l{gl;scene;camera;canvas;program;constructor(e){this.canvas=e,this.gl=new s.Renderer({canvas:e}),this.gl.setSize(e.clientWidth,e.clientHeight),this.gl.gl.clearColor(1,1,1,1),this.scene=new s.Transform,this.camera=new s.Camera(this.gl.gl,{fov:45}),this.camera.position.set(1,1,7),this.camera.lookAt([0,0,0]),this.program=p(this.gl.gl)}resize(){this.canvas.width=this.canvas.clientWidth,this.canvas.height=this.canvas.clientHeight,this.gl.setSize(this.canvas.clientWidth,this.canvas.clientHeight),this.camera.perspective({aspect:this.canvas.clientWidth/this.canvas.clientHeight})}render(){this.gl.render({scene:this.scene,camera:this.camera})}update(){}loop(){this.update(),this.render(),requestAnimationFrame(this.loop.bind(this))}addFigure(e){const i=new s.Geometry(this.gl.gl,{position:{size:3,data:new Float32Array(e.position)},normal:{size:3,data:new Float32Array(e.normal??[])},uv:{size:2,data:new Float32Array(e.uv??[])}}),r=new s.Mesh(this.gl.gl,{geometry:i,program:this.program});return r.setParent(this.scene),r}}class d extends l{orbit;constructor(e){super(e);const i=new s.GridHelper(this.gl.gl,{size:10,divisions:10});i.position.y=-.001,i.setParent(this.scene),new s.AxesHelper(this.gl.gl,{size:6,symmetric:!0}).setParent(this.scene),this.orbit=new s.Orbit(this.camera,{element:this.canvas})}update(){this.orbit?.update()}}class g extends l{orbit;constructor(e){super(e),this.orbit=new s.Orbit(this.camera,{element:this.canvas,target:new s.Vec3(0,0,0),minPolarAngle:Math.PI/2,maxPolarAngle:Math.PI/2,enableRotate:!0,enableZoom:!1,enablePan:!1})}update(){this.orbit?.update()}}class b{type;position;normal;uv;material;constructor(e){this.type=e.type,this.position=e.position,this.normal=e.normal??[],this.uv=e.uv??[],this.material=e.material}}var u=(t=>(t[t.Cube=0]="Cube",t[t.Sphere=1]="Sphere",t[t.Plane=2]="Plane",t[t.Cylinder=3]="Cylinder",t[t.Custom=4]="Custom",t))(u||{});class f{positions=[];normals=[];uvs=[];tmpPositions=[];tmpNormals=[];tmpUVs=[];load(e){const i=e.split(`
33
+ `);for(const o of i){if(!o.trim()||o.startsWith("#"))continue;const a=o.trim().split(/\s+/);switch(a[0]){case"v":this.tmpPositions.push(a.slice(1).map(Number));break;case"vn":this.tmpNormals.push(a.slice(1).map(Number));break;case"vt":this.tmpUVs.push(a.slice(1).map(Number));break;case"f":this.processFaceLine(a);break}}const r={type:u.Custom,position:this.positions,...this.normals.length>0&&{normal:this.normals},...this.uvs.length>0&&{uv:this.uvs}};return new b(r)}processFaceLine(e){for(let i=1;i<e.length;i++){const r=e[i];if(!r)continue;const[o,a,c]=r.split("/"),h=o?parseInt(o,10):void 0,m=a?parseInt(a,10):void 0,v=c?parseInt(c,10):void 0;if(h!==void 0){const n=this.tmpPositions[h-1];n&&this.positions.push(...n)}if(m!==void 0){const n=this.tmpUVs[m-1];n&&this.uvs.push(...n)}if(v!==void 0){const n=this.tmpNormals[v-1];n&&this.normals.push(...n)}}}}exports.EditorRenderer=d;exports.ObjLoader=f;exports.PreviewRenderer=g;exports.Renderer=l;exports.createProgram=p;
package/dist/index.d.ts CHANGED
@@ -2,4 +2,5 @@ export * from './core/renderer';
2
2
  export * from './core/editor-renderer';
3
3
  export * from './core/preview-renderer';
4
4
  export * from './loaders/obj-loader';
5
+ export * from './utils/program-settings';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC"}
package/dist/index.es.js CHANGED
@@ -1,5 +1,50 @@
1
- import { Renderer as d, Transform as v, Camera as g, GridHelper as b, AxesHelper as f, Orbit as p, Vec3 as x } from "ogl";
2
- class m {
1
+ import { Texture as u, Program as d, Renderer as g, Transform as b, Camera as f, Geometry as x, Mesh as w, GridHelper as y, AxesHelper as P, Orbit as m, Vec3 as M } from "ogl";
2
+ function z(e) {
3
+ const t = (
4
+ /* glsl */
5
+ `
6
+ attribute vec3 position;
7
+ attribute vec3 normal;
8
+ attribute vec2 uv;
9
+
10
+ uniform mat4 modelViewMatrix;
11
+ uniform mat4 projectionMatrix;
12
+ uniform mat3 normalMatrix;
13
+
14
+ varying vec3 vNormal;
15
+ varying vec2 vUv;
16
+
17
+ void main() {
18
+ vUv = uv;
19
+ vNormal = normalize(normalMatrix * normal);
20
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
21
+ }
22
+ `
23
+ ), i = (
24
+ /* glsl */
25
+ `
26
+ precision highp float;
27
+
28
+ uniform sampler2D tMap;
29
+ varying vec3 vNormal;
30
+ varying vec2 vUv;
31
+
32
+ void main() {
33
+ vec3 tex = texture2D(tMap, vUv).rgb;
34
+ vec3 light = normalize(vec3(0.5, 1.0, -0.3));
35
+ float shading = dot(normalize(vNormal), light) * 0.15;
36
+ gl_FragColor.rgb = tex + shading;
37
+ gl_FragColor.a = 1.0;
38
+ }
39
+ `
40
+ ), s = new u(e);
41
+ return new d(e, {
42
+ vertex: t,
43
+ fragment: i,
44
+ uniforms: { tMap: { value: s } }
45
+ });
46
+ }
47
+ class p {
3
48
  /** Экземпляр рендерера OGL */
4
49
  gl;
5
50
  /** Корневой объект сцены */
@@ -8,18 +53,19 @@ class m {
8
53
  camera;
9
54
  /** HTML-элемент canvas, на котором рендерится сцена */
10
55
  canvas;
56
+ program;
11
57
  /**
12
58
  * Конструктор рендерера
13
59
  * @param canvas - HTMLCanvasElement для рендеринга
14
60
  */
15
- constructor(s) {
16
- this.canvas = s, this.gl = new d({ canvas: s }), this.gl.setSize(s.clientWidth, s.clientHeight), this.gl.gl.clearColor(1, 1, 1, 1), this.scene = new v(), this.camera = new g(this.gl.gl, { fov: 45 }), this.camera.position.set(1, 1, 7), this.camera.lookAt([0, 0, 0]);
61
+ constructor(t) {
62
+ this.canvas = t, this.gl = new g({ canvas: t }), this.gl.setSize(t.clientWidth, t.clientHeight), this.gl.gl.clearColor(1, 1, 1, 1), this.scene = new b(), this.camera = new f(this.gl.gl, { fov: 45 }), this.camera.position.set(1, 1, 7), this.camera.lookAt([0, 0, 0]), this.program = z(this.gl.gl);
17
63
  }
18
64
  /**
19
65
  * Обновляет размер рендерера и камеры при изменении размеров canvas.
20
66
  */
21
67
  resize() {
22
- this.gl.setSize(this.canvas.clientWidth, this.canvas.clientHeight), this.camera.perspective({ aspect: this.canvas.width / this.canvas.height });
68
+ this.canvas.width = this.canvas.clientWidth, this.canvas.height = this.canvas.clientHeight, this.gl.setSize(this.canvas.clientWidth, this.canvas.clientHeight), this.camera.perspective({ aspect: this.canvas.clientWidth / this.canvas.clientHeight });
23
69
  }
24
70
  /**
25
71
  * Выполняет рендеринг сцены с текущей камерой.
@@ -27,6 +73,11 @@ class m {
27
73
  render() {
28
74
  this.gl.render({ scene: this.scene, camera: this.camera });
29
75
  }
76
+ /**
77
+ * Метод для обновления логики рендерера.
78
+ */
79
+ update() {
80
+ }
30
81
  /**
31
82
  * Запускает основной цикл рендеринга.
32
83
  */
@@ -34,12 +85,22 @@ class m {
34
85
  this.update(), this.render(), requestAnimationFrame(this.loop.bind(this));
35
86
  }
36
87
  /**
37
- * Метод для обновления логики рендерера.
88
+ * Публичный метод для добавления фигуры.
89
+ * @param figure Данные фигуры: position, normal, uv
38
90
  */
39
- update() {
91
+ addFigure(t) {
92
+ const i = new x(this.gl.gl, {
93
+ position: { size: 3, data: new Float32Array(t.position) },
94
+ normal: { size: 3, data: new Float32Array(t.normal ?? []) },
95
+ uv: { size: 2, data: new Float32Array(t.uv ?? []) }
96
+ }), s = new w(this.gl.gl, {
97
+ geometry: i,
98
+ program: this.program
99
+ });
100
+ return s.setParent(this.scene), s;
40
101
  }
41
102
  }
42
- class I extends m {
103
+ class N extends p {
43
104
  /** Orbit-контроллер для управления камерой */
44
105
  orbit;
45
106
  /**
@@ -47,10 +108,10 @@ class I extends m {
47
108
  * Создает сетку, оси координат и orbit-контроллер.
48
109
  * @param canvas - HTMLCanvasElement для рендеринга
49
110
  */
50
- constructor(s) {
51
- super(s);
52
- const t = new b(this.gl.gl, { size: 10, divisions: 10 });
53
- t.position.y = -1e-3, t.setParent(this.scene), new f(this.gl.gl, { size: 6, symmetric: !0 }).setParent(this.scene), this.orbit = new p(this.camera);
111
+ constructor(t) {
112
+ super(t);
113
+ const i = new y(this.gl.gl, { size: 10, divisions: 10 });
114
+ i.position.y = -1e-3, i.setParent(this.scene), new P(this.gl.gl, { size: 6, symmetric: !0 }).setParent(this.scene), this.orbit = new m(this.camera, { element: this.canvas });
54
115
  }
55
116
  /**
56
117
  * Обновление состояния рендерера.
@@ -59,16 +120,17 @@ class I extends m {
59
120
  this.orbit?.update();
60
121
  }
61
122
  }
62
- class C extends m {
123
+ class F extends p {
63
124
  /** Orbit-контроллер для управления камерой */
64
125
  orbit;
65
126
  /**
66
127
  * Инициализация сцены предпросмотра.
67
128
  * @param canvas - HTMLCanvasElement для рендеринга
68
129
  */
69
- constructor(s) {
70
- super(s), this.orbit = new p(this.camera, {
71
- target: new x(0, 0, 0),
130
+ constructor(t) {
131
+ super(t), this.orbit = new m(this.camera, {
132
+ element: this.canvas,
133
+ target: new M(0, 0, 0),
72
134
  minPolarAngle: Math.PI / 2,
73
135
  maxPolarAngle: Math.PI / 2,
74
136
  enableRotate: !0,
@@ -83,7 +145,7 @@ class C extends m {
83
145
  this.orbit?.update();
84
146
  }
85
147
  }
86
- class P {
148
+ class C {
87
149
  /** Тип фигуры */
88
150
  type;
89
151
  /** Позиции вершин */
@@ -98,15 +160,19 @@ class P {
98
160
  * Создаёт новую фигуру
99
161
  * @param data - исходные данные фигуры
100
162
  */
101
- constructor(s) {
102
- this.type = s.type, this.position = s.position, this.normal = s.normal ?? [], this.uv = s.uv ?? [], this.material = s.material;
163
+ constructor(t) {
164
+ this.type = t.type, this.position = t.position, this.normal = t.normal ?? [], this.uv = t.uv ?? [], this.material = t.material;
103
165
  }
104
166
  }
105
- var u = /* @__PURE__ */ ((e) => (e[e.Cube = 0] = "Cube", e[e.Sphere = 1] = "Sphere", e[e.Plane = 2] = "Plane", e[e.Cylinder = 3] = "Cylinder", e[e.Custom = 4] = "Custom", e))(u || {});
106
- class y {
167
+ var v = /* @__PURE__ */ ((e) => (e[e.Cube = 0] = "Cube", e[e.Sphere = 1] = "Sphere", e[e.Plane = 2] = "Plane", e[e.Cylinder = 3] = "Cylinder", e[e.Custom = 4] = "Custom", e))(v || {});
168
+ class A {
169
+ /** Позиции вершин */
107
170
  positions = [];
171
+ /** Нормали вершин */
108
172
  normals = [];
173
+ /** UV-координаты (опционально) */
109
174
  uvs = [];
175
+ // Временные поля для парсинга файла
110
176
  tmpPositions = [];
111
177
  tmpNormals = [];
112
178
  tmpUVs = [];
@@ -114,61 +180,62 @@ class y {
114
180
  * Загружает OBJ-модель в Figure
115
181
  * @param objContent Строка содержимого .obj файла
116
182
  */
117
- parse(s) {
118
- const t = s.split(`
183
+ load(t) {
184
+ const i = t.split(`
119
185
  `);
120
- for (const n of t) {
186
+ for (const n of i) {
121
187
  if (!n.trim() || n.startsWith("#")) continue;
122
- const i = n.trim().split(/\s+/);
123
- switch (i[0]) {
188
+ const r = n.trim().split(/\s+/);
189
+ switch (r[0]) {
124
190
  case "v":
125
- this.tmpPositions.push(i.slice(1).map(Number));
191
+ this.tmpPositions.push(r.slice(1).map(Number));
126
192
  break;
127
193
  case "vn":
128
- this.tmpNormals.push(i.slice(1).map(Number));
194
+ this.tmpNormals.push(r.slice(1).map(Number));
129
195
  break;
130
196
  case "vt":
131
- this.tmpUVs.push(i.slice(1).map(Number));
197
+ this.tmpUVs.push(r.slice(1).map(Number));
132
198
  break;
133
199
  case "f":
134
- this.processFaceLine(i);
200
+ this.processFaceLine(r);
135
201
  break;
136
202
  }
137
203
  }
138
- const a = {
139
- type: u.Custom,
204
+ const s = {
205
+ type: v.Custom,
140
206
  position: this.positions,
141
207
  ...this.normals.length > 0 && { normal: this.normals },
142
208
  ...this.uvs.length > 0 && { uv: this.uvs }
143
209
  };
144
- return new P(a);
210
+ return new C(s);
145
211
  }
146
212
  /**
147
213
  * Обрабатывает строку face (f) и разворачивает индексы в массивы для рендеринга
148
214
  */
149
- processFaceLine(s) {
150
- for (let t = 1; t < s.length; t++) {
151
- const a = s[t];
152
- if (!a) continue;
153
- const [n, i, o] = a.split("/"), h = n ? parseInt(n, 10) : void 0, c = i ? parseInt(i, 10) : void 0, l = o ? parseInt(o, 10) : void 0;
154
- if (h !== void 0) {
155
- const r = this.tmpPositions[h - 1];
156
- r && this.positions.push(...r);
215
+ processFaceLine(t) {
216
+ for (let i = 1; i < t.length; i++) {
217
+ const s = t[i];
218
+ if (!s) continue;
219
+ const [n, r, o] = s.split("/"), l = n ? parseInt(n, 10) : void 0, c = r ? parseInt(r, 10) : void 0, h = o ? parseInt(o, 10) : void 0;
220
+ if (l !== void 0) {
221
+ const a = this.tmpPositions[l - 1];
222
+ a && this.positions.push(...a);
157
223
  }
158
224
  if (c !== void 0) {
159
- const r = this.tmpUVs[c - 1];
160
- r && this.uvs.push(...r);
225
+ const a = this.tmpUVs[c - 1];
226
+ a && this.uvs.push(...a);
161
227
  }
162
- if (l !== void 0) {
163
- const r = this.tmpNormals[l - 1];
164
- r && this.normals.push(...r);
228
+ if (h !== void 0) {
229
+ const a = this.tmpNormals[h - 1];
230
+ a && this.normals.push(...a);
165
231
  }
166
232
  }
167
233
  }
168
234
  }
169
235
  export {
170
- I as EditorRenderer,
171
- y as ObjLoader,
172
- C as PreviewRenderer,
173
- m as Renderer
236
+ N as EditorRenderer,
237
+ A as ObjLoader,
238
+ F as PreviewRenderer,
239
+ p as Renderer,
240
+ z as createProgram
174
241
  };
package/dist/index.umd.js CHANGED
@@ -1,2 +1,33 @@
1
- (function(i,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("ogl")):typeof define=="function"&&define.amd?define(["exports","ogl"],t):(i=typeof globalThis<"u"?globalThis:i||self,t(i.PlanaraCore={},i.OGL))})(this,(function(i,t){"use strict";class c{gl;scene;camera;canvas;constructor(e){this.canvas=e,this.gl=new t.Renderer({canvas:e}),this.gl.setSize(e.clientWidth,e.clientHeight),this.gl.gl.clearColor(1,1,1,1),this.scene=new t.Transform,this.camera=new t.Camera(this.gl.gl,{fov:45}),this.camera.position.set(1,1,7),this.camera.lookAt([0,0,0])}resize(){this.gl.setSize(this.canvas.clientWidth,this.canvas.clientHeight),this.camera.perspective({aspect:this.canvas.width/this.canvas.height})}render(){this.gl.render({scene:this.scene,camera:this.camera})}loop(){this.update(),this.render(),requestAnimationFrame(this.loop.bind(this))}update(){}}class v extends c{orbit;constructor(e){super(e);const n=new t.GridHelper(this.gl.gl,{size:10,divisions:10});n.position.y=-.001,n.setParent(this.scene),new t.AxesHelper(this.gl.gl,{size:6,symmetric:!0}).setParent(this.scene),this.orbit=new t.Orbit(this.camera)}update(){this.orbit?.update()}}class f extends c{orbit;constructor(e){super(e),this.orbit=new t.Orbit(this.camera,{target:new t.Vec3(0,0,0),minPolarAngle:Math.PI/2,maxPolarAngle:Math.PI/2,enableRotate:!0,enableZoom:!1,enablePan:!1})}update(){this.orbit?.update()}}class b{type;position;normal;uv;material;constructor(e){this.type=e.type,this.position=e.position,this.normal=e.normal??[],this.uv=e.uv??[],this.material=e.material}}var l=(s=>(s[s.Cube=0]="Cube",s[s.Sphere=1]="Sphere",s[s.Plane=2]="Plane",s[s.Cylinder=3]="Cylinder",s[s.Custom=4]="Custom",s))(l||{});class g{positions=[];normals=[];uvs=[];tmpPositions=[];tmpNormals=[];tmpUVs=[];parse(e){const n=e.split(`
2
- `);for(const o of n){if(!o.trim()||o.startsWith("#"))continue;const r=o.trim().split(/\s+/);switch(r[0]){case"v":this.tmpPositions.push(r.slice(1).map(Number));break;case"vn":this.tmpNormals.push(r.slice(1).map(Number));break;case"vt":this.tmpUVs.push(r.slice(1).map(Number));break;case"f":this.processFaceLine(r);break}}const h={type:l.Custom,position:this.positions,...this.normals.length>0&&{normal:this.normals},...this.uvs.length>0&&{uv:this.uvs}};return new b(h)}processFaceLine(e){for(let n=1;n<e.length;n++){const h=e[n];if(!h)continue;const[o,r,p]=h.split("/"),m=o?parseInt(o,10):void 0,d=r?parseInt(r,10):void 0,u=p?parseInt(p,10):void 0;if(m!==void 0){const a=this.tmpPositions[m-1];a&&this.positions.push(...a)}if(d!==void 0){const a=this.tmpUVs[d-1];a&&this.uvs.push(...a)}if(u!==void 0){const a=this.tmpNormals[u-1];a&&this.normals.push(...a)}}}}i.EditorRenderer=v,i.ObjLoader=g,i.PreviewRenderer=f,i.Renderer=c,Object.defineProperty(i,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(r,i){typeof exports=="object"&&typeof module<"u"?i(exports,require("ogl")):typeof define=="function"&&define.amd?define(["exports","ogl"],i):(r=typeof globalThis<"u"?globalThis:r||self,i(r.PlanaraCore={},r.OGL))})(this,(function(r,i){"use strict";function h(t){const e=`
2
+ attribute vec3 position;
3
+ attribute vec3 normal;
4
+ attribute vec2 uv;
5
+
6
+ uniform mat4 modelViewMatrix;
7
+ uniform mat4 projectionMatrix;
8
+ uniform mat3 normalMatrix;
9
+
10
+ varying vec3 vNormal;
11
+ varying vec2 vUv;
12
+
13
+ void main() {
14
+ vUv = uv;
15
+ vNormal = normalize(normalMatrix * normal);
16
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
17
+ }
18
+ `,s=`
19
+ precision highp float;
20
+
21
+ uniform sampler2D tMap;
22
+ varying vec3 vNormal;
23
+ varying vec2 vUv;
24
+
25
+ void main() {
26
+ vec3 tex = texture2D(tMap, vUv).rgb;
27
+ vec3 light = normalize(vec3(0.5, 1.0, -0.3));
28
+ float shading = dot(normalize(vNormal), light) * 0.15;
29
+ gl_FragColor.rgb = tex + shading;
30
+ gl_FragColor.a = 1.0;
31
+ }
32
+ `,n=new i.Texture(t);return new i.Program(t,{vertex:e,fragment:s,uniforms:{tMap:{value:n}}})}class l{gl;scene;camera;canvas;program;constructor(e){this.canvas=e,this.gl=new i.Renderer({canvas:e}),this.gl.setSize(e.clientWidth,e.clientHeight),this.gl.gl.clearColor(1,1,1,1),this.scene=new i.Transform,this.camera=new i.Camera(this.gl.gl,{fov:45}),this.camera.position.set(1,1,7),this.camera.lookAt([0,0,0]),this.program=h(this.gl.gl)}resize(){this.canvas.width=this.canvas.clientWidth,this.canvas.height=this.canvas.clientHeight,this.gl.setSize(this.canvas.clientWidth,this.canvas.clientHeight),this.camera.perspective({aspect:this.canvas.clientWidth/this.canvas.clientHeight})}render(){this.gl.render({scene:this.scene,camera:this.camera})}update(){}loop(){this.update(),this.render(),requestAnimationFrame(this.loop.bind(this))}addFigure(e){const s=new i.Geometry(this.gl.gl,{position:{size:3,data:new Float32Array(e.position)},normal:{size:3,data:new Float32Array(e.normal??[])},uv:{size:2,data:new Float32Array(e.uv??[])}}),n=new i.Mesh(this.gl.gl,{geometry:s,program:this.program});return n.setParent(this.scene),n}}class g extends l{orbit;constructor(e){super(e);const s=new i.GridHelper(this.gl.gl,{size:10,divisions:10});s.position.y=-.001,s.setParent(this.scene),new i.AxesHelper(this.gl.gl,{size:6,symmetric:!0}).setParent(this.scene),this.orbit=new i.Orbit(this.camera,{element:this.canvas})}update(){this.orbit?.update()}}class f extends l{orbit;constructor(e){super(e),this.orbit=new i.Orbit(this.camera,{element:this.canvas,target:new i.Vec3(0,0,0),minPolarAngle:Math.PI/2,maxPolarAngle:Math.PI/2,enableRotate:!0,enableZoom:!1,enablePan:!1})}update(){this.orbit?.update()}}class b{type;position;normal;uv;material;constructor(e){this.type=e.type,this.position=e.position,this.normal=e.normal??[],this.uv=e.uv??[],this.material=e.material}}var m=(t=>(t[t.Cube=0]="Cube",t[t.Sphere=1]="Sphere",t[t.Plane=2]="Plane",t[t.Cylinder=3]="Cylinder",t[t.Custom=4]="Custom",t))(m||{});class w{positions=[];normals=[];uvs=[];tmpPositions=[];tmpNormals=[];tmpUVs=[];load(e){const s=e.split(`
33
+ `);for(const c of s){if(!c.trim()||c.startsWith("#"))continue;const a=c.trim().split(/\s+/);switch(a[0]){case"v":this.tmpPositions.push(a.slice(1).map(Number));break;case"vn":this.tmpNormals.push(a.slice(1).map(Number));break;case"vt":this.tmpUVs.push(a.slice(1).map(Number));break;case"f":this.processFaceLine(a);break}}const n={type:m.Custom,position:this.positions,...this.normals.length>0&&{normal:this.normals},...this.uvs.length>0&&{uv:this.uvs}};return new b(n)}processFaceLine(e){for(let s=1;s<e.length;s++){const n=e[s];if(!n)continue;const[c,a,p]=n.split("/"),v=c?parseInt(c,10):void 0,u=a?parseInt(a,10):void 0,d=p?parseInt(p,10):void 0;if(v!==void 0){const o=this.tmpPositions[v-1];o&&this.positions.push(...o)}if(u!==void 0){const o=this.tmpUVs[u-1];o&&this.uvs.push(...o)}if(d!==void 0){const o=this.tmpNormals[d-1];o&&this.normals.push(...o)}}}}r.EditorRenderer=g,r.ObjLoader=w,r.PreviewRenderer=f,r.Renderer=l,r.createProgram=h,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"})}));
@@ -1,7 +1,10 @@
1
1
  import { Figure } from '@planara/types';
2
2
  export declare class ObjLoader {
3
+ /** Позиции вершин */
3
4
  private positions;
5
+ /** Нормали вершин */
4
6
  private normals;
7
+ /** UV-координаты (опционально) */
5
8
  private uvs;
6
9
  private tmpPositions;
7
10
  private tmpNormals;
@@ -10,7 +13,7 @@ export declare class ObjLoader {
10
13
  * Загружает OBJ-модель в Figure
11
14
  * @param objContent Строка содержимого .obj файла
12
15
  */
13
- parse(objContent: string): Figure;
16
+ load(objContent: string): Figure;
14
17
  /**
15
18
  * Обрабатывает строку face (f) и разворачивает индексы в массивы для рендеринга
16
19
  */
@@ -1 +1 @@
1
- {"version":3,"file":"obj-loader.d.ts","sourceRoot":"","sources":["../../src/loaders/obj-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA+B,MAAM,gBAAgB,CAAC;AAErE,qBAAa,SAAS;IACpB,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,GAAG,CAAgB;IAE3B,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,MAAM,CAAkB;IAEhC;;;OAGG;IACH,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAmCjC;;OAEG;IACH,OAAO,CAAC,eAAe;CA2BxB"}
1
+ {"version":3,"file":"obj-loader.d.ts","sourceRoot":"","sources":["../../src/loaders/obj-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAA+B,MAAM,gBAAgB,CAAC;AAErE,qBAAa,SAAS;IACpB,qBAAqB;IACrB,OAAO,CAAC,SAAS,CAAgB;IAEjC,qBAAqB;IACrB,OAAO,CAAC,OAAO,CAAgB;IAE/B,kCAAkC;IAClC,OAAO,CAAC,GAAG,CAAgB;IAG3B,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,MAAM,CAAkB;IAEhC;;;OAGG;IACI,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAmCvC;;OAEG;IACH,OAAO,CAAC,eAAe;CA2BxB"}
@@ -0,0 +1,12 @@
1
+ import { OGLRenderingContext, Program } from 'ogl';
2
+ /**
3
+ * Создает универсальный Program для рендерера.
4
+ *
5
+ * Включает базовый vertex и fragment шейдеры, добавляет uniform `tMap` с дефолтной текстурой.
6
+ * Этот Program можно использовать для всех фигур в сцене, а также для сетки и осей.
7
+ *
8
+ * @param {OGLRenderingContext} gl - WebGL контекст.
9
+ * @returns {Program} Экземпляр Program с базовыми шейдерами и uniform.
10
+ */
11
+ export declare function createProgram(gl: OGLRenderingContext): Program;
12
+ //# sourceMappingURL=program-settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program-settings.d.ts","sourceRoot":"","sources":["../../src/utils/program-settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,mBAAmB,EAAE,OAAO,EAAW,MAAM,KAAK,CAAC;AAEjE;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,mBAAmB,GAAG,OAAO,CA2C9D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planara/core",
3
- "version": "1.2.4",
3
+ "version": "1.3.0",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"