protosprite-geom 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -0
- package/dist/core.js +1 -1
- package/dist/proto_dist/sprite_geometry_pb.d.ts +108 -36
- package/dist/proto_dist/sprite_geometry_pb.js +17 -7
- package/dist/proto_dist/sprite_geometry_pb.js.map +1 -1
- package/dist/src/core/data.d.ts +18 -5
- package/dist/src/core/data.js +60 -18
- package/dist/src/core/data.js.map +1 -1
- package/dist/src/core/index.d.ts +2 -1
- package/dist/src/core/protosprite-geom.d.ts +17 -1
- package/dist/src/core/protosprite-geom.js +54 -1
- package/dist/src/core/protosprite-geom.js.map +1 -1
- package/dist/trace.js +67 -5
- package/dist/trace.js.map +1 -1
- package/package.json +3 -3
- package/proto_dist/sprite_geometry_pb.ts +124 -46
- package/src/core/data.ts +72 -28
- package/src/core/index.ts +8 -0
- package/src/core/protosprite-geom.ts +87 -1
- package/src/trace/index.ts +80 -5
package/src/core/data.ts
CHANGED
|
@@ -9,8 +9,12 @@ import {
|
|
|
9
9
|
FrameGeometrySchema,
|
|
10
10
|
FrameLayerGeometry,
|
|
11
11
|
FrameLayerGeometrySchema,
|
|
12
|
+
IndexedPolygon,
|
|
13
|
+
IndexedPolygonSchema,
|
|
12
14
|
Polygon,
|
|
13
15
|
PolygonSchema,
|
|
16
|
+
ShapePoolEntry,
|
|
17
|
+
ShapePoolEntrySchema,
|
|
14
18
|
SpriteGeometry,
|
|
15
19
|
SpriteGeometryEntry,
|
|
16
20
|
SpriteGeometryEntrySchema,
|
|
@@ -89,70 +93,102 @@ export class ConvexDecompositionData {
|
|
|
89
93
|
}
|
|
90
94
|
}
|
|
91
95
|
|
|
96
|
+
export class IndexedPolygonData {
|
|
97
|
+
public vertexIndices: number[] = [];
|
|
98
|
+
|
|
99
|
+
static fromProto(proto: IndexedPolygon) {
|
|
100
|
+
const instance = new IndexedPolygonData();
|
|
101
|
+
instance.vertexIndices = [...proto.vertexIndices];
|
|
102
|
+
return instance;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
toProto(protoIn?: IndexedPolygon) {
|
|
106
|
+
const proto = protoIn ?? create(IndexedPolygonSchema);
|
|
107
|
+
proto.vertexIndices = [...this.vertexIndices];
|
|
108
|
+
return proto;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
clone() {
|
|
112
|
+
const other = new IndexedPolygonData();
|
|
113
|
+
other.vertexIndices = [...this.vertexIndices];
|
|
114
|
+
return other;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export class ShapePoolEntryData {
|
|
119
|
+
public polygon: IndexedPolygonData = new IndexedPolygonData();
|
|
120
|
+
public convexDecompositionComponents: IndexedPolygonData[] = [];
|
|
121
|
+
|
|
122
|
+
static fromProto(proto: ShapePoolEntry) {
|
|
123
|
+
const instance = new ShapePoolEntryData();
|
|
124
|
+
if (proto.polygon) {
|
|
125
|
+
instance.polygon = IndexedPolygonData.fromProto(proto.polygon);
|
|
126
|
+
}
|
|
127
|
+
instance.convexDecompositionComponents = proto.convexDecompositionComponents.map(
|
|
128
|
+
IndexedPolygonData.fromProto
|
|
129
|
+
);
|
|
130
|
+
return instance;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
toProto(protoIn?: ShapePoolEntry) {
|
|
134
|
+
const proto = protoIn ?? create(ShapePoolEntrySchema);
|
|
135
|
+
proto.polygon = this.polygon.toProto();
|
|
136
|
+
proto.convexDecompositionComponents = this.convexDecompositionComponents.map((c) => c.toProto());
|
|
137
|
+
return proto;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
clone() {
|
|
141
|
+
const other = new ShapePoolEntryData();
|
|
142
|
+
other.polygon = this.polygon.clone();
|
|
143
|
+
other.convexDecompositionComponents = this.convexDecompositionComponents.map((c) => c.clone());
|
|
144
|
+
return other;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
92
148
|
export class FrameLayerGeometryData {
|
|
93
149
|
public layerIndex = 0;
|
|
94
|
-
public
|
|
95
|
-
public convexDecompositions: ConvexDecompositionData[] = [];
|
|
150
|
+
public shapeIndices: number[] = [];
|
|
96
151
|
|
|
97
152
|
static fromProto(proto: FrameLayerGeometry) {
|
|
98
153
|
const instance = new FrameLayerGeometryData();
|
|
99
154
|
instance.layerIndex = proto.layerIndex;
|
|
100
|
-
instance.
|
|
101
|
-
instance.convexDecompositions = proto.convexDecompositions.map(
|
|
102
|
-
ConvexDecompositionData.fromProto
|
|
103
|
-
);
|
|
155
|
+
instance.shapeIndices = [...proto.shapeIndices];
|
|
104
156
|
return instance;
|
|
105
157
|
}
|
|
106
158
|
|
|
107
159
|
toProto(protoIn?: FrameLayerGeometry) {
|
|
108
160
|
const proto = protoIn ?? create(FrameLayerGeometrySchema);
|
|
109
161
|
proto.layerIndex = this.layerIndex;
|
|
110
|
-
proto.
|
|
111
|
-
proto.convexDecompositions = this.convexDecompositions.map((d) =>
|
|
112
|
-
d.toProto()
|
|
113
|
-
);
|
|
162
|
+
proto.shapeIndices = [...this.shapeIndices];
|
|
114
163
|
return proto;
|
|
115
164
|
}
|
|
116
165
|
|
|
117
166
|
clone() {
|
|
118
167
|
const other = new FrameLayerGeometryData();
|
|
119
168
|
other.layerIndex = this.layerIndex;
|
|
120
|
-
other.
|
|
121
|
-
other.convexDecompositions = this.convexDecompositions.map((d) =>
|
|
122
|
-
d.clone()
|
|
123
|
-
);
|
|
169
|
+
other.shapeIndices = [...this.shapeIndices];
|
|
124
170
|
return other;
|
|
125
171
|
}
|
|
126
172
|
}
|
|
127
173
|
|
|
128
174
|
export class CompositeFrameGeometryData {
|
|
129
|
-
public
|
|
130
|
-
public convexDecompositions: ConvexDecompositionData[] = [];
|
|
175
|
+
public shapeIndices: number[] = [];
|
|
131
176
|
|
|
132
177
|
static fromProto(proto: CompositeFrameGeometry) {
|
|
133
178
|
const instance = new CompositeFrameGeometryData();
|
|
134
|
-
instance.
|
|
135
|
-
instance.convexDecompositions = proto.convexDecompositions.map(
|
|
136
|
-
ConvexDecompositionData.fromProto
|
|
137
|
-
);
|
|
179
|
+
instance.shapeIndices = [...proto.shapeIndices];
|
|
138
180
|
return instance;
|
|
139
181
|
}
|
|
140
182
|
|
|
141
183
|
toProto(protoIn?: CompositeFrameGeometry) {
|
|
142
184
|
const proto = protoIn ?? create(CompositeFrameGeometrySchema);
|
|
143
|
-
proto.
|
|
144
|
-
proto.convexDecompositions = this.convexDecompositions.map((d) =>
|
|
145
|
-
d.toProto()
|
|
146
|
-
);
|
|
185
|
+
proto.shapeIndices = [...this.shapeIndices];
|
|
147
186
|
return proto;
|
|
148
187
|
}
|
|
149
188
|
|
|
150
189
|
clone() {
|
|
151
190
|
const other = new CompositeFrameGeometryData();
|
|
152
|
-
other.
|
|
153
|
-
other.convexDecompositions = this.convexDecompositions.map((d) =>
|
|
154
|
-
d.clone()
|
|
155
|
-
);
|
|
191
|
+
other.shapeIndices = [...this.shapeIndices];
|
|
156
192
|
return other;
|
|
157
193
|
}
|
|
158
194
|
}
|
|
@@ -193,12 +229,16 @@ export class SpriteGeometryEntryData {
|
|
|
193
229
|
public spriteName = "";
|
|
194
230
|
public frames: FrameGeometryData[] = [];
|
|
195
231
|
public simplifyTolerance = 1.0;
|
|
232
|
+
public shapePool: ShapePoolEntryData[] = [];
|
|
233
|
+
public vertexPool: Vec2Data[] = [];
|
|
196
234
|
|
|
197
235
|
static fromProto(proto: SpriteGeometryEntry) {
|
|
198
236
|
const instance = new SpriteGeometryEntryData();
|
|
199
237
|
instance.spriteName = proto.spriteName;
|
|
200
238
|
instance.frames = proto.frames.map(FrameGeometryData.fromProto);
|
|
201
239
|
instance.simplifyTolerance = proto.simplifyTolerance;
|
|
240
|
+
instance.shapePool = proto.shapePool.map(ShapePoolEntryData.fromProto);
|
|
241
|
+
instance.vertexPool = proto.vertexPool.map(Vec2Data.fromProto);
|
|
202
242
|
return instance;
|
|
203
243
|
}
|
|
204
244
|
|
|
@@ -207,6 +247,8 @@ export class SpriteGeometryEntryData {
|
|
|
207
247
|
proto.spriteName = this.spriteName;
|
|
208
248
|
proto.frames = this.frames.map((f) => f.toProto());
|
|
209
249
|
proto.simplifyTolerance = this.simplifyTolerance;
|
|
250
|
+
proto.shapePool = this.shapePool.map((s) => s.toProto());
|
|
251
|
+
proto.vertexPool = this.vertexPool.map((v) => v.toProto());
|
|
210
252
|
return proto;
|
|
211
253
|
}
|
|
212
254
|
|
|
@@ -215,6 +257,8 @@ export class SpriteGeometryEntryData {
|
|
|
215
257
|
other.spriteName = this.spriteName;
|
|
216
258
|
other.frames = this.frames.map((f) => f.clone());
|
|
217
259
|
other.simplifyTolerance = this.simplifyTolerance;
|
|
260
|
+
other.shapePool = this.shapePool.map((s) => s.clone());
|
|
261
|
+
other.vertexPool = this.vertexPool.map((v) => v.clone());
|
|
218
262
|
return other;
|
|
219
263
|
}
|
|
220
264
|
}
|
package/src/core/index.ts
CHANGED
|
@@ -8,6 +8,8 @@ export {
|
|
|
8
8
|
Vec2Data,
|
|
9
9
|
PolygonData,
|
|
10
10
|
ConvexDecompositionData,
|
|
11
|
+
IndexedPolygonData,
|
|
12
|
+
ShapePoolEntryData,
|
|
11
13
|
FrameLayerGeometryData,
|
|
12
14
|
CompositeFrameGeometryData,
|
|
13
15
|
FrameGeometryData,
|
|
@@ -16,3 +18,9 @@ export {
|
|
|
16
18
|
} from "./data.js";
|
|
17
19
|
|
|
18
20
|
export type { SpriteSourceData } from "./data.js";
|
|
21
|
+
|
|
22
|
+
export type {
|
|
23
|
+
ResolvedLayerGeometry,
|
|
24
|
+
ResolvedCompositeGeometry,
|
|
25
|
+
ResolvedFrameGeometry
|
|
26
|
+
} from "./protosprite-geom.js";
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import { fromBinary, toBinary, toJson } from "@bufbuild/protobuf";
|
|
2
2
|
import { ProtoSpriteSheet } from "protosprite-core";
|
|
3
3
|
import { SpriteGeometrySchema } from "../../proto_dist/sprite_geometry_pb.js";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
ConvexDecompositionData,
|
|
6
|
+
IndexedPolygonData,
|
|
7
|
+
PolygonData,
|
|
8
|
+
SpriteGeometryData,
|
|
9
|
+
SpriteGeometryEntryData,
|
|
10
|
+
Vec2Data
|
|
11
|
+
} from "./data.js";
|
|
5
12
|
import fs from "fs";
|
|
6
13
|
|
|
7
14
|
export class ProtoSpriteGeometry {
|
|
@@ -68,4 +75,83 @@ export class ProtoSpriteGeometry {
|
|
|
68
75
|
};
|
|
69
76
|
}
|
|
70
77
|
}
|
|
78
|
+
|
|
79
|
+
getEntry(spriteName: string): SpriteGeometryEntryData | undefined {
|
|
80
|
+
return this.data.entries.find((e) => e.spriteName === spriteName);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
getFrameGeometry(
|
|
84
|
+
spriteName: string,
|
|
85
|
+
frameIndex: number
|
|
86
|
+
): ResolvedFrameGeometry | undefined {
|
|
87
|
+
const entry = this.getEntry(spriteName);
|
|
88
|
+
if (!entry) return undefined;
|
|
89
|
+
|
|
90
|
+
const frameGeom = entry.frames.find((f) => f.frameIndex === frameIndex);
|
|
91
|
+
if (!frameGeom) return undefined;
|
|
92
|
+
|
|
93
|
+
const shapePool = entry.shapePool;
|
|
94
|
+
const vertexPool = entry.vertexPool;
|
|
95
|
+
|
|
96
|
+
const resolveIndexedPolygon = (indexed: IndexedPolygonData): PolygonData => {
|
|
97
|
+
const poly = new PolygonData();
|
|
98
|
+
poly.vertices = indexed.vertexIndices.map((vi) => vertexPool[vi]);
|
|
99
|
+
return poly;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const resolveShape = (idx: number): { polygon: PolygonData; decomposition: ConvexDecompositionData } | undefined => {
|
|
103
|
+
const shape = shapePool[idx];
|
|
104
|
+
if (!shape) return undefined;
|
|
105
|
+
const polygon = resolveIndexedPolygon(shape.polygon);
|
|
106
|
+
const decomposition = new ConvexDecompositionData();
|
|
107
|
+
decomposition.components = shape.convexDecompositionComponents.map(resolveIndexedPolygon);
|
|
108
|
+
return { polygon, decomposition };
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const layers: ResolvedLayerGeometry[] = frameGeom.layers.map((layer) => {
|
|
112
|
+
const polygons: PolygonData[] = [];
|
|
113
|
+
const convexDecompositions: ConvexDecompositionData[] = [];
|
|
114
|
+
for (const idx of layer.shapeIndices) {
|
|
115
|
+
const resolved = resolveShape(idx);
|
|
116
|
+
if (resolved) {
|
|
117
|
+
polygons.push(resolved.polygon);
|
|
118
|
+
convexDecompositions.push(resolved.decomposition);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return { layerIndex: layer.layerIndex, polygons, convexDecompositions };
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
let composite: ResolvedCompositeGeometry | undefined;
|
|
125
|
+
if (frameGeom.composite) {
|
|
126
|
+
const polygons: PolygonData[] = [];
|
|
127
|
+
const convexDecompositions: ConvexDecompositionData[] = [];
|
|
128
|
+
for (const idx of frameGeom.composite.shapeIndices) {
|
|
129
|
+
const resolved = resolveShape(idx);
|
|
130
|
+
if (resolved) {
|
|
131
|
+
polygons.push(resolved.polygon);
|
|
132
|
+
convexDecompositions.push(resolved.decomposition);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
composite = { polygons, convexDecompositions };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return { frameIndex: frameGeom.frameIndex, layers, composite };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface ResolvedLayerGeometry {
|
|
143
|
+
layerIndex: number;
|
|
144
|
+
polygons: PolygonData[];
|
|
145
|
+
convexDecompositions: ConvexDecompositionData[];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface ResolvedCompositeGeometry {
|
|
149
|
+
polygons: PolygonData[];
|
|
150
|
+
convexDecompositions: ConvexDecompositionData[];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface ResolvedFrameGeometry {
|
|
154
|
+
frameIndex: number;
|
|
155
|
+
layers: ResolvedLayerGeometry[];
|
|
156
|
+
composite?: ResolvedCompositeGeometry;
|
|
71
157
|
}
|
package/src/trace/index.ts
CHANGED
|
@@ -12,9 +12,12 @@ import {
|
|
|
12
12
|
ConvexDecompositionData,
|
|
13
13
|
FrameGeometryData,
|
|
14
14
|
FrameLayerGeometryData,
|
|
15
|
+
IndexedPolygonData,
|
|
15
16
|
PolygonData,
|
|
17
|
+
ShapePoolEntryData,
|
|
16
18
|
SpriteGeometryData,
|
|
17
|
-
SpriteGeometryEntryData
|
|
19
|
+
SpriteGeometryEntryData,
|
|
20
|
+
Vec2Data
|
|
18
21
|
} from "../core/data.js";
|
|
19
22
|
import { decomposeConvex } from "./convex.js";
|
|
20
23
|
import { simplifyPolygon } from "./simplify.js";
|
|
@@ -90,6 +93,67 @@ function traceAndProcess(
|
|
|
90
93
|
return { polygons, convexDecompositions };
|
|
91
94
|
}
|
|
92
95
|
|
|
96
|
+
class VertexPoolBuilder {
|
|
97
|
+
private pool: Vec2Data[] = [];
|
|
98
|
+
private hashMap = new Map<string, number>();
|
|
99
|
+
|
|
100
|
+
addVertex(v: Vec2Data): number {
|
|
101
|
+
const key = `${v.x},${v.y}`;
|
|
102
|
+
const existing = this.hashMap.get(key);
|
|
103
|
+
if (existing !== undefined) {
|
|
104
|
+
return existing;
|
|
105
|
+
}
|
|
106
|
+
const index = this.pool.length;
|
|
107
|
+
this.pool.push(v);
|
|
108
|
+
this.hashMap.set(key, index);
|
|
109
|
+
return index;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
getPool(): Vec2Data[] {
|
|
113
|
+
return this.pool;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
class ShapePoolBuilder {
|
|
118
|
+
private pool: ShapePoolEntryData[] = [];
|
|
119
|
+
private hashMap = new Map<string, number>();
|
|
120
|
+
private vertexBuilder: VertexPoolBuilder;
|
|
121
|
+
|
|
122
|
+
constructor(vertexBuilder: VertexPoolBuilder) {
|
|
123
|
+
this.vertexBuilder = vertexBuilder;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private indexPolygon(polygon: PolygonData): IndexedPolygonData {
|
|
127
|
+
const indexed = new IndexedPolygonData();
|
|
128
|
+
indexed.vertexIndices = polygon.vertices.map((v) => this.vertexBuilder.addVertex(v));
|
|
129
|
+
return indexed;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private hashIndexedPolygon(indexed: IndexedPolygonData): string {
|
|
133
|
+
return indexed.vertexIndices.join(";");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
addShape(polygon: PolygonData, decomposition: ConvexDecompositionData): number {
|
|
137
|
+
const indexedPolygon = this.indexPolygon(polygon);
|
|
138
|
+
const key = this.hashIndexedPolygon(indexedPolygon);
|
|
139
|
+
const existing = this.hashMap.get(key);
|
|
140
|
+
if (existing !== undefined) {
|
|
141
|
+
return existing;
|
|
142
|
+
}
|
|
143
|
+
const index = this.pool.length;
|
|
144
|
+
const entry = new ShapePoolEntryData();
|
|
145
|
+
entry.polygon = indexedPolygon;
|
|
146
|
+
entry.convexDecompositionComponents = decomposition.components.map((c) => this.indexPolygon(c));
|
|
147
|
+
this.pool.push(entry);
|
|
148
|
+
this.hashMap.set(key, index);
|
|
149
|
+
return index;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
getPool(): ShapePoolEntryData[] {
|
|
153
|
+
return this.pool;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
93
157
|
export async function traceSpriteSheet(
|
|
94
158
|
sheet: ProtoSpriteSheet,
|
|
95
159
|
options: TraceSpriteSheetOptions
|
|
@@ -115,6 +179,9 @@ export async function traceSpriteSheet(
|
|
|
115
179
|
entry.spriteName = sprite.data.name;
|
|
116
180
|
entry.simplifyTolerance = tolerance;
|
|
117
181
|
|
|
182
|
+
const vertexBuilder = new VertexPoolBuilder();
|
|
183
|
+
const poolBuilder = new ShapePoolBuilder(vertexBuilder);
|
|
184
|
+
|
|
118
185
|
// Try sprite-level pixel source, fall back to sheet image.
|
|
119
186
|
let spriteImg = sheetImg;
|
|
120
187
|
if (sprite.data.pixelSource) {
|
|
@@ -176,8 +243,11 @@ export async function traceSpriteSheet(
|
|
|
176
243
|
}
|
|
177
244
|
}
|
|
178
245
|
|
|
179
|
-
|
|
180
|
-
|
|
246
|
+
const shapeIndices: number[] = [];
|
|
247
|
+
for (let i = 0; i < polygons.length; i++) {
|
|
248
|
+
shapeIndices.push(poolBuilder.addShape(polygons[i], convexDecompositions[i]));
|
|
249
|
+
}
|
|
250
|
+
layerGeom.shapeIndices = shapeIndices;
|
|
181
251
|
frameGeom.layers.push(layerGeom);
|
|
182
252
|
}
|
|
183
253
|
}
|
|
@@ -202,14 +272,19 @@ export async function traceSpriteSheet(
|
|
|
202
272
|
);
|
|
203
273
|
|
|
204
274
|
const compositeGeom = new CompositeFrameGeometryData();
|
|
205
|
-
|
|
206
|
-
|
|
275
|
+
const shapeIndices: number[] = [];
|
|
276
|
+
for (let i = 0; i < polygons.length; i++) {
|
|
277
|
+
shapeIndices.push(poolBuilder.addShape(polygons[i], convexDecompositions[i]));
|
|
278
|
+
}
|
|
279
|
+
compositeGeom.shapeIndices = shapeIndices;
|
|
207
280
|
frameGeom.composite = compositeGeom;
|
|
208
281
|
}
|
|
209
282
|
|
|
210
283
|
entry.frames.push(frameGeom);
|
|
211
284
|
}
|
|
212
285
|
|
|
286
|
+
entry.shapePool = poolBuilder.getPool();
|
|
287
|
+
entry.vertexPool = vertexBuilder.getPool();
|
|
213
288
|
result.entries.push(entry);
|
|
214
289
|
}
|
|
215
290
|
|