Add a Texture tab for defining frames
A new Texture tab next to Scene/Game/Graph shows a texture sheet and lets frames be drawn on it: drag to create, move, resize via eight handles, edit name and rect in the inspector, Delete to remove. Every change is a command, so one gesture is one undo step. "Slice..." cuts a grid from columns and rows with optional offset and spacing, previewing the resulting frame count and cell size live. Sprites pick a frame instead of the whole texture through the same `texture` property: it now holds either a texture id or a frame id. Frame ids come from the same generator and are document-wide unique, so one picker, one property and one set of instance overrides cover both cases, and every sprite written before this still means the same thing. A Graphics fill ignores a Pixi sub-texture's frame and draws the whole image, because it derives its uvs from the shape bounds and the inverted style matrix. The cutout is therefore a matrix (`viewport/textureFill.ts`), which keeps a sheet at a single GPU upload no matter how many of its frames are on screen at once. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5a6af74e44
commit
35a1a23af8
29 files changed
+2650
-53
No files matched your search
+18
-10
@@ -71,32 +71,40 @@ export type PropertyUsage =
|
||||
| { on: 'object'; holder: ObjectHolder; object: SceneObject; key: string };
|
||||
|
||||
/**
|
||||
* Every property that references `assetId`, on assets and on the overrides of placed objects.
|
||||
* Every property that references one of `ids`, on assets and on the overrides of placed
|
||||
* objects.
|
||||
*
|
||||
* This is the other half of "where is this asset used": `findUsages` finds assets that were
|
||||
* *placed*, which is meaningless for a texture – a texture is never placed, it is worn by
|
||||
* sprites through their `texture` property. Deleting one therefore has to count both, or it
|
||||
* reports "0 uses" for a picture that ten sprites are showing.
|
||||
*
|
||||
* A reference is deliberately left dangling rather than cleared when its asset goes: a
|
||||
* Several ids rather than one because a texture is referenced by more than its own id: every
|
||||
* frame cut from it is a reference to the same picture (see `textureRefIds`). Deleting the
|
||||
* texture has to count the sprites wearing a frame of it too, or it under-reports exactly the
|
||||
* sheets that were sliced – the ones with the most users.
|
||||
*
|
||||
* A reference is deliberately left dangling rather than cleared when its target goes: a
|
||||
* dangling one resolves to "no picture" everywhere it is read, and it comes back by itself
|
||||
* when the delete is undone.
|
||||
*/
|
||||
export function findPropertyUsages(project: Project, assetId: string): PropertyUsage[] {
|
||||
if (!assetId) return [];
|
||||
export function findPropertyUsages(project: Project, ids: string | readonly string[]): PropertyUsage[] {
|
||||
const wanted = new Set((typeof ids === 'string' ? [ids] : ids).filter(Boolean));
|
||||
if (wanted.size === 0) return [];
|
||||
const result: PropertyUsage[] = [];
|
||||
const assetKeys = new Map<string, string[]>();
|
||||
const refKeys = new Map<string, string[]>();
|
||||
const matches = (value: unknown): boolean => typeof value === 'string' && wanted.has(value);
|
||||
for (const asset of project.assets) {
|
||||
const keys = schemaForAsset(asset)
|
||||
.filter((def) => def.kind === 'asset')
|
||||
.filter((def) => def.kind === 'asset' || def.kind === 'texture')
|
||||
.map((def) => def.key);
|
||||
assetKeys.set(asset.id, keys);
|
||||
for (const key of keys) if (asset.props[key] === assetId) result.push({ on: 'asset', asset, key });
|
||||
refKeys.set(asset.id, keys);
|
||||
for (const key of keys) if (matches(asset.props[key])) result.push({ on: 'asset', asset, key });
|
||||
}
|
||||
for (const holder of objectHolders(project)) {
|
||||
for (const object of holder.objects) {
|
||||
for (const key of assetKeys.get(object.assetId) ?? [])
|
||||
if (object.overrides[key] === assetId) result.push({ on: 'object', holder, object, key });
|
||||
for (const key of refKeys.get(object.assetId) ?? [])
|
||||
if (matches(object.overrides[key])) result.push({ on: 'object', holder, object, key });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
Reference in new issue
Block a user