summaryrefslogtreecommitdiff
path: root/cpp-timeplot/src/renderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp-timeplot/src/renderer.cpp')
-rw-r--r--cpp-timeplot/src/renderer.cpp180
1 files changed, 180 insertions, 0 deletions
diff --git a/cpp-timeplot/src/renderer.cpp b/cpp-timeplot/src/renderer.cpp
new file mode 100644
index 0000000..1c61698
--- /dev/null
+++ b/cpp-timeplot/src/renderer.cpp
@@ -0,0 +1,180 @@
+#include "renderer.h"
+#include "waterfall.h"
+#include <fstream>
+#include <sstream>
+#include <iostream>
+
+Renderer::Renderer(wgpu::Device device, wgpu::Surface surface, int width, int height)
+ : device_(device), surface_(surface), width_(width), height_(height), time_(0.0f),
+ surfaceFormat_(wgpu::TextureFormat::BGRA8Unorm) {}
+
+Renderer::~Renderer() = default;
+
+bool Renderer::initialize() {
+ configureSurface();
+ createPipelines();
+
+ // Create two waterfall views side-by-side
+ waterfalls_.push_back(std::make_unique<Waterfall>(
+ device_, 0.0f, 0.1f, 0.5f, 0.9f, "Frequency vs Time"));
+ waterfalls_.push_back(std::make_unique<Waterfall>(
+ device_, 0.5f, 0.1f, 0.5f, 0.9f, "Position vs Time"));
+
+ for (auto& waterfall : waterfalls_) {
+ if (!waterfall->initialize()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void Renderer::configureSurface() {
+ wgpu::SurfaceConfiguration config{};
+ config.device = device_;
+ config.format = surfaceFormat_;
+ config.usage = wgpu::TextureUsage::RenderAttachment;
+ config.width = width_;
+ config.height = height_;
+ config.presentMode = wgpu::PresentMode::Fifo;
+ config.alphaMode = wgpu::CompositeAlphaMode::Auto;
+
+ surface_.configure(config);
+}
+
+void Renderer::createPipelines() {
+ // Load shader
+ std::ifstream shaderFile("shaders/waterfall.wgsl");
+ std::stringstream buffer;
+ buffer << shaderFile.rdbuf();
+ std::string shaderCode = buffer.str();
+
+ wgpu::ShaderSourceWGSL wgslSource{};
+ wgslSource.chain.sType = wgpu::SType::ShaderSourceWGSL;
+ wgslSource.code.data = shaderCode.c_str();
+ wgslSource.code.length = shaderCode.length();
+
+ wgpu::ShaderModuleDescriptor shaderDesc{};
+ shaderDesc.nextInChain = &wgslSource.chain;
+ wgpu::ShaderModule shader = device_.createShaderModule(shaderDesc);
+
+ // Vertex buffer layout
+ wgpu::VertexAttribute attributes[2];
+ attributes[0].format = wgpu::VertexFormat::Float32x2;
+ attributes[0].offset = 0;
+ attributes[0].shaderLocation = 0;
+
+ attributes[1].format = wgpu::VertexFormat::Float32x3;
+ attributes[1].offset = 2 * sizeof(float);
+ attributes[1].shaderLocation = 1;
+
+ wgpu::VertexBufferLayout vertexBufferLayout{};
+ vertexBufferLayout.arrayStride = 5 * sizeof(float);
+ vertexBufferLayout.stepMode = wgpu::VertexStepMode::Vertex;
+ vertexBufferLayout.attributeCount = 2;
+ vertexBufferLayout.attributes = attributes;
+
+ // Pipeline layout
+ wgpu::PipelineLayoutDescriptor layoutDesc{};
+ wgpu::PipelineLayout pipelineLayout = device_.createPipelineLayout(layoutDesc);
+
+ // Color target
+ wgpu::BlendState blend{};
+ blend.color.operation = wgpu::BlendOperation::Add;
+ blend.color.srcFactor = wgpu::BlendFactor::One;
+ blend.color.dstFactor = wgpu::BlendFactor::Zero;
+ blend.alpha.operation = wgpu::BlendOperation::Add;
+ blend.alpha.srcFactor = wgpu::BlendFactor::One;
+ blend.alpha.dstFactor = wgpu::BlendFactor::Zero;
+
+ wgpu::ColorTargetState colorTarget{};
+ colorTarget.format = surfaceFormat_;
+ colorTarget.blend = &blend;
+ colorTarget.writeMask = wgpu::ColorWriteMask::All;
+
+ wgpu::FragmentState fragmentState{};
+ fragmentState.module = shader;
+ fragmentState.entryPoint.data = "fs_main";
+ fragmentState.entryPoint.length = 7;
+ fragmentState.targetCount = 1;
+ fragmentState.targets = &colorTarget;
+
+ // Line strip pipeline
+ wgpu::RenderPipelineDescriptor pipelineDesc{};
+ pipelineDesc.layout = pipelineLayout;
+ pipelineDesc.vertex.module = shader;
+ pipelineDesc.vertex.entryPoint.data = "vs_main";
+ pipelineDesc.vertex.entryPoint.length = 7;
+ pipelineDesc.vertex.bufferCount = 1;
+ pipelineDesc.vertex.buffers = &vertexBufferLayout;
+ pipelineDesc.primitive.topology = wgpu::PrimitiveTopology::LineStrip;
+ pipelineDesc.fragment = &fragmentState;
+ pipelineDesc.multisample.count = 1;
+ pipelineDesc.multisample.mask = ~0u;
+
+ linePipeline_ = device_.createRenderPipeline(pipelineDesc);
+
+ // Line list pipeline for grid
+ pipelineDesc.primitive.topology = wgpu::PrimitiveTopology::LineList;
+ lineListPipeline_ = device_.createRenderPipeline(pipelineDesc);
+}
+
+void Renderer::update() {
+ time_ += 0.016f; // ~60fps
+
+ for (auto& waterfall : waterfalls_) {
+ waterfall->update(time_);
+ }
+}
+
+void Renderer::render() {
+ wgpu::SurfaceTexture surfaceTexture;
+ surface_.getCurrentTexture(&surfaceTexture);
+
+ if (surfaceTexture.status != wgpu::SurfaceGetCurrentTextureStatus::SuccessOptimal &&
+ surfaceTexture.status != wgpu::SurfaceGetCurrentTextureStatus::SuccessSuboptimal) {
+ std::cerr << "Failed to get surface texture" << std::endl;
+ return;
+ }
+
+ wgpu::Texture texture(surfaceTexture.texture);
+ wgpu::TextureView textureView = texture.createView();
+
+ wgpu::CommandEncoder encoder = device_.createCommandEncoder();
+
+ wgpu::RenderPassColorAttachment colorAttachment{};
+ colorAttachment.view = textureView;
+ colorAttachment.loadOp = wgpu::LoadOp::Clear;
+ colorAttachment.storeOp = wgpu::StoreOp::Store;
+ colorAttachment.clearValue = {0.1, 0.1, 0.15, 1.0};
+
+ wgpu::RenderPassDescriptor renderPassDesc{};
+ renderPassDesc.colorAttachmentCount = 1;
+ renderPassDesc.colorAttachments = &colorAttachment;
+
+ wgpu::RenderPassEncoder pass = encoder.beginRenderPass(renderPassDesc);
+
+ for (auto& waterfall : waterfalls_) {
+ waterfall->render(pass, linePipeline_, lineListPipeline_, width_, height_);
+ }
+
+ pass.end();
+
+ wgpu::CommandBuffer commands = encoder.finish();
+ device_.getQueue().submit(1, &commands);
+ surface_.present();
+}
+
+void Renderer::resize(int width, int height) {
+ if (width > 0 && height > 0) {
+ width_ = width;
+ height_ = height;
+ configureSurface();
+ }
+}
+
+void Renderer::toggleGrid() {
+ for (auto& waterfall : waterfalls_) {
+ waterfall->toggleGrid();
+ }
+}