diff --git a/glm b/glm new file mode 160000 index 0000000..8f6213d --- /dev/null +++ b/glm @@ -0,0 +1 @@ +Subproject commit 8f6213d379a904f5ae910e09a114e066e25faf57 diff --git a/tests/g3test.cpp b/tests/g3test.cpp new file mode 100644 index 0000000..e3e0a49 --- /dev/null +++ b/tests/g3test.cpp @@ -0,0 +1,285 @@ +#include "../util/grid/grid3.hpp" +#include "../util/output/bmpwriter.hpp" +#include "../util/noise/pnoise2.hpp" +#include "../util/timing_decorator.cpp" +#include +#include +#include + +// Separate component storage +class ComponentManager { +private: + std::unordered_map colors_; + std::unordered_map sizes_; + +public: + void set_color(size_t id, const Vec4ui8& color) { colors_[id] = color; } + Vec4ui8 get_color(size_t id) const { + auto it = colors_.find(id); + return it != colors_.end() ? it->second : Vec4ui8(1, 1, 1, 1); + } +}; + +// Generate noise-based positions +std::vector generate_noise_positions(int width, int height, float scale = 0.01f, float threshold = 0.3f) { + std::vector positions; + PNoise2 noise_generator(std::random_device{}()); + + // Generate positions based on 2D noise + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + // Convert to normalized coordinates + float nx = static_cast(x) / width; + float ny = static_cast(y) / height; + + // Generate noise at multiple octaves for more interesting patterns + float noise_value = 0.0f; + float amplitude = 1.0f; + float frequency = 1.0f; + float max_value = 0.0f; + + for (int i = 0; i < 4; i++) { + Vec2 sample_point(nx * frequency * scale, ny * frequency * scale); + noise_value += amplitude * noise_generator.permute(sample_point); + max_value += amplitude; + amplitude *= 0.5f; + frequency *= 2.0f; + } + + noise_value = (noise_value / max_value + 1.0f) * 0.5f; // Normalize to [0, 1] + + // Threshold to create sparse distribution + if (noise_value > threshold) { + // Map to world coordinates [-512, 512] + float world_x = (nx * 2.0f - 1.0f) * 512.0f; + float world_y = (ny * 2.0f - 1.0f) * 512.0f; + float world_z = noise_value * 100.0f; // Use noise value for height + + positions.emplace_back(world_x, world_y, world_z); + } + } + } + + return positions; +} + +// Generate 3D noise-based positions (more varied in 3D space) +std::vector generate_3d_noise_positions(int grid_size, float scale = 0.02f, float threshold = 0.4f) { + std::vector positions; + PNoise2 noise_generator(std::random_device{}()); + int sizehalf = grid_size / 2; + for (int x = 0; x < grid_size; x++) { + for (int y = 0; y < grid_size; y++) { + for (int z = 0; z < grid_size; z++) { + // Convert to normalized coordinates + float nx = static_cast(x) / sizehalf; + float ny = static_cast(y) / sizehalf; + float nz = static_cast(z) / sizehalf; + + // Generate 3D noise + Vec3f sample_point(nx, ny, nz); + float noise_value = noise_generator.permute(sample_point); + + // Threshold to create sparse distribution + if (noise_value > threshold) { + // Map to world coordinates [-512, 512] + float world_x = (x - sizehalf); + float world_y = (y - sizehalf); + float world_z = (z - sizehalf); + + positions.emplace_back(world_x, world_y, world_z); + } + } + } + } + + return positions; +} + +// Generate gradient color based on position +Vec4ui8 get_gradient_color(const Vec3f& pos, const Vec3f& min_pos, const Vec3f& max_pos) { + // Normalize position to [0, 1] + Vec3f normalized( + (pos.x - min_pos.x) / (max_pos.x - min_pos.x), + (pos.y - min_pos.y) / (max_pos.y - min_pos.y), + (pos.z - min_pos.z) / (max_pos.z - min_pos.z) + ); + + // Create RGB gradient based on normalized coordinates + uint8_t r = static_cast(normalized.x * 255); + uint8_t g = static_cast(normalized.y * 255); + uint8_t b = static_cast(normalized.z * 255); + + return Vec4ui8(r, g, b, 255); +} + +// Generate noise-based color +Vec4ui8 get_noise_color(const Vec3f& pos, PNoise2& noise_generator) { + // Use noise to generate color + Vec3f sample_point(pos.x * 0.005f, pos.y * 0.005f, pos.z * 0.005f); + float noise_r = noise_generator.permute(sample_point); + noise_r = (noise_r + 1.0f) * 0.5f; // Normalize to [0, 1] + + sample_point = Vec3f(pos.x * 0.007f, pos.y * 0.007f, pos.z * 0.007f); + float noise_g = noise_generator.permute(sample_point); + noise_g = (noise_g + 1.0f) * 0.5f; + + sample_point = Vec3f(pos.x * 0.009f, pos.y * 0.009f, pos.z * 0.009f); + float noise_b = noise_generator.permute(sample_point); + noise_b = (noise_b + 1.0f) * 0.5f; + + uint8_t r = static_cast(noise_r * 255); + uint8_t g = static_cast(noise_g * 255); + uint8_t b = static_cast(noise_b * 255); + + return Vec4ui8(r, g, b, 255); +} + +// Function to save frame with given filename +bool save_frame(const frame& f, const std::string& filename) { + return BMPWriter::saveBMP(filename, f); +} + +// Create directory if it doesn't exist +void ensure_directory(const std::string& path) { + std::filesystem::create_directories(path); +} + +int main() { + // Create output directory + ensure_directory("output"); + + // Create pure spatial grid + Grid3 grid(10.0f, 15.0f); // Larger cell size for sparse distribution + + // Separate component storage + ComponentManager components; + + // Generate noise-based positions + std::cout << "Generating noise-based positions..." << std::endl; + + // Option 1: 2D noise (faster) + // auto positions = generate_noise_positions(200, 200, 0.02f, 0.4f); + + // Option 2: 3D noise (more interesting, but slower) + auto positions = generate_3d_noise_positions(1024, 0.05f, 0.5f); + + std::cout << "Generated " << positions.size() << " positions" << std::endl; + + // Add positions to grid + std::cout << "Adding positions to grid..." << std::endl; + std::vector ids = grid.bulk_add_positions(positions); + + // Generate bounds for color gradient + auto bounds = grid.get_bounds(); + Vec3f min_pos = bounds.first; + Vec3f max_pos = bounds.second; + + // Create noise generator for colors + PNoise2 color_noise_generator(42); // Fixed seed for consistent colors + + // Assign colors to components + std::cout << "Assigning colors..." << std::endl; + for (size_t i = 0; i < ids.size(); i++) { + Vec3f pos = grid.get_position(ids[i]); + + // Choose color method: + // Vec4ui8 color = get_gradient_color(pos, min_pos, max_pos); + Vec4ui8 color = get_noise_color(pos, color_noise_generator); + + components.set_color(ids[i], color); + } + + // Query neighbors for first few points (optional) + if (!ids.empty()) { + auto neighbors = grid.get_neighbors(ids[0]); + std::cout << "First point has " << neighbors.size() << " neighbors" << std::endl; + } + + // Region to render (full noise map area) + Vec3f render_min(-512, -512, -512); + Vec3f render_max(512, 512, 512); + Vec2 resolution(1024, 1024); // Higher resolution for better detail + + // Define multiple view angles + struct ViewAngle { + std::string name; + Vec3f eye_position; + Vec3f look_at; + }; + + std::vector view_angles = { + // Orthographic views + {"front", Vec3f(0, 0, -800), Vec3f(0, 0, 0)}, + {"back", Vec3f(0, 0, 800), Vec3f(0, 0, 0)}, + {"left", Vec3f(-800, 0, 0), Vec3f(0, 0, 0)}, + {"right", Vec3f(800, 0, 0), Vec3f(0, 0, 0)}, + {"top", Vec3f(0, 800, 0), Vec3f(0, 0, 0)}, + {"bottom", Vec3f(0, -800, 0), Vec3f(0, 0, 0)}, + + // 45° angle views + {"front_right_top", Vec3f(800, 800, -800), Vec3f(0, 0, 0)}, + {"front_left_top", Vec3f(-800, 800, -800), Vec3f(0, 0, 0)}, + {"front_right_bottom", Vec3f(800, -800, -800), Vec3f(0, 0, 0)}, + {"front_left_bottom", Vec3f(-800, -800, -800), Vec3f(0, 0, 0)}, + + {"back_right_top", Vec3f(800, 800, 800), Vec3f(0, 0, 0)}, + {"back_left_top", Vec3f(-800, 800, 800), Vec3f(0, 0, 0)}, + {"back_right_bottom", Vec3f(800, -800, 800), Vec3f(0, 0, 0)}, + {"back_left_bottom", Vec3f(-800, -800, 800), Vec3f(0, 0, 0)}, + + // Additional interesting angles + {"diagonal_xy", Vec3f(800, 800, 0), Vec3f(0, 0, 0)}, + {"diagonal_xz", Vec3f(800, 0, 800), Vec3f(0, 0, 0)}, + {"diagonal_yz", Vec3f(0, 800, 800), Vec3f(0, 0, 0)}, + + // Isometric-like views + {"isometric_1", Vec3f(600, 600, 600), Vec3f(0, 0, 0)}, + {"isometric_2", Vec3f(-600, 600, 600), Vec3f(0, 0, 0)}, + {"isometric_3", Vec3f(600, -600, 600), Vec3f(0, 0, 0)}, + {"isometric_4", Vec3f(-600, -600, 600), Vec3f(0, 0, 0)} + }; + + // Render and save from each angle + std::cout << "Rendering from multiple angles..." << std::endl; + int saved_count = 0; + + for (const auto& view : view_angles) { + // Create view ray + Vec3f direction = (view.look_at - view.eye_position).normalized(); + Ray3 view_ray(view.eye_position, direction); + + // Render the frame + auto frame = Grid3View::render_region( + grid, + render_min, + render_max, + resolution, + view_ray, + [&](size_t id) { return components.get_color(id); }, + frame::colormap::RGBA, + Vec4ui8(0, 0, 0, 255) // Black background + ); + + // Save the rendered frame + std::string filename = "output/view_" + view.name + ".bmp"; + bool saved = save_frame(frame, filename); + + if (saved) { + saved_count++; + std::cout << "Saved: " << filename << std::endl; + } else { + std::cout << "Failed to save: " << filename << std::endl; + } + } + + std::cout << "\nSuccessfully saved " << saved_count << " out of " << view_angles.size() + << " views to output/" << std::endl; + + // Optional: Save a summary image with grid statistics + std::cout << "\nGrid statistics:" << std::endl; + std::cout << "Total positions: " << grid.size() << std::endl; + std::cout << "Bounds: [" << min_pos << "] to [" << max_pos << "]" << std::endl; + + return 0; +} \ No newline at end of file diff --git a/util/output/bmpwriter.hpp b/util/output/bmpwriter.hpp index f1db6e6..1173661 100644 --- a/util/output/bmpwriter.hpp +++ b/util/output/bmpwriter.hpp @@ -143,7 +143,7 @@ public: return true; } - static bool saveBMP(const std::string& filename, frame& frame) { + static bool saveBMP(const std::string& filename, const frame& frame) { if (frame.colorFormat == frame::colormap::RGB) { return saveBMP(filename, frame.getData(), frame.getWidth(), frame.getHeight()); } else if (frame.colorFormat == frame::colormap::RGBA) { diff --git a/util/output/frame.hpp b/util/output/frame.hpp index 9b29461..28fa3ad 100644 --- a/util/output/frame.hpp +++ b/util/output/frame.hpp @@ -48,11 +48,11 @@ public: colormap colorFormat = colormap::RGB; compresstype cformat = compresstype::RAW; - const size_t& getWidth() { + const size_t& getWidth() const { return width; } - const size_t& getHeight() { + const size_t& getHeight() const { return height; } frame() {};