@planara/core 1.3.1 → 1.4.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.
@@ -1,4 +1,6 @@
1
1
  import { Renderer } from './renderer';
2
+ import { Mesh } from 'ogl';
3
+ import { Figure } from '@planara/types';
2
4
  /**
3
5
  * Рендерер для редактора.
4
6
  * Добавляет сетку, оси координат и поддержку Orbit для управления камерой.
@@ -7,6 +9,10 @@ import { Renderer } from './renderer';
7
9
  export declare class EditorRenderer extends Renderer {
8
10
  /** Orbit-контроллер для управления камерой */
9
11
  private orbit;
12
+ /** Raycast для подсветки моделей при наведении */
13
+ private raycast;
14
+ /** Курсор мыши для остлеживания наведения на 3D-модель */
15
+ private readonly mouse;
10
16
  /**
11
17
  * Инициализация сцены редактора.
12
18
  * Создает сетку, оси координат и orbit-контроллер.
@@ -17,5 +23,23 @@ export declare class EditorRenderer extends Renderer {
17
23
  * Обновление состояния рендерера.
18
24
  */
19
25
  protected update(): void;
26
+ /**
27
+ * Метод для добавления фигуры.
28
+ * Настройка raycast.
29
+ * @param figure Данные фигуры: position, normal, uv
30
+ */
31
+ addFigure(figure: Figure): Mesh<import('ogl').Geometry, import('ogl').Program>;
32
+ /**
33
+ * Обновление uniform uHit для конкретной 3D-модели
34
+ */
35
+ protected updateHitUniform(mesh: Mesh): void;
36
+ /**
37
+ * Инициализация обработчиков мыши для raycast
38
+ */
39
+ private initMouseListeners;
40
+ /**
41
+ * Обработчик движения мыши
42
+ */
43
+ private handleMouseMove;
20
44
  }
21
45
  //# sourceMappingURL=editor-renderer.d.ts.map
@@ -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;gBACgB,MAAM,EAAE,iBAAiB;IAgB5C;;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;AACtC,OAAO,EAAgD,KAAK,IAAI,EAAE,MAAM,KAAK,CAAC;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAE7C;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IAC1C,8CAA8C;IAC9C,OAAO,CAAC,KAAK,CAAS;IAEtB,kDAAkD;IAClD,OAAO,CAAC,OAAO,CAAW;IAE1B,0DAA0D;IAC1D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAE9B;;;;OAIG;gBACgB,MAAM,EAAE,iBAAiB;IAyB5C;;OAEG;IACH,SAAS,CAAC,MAAM;IAKhB;;;;OAIG;IACa,SAAS,CAAC,MAAM,EAAE,MAAM;IAsBxC;;OAEG;IACH,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI;IAIrC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAO1B;;OAEG;IACH,OAAO,CAAC,eAAe,CA2BrB;CACH"}
@@ -13,7 +13,10 @@ export declare abstract class Renderer {
13
13
  protected camera: Camera;
14
14
  /** HTML-элемент canvas, на котором рендерится сцена */
15
15
  protected canvas: HTMLCanvasElement;
16
+ /** Program для настройки рендеринга моделей */
16
17
  protected program: Program;
18
+ /** Массив моделей на сцене */
19
+ protected meshes: Mesh[];
17
20
  /**
18
21
  * Конструктор рендерера
19
22
  * @param canvas - HTMLCanvasElement для рендеринга
@@ -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,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"}
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,+CAA+C;IAC/C,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC;IAE3B,8BAA8B;IAC9B,SAAS,CAAC,MAAM,EAAG,IAAI,EAAE,CAAC;IAE1B;;;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;CAqBhC"}
package/dist/index.cjs.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("ogl");function v(t){const e=`
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("ogl");function v(s){const e=`
2
2
  attribute vec3 position;
3
3
  attribute vec3 normal;
4
4
  attribute vec2 uv;
@@ -15,7 +15,7 @@
15
15
  vNormal = normalize(normalMatrix * normal);
16
16
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
17
17
  }
18
- `,s=`
18
+ `,t=`
19
19
  precision highp float;
20
20
 
21
21
  uniform sampler2D tMap;
@@ -29,5 +29,5 @@
29
29
  gl_FragColor.rgb = tex + shading;
30
30
  gl_FragColor.a = 1.0;
31
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;
32
+ `,i=new r.Texture(s);return new r.Program(s,{vertex:e,fragment:t,uniforms:{tMap:{value:i}}})}class h{gl;scene;camera;canvas;program;meshes;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]),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 t=new r.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??[])}}),i=new r.Mesh(this.gl.gl,{geometry:t,program:this.program});return i.setParent(this.scene),this.meshes.push(i),i}}class p extends h{orbit;raycast;mouse;constructor(e){super(e);const t=new r.GridHelper(this.gl.gl,{size:10,divisions:10});t.position.y=-.001,t.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}),this.raycast=new r.Raycast,this.mouse=new r.Vec2,this.initMouseListeners()}update(){this.orbit?.update()}addFigure(e){const t=super.addFigure(e);if(t.geometry){const i=t.geometry.constructor.name;t.geometry.raycast=i.includes("Sphere")?"sphere":"box"}return t.isHit=!1,t.onBeforeRender(({mesh:i})=>{this.updateHitUniform(i)}),t}updateHitUniform(e){this.program.uniforms.uHit.value=e.isHit?1:0}initMouseListeners(){window.addEventListener("load",()=>{document.addEventListener("mousemove",this.handleMouseMove,!1),document.addEventListener("touchmove",this.handleMouseMove,!1)})}handleMouseMove=e=>{let t,i;if(e instanceof MouseEvent)t=e.clientX,i=e.clientY;else{if(e.touches[0]===void 0)return;t=e.touches[0].clientX,i=e.touches[0].clientY}this.mouse.set(2*(t/this.canvas.width)-1,2*(1-i/this.canvas.height)-1),this.raycast.castMouse(this.camera,this.mouse),this.meshes.forEach(a=>a.isHit=!1),this.raycast.intersectBounds(this.meshes).forEach(a=>a.isHit=!0)}}class g 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 f{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=(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))(d||{});class b{positions=[];normals=[];uvs=[];tmpPositions=[];tmpNormals=[];tmpUVs=[];load(e){const t=e.split(`
33
+ `);for(const n of t){if(!n.trim()||n.startsWith("#"))continue;const a=n.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 i={type:d.Custom,position:this.positions,...this.normals.length>0&&{normal:this.normals},...this.uvs.length>0&&{uv:this.uvs}};return new f(i)}processFaceLine(e){for(let t=1;t<e.length;t++){const i=e[t];if(!i)continue;const[n,a,c]=i.split("/"),l=n?parseInt(n,10):void 0,m=a?parseInt(a,10):void 0,u=c?parseInt(c,10):void 0;if(l!==void 0){const o=this.tmpPositions[l-1];o&&this.positions.push(...o)}if(m!==void 0){const o=this.tmpUVs[m-1];o&&this.uvs.push(...o)}if(u!==void 0){const o=this.tmpNormals[u-1];o&&this.normals.push(...o)}}}}exports.EditorRenderer=p;exports.ObjLoader=b;exports.PreviewRenderer=g;exports.Renderer=h;exports.createProgram=v;
package/dist/index.es.js CHANGED
@@ -1,6 +1,6 @@
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 = (
1
+ import { Texture as p, Program as d, Renderer as g, Transform as f, Camera as b, Geometry as w, Mesh as x, GridHelper as y, AxesHelper as M, Orbit as m, Raycast as P, Vec2 as z, Vec3 as C } from "ogl";
2
+ function F(s) {
3
+ const e = (
4
4
  /* glsl */
5
5
  `
6
6
  attribute vec3 position;
@@ -20,7 +20,7 @@ function z(e) {
20
20
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
21
21
  }
22
22
  `
23
- ), s = (
23
+ ), t = (
24
24
  /* glsl */
25
25
  `
26
26
  precision highp float;
@@ -37,14 +37,14 @@ function z(e) {
37
37
  gl_FragColor.a = 1.0;
38
38
  }
39
39
  `
40
- ), i = new u(e);
41
- return new d(e, {
42
- vertex: t,
43
- fragment: s,
40
+ ), i = new p(s);
41
+ return new d(s, {
42
+ vertex: e,
43
+ fragment: t,
44
44
  uniforms: { tMap: { value: i } }
45
45
  });
46
46
  }
47
- class p {
47
+ class u {
48
48
  /** Экземпляр рендерера OGL */
49
49
  gl;
50
50
  /** Корневой объект сцены */
@@ -53,13 +53,16 @@ class p {
53
53
  camera;
54
54
  /** HTML-элемент canvas, на котором рендерится сцена */
55
55
  canvas;
56
+ /** Program для настройки рендеринга моделей */
56
57
  program;
58
+ /** Массив моделей на сцене */
59
+ meshes;
57
60
  /**
58
61
  * Конструктор рендерера
59
62
  * @param canvas - HTMLCanvasElement для рендеринга
60
63
  */
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);
64
+ constructor(e) {
65
+ this.canvas = e, this.gl = new g({ canvas: e }), this.gl.setSize(e.clientWidth, e.clientHeight), this.gl.gl.clearColor(1, 1, 1, 1), this.scene = new f(), this.camera = new b(this.gl.gl, { fov: 45 }), this.camera.position.set(1, 1, 7), this.camera.lookAt([0, 0, 0]), this.program = F(this.gl.gl);
63
66
  }
64
67
  /**
65
68
  * Обновляет размер рендерера и камеры при изменении размеров canvas.
@@ -88,30 +91,34 @@ class p {
88
91
  * Публичный метод для добавления фигуры.
89
92
  * @param figure Данные фигуры: position, normal, uv
90
93
  */
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,
94
+ addFigure(e) {
95
+ const t = new w(this.gl.gl, {
96
+ position: { size: 3, data: new Float32Array(e.position) },
97
+ normal: { size: 3, data: new Float32Array(e.normal ?? []) },
98
+ uv: { size: 2, data: new Float32Array(e.uv ?? []) }
99
+ }), i = new x(this.gl.gl, {
100
+ geometry: t,
98
101
  program: this.program
99
102
  });
100
- return i.setParent(this.scene), i;
103
+ return i.setParent(this.scene), this.meshes.push(i), i;
101
104
  }
102
105
  }
103
- class N extends p {
106
+ class N extends u {
104
107
  /** Orbit-контроллер для управления камерой */
105
108
  orbit;
109
+ /** Raycast для подсветки моделей при наведении */
110
+ raycast;
111
+ /** Курсор мыши для остлеживания наведения на 3D-модель */
112
+ mouse;
106
113
  /**
107
114
  * Инициализация сцены редактора.
108
115
  * Создает сетку, оси координат и orbit-контроллер.
109
116
  * @param canvas - HTMLCanvasElement для рендеринга
110
117
  */
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 });
118
+ constructor(e) {
119
+ super(e);
120
+ const t = new y(this.gl.gl, { size: 10, divisions: 10 });
121
+ t.position.y = -1e-3, t.setParent(this.scene), new M(this.gl.gl, { size: 6, symmetric: !0 }).setParent(this.scene), this.orbit = new m(this.camera, { element: this.canvas }), this.raycast = new P(), this.mouse = new z(), this.initMouseListeners();
115
122
  }
116
123
  /**
117
124
  * Обновление состояния рендерера.
@@ -119,18 +126,60 @@ class N extends p {
119
126
  update() {
120
127
  this.orbit?.update();
121
128
  }
129
+ /**
130
+ * Метод для добавления фигуры.
131
+ * Настройка raycast.
132
+ * @param figure Данные фигуры: position, normal, uv
133
+ */
134
+ addFigure(e) {
135
+ const t = super.addFigure(e);
136
+ if (t.geometry) {
137
+ const i = t.geometry.constructor.name;
138
+ t.geometry.raycast = i.includes("Sphere") ? "sphere" : "box";
139
+ }
140
+ return t.isHit = !1, t.onBeforeRender(({ mesh: i }) => {
141
+ this.updateHitUniform(i);
142
+ }), t;
143
+ }
144
+ /**
145
+ * Обновление uniform uHit для конкретной 3D-модели
146
+ */
147
+ updateHitUniform(e) {
148
+ this.program.uniforms.uHit.value = e.isHit ? 1 : 0;
149
+ }
150
+ /**
151
+ * Инициализация обработчиков мыши для raycast
152
+ */
153
+ initMouseListeners() {
154
+ window.addEventListener("load", () => {
155
+ document.addEventListener("mousemove", this.handleMouseMove, !1), document.addEventListener("touchmove", this.handleMouseMove, !1);
156
+ });
157
+ }
158
+ /**
159
+ * Обработчик движения мыши
160
+ */
161
+ handleMouseMove = (e) => {
162
+ let t, i;
163
+ if (e instanceof MouseEvent)
164
+ t = e.clientX, i = e.clientY;
165
+ else {
166
+ if (e.touches[0] === void 0) return;
167
+ t = e.touches[0].clientX, i = e.touches[0].clientY;
168
+ }
169
+ this.mouse.set(2 * (t / this.canvas.width) - 1, 2 * (1 - i / this.canvas.height) - 1), this.raycast.castMouse(this.camera, this.mouse), this.meshes.forEach((r) => r.isHit = !1), this.raycast.intersectBounds(this.meshes).forEach((r) => r.isHit = !0);
170
+ };
122
171
  }
123
- class F extends p {
172
+ class U extends u {
124
173
  /** Orbit-контроллер для управления камерой */
125
174
  orbit;
126
175
  /**
127
176
  * Инициализация сцены предпросмотра.
128
177
  * @param canvas - HTMLCanvasElement для рендеринга
129
178
  */
130
- constructor(t) {
131
- super(t), this.orbit = new c(this.camera, {
179
+ constructor(e) {
180
+ super(e), this.orbit = new m(this.camera, {
132
181
  element: this.canvas,
133
- target: new M(0, 0, 0),
182
+ target: new C(0, 0, 0),
134
183
  minPolarAngle: Math.PI / 2,
135
184
  maxPolarAngle: Math.PI / 2,
136
185
  enableRotate: !0,
@@ -145,7 +194,7 @@ class F extends p {
145
194
  this.orbit?.update();
146
195
  }
147
196
  }
148
- class C {
197
+ class I {
149
198
  /** Тип фигуры */
150
199
  type;
151
200
  /** Позиции вершин */
@@ -160,11 +209,11 @@ class C {
160
209
  * Создаёт новую фигуру
161
210
  * @param data - исходные данные фигуры
162
211
  */
163
- constructor(t) {
164
- this.type = t.type, this.position = t.position, this.normal = t.normal ?? [], this.uv = t.uv ?? [], this.material = t.material;
212
+ constructor(e) {
213
+ this.type = e.type, this.position = e.position, this.normal = e.normal ?? [], this.uv = e.uv ?? [], this.material = e.material;
165
214
  }
166
215
  }
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 || {});
216
+ var v = /* @__PURE__ */ ((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))(v || {});
168
217
  class A {
169
218
  /** Позиции вершин */
170
219
  positions = [];
@@ -180,12 +229,12 @@ class A {
180
229
  * Загружает OBJ-модель в Figure
181
230
  * @param objContent Строка содержимого .obj файла
182
231
  */
183
- load(t) {
184
- const s = t.split(`
232
+ load(e) {
233
+ const t = e.split(`
185
234
  `);
186
- for (const n of s) {
187
- if (!n.trim() || n.startsWith("#")) continue;
188
- const r = n.trim().split(/\s+/);
235
+ for (const o of t) {
236
+ if (!o.trim() || o.startsWith("#")) continue;
237
+ const r = o.trim().split(/\s+/);
189
238
  switch (r[0]) {
190
239
  case "v":
191
240
  this.tmpPositions.push(r.slice(1).map(Number));
@@ -207,26 +256,26 @@ class A {
207
256
  ...this.normals.length > 0 && { normal: this.normals },
208
257
  ...this.uvs.length > 0 && { uv: this.uvs }
209
258
  };
210
- return new C(i);
259
+ return new I(i);
211
260
  }
212
261
  /**
213
262
  * Обрабатывает строку face (f) и разворачивает индексы в массивы для рендеринга
214
263
  */
215
- processFaceLine(t) {
216
- for (let s = 1; s < t.length; s++) {
217
- const i = t[s];
264
+ processFaceLine(e) {
265
+ for (let t = 1; t < e.length; t++) {
266
+ const i = e[t];
218
267
  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];
268
+ const [o, r, n] = i.split("/"), h = o ? parseInt(o, 10) : void 0, c = r ? parseInt(r, 10) : void 0, l = n ? parseInt(n, 10) : void 0;
269
+ if (h !== void 0) {
270
+ const a = this.tmpPositions[h - 1];
222
271
  a && this.positions.push(...a);
223
272
  }
224
- if (m !== void 0) {
225
- const a = this.tmpUVs[m - 1];
273
+ if (c !== void 0) {
274
+ const a = this.tmpUVs[c - 1];
226
275
  a && this.uvs.push(...a);
227
276
  }
228
- if (h !== void 0) {
229
- const a = this.tmpNormals[h - 1];
277
+ if (l !== void 0) {
278
+ const a = this.tmpNormals[l - 1];
230
279
  a && this.normals.push(...a);
231
280
  }
232
281
  }
@@ -235,7 +284,7 @@ class A {
235
284
  export {
236
285
  N as EditorRenderer,
237
286
  A as ObjLoader,
238
- F as PreviewRenderer,
239
- p as Renderer,
240
- z as createProgram
287
+ U as PreviewRenderer,
288
+ u as Renderer,
289
+ F as createProgram
241
290
  };
package/dist/index.umd.js CHANGED
@@ -1,4 +1,4 @@
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=`
1
+ (function(a,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("ogl")):typeof define=="function"&&define.amd?define(["exports","ogl"],r):(a=typeof globalThis<"u"?globalThis:a||self,r(a.PlanaraCore={},a.OGL))})(this,(function(a,r){"use strict";function m(s){const e=`
2
2
  attribute vec3 position;
3
3
  attribute vec3 normal;
4
4
  attribute vec2 uv;
@@ -15,7 +15,7 @@
15
15
  vNormal = normalize(normalMatrix * normal);
16
16
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
17
17
  }
18
- `,s=`
18
+ `,t=`
19
19
  precision highp float;
20
20
 
21
21
  uniform sampler2D tMap;
@@ -29,5 +29,5 @@
29
29
  gl_FragColor.rgb = tex + shading;
30
30
  gl_FragColor.a = 1.0;
31
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"})}));
32
+ `,i=new r.Texture(s);return new r.Program(s,{vertex:e,fragment:t,uniforms:{tMap:{value:i}}})}class c{gl;scene;camera;canvas;program;meshes;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]),this.program=m(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 t=new r.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??[])}}),i=new r.Mesh(this.gl.gl,{geometry:t,program:this.program});return i.setParent(this.scene),this.meshes.push(i),i}}class f extends c{orbit;raycast;mouse;constructor(e){super(e);const t=new r.GridHelper(this.gl.gl,{size:10,divisions:10});t.position.y=-.001,t.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}),this.raycast=new r.Raycast,this.mouse=new r.Vec2,this.initMouseListeners()}update(){this.orbit?.update()}addFigure(e){const t=super.addFigure(e);if(t.geometry){const i=t.geometry.constructor.name;t.geometry.raycast=i.includes("Sphere")?"sphere":"box"}return t.isHit=!1,t.onBeforeRender(({mesh:i})=>{this.updateHitUniform(i)}),t}updateHitUniform(e){this.program.uniforms.uHit.value=e.isHit?1:0}initMouseListeners(){window.addEventListener("load",()=>{document.addEventListener("mousemove",this.handleMouseMove,!1),document.addEventListener("touchmove",this.handleMouseMove,!1)})}handleMouseMove=e=>{let t,i;if(e instanceof MouseEvent)t=e.clientX,i=e.clientY;else{if(e.touches[0]===void 0)return;t=e.touches[0].clientX,i=e.touches[0].clientY}this.mouse.set(2*(t/this.canvas.width)-1,2*(1-i/this.canvas.height)-1),this.raycast.castMouse(this.camera,this.mouse),this.meshes.forEach(n=>n.isHit=!1),this.raycast.intersectBounds(this.meshes).forEach(n=>n.isHit=!0)}}class g extends c{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 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 y{positions=[];normals=[];uvs=[];tmpPositions=[];tmpNormals=[];tmpUVs=[];load(e){const t=e.split(`
33
+ `);for(const h of t){if(!h.trim()||h.startsWith("#"))continue;const n=h.trim().split(/\s+/);switch(n[0]){case"v":this.tmpPositions.push(n.slice(1).map(Number));break;case"vn":this.tmpNormals.push(n.slice(1).map(Number));break;case"vt":this.tmpUVs.push(n.slice(1).map(Number));break;case"f":this.processFaceLine(n);break}}const i={type:l.Custom,position:this.positions,...this.normals.length>0&&{normal:this.normals},...this.uvs.length>0&&{uv:this.uvs}};return new b(i)}processFaceLine(e){for(let t=1;t<e.length;t++){const i=e[t];if(!i)continue;const[h,n,u]=i.split("/"),d=h?parseInt(h,10):void 0,v=n?parseInt(n,10):void 0,p=u?parseInt(u,10):void 0;if(d!==void 0){const o=this.tmpPositions[d-1];o&&this.positions.push(...o)}if(v!==void 0){const o=this.tmpUVs[v-1];o&&this.uvs.push(...o)}if(p!==void 0){const o=this.tmpNormals[p-1];o&&this.normals.push(...o)}}}}a.EditorRenderer=f,a.ObjLoader=y,a.PreviewRenderer=g,a.Renderer=c,a.createProgram=m,Object.defineProperty(a,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planara/core",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "registry": "https://registry.npmjs.org/"