import { Dyno } from "./base"; import type { AllSamplerTypes, IsamplerTypes, NormalSamplerTypes, Sampler2DArrayTypes, Sampler2DTypes, Sampler3DTypes, SamplerCubeTypes, SamplerShadowTypes, SamplerTypes, UsamplerTypes, } from "./types"; import { DynoOutput, type DynoVal, type DynoValue, type HasDynoOut, valType, } from "./value"; export const textureSize = ( texture: DynoVal, lod?: DynoVal<"int">, ): DynoVal> => new TextureSize({ texture, lod }); export const texture = ( texture: DynoVal, coord: DynoVal>, bias?: DynoVal<"float">, ): DynoVal> => new Texture({ texture, coord, bias }); export const texelFetch = ( texture: DynoVal, coord: DynoVal>, lod?: DynoVal<"int">, ): DynoVal> => new TexelFetch({ texture, coord, lod }); export class TextureSize extends Dyno<{ texture: T; lod: "int" }, { size: TextureSizeType }> implements HasDynoOut> { constructor({ texture, lod }: { texture: DynoVal; lod?: DynoVal<"int"> }) { const textureType = valType(texture); super({ inTypes: { texture: textureType, lod: "int" }, outTypes: { size: textureSizeType(textureType) }, inputs: { texture, lod }, statements: ({ inputs, outputs }) => [ `${outputs.size} = textureSize(${inputs.texture}, ${inputs.lod ?? "0"});`, ], }); } dynoOut(): DynoValue> { return new DynoOutput(this, "size"); } } export class Texture extends Dyno< { texture: T; coord: TextureCoordType; bias: "float" }, { sample: TextureReturnType } > implements HasDynoOut> { constructor({ texture, coord, bias, }: { texture: DynoVal; coord: DynoVal>; bias?: DynoVal<"float">; }) { const textureType = valType(texture); super({ inTypes: { texture: textureType, coord: textureCoordType(textureType), bias: "float", }, outTypes: { sample: textureReturnType(textureType) }, inputs: { texture, coord, bias }, statements: ({ inputs, outputs }) => [ `${outputs.sample} = texture(${inputs.texture}, ${inputs.coord}${inputs.bias ? `, ${inputs.bias}` : ""});`, ], }); } dynoOut(): DynoValue> { return new DynoOutput(this, "sample"); } } export class TexelFetch extends Dyno< { texture: T; coord: TextureSizeType; lod: "int" }, { texel: TextureReturnType } > implements HasDynoOut> { constructor({ texture, coord, lod, }: { texture: DynoVal; coord: DynoVal>; lod?: DynoVal<"int">; }) { const textureType = valType(texture); super({ inTypes: { texture: textureType, coord: textureSizeType(textureType), lod: "int", }, outTypes: { texel: textureReturnType(textureType) }, inputs: { texture, coord, lod }, statements: ({ inputs, outputs }) => [ `${outputs.texel} = texelFetch(${inputs.texture}, ${inputs.coord}, ${inputs.lod ?? "0"});`, ], }); } dynoOut(): DynoValue> { return new DynoOutput(this, "texel"); } } type TextureSizeType = T extends | Sampler2DTypes | SamplerCubeTypes ? "ivec2" : T extends Sampler3DTypes | Sampler2DArrayTypes ? "ivec3" : never; function textureSizeType( textureType: T, ): TextureSizeType { switch (textureType) { case "sampler2D": case "usampler2D": case "isampler2D": case "samplerCube": case "usamplerCube": case "isamplerCube": case "sampler2DShadow": case "samplerCubeShadow": return "ivec2" as TextureSizeType; case "sampler3D": case "usampler3D": case "isampler3D": case "sampler2DArray": case "usampler2DArray": case "isampler2DArray": case "sampler2DArrayShadow": return "ivec3" as TextureSizeType; default: throw new Error(`Invalid texture type: ${textureType}`); } } type TextureCoordType = T extends Sampler2DTypes ? "vec2" : T extends | Sampler3DTypes | Sampler2DArrayTypes | SamplerCubeTypes | Sampler2DArrayTypes ? "vec3" : T extends "samperCubeShadow" | "sampler2DArrayShadow" ? "vec4" : never; function textureCoordType( textureType: T, ): TextureCoordType { switch (textureType) { case "sampler2D": case "usampler2D": case "isampler2D": return "vec2" as TextureCoordType; case "sampler3D": case "usampler3D": case "isampler3D": case "samplerCube": case "usamplerCube": case "isamplerCube": case "sampler2DArray": case "usampler2DArray": case "isampler2DArray": case "sampler2DShadow": return "vec3" as TextureCoordType; case "samplerCubeShadow": case "sampler2DArrayShadow": return "vec4" as TextureCoordType; default: throw new Error(`Invalid texture type: ${textureType}`); } } type TextureReturnType = T extends SamplerTypes ? "vec4" : T extends UsamplerTypes ? "uvec4" : T extends IsamplerTypes ? "ivec4" : T extends SamplerShadowTypes ? "float" : never; function textureReturnType( textureType: T, ): TextureReturnType { switch (textureType) { case "sampler2D": case "sampler2DArray": case "sampler3D": case "samplerCube": case "sampler2DShadow": return "vec4" as TextureReturnType; case "usampler2D": case "usampler2DArray": case "usampler3D": case "usamplerCube": return "uvec4" as TextureReturnType; case "isampler2D": case "isampler2DArray": case "isampler3D": case "isamplerCube": return "ivec4" as TextureReturnType; case "samplerCubeShadow": case "sampler2DArrayShadow": return "float" as TextureReturnType; default: throw new Error(`Invalid texture type: ${textureType}`); } }