-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
34 changed files
with
2,151 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,232 @@ | ||
import type { | ||
BatchInstruction, | ||
FilterInstruction, | ||
GraphicsInstruction, | ||
MaskInstruction, | ||
MeshInstruction, | ||
NineSliceInstruction, | ||
TilingSpriteInstruction, | ||
} from '@devtool/frontend/pages/rendering/instructions/Instructions'; | ||
import type { | ||
Batch, | ||
BlurFilter, | ||
Filter, | ||
GlProgram, | ||
GpuProgram, | ||
Graphics, | ||
Mesh, | ||
NineSliceSprite, | ||
FilterInstruction as PixiFilterInstruction, | ||
Sprite, | ||
StencilMaskInstruction, | ||
TilingSprite, | ||
} from 'pixi.js'; | ||
import { getRenderableData, getStateData, getTextureData } from './renderableData'; | ||
import { PixiDevtools } from '../pixi'; | ||
import { getProgramSource } from './program'; | ||
|
||
type TextureCache = Parameters<typeof getTextureData>[1]; | ||
export function getBatchInstruction(instruction: Batch, textureCache: TextureCache): BatchInstruction { | ||
const textures: BatchInstruction['textures'] = []; | ||
instruction.textures.textures.forEach((texture) => { | ||
if (texture == null) return; | ||
const tex = getTextureData(texture, textureCache); | ||
if (tex) { | ||
textures.push(tex); | ||
} else { | ||
console.log('Texture not found', texture); | ||
} | ||
}); | ||
|
||
return { | ||
type: 'batch', | ||
action: instruction.action, | ||
blendMode: instruction.blendMode, | ||
size: instruction.size, | ||
start: instruction.start, | ||
drawCalls: 0, | ||
drawTextures: [], | ||
textures, | ||
}; | ||
} | ||
|
||
export function getGraphicsInstruction(instruction: Graphics, _textureCache: TextureCache): GraphicsInstruction { | ||
return { | ||
type: 'graphics', | ||
action: 'draw', | ||
renderable: { | ||
...getRenderableData(instruction), | ||
}, | ||
drawCalls: 0, | ||
drawTextures: [], | ||
}; | ||
} | ||
|
||
export function getNineSliceInstruction( | ||
instruction: NineSliceSprite, | ||
textureCache: TextureCache, | ||
): NineSliceInstruction { | ||
return { | ||
type: 'nineSlice', | ||
action: 'draw', | ||
renderable: { | ||
topHeight: instruction.topHeight, | ||
bottomHeight: instruction.bottomHeight, | ||
leftWidth: instruction.leftWidth, | ||
rightWidth: instruction.rightWidth, | ||
texture: instruction.texture ? getTextureData(instruction.texture._source, textureCache) : null, | ||
originalWidth: instruction.originalWidth, | ||
originalHeight: instruction.originalHeight, | ||
...getRenderableData(instruction), | ||
}, | ||
drawCalls: 0, | ||
drawTextures: [], | ||
}; | ||
} | ||
|
||
export function getMaskInstruction(instruction: StencilMaskInstruction, _textureCache: TextureCache): MaskInstruction { | ||
const mask = instruction.mask?.mask; | ||
return { | ||
type: instruction.renderPipeId, | ||
action: instruction.action, | ||
mask: mask | ||
? { | ||
...getRenderableData(mask), | ||
} | ||
: null, | ||
drawCalls: 0, | ||
drawTextures: [], | ||
}; | ||
} | ||
|
||
export function getFilterInstruction( | ||
instruction: PixiFilterInstruction, | ||
textureCache: TextureCache, | ||
): FilterInstruction { | ||
const rendererType = PixiDevtools.renderer.name === 'webgl' ? 'webgl' : 'webgpu'; | ||
const getProgramSource = (filter: Filter, shader: 'fragment' | 'vertex'): string => { | ||
const type = rendererType === 'webgl' ? 'glProgram' : 'gpuProgram'; | ||
let program: GlProgram | GpuProgram; | ||
|
||
// if blur filter then you need to get the blurX/blurY shaders | ||
if ((filter as BlurFilter).blurXFilter) { | ||
program = (filter as BlurFilter).blurXFilter[type]; | ||
} else { | ||
program = filter[type]; | ||
} | ||
|
||
if (!program) { | ||
return ''; | ||
} | ||
|
||
const source = program[shader]; | ||
|
||
if (!source) { | ||
return ''; | ||
} | ||
|
||
if (typeof source === 'string') { | ||
return source; | ||
} | ||
|
||
return source.source; | ||
}; | ||
|
||
return { | ||
type: 'filter', | ||
action: instruction.action, | ||
filter: instruction.filterEffect?.filters?.map((filter) => { | ||
return { | ||
type: filter.constructor.name, | ||
padding: filter.padding, | ||
resolution: filter.resolution, | ||
antialias: filter.antialias, | ||
blendMode: filter.blendMode, | ||
program: { | ||
fragment: getProgramSource(filter, 'fragment'), | ||
vertex: getProgramSource(filter, 'vertex'), | ||
}, | ||
state: getStateData(filter._state), | ||
}; | ||
}), | ||
renderables: | ||
instruction.renderables?.map((renderable) => ({ | ||
texture: (renderable as Sprite).texture | ||
? getTextureData((renderable as Sprite).texture.source, textureCache) | ||
: null, | ||
...getRenderableData(renderable), | ||
})) || ([] as FilterInstruction['renderables']), | ||
drawCalls: 0, | ||
drawTextures: [], | ||
}; | ||
} | ||
|
||
interface PixiMeshObjectInstruction { | ||
renderPipeId: string; | ||
mesh: Mesh; | ||
} | ||
|
||
export function getMeshInstruction( | ||
instruction: Mesh | PixiMeshObjectInstruction, | ||
textureCache: TextureCache, | ||
): MeshInstruction { | ||
const mesh = (instruction as PixiMeshObjectInstruction)?.mesh || instruction; | ||
const rendererType = PixiDevtools.renderer.name === 'webgl' ? 'webgl' : 'webgpu'; | ||
let shader = mesh.shader; | ||
const program = { | ||
fragment: null as string | null, | ||
vertex: null as string | null, | ||
}; | ||
|
||
if (!shader) { | ||
shader = PixiDevtools.renderer.renderPipes.mesh['_adaptor']._shader; | ||
program.fragment = getProgramSource(shader, 'fragment', rendererType); | ||
program.vertex = getProgramSource(shader, 'vertex', rendererType); | ||
} else { | ||
program.fragment = getProgramSource(shader, 'fragment', rendererType); | ||
program.vertex = getProgramSource(shader, 'vertex', rendererType); | ||
} | ||
return { | ||
type: 'mesh', | ||
action: 'draw', | ||
renderable: { | ||
texture: mesh.texture ? getTextureData(mesh.texture.source, textureCache) : null, | ||
program, | ||
state: getStateData(mesh.state), | ||
geometry: { | ||
indices: Array.from(mesh.geometry.indices), | ||
positions: Array.from(mesh.geometry.positions), | ||
uvs: Array.from(mesh.geometry.uvs), | ||
}, | ||
...getRenderableData(mesh), | ||
}, | ||
drawCalls: 0, | ||
drawTextures: [], | ||
}; | ||
} | ||
|
||
export function getTileSpriteInstruction( | ||
tilingSprite: TilingSprite, | ||
textureCache: TextureCache, | ||
): TilingSpriteInstruction { | ||
return { | ||
type: 'tilingSprite', | ||
action: 'draw', | ||
renderable: { | ||
...getRenderableData(tilingSprite), | ||
texture: tilingSprite.texture ? getTextureData(tilingSprite.texture.source, textureCache) : null, | ||
tilePosition: { | ||
x: tilingSprite.tilePosition.x, | ||
y: tilingSprite.tilePosition.y, | ||
}, | ||
tileScale: { | ||
x: tilingSprite.tileScale.x, | ||
y: tilingSprite.tileScale.y, | ||
}, | ||
tileRotation: tilingSprite.tileRotation, | ||
clampMargin: tilingSprite.clampMargin, | ||
}, | ||
drawCalls: 0, | ||
drawTextures: [], | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import type { Filter, TextureShader } from 'pixi.js'; | ||
|
||
export function getProgramSource( | ||
filter: Filter | TextureShader, | ||
shader: 'fragment' | 'vertex', | ||
rendererType: 'webgl' | 'webgpu', | ||
): string { | ||
const type = rendererType === 'webgl' ? 'glProgram' : 'gpuProgram'; | ||
const program = filter[type]; | ||
const source = program[shader]; | ||
|
||
if (!source) { | ||
return ''; | ||
} | ||
|
||
if (typeof source === 'string') { | ||
return source; | ||
} | ||
|
||
return source.source; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import type { GlRenderTarget, WebGLRenderer } from 'pixi.js'; | ||
|
||
export function readGlPixels( | ||
gl: WebGLRenderingContext, | ||
renderer: WebGLRenderer, | ||
canvasTextures: string[], | ||
width: number, | ||
height: number, | ||
) { | ||
// Create a buffer to hold the pixel data | ||
// Uint8Array for 8-bit per channel (RGBA), adjust as needed | ||
const pixels = new Uint8Array(width * height * 4); | ||
|
||
const renterTarget = renderer.renderTarget.getRenderTarget(renderer.renderTarget.renderTarget); | ||
const glRenterTarget = renderer.renderTarget.getGpuRenderTarget(renterTarget) as GlRenderTarget; | ||
// Bind the framebuffer you want to read from (null for default framebuffer) | ||
gl.bindFramebuffer(gl.FRAMEBUFFER, glRenterTarget.resolveTargetFramebuffer); | ||
|
||
// Read the pixels | ||
gl.readPixels( | ||
0, | ||
0, // Start reading from the bottom left of the framebuffer | ||
width, | ||
height, // The dimensions of the area you want to read | ||
gl.RGBA, // Format of the pixel data | ||
gl.UNSIGNED_BYTE, // Type of the pixel data | ||
pixels, // The buffer to read the pixels into | ||
); | ||
|
||
// Create a 2D canvas to draw the pixels on | ||
const canvas2d = document.createElement('canvas'); | ||
canvas2d.width = width; | ||
canvas2d.height = height; | ||
const ctx = canvas2d.getContext('2d')!; | ||
|
||
// Create an ImageData object | ||
const imageData = new ImageData(new Uint8ClampedArray(pixels), width, height); | ||
|
||
// Draw the ImageData object to the canvas | ||
ctx.putImageData(imageData, 0, 0); | ||
|
||
// Convert the canvas to a data URL and set it as the src of an image element | ||
const dataUrl = canvas2d.toDataURL('image/webp', 0.5); | ||
canvasTextures.push(dataUrl); | ||
} |
Oops, something went wrong.