summaryrefslogtreecommitdiff
path: root/tools/shadertoy/template.cc
blob: 288283d34288bdbfcadfa55e243412a6d3eff5f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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);
}