diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-10 17:47:15 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-10 17:47:15 +0100 |
| commit | ae810e1a9c68d05bee254ef570fbb0e783e25931 (patch) | |
| tree | 407f3d7d8e03da07d8f7995df78d37be7d1f32c1 /tools/shadertoy/template.cc | |
| parent | f3c7ef8cd612f5ac908f39310c4c11566879313f (diff) | |
feat: Add ShaderToy conversion tools
Add automated conversion pipeline for ShaderToy shaders to demo effects:
- convert_shadertoy.py: Automated code generation script
- Manual templates: Header, implementation, and WGSL boilerplate
- Example shader: Test case for conversion workflow
- README: Complete conversion guide with examples
Handles basic GLSL→WGSL conversion (types, uniforms, mainImage extraction).
Manual fixes needed for fragColor returns and complex type inference.
Organized under tools/shadertoy/ for maintainability.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'tools/shadertoy/template.cc')
| -rw-r--r-- | tools/shadertoy/template.cc | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/tools/shadertoy/template.cc b/tools/shadertoy/template.cc new file mode 100644 index 0000000..288283d --- /dev/null +++ b/tools/shadertoy/template.cc @@ -0,0 +1,120 @@ +// This file is part of the 64k demo project. +// ShaderToy effect implementation - REPLACE THIS LINE +// TODO: Update description, rename class + +#include "gpu/effects/shadertoy_effect.h" +#include "gpu/effects/shader_composer.h" +#include "generated/assets.h" + +// TODO: Rename class and adjust constructor parameters +ShaderToyEffect::ShaderToyEffect(const GpuContext& ctx) : Effect(ctx) { +} + +ShaderToyEffect::~ShaderToyEffect() { + if (sampler_) + wgpuSamplerRelease(sampler_); + if (bind_group_) + wgpuBindGroupRelease(bind_group_); + if (pipeline_) + wgpuRenderPipelineRelease(pipeline_); +} + +void ShaderToyEffect::init(MainSequence* demo) { + demo_ = demo; + params_.init(ctx_.device); + + WGPUSamplerDescriptor sampler_desc = {}; + sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge; + sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge; + sampler_desc.magFilter = WGPUFilterMode_Linear; + sampler_desc.minFilter = WGPUFilterMode_Linear; + sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Linear; + sampler_desc.maxAnisotropy = 1; + sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc); + + // TODO: Update asset name to match your shader file + size_t shader_size; + const char* shader_code = (const char*)GetAsset( + AssetId::ASSET_SHADERTOY_SHADER, &shader_size); + + std::string composed = ShaderComposer::Get().Compose({}, shader_code); + + WGPUShaderSourceWGSL wgsl = {}; + wgsl.chain.sType = WGPUSType_ShaderSourceWGSL; + wgsl.code = str_view(composed.c_str()); + + WGPUShaderModuleDescriptor desc = {}; + desc.nextInChain = &wgsl.chain; + WGPUShaderModule module = wgpuDeviceCreateShaderModule(ctx_.device, &desc); + + const WGPUColorTargetState target = { + .format = ctx_.format, + .writeMask = WGPUColorWriteMask_All, + }; + WGPUFragmentState frag = {}; + frag.module = module; + frag.entryPoint = str_view("fs_main"); + frag.targetCount = 1; + frag.targets = ⌖ + + const WGPUDepthStencilState depth_stencil = { + .format = WGPUTextureFormat_Depth24Plus, + .depthWriteEnabled = WGPUOptionalBool_False, + .depthCompare = WGPUCompareFunction_Always, + }; + + WGPURenderPipelineDescriptor pipeline_desc = {}; + pipeline_desc.label = label_view("ShaderToyEffect"); + pipeline_desc.vertex.module = module; + pipeline_desc.vertex.entryPoint = str_view("vs_main"); + pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList; + pipeline_desc.primitive.cullMode = WGPUCullMode_None; + pipeline_desc.depthStencil = &depth_stencil; + pipeline_desc.multisample.count = 1; + pipeline_desc.multisample.mask = 0xFFFFFFFF; + pipeline_desc.fragment = &frag; + + pipeline_ = wgpuDeviceCreateRenderPipeline(ctx_.device, &pipeline_desc); + wgpuShaderModuleRelease(module); + + WGPUTextureView prev_view = demo_->get_prev_texture_view(); + const WGPUBindGroupEntry entries[] = { + {.binding = 0, .sampler = sampler_}, + {.binding = 1, .textureView = prev_view}, + {.binding = 2, + .buffer = uniforms_.get().buffer, + .size = sizeof(CommonPostProcessUniforms)}, + {.binding = 3, + .buffer = params_.get().buffer, + .size = sizeof(ShaderToyParams)}, + }; + const WGPUBindGroupDescriptor bg_desc = { + .layout = wgpuRenderPipelineGetBindGroupLayout(pipeline_, 0), + .entryCount = 4, + .entries = entries, + }; + bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc); +} + +void ShaderToyEffect::render(WGPURenderPassEncoder pass, float time, + float beat, float intensity, float aspect_ratio) { + const CommonPostProcessUniforms uniforms = { + .resolution = {static_cast<float>(width_), static_cast<float>(height_)}, + .aspect_ratio = aspect_ratio, + .time = time, + .beat = beat, + .audio_intensity = intensity, + }; + uniforms_.update(ctx_.queue, uniforms); + + // TODO: Update parameters based on your effect + const ShaderToyParams params = { + .param1 = 1.0f, + .param2 = beat, + }; + params_.update(ctx_.queue, params); + + wgpuRenderPassEncoderSetPipeline(pass, pipeline_); + wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); + wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0); +} |
