|
1 | 1 | import { type ShaderGenerator, type Snippet, WgslGenerator } from 'typegpu'; |
2 | 2 | import type * as tinyest from 'tinyest'; |
| 3 | +import type { AnyData } from 'typegpu/data'; |
| 4 | + |
| 5 | +const wgslToGlslTypeMap = { |
| 6 | + f32: 'float', |
| 7 | + f64: 'double', |
| 8 | + i32: 'int', |
| 9 | + u32: 'uint', |
| 10 | + void: 'void', |
| 11 | +}; |
| 12 | + |
| 13 | +function resolveSchema( |
| 14 | + ctx: ShaderGenerator.ResolutionCtx, |
| 15 | + schema: AnyData, |
| 16 | +): { typePrefix: string; typeSuffix: string } { |
| 17 | + if (schema.type in wgslToGlslTypeMap) { |
| 18 | + return { |
| 19 | + typePrefix: |
| 20 | + wgslToGlslTypeMap[schema.type as keyof typeof wgslToGlslTypeMap], |
| 21 | + typeSuffix: '', |
| 22 | + }; |
| 23 | + } |
| 24 | + |
| 25 | + if (schema.type === 'array') { |
| 26 | + return { |
| 27 | + typePrefix: resolveSchema(ctx, schema.elementType as AnyData).typePrefix, |
| 28 | + typeSuffix: `[${schema.length}]`, |
| 29 | + }; |
| 30 | + } |
| 31 | + |
| 32 | + // TODO: Make struct declaration the responsibility of the |
| 33 | + // shader generator |
| 34 | + // if (schema.type === 'struct') { |
| 35 | + // ctx.addDeclaration(); |
| 36 | + |
| 37 | + // const fields = schema.fields.map((field) => |
| 38 | + // `${resolveSchema(ctx, field.type).typePrefix} ${field.name}` |
| 39 | + // ).join(', '); |
| 40 | + // return { |
| 41 | + // typePrefix: `struct ${structName} { ${fields} }`, |
| 42 | + // typeSuffix: '', |
| 43 | + // }; |
| 44 | + // } |
| 45 | + |
| 46 | + throw new Error(`Unsupported type: ${String(schema)}`); |
| 47 | +} |
3 | 48 |
|
4 | 49 | export class GLSLShaderGenerator extends WgslGenerator |
5 | 50 | implements ShaderGenerator { |
6 | 51 | public override expression(expression: tinyest.Expression): Snippet { |
7 | 52 | return super.expression(expression); |
8 | 53 | } |
9 | 54 |
|
10 | | - public override functionBody(bodyNode: tinyest.Block): string { |
11 | | - return 'hello'; |
| 55 | + public override functionHeader( |
| 56 | + { type, args, id, returnType }: ShaderGenerator.FunctionHeaderOptions, |
| 57 | + ): string { |
| 58 | + if (type === 'compute') { |
| 59 | + throw new Error('Compute shaders are not supported in GLSL'); |
| 60 | + } |
| 61 | + |
| 62 | + const argList = args.map((arg) => { |
| 63 | + const segment = resolveSchema(this.ctx, arg.dataType as AnyData); |
| 64 | + return `${segment.typePrefix} ${arg.value}${segment.typeSuffix}`; |
| 65 | + }).join(', '); |
| 66 | + |
| 67 | + const returnSegment = resolveSchema(this.ctx, returnType); |
| 68 | + |
| 69 | + if (returnSegment.typeSuffix.length > 0) { |
| 70 | + throw new Error(`Unsupported return type: ${String(returnType)}`); |
| 71 | + } |
| 72 | + |
| 73 | + // Entry functions are always named 'main' in GLSL |
| 74 | + const realId = type === 'normal' ? id : 'main'; |
| 75 | + |
| 76 | + return `${returnSegment.typePrefix} ${realId}(${argList})`; |
12 | 77 | } |
13 | 78 | } |
0 commit comments