Frames: cut each frame into its own GPU texture, no more fill matrix (#47)
game-maker / suite (push) Successful in 8m18s
game-maker / suite (push) Successful in 8m18s
A frame drawn straight from the sheet showed a hairline of the neighbouring cell along any edge that fell inside a screen pixel: with antialias on, a partly covered pixel is still evaluated at its centre, past the edge. On top of that Pixi rewrites a Graphics fill texture from clamp-to-edge to repeat at draw time (generateTextureFillMatrix.mjs), so the top row of a sheet read its bottom row. TextureLibrary.get(ref) now cuts the rectangle out of the loaded sheet with an OffscreenCanvas on first use and uploads the cut (key file|x,y,w,h, kept for the session). Address mode is mirror-repeat: Pixi only rewrites clamp-to-edge, and within a texel of the border mirror behaves like clamp, for linear as well as nearest. Loaded sheets get it too, since whole pictures wrapped at their own borders the same way. viewport/textureFill.ts and its test are gone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
06e1494f94
commit
05f7a2745e
9 files changed
+150
-150
No files matched your search
+14
-3
@@ -1,6 +1,7 @@
|
||||
import { type Application, Color, type ColorSource, type Container, Rectangle, Text } from 'pixi.js';
|
||||
import { resolveObjects } from '../core/model/instance';
|
||||
import { findObjectHolder } from '../core/model/Project';
|
||||
import type { FrameRect } from '../core/model/texture';
|
||||
import { activeDrag, Button, ui, Widget } from '../ui';
|
||||
import { textureLibrary } from '../viewport/TextureLibrary';
|
||||
import type { CentreTab, Editor } from './Editor';
|
||||
@@ -348,9 +349,9 @@ export function installDebugHook(app: Application, state: EditorState, editor: E
|
||||
const hex = (value: number | undefined) => (value ?? 0).toString(16).padStart(2, '0');
|
||||
return `#${hex(pixels[0])}${hex(pixels[1])}${hex(pixels[2])}`;
|
||||
},
|
||||
/** The filter the GPU sampler actually got, next to the model's – only the driver knows the former. */
|
||||
textureFilter: (file: string) => {
|
||||
const texture = textureLibrary.peek(file);
|
||||
/** The filter and wrap the GPU sampler actually got, next to the model's – only the driver knows the former. */
|
||||
textureFilter: (file: string, rect: FrameRect | null = null) => {
|
||||
const texture = textureLibrary.peek(file, rect);
|
||||
if (!texture) return null;
|
||||
const source = texture.source;
|
||||
const renderer = app.renderer as unknown as {
|
||||
@@ -363,14 +364,24 @@ export function installDebugHook(app: Application, state: EditorState, editor: E
|
||||
(source as unknown as { _gpuData: Record<number, unknown> })._gpuData[renderer.uid],
|
||||
);
|
||||
let magFilter = 0;
|
||||
let wrapT = 0;
|
||||
if (gl) {
|
||||
// Through Pixi rather than a raw `bindTexture`, so its idea of what is bound stays true.
|
||||
renderer.texture.bindSource(source, 0);
|
||||
magFilter = gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER) as number;
|
||||
wrapT = gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T) as number;
|
||||
}
|
||||
return {
|
||||
scaleMode: source.scaleMode,
|
||||
gpu: magFilter === gl?.NEAREST ? 'nearest' : magFilter === gl?.LINEAR ? 'linear' : 'none',
|
||||
wrap:
|
||||
wrapT === gl?.CLAMP_TO_EDGE
|
||||
? 'clamp'
|
||||
: wrapT === gl?.REPEAT
|
||||
? 'repeat'
|
||||
: wrapT === gl?.MIRRORED_REPEAT
|
||||
? 'mirror'
|
||||
: 'none',
|
||||
uploaded,
|
||||
};
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user