summaryrefslogtreecommitdiff
path: root/tools/shadertoy/template.cc
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-10 17:47:15 +0100
committerskal <pascal.massimino@gmail.com>2026-02-10 17:47:15 +0100
commitae810e1a9c68d05bee254ef570fbb0e783e25931 (patch)
tree407f3d7d8e03da07d8f7995df78d37be7d1f32c1 /tools/shadertoy/template.cc
parentf3c7ef8cd612f5ac908f39310c4c11566879313f (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.cc120
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 = &target;
+
+ 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);
+}