abstract-3d 2.3.5 → 2.3.8
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/lib/abstract-3d.d.ts +3 -1
- package/lib/abstract-3d.d.ts.map +1 -1
- package/lib/abstract-3d.js.map +1 -1
- package/lib/renderers/dxf/dxf-geometries/dxf-image.d.ts.map +1 -1
- package/lib/renderers/dxf/dxf-geometries/dxf-image.js +9 -3
- package/lib/renderers/dxf/dxf-geometries/dxf-image.js.map +1 -1
- package/lib/renderers/react/react-group.d.ts.map +1 -1
- package/lib/renderers/react/react-group.js +4 -19
- package/lib/renderers/react/react-group.js.map +1 -1
- package/lib/renderers/react/react-image.d.ts +29 -0
- package/lib/renderers/react/react-image.d.ts.map +1 -0
- package/lib/renderers/react/react-image.js +84 -0
- package/lib/renderers/react/react-image.js.map +1 -0
- package/lib/renderers/react/react-material.d.ts +5 -17
- package/lib/renderers/react/react-material.d.ts.map +1 -1
- package/lib/renderers/react/react-material.js +21 -92
- package/lib/renderers/react/react-material.js.map +1 -1
- package/lib/renderers/react/react-mesh.d.ts +8 -1
- package/lib/renderers/react/react-mesh.d.ts.map +1 -1
- package/lib/renderers/react/react-mesh.js +5 -6
- package/lib/renderers/react/react-mesh.js.map +1 -1
- package/lib/renderers/svg/svg-encoding.d.ts +1 -0
- package/lib/renderers/svg/svg-encoding.d.ts.map +1 -1
- package/lib/renderers/svg/svg-encoding.js +5 -2
- package/lib/renderers/svg/svg-encoding.js.map +1 -1
- package/lib/renderers/svg/svg-geometries/svg-image.d.ts.map +1 -1
- package/lib/renderers/svg/svg-geometries/svg-image.js +18 -2
- package/lib/renderers/svg/svg-geometries/svg-image.js.map +1 -1
- package/lib/renderers/svg/svg-geometries/svg-plane.d.ts.map +1 -1
- package/lib/renderers/svg/svg-geometries/svg-plane.js +1 -15
- package/lib/renderers/svg/svg-geometries/svg-plane.js.map +1 -1
- package/package.json +2 -2
- package/src/abstract-3d.ts +9 -5
- package/src/renderers/dxf/dxf-geometries/dxf-image.ts +20 -19
- package/src/renderers/react/react-group.tsx +26 -34
- package/src/renderers/react/react-image.tsx +149 -0
- package/src/renderers/react/react-material.tsx +33 -166
- package/src/renderers/react/react-mesh.tsx +27 -14
- package/src/renderers/svg/svg-encoding.ts +6 -4
- package/src/renderers/svg/svg-geometries/svg-image.ts +22 -2
- package/src/renderers/svg/svg-geometries/svg-plane.ts +1 -21
- package/src/.DS_Store +0 -0
- package/src/renderers/.DS_Store +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { createSVG } from "abstract-image";
|
|
3
2
|
import { ThreeEvent, useFrame } from "@react-three/fiber";
|
|
4
3
|
import type { Group } from "three";
|
|
5
|
-
import { Group as Group_1
|
|
4
|
+
import { Group as Group_1 } from "../../abstract-3d.js";
|
|
6
5
|
import { MaterialState, ReactMaterial } from "./react-material.js";
|
|
7
6
|
import { ReactMesh } from "./react-mesh.js";
|
|
8
7
|
|
|
@@ -126,40 +125,33 @@ export function ReactGroup({
|
|
|
126
125
|
useAlphaTest={useAlphaTest}
|
|
127
126
|
/>
|
|
128
127
|
))}
|
|
129
|
-
{g.meshes?.map((m, i) =>
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
isText={m.geometry.type === "Text"}
|
|
136
|
-
hoveredId={hoveredId || hoveredIdExternal}
|
|
128
|
+
{g.meshes?.map((m, i) => {
|
|
129
|
+
const hoveredIdFinal = hoveredId || hoveredIdExternal;
|
|
130
|
+
return (
|
|
131
|
+
<ReactMesh
|
|
132
|
+
key={`mesh_${i}`}
|
|
133
|
+
mesh={m}
|
|
137
134
|
materialStateImages={materialStateImages}
|
|
138
|
-
disabled={disabled}
|
|
139
|
-
state={materialState}
|
|
140
135
|
useAlphaTest={useAlphaTest}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
136
|
+
id={id}
|
|
137
|
+
hoveredId={hoveredIdFinal}
|
|
138
|
+
materialState={materialState}
|
|
139
|
+
selectedIds={selectedIds}
|
|
140
|
+
>
|
|
141
|
+
{m.geometry.type === "Image" ? undefined : (
|
|
142
|
+
<ReactMaterial
|
|
143
|
+
material={m.material}
|
|
144
|
+
id={id}
|
|
145
|
+
selectedIds={selectedIds}
|
|
146
|
+
isText={m.geometry.type === "Text"}
|
|
147
|
+
hoveredId={hoveredIdFinal}
|
|
148
|
+
disabled={disabled}
|
|
149
|
+
materialState={materialState}
|
|
150
|
+
/>
|
|
151
|
+
)}
|
|
152
|
+
</ReactMesh>
|
|
153
|
+
);
|
|
154
|
+
})}
|
|
144
155
|
</group>
|
|
145
156
|
);
|
|
146
157
|
}
|
|
147
|
-
|
|
148
|
-
function getMaterial(mesh: Mesh): Material {
|
|
149
|
-
if(mesh.geometry.type !== "Image") {
|
|
150
|
-
return mesh.material;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
switch(mesh.geometry.image.type) {
|
|
154
|
-
case "AbstractImage": {
|
|
155
|
-
const svg = createSVG(mesh.geometry.image.image);
|
|
156
|
-
const svgUrl = `data:image/svg+xml,${svg}`;
|
|
157
|
-
return {
|
|
158
|
-
...mesh.material,
|
|
159
|
-
imageUrl: svgUrl,
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
default:
|
|
163
|
-
return mesh.material;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
|
+
import { suspend } from "suspend-react";
|
|
3
|
+
import { createSVG } from "abstract-image";
|
|
4
|
+
import { CanvasTexture, DoubleSide, PlaneGeometry, SRGBColorSpace, type Texture, TextureLoader } from "three";
|
|
5
|
+
import { Material, Image as A3dImage } from "../../abstract-3d.js";
|
|
6
|
+
import { ERROR_IMG_KEY, getColor, materialDefaults, MaterialState } from "./react-material.js";
|
|
7
|
+
|
|
8
|
+
export const planeGeometry = new PlaneGeometry();
|
|
9
|
+
|
|
10
|
+
export enum MinificationFilter {
|
|
11
|
+
Nearest = 1003,
|
|
12
|
+
Linear = 1006,
|
|
13
|
+
LinearMipmap = 1008,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export enum MagnificationFilter {
|
|
17
|
+
Nearest = 1003,
|
|
18
|
+
Linear = 1006,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type TextureFilter = {
|
|
22
|
+
readonly min: MinificationFilter;
|
|
23
|
+
readonly mag: MagnificationFilter;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const filter: TextureFilter = { min: MinificationFilter.LinearMipmap, mag: MagnificationFilter.Linear };
|
|
27
|
+
|
|
28
|
+
export function ImageMesh({
|
|
29
|
+
image,
|
|
30
|
+
materialStateImages,
|
|
31
|
+
material,
|
|
32
|
+
id,
|
|
33
|
+
useAlphaTest,
|
|
34
|
+
hoveredId,
|
|
35
|
+
selectedIds,
|
|
36
|
+
materialState,
|
|
37
|
+
}: {
|
|
38
|
+
readonly image: A3dImage;
|
|
39
|
+
readonly material: Material;
|
|
40
|
+
readonly id: string | undefined;
|
|
41
|
+
readonly materialStateImages: Record<string, string> | undefined;
|
|
42
|
+
readonly hoveredId: string | undefined;
|
|
43
|
+
readonly selectedIds: Record<string, boolean> | undefined;
|
|
44
|
+
readonly useAlphaTest: boolean | undefined;
|
|
45
|
+
readonly materialState: MaterialState | undefined;
|
|
46
|
+
}): React.JSX.Element {
|
|
47
|
+
const url =
|
|
48
|
+
materialState === "Error" && materialStateImages?.[ERROR_IMG_KEY]
|
|
49
|
+
? materialStateImages[ERROR_IMG_KEY]
|
|
50
|
+
: image.image.type === "AbstractImage"
|
|
51
|
+
? `data:image/svg+xml,${createSVG(image.image.image)}`
|
|
52
|
+
: image.image.url;
|
|
53
|
+
|
|
54
|
+
const texture = suspend(urlIsSvg(url) ? loadSvg(url, filter) : loadNormal(url, filter), [url]) as Texture | null;
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
return () => {
|
|
57
|
+
if (texture) {
|
|
58
|
+
texture.dispose();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}, [texture]);
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<mesh
|
|
65
|
+
geometry={planeGeometry}
|
|
66
|
+
scale={[image.size.x, image.size.y, 1]}
|
|
67
|
+
position={[image.pos.x, image.pos.y, image.pos.z]}
|
|
68
|
+
rotation={[image.rot?.x ?? 0, image.rot?.y ?? 0, image.rot?.z ?? 0]}
|
|
69
|
+
castShadow
|
|
70
|
+
receiveShadow
|
|
71
|
+
>
|
|
72
|
+
<meshBasicMaterial
|
|
73
|
+
color={getColor(selectedIds, id, hoveredId, material)}
|
|
74
|
+
side={DoubleSide}
|
|
75
|
+
alphaTest={useAlphaTest ?? true ? 0.8 : undefined}
|
|
76
|
+
map={texture}
|
|
77
|
+
{...(material.opacity !== undefined && material.opacity < 1 ? { opacity: material.opacity } : materialDefaults)}
|
|
78
|
+
transparent
|
|
79
|
+
/>
|
|
80
|
+
</mesh>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function urlIsSvg(url: string): boolean {
|
|
85
|
+
return url.startsWith("data:image/svg+xml") || url.endsWith(".svg") || url.includes(".svg?");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function loadSvg(url: string, filter: TextureFilter): Promise<Texture | null> {
|
|
89
|
+
const maxSize = 4096;
|
|
90
|
+
|
|
91
|
+
return new Promise((res) => {
|
|
92
|
+
const img = new Image();
|
|
93
|
+
|
|
94
|
+
// eslint-disable-next-line consistent-return
|
|
95
|
+
img.onload = (): void => {
|
|
96
|
+
const canvas = document.createElement("canvas");
|
|
97
|
+
const imgW = img.naturalWidth;
|
|
98
|
+
const imgH = img.naturalHeight;
|
|
99
|
+
const width = imgW >= imgH ? maxSize : maxSize * (imgW / imgH);
|
|
100
|
+
const height = imgH >= imgW ? maxSize : maxSize * (imgH / imgW);
|
|
101
|
+
|
|
102
|
+
canvas.width = width;
|
|
103
|
+
canvas.height = height;
|
|
104
|
+
|
|
105
|
+
const ctx = canvas.getContext("2d");
|
|
106
|
+
if (!ctx) {
|
|
107
|
+
return res(null);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
111
|
+
ctx.imageSmoothingEnabled = true;
|
|
112
|
+
ctx.imageSmoothingQuality = "high";
|
|
113
|
+
ctx.drawImage(img, 0, 0, width, height);
|
|
114
|
+
|
|
115
|
+
const texture = new CanvasTexture(canvas);
|
|
116
|
+
texture.colorSpace = SRGBColorSpace;
|
|
117
|
+
texture.minFilter = filter.min;
|
|
118
|
+
texture.magFilter = filter.mag;
|
|
119
|
+
texture.generateMipmaps = filter.min === MinificationFilter.LinearMipmap;
|
|
120
|
+
texture.anisotropy = 4;
|
|
121
|
+
texture.needsUpdate = true;
|
|
122
|
+
|
|
123
|
+
res(texture);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
img.onerror = () => res(null);
|
|
127
|
+
img.src = url;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function loadNormal(url: string, filter: TextureFilter): Promise<Texture | null> {
|
|
132
|
+
return new Promise((res) =>
|
|
133
|
+
textureLoader.load(
|
|
134
|
+
url,
|
|
135
|
+
(data) => {
|
|
136
|
+
data.colorSpace = SRGBColorSpace;
|
|
137
|
+
data.minFilter = filter.min;
|
|
138
|
+
data.magFilter = filter.mag;
|
|
139
|
+
data.generateMipmaps = filter.min === MinificationFilter.LinearMipmap;
|
|
140
|
+
data.anisotropy = 4;
|
|
141
|
+
res(data);
|
|
142
|
+
},
|
|
143
|
+
undefined,
|
|
144
|
+
() => res(null)
|
|
145
|
+
)
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const textureLoader = new TextureLoader();
|
|
@@ -1,38 +1,10 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
BackSide,
|
|
5
|
-
CanvasTexture,
|
|
6
|
-
type Color,
|
|
7
|
-
DoubleSide,
|
|
8
|
-
FrontSide,
|
|
9
|
-
type MaterialParameters,
|
|
10
|
-
SRGBColorSpace,
|
|
11
|
-
type Texture,
|
|
12
|
-
TextureLoader,
|
|
13
|
-
} from "three";
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { BackSide, DoubleSide, FrontSide, type MaterialParameters } from "three";
|
|
14
3
|
import { Material } from "../../abstract-3d.js";
|
|
15
4
|
import { shade } from "../../utils.js";
|
|
16
|
-
import { mx_gradient_float } from "three/src/nodes/materialx/lib/mx_noise.js";
|
|
17
5
|
|
|
18
6
|
const decreasedOpacity = 0.125;
|
|
19
7
|
|
|
20
|
-
export enum MinificationFilter {
|
|
21
|
-
Nearest = 1003,
|
|
22
|
-
Linear = 1006,
|
|
23
|
-
LinearMipmap = 1008,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export enum MagnificationFilter {
|
|
27
|
-
Nearest = 1003,
|
|
28
|
-
Linear = 1006,
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export type TextureFilter = {
|
|
32
|
-
readonly min: MinificationFilter;
|
|
33
|
-
readonly mag: MagnificationFilter;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
8
|
export type MaterialState = "Accept" | "Error" | "Warning";
|
|
37
9
|
export const ERROR_IMG_KEY = "error";
|
|
38
10
|
|
|
@@ -42,40 +14,29 @@ export function ReactMaterial({
|
|
|
42
14
|
selectedIds,
|
|
43
15
|
hoveredId,
|
|
44
16
|
disabled,
|
|
45
|
-
|
|
46
|
-
state,
|
|
17
|
+
materialState,
|
|
47
18
|
isText,
|
|
48
19
|
isHotSpot,
|
|
49
20
|
drawBackOnly,
|
|
50
|
-
useAlphaTest,
|
|
51
21
|
}: {
|
|
52
22
|
readonly material: Material;
|
|
53
23
|
readonly id?: string;
|
|
54
24
|
readonly hoveredId?: string | undefined;
|
|
55
25
|
readonly selectedIds?: Record<string, boolean> | undefined;
|
|
56
26
|
readonly disabled?: boolean;
|
|
57
|
-
readonly
|
|
58
|
-
readonly state?: MaterialState | undefined;
|
|
27
|
+
readonly materialState?: MaterialState | undefined;
|
|
59
28
|
readonly isText: boolean;
|
|
60
29
|
readonly isHotSpot?: boolean;
|
|
61
30
|
readonly drawBackOnly?: boolean;
|
|
62
|
-
readonly useAlphaTest?: boolean;
|
|
63
31
|
}): React.JSX.Element {
|
|
64
|
-
const mat =
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const color = selectedIds?.[id]
|
|
73
|
-
? hoveredId === id
|
|
74
|
-
? shade(-0.4, selectMat.normal)
|
|
75
|
-
: selectMat.normal
|
|
76
|
-
: hoveredId === id
|
|
77
|
-
? shade(-0.4, mat.normal)
|
|
78
|
-
: mat.normal;
|
|
32
|
+
const mat = !materialState
|
|
33
|
+
? material
|
|
34
|
+
: materialState === "Accept"
|
|
35
|
+
? acceptMat
|
|
36
|
+
: materialState === "Error"
|
|
37
|
+
? errorMar
|
|
38
|
+
: warningMat;
|
|
39
|
+
const color = getColor(selectedIds, id, hoveredId, mat);
|
|
79
40
|
const colorText = selectedIds?.[id]
|
|
80
41
|
? hoveredId === id
|
|
81
42
|
? shade(-0.4, textSelectMat.normal)
|
|
@@ -84,17 +45,6 @@ export function ReactMaterial({
|
|
|
84
45
|
? shade(-0.4, mat.normal)
|
|
85
46
|
: mat.normal;
|
|
86
47
|
const opacity = material.opacity !== undefined ? material.opacity : materialDefaults.opacity!;
|
|
87
|
-
if (material.imageUrl) {
|
|
88
|
-
return (
|
|
89
|
-
<TextureMaterial
|
|
90
|
-
url={state === "Error" ? materialStateImages?.[ERROR_IMG_KEY] ?? material.imageUrl : material.imageUrl}
|
|
91
|
-
color={color}
|
|
92
|
-
material={mat}
|
|
93
|
-
useAlphaTest={useAlphaTest}
|
|
94
|
-
filter={{ mag: MagnificationFilter.Linear, min: MinificationFilter.LinearMipmap }}
|
|
95
|
-
/>
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
48
|
if (isText) {
|
|
99
49
|
return (
|
|
100
50
|
<meshBasicMaterial
|
|
@@ -137,114 +87,31 @@ export function ReactMaterial({
|
|
|
137
87
|
/>
|
|
138
88
|
);
|
|
139
89
|
}
|
|
140
|
-
const materialDefaults: MaterialParameters = { transparent: false, depthWrite: true, depthTest: true, opacity: 1.0 };
|
|
141
|
-
|
|
142
|
-
function TextureMaterial({
|
|
143
|
-
url,
|
|
144
|
-
color,
|
|
145
|
-
material,
|
|
146
|
-
useAlphaTest = true,
|
|
147
|
-
filter = {
|
|
148
|
-
min: MinificationFilter.LinearMipmap,
|
|
149
|
-
mag: MagnificationFilter.Linear
|
|
150
|
-
},
|
|
151
|
-
}: {
|
|
152
|
-
readonly url: string;
|
|
153
|
-
readonly color: string | Color | undefined;
|
|
154
|
-
readonly material: Material;
|
|
155
|
-
readonly useAlphaTest?: boolean;
|
|
156
|
-
readonly filter?: TextureFilter;
|
|
157
|
-
}): React.JSX.Element {
|
|
158
|
-
const texture = suspend(urlIsSvg(url) ? loadSvg(url, filter) : loadNormal(url, filter), [url]) as Texture | null;
|
|
159
|
-
useEffect(() => {
|
|
160
|
-
return () => {
|
|
161
|
-
if (texture) {
|
|
162
|
-
texture.dispose();
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
}, [texture]);
|
|
166
|
-
|
|
167
|
-
return (
|
|
168
|
-
<meshBasicMaterial
|
|
169
|
-
color={color}
|
|
170
|
-
side={DoubleSide}
|
|
171
|
-
alphaTest={useAlphaTest ? 0.8 : undefined}
|
|
172
|
-
map={texture}
|
|
173
|
-
{...(material.opacity !== undefined && material.opacity < 1 ? { opacity: material.opacity } : materialDefaults)}
|
|
174
|
-
transparent
|
|
175
|
-
/>
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function urlIsSvg(url: string): boolean {
|
|
180
|
-
return url.startsWith("data:image/svg+xml") || url.endsWith(".svg") || url.includes(".svg?");
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function loadSvg(url: string, filter: TextureFilter): Promise<Texture | null> {
|
|
184
|
-
const maxSize = 4096;
|
|
185
|
-
|
|
186
|
-
return new Promise((res) => {
|
|
187
|
-
const img = new Image();
|
|
188
|
-
|
|
189
|
-
// eslint-disable-next-line consistent-return
|
|
190
|
-
img.onload = ((): void => {
|
|
191
|
-
const canvas = document.createElement("canvas");
|
|
192
|
-
const imgW = img.naturalWidth;
|
|
193
|
-
const imgH = img.naturalHeight;
|
|
194
|
-
const width = imgW >= imgH ? maxSize : (maxSize * (imgW / imgH));
|
|
195
|
-
const height = imgH >= imgW ? maxSize : (maxSize * (imgH / imgW));
|
|
196
|
-
|
|
197
|
-
canvas.width = width;
|
|
198
|
-
canvas.height = height;
|
|
199
|
-
|
|
200
|
-
const ctx = canvas.getContext("2d");
|
|
201
|
-
if (!ctx) {
|
|
202
|
-
return res(null);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
206
|
-
ctx.imageSmoothingEnabled = true;
|
|
207
|
-
ctx.imageSmoothingQuality = "high";
|
|
208
|
-
ctx.drawImage(img, 0, 0, width, height);
|
|
209
|
-
|
|
210
|
-
const texture = new CanvasTexture(canvas);
|
|
211
|
-
texture.colorSpace = SRGBColorSpace;
|
|
212
|
-
texture.minFilter = filter.min;
|
|
213
|
-
texture.magFilter = filter.mag;
|
|
214
|
-
texture.generateMipmaps = filter.min === MinificationFilter.LinearMipmap;
|
|
215
|
-
texture.anisotropy = 4;
|
|
216
|
-
texture.needsUpdate = true;
|
|
217
|
-
|
|
218
|
-
res(texture);
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
img.onerror = () => res(null);
|
|
222
|
-
img.src = url;
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
function loadNormal(url: string, filter: TextureFilter): Promise<Texture | null> {
|
|
227
|
-
return new Promise((res) =>
|
|
228
|
-
textureLoader.load(
|
|
229
|
-
url,
|
|
230
|
-
(data) => {
|
|
231
|
-
data.colorSpace = SRGBColorSpace;
|
|
232
|
-
data.minFilter = filter.min;
|
|
233
|
-
data.magFilter = filter.mag;
|
|
234
|
-
data.generateMipmaps = filter.min === MinificationFilter.LinearMipmap;
|
|
235
|
-
data.anisotropy = 4;
|
|
236
|
-
res(data);
|
|
237
|
-
},
|
|
238
|
-
undefined,
|
|
239
|
-
() => res(null)
|
|
240
|
-
)
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
90
|
|
|
244
|
-
const
|
|
91
|
+
export const materialDefaults: MaterialParameters = {
|
|
92
|
+
transparent: false,
|
|
93
|
+
depthWrite: true,
|
|
94
|
+
depthTest: true,
|
|
95
|
+
opacity: 1.0,
|
|
96
|
+
};
|
|
245
97
|
|
|
246
98
|
const acceptMat: Material = { normal: "rgb(0,148,91)", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
|
|
247
99
|
const selectMat: Material = { normal: "rgb(14,82,184)", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
|
|
248
100
|
const textSelectMat: Material = { normal: "rgb(0, 26, 65)", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
|
|
249
101
|
const errorMar: Material = { normal: "#b82f3a", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
|
|
250
102
|
const warningMat: Material = { normal: "rgb(240, 197, 48)", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
|
|
103
|
+
|
|
104
|
+
export function getColor(
|
|
105
|
+
selectedIds: Record<string, boolean> | undefined,
|
|
106
|
+
id: string | undefined,
|
|
107
|
+
hoveredId: string | undefined,
|
|
108
|
+
mat: Material
|
|
109
|
+
): string | undefined {
|
|
110
|
+
return selectedIds?.[id ?? ""]
|
|
111
|
+
? hoveredId === id
|
|
112
|
+
? shade(-0.4, selectMat.normal)
|
|
113
|
+
: selectMat.normal
|
|
114
|
+
: hoveredId === id
|
|
115
|
+
? shade(-0.4, mat.normal)
|
|
116
|
+
: mat.normal;
|
|
117
|
+
}
|
|
@@ -41,6 +41,10 @@ import {
|
|
|
41
41
|
equals,
|
|
42
42
|
} from "../../abstract-3d.js";
|
|
43
43
|
import { exhaustiveCheck } from "ts-exhaustive-check";
|
|
44
|
+
import { ImageMesh, planeGeometry } from "./react-image.js";
|
|
45
|
+
import { MaterialState } from "./react-material.js";
|
|
46
|
+
|
|
47
|
+
// dummy
|
|
44
48
|
|
|
45
49
|
extend({
|
|
46
50
|
SphereGeometry,
|
|
@@ -64,7 +68,6 @@ const boxGeometry = new BoxGeometry();
|
|
|
64
68
|
const cylinderGeometry = new CylinderGeometry(1, 1, 1, CYLINDER_SEGMENTS, 1);
|
|
65
69
|
const cylinderGeometryOpen = new CylinderGeometry(1, 1, 1, CYLINDER_SEGMENTS, 1, true);
|
|
66
70
|
const coneGeometry = new ConeGeometry(1, 1, 16, 1);
|
|
67
|
-
const planeGeometry = new PlaneGeometry();
|
|
68
71
|
const sphereGeometry = new SphereGeometry(1, 12, 12);
|
|
69
72
|
export const euler = new Euler();
|
|
70
73
|
export const vector3 = new Vector3();
|
|
@@ -73,9 +76,21 @@ export const quaternion = new Quaternion();
|
|
|
73
76
|
export function ReactMesh({
|
|
74
77
|
mesh,
|
|
75
78
|
children,
|
|
79
|
+
id,
|
|
80
|
+
hoveredId,
|
|
81
|
+
selectedIds,
|
|
82
|
+
materialStateImages,
|
|
83
|
+
materialState,
|
|
84
|
+
useAlphaTest,
|
|
76
85
|
}: {
|
|
77
86
|
readonly mesh: Mesh;
|
|
78
87
|
readonly children?: React.JSX.Element;
|
|
88
|
+
readonly id?: string | undefined;
|
|
89
|
+
readonly hoveredId?: string | undefined;
|
|
90
|
+
readonly selectedIds?: Record<string, boolean> | undefined;
|
|
91
|
+
readonly materialStateImages?: Record<string, string> | undefined;
|
|
92
|
+
readonly materialState?: MaterialState | undefined;
|
|
93
|
+
readonly useAlphaTest?: boolean | undefined;
|
|
79
94
|
}): React.JSX.Element {
|
|
80
95
|
switch (mesh.geometry.type) {
|
|
81
96
|
case "Box": {
|
|
@@ -185,21 +200,19 @@ export function ReactMesh({
|
|
|
185
200
|
);
|
|
186
201
|
}
|
|
187
202
|
}
|
|
188
|
-
case "Image":
|
|
189
|
-
const { pos, size, rot } = mesh.geometry;
|
|
203
|
+
case "Image":
|
|
190
204
|
return (
|
|
191
|
-
<
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
{
|
|
200
|
-
|
|
205
|
+
<ImageMesh
|
|
206
|
+
image={mesh.geometry}
|
|
207
|
+
materialStateImages={materialStateImages}
|
|
208
|
+
useAlphaTest={useAlphaTest}
|
|
209
|
+
id={id}
|
|
210
|
+
hoveredId={hoveredId}
|
|
211
|
+
selectedIds={selectedIds}
|
|
212
|
+
materialState={materialState}
|
|
213
|
+
material={mesh.material}
|
|
214
|
+
/>
|
|
201
215
|
);
|
|
202
|
-
}
|
|
203
216
|
case "Plane": {
|
|
204
217
|
const { pos, size, rot, holes } = mesh.geometry;
|
|
205
218
|
const filteredHoles = holes?.filter((h) => !holeIsZero(h));
|
|
@@ -173,6 +173,8 @@ export type EmbededImage =
|
|
|
173
173
|
| { readonly type: "url"; readonly url: string }
|
|
174
174
|
| { readonly type: "svg"; readonly svg: string };
|
|
175
175
|
|
|
176
|
+
export const rawSvgPrefix = "data:image/svg+xml,";
|
|
177
|
+
|
|
176
178
|
export const svgImage = (
|
|
177
179
|
p: Vec2,
|
|
178
180
|
size: Vec2,
|
|
@@ -183,11 +185,11 @@ export const svgImage = (
|
|
|
183
185
|
): string => {
|
|
184
186
|
const matrix = svgTrsMatrix(p, rot, scale);
|
|
185
187
|
|
|
186
|
-
return `<g transform="${matrix}"
|
|
188
|
+
return `<g transform="${matrix}">
|
|
189
|
+
${background ? `<rect width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}" fill="${background}"/>` : ""}
|
|
190
|
+
${
|
|
187
191
|
data.type === "url"
|
|
188
|
-
?
|
|
189
|
-
background ? `<rect width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}" fill="${background}"/>` : ""
|
|
190
|
-
}<image width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}" href="${data.url}"/>`
|
|
192
|
+
? `<image width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}" href="${data.url}"/>`
|
|
191
193
|
: `<svg width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}">${data.svg}</svg>`
|
|
192
194
|
}</g>`;
|
|
193
195
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createSVG } from "abstract-image";
|
|
2
2
|
import { Image, Vec2, Vec3, vec2Scale, vec3TransRot, vec3RotCombine, vec3Zero, vec3 } from "../../../abstract-3d.js";
|
|
3
3
|
import { zElem, zOrderElement, SvgOptions } from "./shared.js";
|
|
4
|
-
import { svgImage } from "../svg-encoding.js";
|
|
4
|
+
import { EmbededImage, rawSvgPrefix, svgImage } from "../svg-encoding.js";
|
|
5
5
|
import { exhaustiveCheck } from "ts-exhaustive-check";
|
|
6
6
|
|
|
7
7
|
export function image(
|
|
@@ -29,7 +29,27 @@ export function image(
|
|
|
29
29
|
const img = svgImage(point(v4.x, v4.y), i.size, rot, { type: "svg", svg }, opts.background, scale);
|
|
30
30
|
return [zElem(img, (v2.z + v4.z) / 2)];
|
|
31
31
|
}
|
|
32
|
+
case "Url": {
|
|
33
|
+
const imageData = opts.imageDataByUrl?.[i.image.url];
|
|
34
|
+
const image: EmbededImage | undefined = imageData?.startsWith(rawSvgPrefix)
|
|
35
|
+
? {
|
|
36
|
+
type: "svg",
|
|
37
|
+
svg: decodeURIComponent(imageData.slice(rawSvgPrefix.length)).replace(
|
|
38
|
+
/^\s*(<\?xml[^>]*\?>\s*)?(<!DOCTYPE[^>]*>\s*)?/i,
|
|
39
|
+
""
|
|
40
|
+
),
|
|
41
|
+
}
|
|
42
|
+
: i.image.url
|
|
43
|
+
? { type: "url", url: imageData ?? i.image.url }
|
|
44
|
+
: undefined;
|
|
45
|
+
|
|
46
|
+
if (image) {
|
|
47
|
+
const img = svgImage(point(v4.x, v4.y), i.size, rot, image, opts.background);
|
|
48
|
+
return [zElem(img, (v2.z + v4.z) / 2)];
|
|
49
|
+
}
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
32
52
|
default:
|
|
33
|
-
return exhaustiveCheck(i.image
|
|
53
|
+
return exhaustiveCheck(i.image);
|
|
34
54
|
}
|
|
35
55
|
}
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
Hole,
|
|
13
13
|
} from "../../../abstract-3d.js";
|
|
14
14
|
import { gray, black, zElem, zOrderElement, SvgOptions } from "./shared.js";
|
|
15
|
-
import {
|
|
15
|
+
import { svgPolygon } from "../svg-encoding.js";
|
|
16
16
|
import { rgbGrayScale } from "../../../utils.js";
|
|
17
17
|
|
|
18
18
|
export function plane(
|
|
@@ -34,24 +34,6 @@ export function plane(
|
|
|
34
34
|
const v3 = vec3tr(half.x, half.y);
|
|
35
35
|
const v4 = vec3tr(-half.x, half.y);
|
|
36
36
|
|
|
37
|
-
const imageData = material.imageUrl ? opts.imageDataByUrl?.[material.imageUrl] : undefined;
|
|
38
|
-
const image: EmbededImage | undefined = imageData?.startsWith(rawSvgPrefix)
|
|
39
|
-
? {
|
|
40
|
-
type: "svg",
|
|
41
|
-
svg: decodeURIComponent(imageData.slice(rawSvgPrefix.length)).replace(
|
|
42
|
-
/^\s*(<\?xml[^>]*\?>\s*)?(<!DOCTYPE[^>]*>\s*)?/i,
|
|
43
|
-
""
|
|
44
|
-
),
|
|
45
|
-
}
|
|
46
|
-
: material.imageUrl
|
|
47
|
-
? { type: "url", url: imageData ?? material.imageUrl }
|
|
48
|
-
: undefined;
|
|
49
|
-
|
|
50
|
-
if (image) {
|
|
51
|
-
const img = svgImage(point(v4.x, v4.y), p.size, rot, image, opts.background);
|
|
52
|
-
return [zElem(img, (v2.z + v4.z) / 2)];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
37
|
const points = [point(v1.x, v1.y), point(v2.x, v2.y), point(v3.x, v3.y), point(v4.x, v4.y)];
|
|
56
38
|
|
|
57
39
|
const [strokeColor, fill, strokeThickness] = opts.only_stroke
|
|
@@ -64,5 +46,3 @@ export function plane(
|
|
|
64
46
|
),
|
|
65
47
|
];
|
|
66
48
|
}
|
|
67
|
-
|
|
68
|
-
const rawSvgPrefix = "data:image/svg+xml,";
|
package/src/.DS_Store
DELETED
|
Binary file
|
package/src/renderers/.DS_Store
DELETED
|
Binary file
|