#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "helper.hpp" #include #include #include #include #include #include #include "camera.hpp" #include "ray.hpp" #include "random_sampler.hpp" #include "random_sampler_wrapper.hpp" inline unsigned int packColor(unsigned int r, unsigned int g, unsigned int b) { return (b << 16) + (g << 8) + r; } #include // AtomicFloat Class class AtomicFloat { public: // AtomicFloat Public Methods explicit AtomicFloat(float v = 0.0f) { bits = floatToBits(v); } operator float() const { return bitsToFloat(bits); } float operator=(float v) { bits = floatToBits(v); return v; } void add(float v) { uint32_t oldBits = bits, newBits; do { newBits = floatToBits(bitsToFloat(oldBits) + v); } while (!bits.compare_exchange_weak(oldBits, newBits)); } private: // AtomicFloat Private Data std::atomic bits; // Helper functions to convert between float and uint32_t static uint32_t floatToBits(float f) { uint32_t u; memcpy(&u, &f, sizeof(uint32_t)); return u; } static float bitsToFloat(uint32_t u) { float f; memcpy(&f, &u, sizeof(uint32_t)); return f; } }; class Film { public: Film() { } Film(unsigned int width, unsigned int height) { init(width, height); } void init(unsigned int w, unsigned int h) { width = w; height = h; size_t size = width * height; accu_x = std::make_unique(size); accu_y = std::make_unique(size); accu_z = std::make_unique(size); splat_count = std::make_unique[]>(size); clear(); } // atomic safe void addSplat(int x, int y, const Vec3fa& value) { size_t index = y * width + x; accu_x[index].add(value.x); accu_y[index].add(value.y); accu_z[index].add(value.z); if(count) splat_count[index].fetch_add(1, std::memory_order_relaxed); } void writeToFramebuffer(unsigned int* pixels) { parallel_for(size_t(0), size_t(width * height), [&](const range& range) { for (size_t i = range.begin(); i < range.end(); ++i) { pixels[i] = getPackedColor(i); } }); } unsigned int getPackedColor(size_t index) const { float divider = 1.0; if (count) { unsigned int count = splat_count[index].load(std::memory_order_relaxed); if (count == 0) return 0; // Return black if no splats divider = 1.0 / count; } float accu_x_val = accu_x[index] *divider* scalar; float accu_y_val = accu_y[index] * divider* scalar; float accu_z_val = accu_z[index] * divider* scalar; unsigned int r = static_cast(255.01f * clamp(accu_x_val, 0.0f, 1.0f)); unsigned int g = static_cast(255.01f * clamp(accu_y_val, 0.0f, 1.0f)); unsigned int b = static_cast(255.01f * clamp(accu_z_val, 0.0f, 1.0f)); return packColor(r, g, b); } unsigned int getPackedColor(int x, int y) const { return getPackedColor(y * width + x); } void clear() { parallel_for(size_t(0), size_t(width * height), [&](const range& range) { for (size_t i = range.begin(); i < range.end(); ++i) { accu_x[i] = 0.0f; accu_y[i] = 0.0f; accu_z[i] = 0.0f; splat_count[i].store(0, std::memory_order_relaxed); } }); } float scalar = 1.0; unsigned int width, height; bool count = true; private: std::unique_ptr accu_x, accu_y, accu_z; std::unique_ptr[]> splat_count; };