@planara/core 1.2.5 → 1.3.1

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.
@@ -1,4 +1,5 @@
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
  * Отвечает за инициализацию сцены, камеры и цикла рендеринга.
@@ -12,6 +13,7 @@ export declare abstract class Renderer {
12
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 для рендеринга
@@ -33,5 +35,10 @@ export declare abstract class Renderer {
33
35
  * Запускает основной цикл рендеринга.
34
36
  */
35
37
  loop(): void;
38
+ /**
39
+ * Публичный метод для добавления фигуры.
40
+ * @param figure Данные фигуры: position, normal, uv
41
+ */
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;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;;;OAGG;IACH,SAAS,aAAa,MAAM,EAAE,iBAAiB;IAa/C;;OAEG;IACI,MAAM;IAUb;;OAEG;IACH,SAAS,CAAC,MAAM;IAIhB;;OAEG;IACH,SAAS,CAAC,MAAM,IAAI,IAAI;IAExB;;OAEG;IACI,IAAI;CAKZ"}
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;IAMb;;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 r=require("ogl");class h{gl;scene;camera;canvas;constructor(e){this.canvas=e,this.gl=new r.Renderer({canvas:e}),this.gl.setSize(e.clientWidth,e.clientHeight),this.gl.gl.clearColor(1,1,1,1),this.scene=new r.Transform,this.camera=new r.Camera(this.gl.gl,{fov:45}),this.camera.position.set(1,1,7),this.camera.lookAt([0,0,0])}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))}}class u extends h{orbit;constructor(e){super(e);const s=new r.GridHelper(this.gl.gl,{size:10,divisions:10});s.position.y=-.001,s.setParent(this.scene),new r.AxesHelper(this.gl.gl,{size:6,symmetric:!0}).setParent(this.scene),this.orbit=new r.Orbit(this.camera,{element:this.canvas})}update(){this.orbit?.update()}}class v extends h{orbit;constructor(e){super(e),this.orbit=new r.Orbit(this.camera,{element:this.canvas,target:new r.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 d=(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))(d||{});class b{positions=[];normals=[];uvs=[];tmpPositions=[];tmpNormals=[];tmpUVs=[];parse(e){const s=e.split(`
2
- `);for(const a of s){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:d.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 s=1;s<e.length;s++){const o=e[s];if(!o)continue;const[a,i,c]=o.split("/"),l=a?parseInt(a,10):void 0,p=i?parseInt(i,10):void 0,m=c?parseInt(c,10):void 0;if(l!==void 0){const n=this.tmpPositions[l-1];n&&this.positions.push(...n)}if(p!==void 0){const n=this.tmpUVs[p-1];n&&this.uvs.push(...n)}if(m!==void 0){const n=this.tmpNormals[m-1];n&&this.normals.push(...n)}}}}exports.EditorRenderer=u;exports.ObjLoader=b;exports.PreviewRenderer=v;exports.Renderer=h;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("ogl");function v(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
+ `,r=new i.Texture(t);return new i.Program(t,{vertex:e,fragment:s,uniforms:{tMap:{value:r}}})}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=v(this.gl.gl)}resize(){this.gl.setSize(this.canvas.width,this.canvas.height),this.camera.perspective({aspect:this.canvas.width/this.canvas.height})}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??[])}}),r=new i.Mesh(this.gl.gl,{geometry:s,program:this.program});return r.setParent(this.scene),r}}class d 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 g 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 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 s=e.split(`
33
+ `);for(const o of s){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 s=1;s<e.length;s++){const r=e[s];if(!r)continue;const[o,a,c]=r.split("/"),m=o?parseInt(o,10):void 0,h=a?parseInt(a,10):void 0,p=c?parseInt(c,10):void 0;if(m!==void 0){const n=this.tmpPositions[m-1];n&&this.positions.push(...n)}if(h!==void 0){const n=this.tmpUVs[h-1];n&&this.uvs.push(...n)}if(p!==void 0){const n=this.tmpNormals[p-1];n&&this.normals.push(...n)}}}}exports.EditorRenderer=d;exports.ObjLoader=f;exports.PreviewRenderer=g;exports.Renderer=l;exports.createProgram=v;
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 c, 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
+ ), s = (
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
+ ), i = new u(e);
41
+ return new d(e, {
42
+ vertex: t,
43
+ fragment: s,
44
+ uniforms: { tMap: { value: i } }
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.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 });
68
+ this.gl.setSize(this.canvas.width, this.canvas.height), this.camera.perspective({ aspect: this.canvas.width / this.canvas.height });
23
69
  }
24
70
  /**
25
71
  * Выполняет рендеринг сцены с текущей камерой.
@@ -38,8 +84,23 @@ class m {
38
84
  loop() {
39
85
  this.update(), this.render(), requestAnimationFrame(this.loop.bind(this));
40
86
  }
87
+ /**
88
+ * Публичный метод для добавления фигуры.
89
+ * @param figure Данные фигуры: position, normal, uv
90
+ */
91
+ addFigure(t) {
92
+ const s = 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
+ }), i = new w(this.gl.gl, {
97
+ geometry: s,
98
+ program: this.program
99
+ });
100
+ return i.setParent(this.scene), i;
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 e = new b(this.gl.gl, { size: 10, divisions: 10 });
53
- e.position.y = -1e-3, e.setParent(this.scene), new f(this.gl.gl, { size: 6, symmetric: !0 }).setParent(this.scene), this.orbit = new p(this.camera, { element: this.canvas });
111
+ constructor(t) {
112
+ super(t);
113
+ const s = new y(this.gl.gl, { size: 10, divisions: 10 });
114
+ s.position.y = -1e-3, s.setParent(this.scene), new P(this.gl.gl, { size: 6, symmetric: !0 }).setParent(this.scene), this.orbit = new c(this.camera, { element: this.canvas });
54
115
  }
55
116
  /**
56
117
  * Обновление состояния рендерера.
@@ -59,17 +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, {
130
+ constructor(t) {
131
+ super(t), this.orbit = new c(this.camera, {
71
132
  element: this.canvas,
72
- target: new x(0, 0, 0),
133
+ target: new M(0, 0, 0),
73
134
  minPolarAngle: Math.PI / 2,
74
135
  maxPolarAngle: Math.PI / 2,
75
136
  enableRotate: !0,
@@ -84,7 +145,7 @@ class C extends m {
84
145
  this.orbit?.update();
85
146
  }
86
147
  }
87
- class P {
148
+ class C {
88
149
  /** Тип фигуры */
89
150
  type;
90
151
  /** Позиции вершин */
@@ -99,15 +160,19 @@ class P {
99
160
  * Создаёт новую фигуру
100
161
  * @param data - исходные данные фигуры
101
162
  */
102
- constructor(s) {
103
- 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;
104
165
  }
105
166
  }
106
- var u = /* @__PURE__ */ ((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 || {});
107
- 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
+ /** Позиции вершин */
108
170
  positions = [];
171
+ /** Нормали вершин */
109
172
  normals = [];
173
+ /** UV-координаты (опционально) */
110
174
  uvs = [];
175
+ // Временные поля для парсинга файла
111
176
  tmpPositions = [];
112
177
  tmpNormals = [];
113
178
  tmpUVs = [];
@@ -115,61 +180,62 @@ class y {
115
180
  * Загружает OBJ-модель в Figure
116
181
  * @param objContent Строка содержимого .obj файла
117
182
  */
118
- parse(s) {
119
- const e = s.split(`
183
+ load(t) {
184
+ const s = t.split(`
120
185
  `);
121
- for (const a of e) {
122
- if (!a.trim() || a.startsWith("#")) continue;
123
- const i = a.trim().split(/\s+/);
124
- switch (i[0]) {
186
+ for (const n of s) {
187
+ if (!n.trim() || n.startsWith("#")) continue;
188
+ const r = n.trim().split(/\s+/);
189
+ switch (r[0]) {
125
190
  case "v":
126
- this.tmpPositions.push(i.slice(1).map(Number));
191
+ this.tmpPositions.push(r.slice(1).map(Number));
127
192
  break;
128
193
  case "vn":
129
- this.tmpNormals.push(i.slice(1).map(Number));
194
+ this.tmpNormals.push(r.slice(1).map(Number));
130
195
  break;
131
196
  case "vt":
132
- this.tmpUVs.push(i.slice(1).map(Number));
197
+ this.tmpUVs.push(r.slice(1).map(Number));
133
198
  break;
134
199
  case "f":
135
- this.processFaceLine(i);
200
+ this.processFaceLine(r);
136
201
  break;
137
202
  }
138
203
  }
139
- const r = {
140
- type: u.Custom,
204
+ const i = {
205
+ type: v.Custom,
141
206
  position: this.positions,
142
207
  ...this.normals.length > 0 && { normal: this.normals },
143
208
  ...this.uvs.length > 0 && { uv: this.uvs }
144
209
  };
145
- return new P(r);
210
+ return new C(i);
146
211
  }
147
212
  /**
148
213
  * Обрабатывает строку face (f) и разворачивает индексы в массивы для рендеринга
149
214
  */
150
- processFaceLine(s) {
151
- for (let e = 1; e < s.length; e++) {
152
- const r = s[e];
153
- if (!r) continue;
154
- const [a, i, o] = r.split("/"), h = a ? parseInt(a, 10) : void 0, c = i ? parseInt(i, 10) : void 0, l = o ? parseInt(o, 10) : void 0;
155
- if (h !== void 0) {
156
- const n = this.tmpPositions[h - 1];
157
- n && this.positions.push(...n);
215
+ processFaceLine(t) {
216
+ for (let s = 1; s < t.length; s++) {
217
+ const i = t[s];
218
+ if (!i) continue;
219
+ const [n, r, o] = i.split("/"), l = n ? parseInt(n, 10) : void 0, m = 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);
158
223
  }
159
- if (c !== void 0) {
160
- const n = this.tmpUVs[c - 1];
161
- n && this.uvs.push(...n);
224
+ if (m !== void 0) {
225
+ const a = this.tmpUVs[m - 1];
226
+ a && this.uvs.push(...a);
162
227
  }
163
- if (l !== void 0) {
164
- const n = this.tmpNormals[l - 1];
165
- n && this.normals.push(...n);
228
+ if (h !== void 0) {
229
+ const a = this.tmpNormals[h - 1];
230
+ a && this.normals.push(...a);
166
231
  }
167
232
  }
168
233
  }
169
234
  }
170
235
  export {
171
- I as EditorRenderer,
172
- y as ObjLoader,
173
- C as PreviewRenderer,
174
- m as Renderer
236
+ N as EditorRenderer,
237
+ A as ObjLoader,
238
+ F as PreviewRenderer,
239
+ p as Renderer,
240
+ z as createProgram
175
241
  };
package/dist/index.umd.js CHANGED
@@ -1,2 +1,33 @@
1
- (function(i,s){typeof exports=="object"&&typeof module<"u"?s(exports,require("ogl")):typeof define=="function"&&define.amd?define(["exports","ogl"],s):(i=typeof globalThis<"u"?globalThis:i||self,s(i.PlanaraCore={},i.OGL))})(this,(function(i,s){"use strict";class c{gl;scene;camera;canvas;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])}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))}}class v extends c{orbit;constructor(e){super(e);const n=new s.GridHelper(this.gl.gl,{size:10,divisions:10});n.position.y=-.001,n.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 f extends c{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 l=(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))(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 c{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.gl.setSize(this.canvas.width,this.canvas.height),this.camera.perspective({aspect:this.canvas.width/this.canvas.height})}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 c{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 c{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 l of s){if(!l.trim()||l.startsWith("#"))continue;const a=l.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[l,a,p]=n.split("/"),v=l?parseInt(l,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=c,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;IACI,KAAK,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAmCxC;;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.5",
3
+ "version": "1.3.1",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"