Shader assets: graph-built shaders, the Shader tab and sprite rows from the graph (#62)
game-maker / suite (push) Failing after 3m59s
game-maker / suite (push) Failing after 3m59s
A shader is an asset carrying a node graph (Texture color, Output, Property, Color, Add/Subtract/Multiply/Divide, Mix, Luminance) that compiles to the GLSL fragment of a Pixi filter. The Shader tab reuses the Behavior canvas; a sprite wears a shader through its Shader picker, and the rows below it are the graph's Property nodes. Property schema, resolution and deviation take the project because a sprite's rows now live in another asset. The built-in registry of the prototype is gone; "Adjust colors" ships as a graph in the fixture and the three example games. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
6141d07d4f
commit
42cafa7543
62 files changed
+1682
-144
No files matched your search
@@ -28,6 +28,7 @@ import {
|
||||
} from '../../core/graph';
|
||||
import type { GraphAsset } from '../../core/model/Asset';
|
||||
import { graphLookup } from '../../core/model/graphLookup';
|
||||
import { shaderLibrary } from '../../viewport/ShaderLibrary';
|
||||
import { findAsset, findGraphAsset } from '../../core/model/Project';
|
||||
import { type Trace, TRACE_FADE } from '../../runtime/systems/BehaviorSystem';
|
||||
import { beadsInFlight, launchBead } from './beads';
|
||||
@@ -218,6 +219,8 @@ export class GraphCanvas extends Widget {
|
||||
}
|
||||
const seen = new Set<string>();
|
||||
const lookup = graphLookup(this.state.project);
|
||||
// A shader node's problem is the compiler's, not a call's.
|
||||
const shaderProblems = asset.type === 'shader' ? shaderLibrary.buildFor(asset).problems : null;
|
||||
for (const node of asset.graph.nodes) {
|
||||
const def = resolveDef(node, asset.graph, lookup);
|
||||
if (!def) continue;
|
||||
@@ -230,7 +233,10 @@ export class GraphCanvas extends Widget {
|
||||
this.views.set(node.id, view);
|
||||
this.nodeLayer.addChild(view);
|
||||
}
|
||||
view.sync(node, asset.graph, this.state.project, def, callProblem(node, lookup, asset.id));
|
||||
const problem = shaderProblems
|
||||
? (shaderProblems[node.id] ?? null)
|
||||
: callProblem(node, lookup, asset.id);
|
||||
view.sync(node, asset.graph, this.state.project, def, problem);
|
||||
}
|
||||
for (const [id, view] of this.views) {
|
||||
if (!seen.has(id)) {
|
||||
|
||||
@@ -51,6 +51,8 @@ export function categoryColor(category: NodeCategory): number {
|
||||
return c.categoryAction;
|
||||
case 'state':
|
||||
return c.categoryState;
|
||||
case 'shader':
|
||||
return c.categoryShader;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +73,8 @@ export function portColor(type: PortType): number {
|
||||
return c.portList;
|
||||
case 'struct':
|
||||
return c.portStruct;
|
||||
case 'vec3':
|
||||
return c.portVec3;
|
||||
case 'any':
|
||||
return c.portAny;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ import type { GraphAsset } from '../../core/model/Asset';
|
||||
import { graphLookup } from '../../core/model/graphLookup';
|
||||
import type { PropertyBag } from '../../core/model/Properties';
|
||||
import type { Project } from '../../core/model/Project';
|
||||
import { nextPropertyName, PROPERTY_NAME_PARAM, SHADER_PROPERTY } from '../../core/properties/shaders';
|
||||
import { SHADER_NODES, SHADER_OUTPUT } from '../../core/shader/nodes';
|
||||
|
||||
/**
|
||||
* One row of the palette. `def` is the definition the node would actually have once placed, so the
|
||||
@@ -29,17 +31,26 @@ export interface PaletteEntry {
|
||||
|
||||
/**
|
||||
* The node types offerable in `asset`'s graph. A state machine holds states and nothing else, each
|
||||
* new one named by its number. In a behavior, every other behavior appears under its own name
|
||||
* instead of behind a generic "Run behavior", and the two terminals drop out once the graph has them.
|
||||
* new one named by its number; a shader holds shader nodes, its one Output dropping out once
|
||||
* placed. In a behavior, every other behavior appears under its own name instead of behind a
|
||||
* generic "Run behavior", and the two terminals drop out once the graph has them.
|
||||
*/
|
||||
export function paletteEntries(project: Project, asset: GraphAsset): PaletteEntry[] {
|
||||
if (asset.type === 'statemachine') {
|
||||
const params = { [STATE_NAME_PARAM]: nextStateName(asset.graph) };
|
||||
return [{ id: State.type, hint: State.category, def: State, params }];
|
||||
}
|
||||
if (asset.type === 'shader') {
|
||||
const hasOutput = asset.graph.nodes.some((n) => n.type === SHADER_OUTPUT);
|
||||
return SHADER_NODES.filter((def) => def.type !== SHADER_OUTPUT || !hasOutput).map((def) => {
|
||||
const params: PropertyBag =
|
||||
def.type === SHADER_PROPERTY ? { [PROPERTY_NAME_PARAM]: nextPropertyName(asset.graph) } : {};
|
||||
return { id: def.type, hint: def.category, def, params };
|
||||
});
|
||||
}
|
||||
const entries: PaletteEntry[] = [];
|
||||
for (const def of allNodeDefs()) {
|
||||
if (def.type === RUN_BEHAVIOR || def.category === 'state') continue;
|
||||
if (def.type === RUN_BEHAVIOR || def.category === 'state' || def.category === 'shader') continue;
|
||||
if (isTerminalType(def.type) && terminalNode(asset.graph, def.type)) continue;
|
||||
entries.push({ id: def.type, hint: def.category, def, params: {} });
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user