This commit is contained in:
zongor 2025-07-23 21:58:27 -04:00
commit f042e07ee7
9 changed files with 442 additions and 0 deletions

6
.ccls Normal file
View File

@ -0,0 +1,6 @@
%compile_flags
-Isrc
-std=c++23
-Wall
-Wextra
-O2

105
.gitignore vendored Normal file
View File

@ -0,0 +1,105 @@
# -*- mode: gitignore; -*-
*~
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
*.elc
auto-save-list
tramp
.\#*
# Org-mode
.org-id-locations
*_archive
# flymake-mode
*_flymake.*
# eshell files
/eshell/history
/eshell/lastdir
# elpa packages
/elpa/
# reftex files
*.rel
# AUCTeX auto folder
/auto/
# cask packages
.cask/
dist/
# Flycheck
flycheck_*.el
# server auth directory
/server/
# projectiles files
.projectile
# directory configuration
.dir-locals.el
.ccls-cache/
# network security
/network-security.data
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
build/
.ccls-cache/

36
Makefile Normal file
View File

@ -0,0 +1,36 @@
CXX := g++
SRC_DIR := src
BUILD_DIR := build
TARGET := $(BUILD_DIR)/holst
STD ?= c++23
CXXFLAGS := -std=$(STD) -Wall -Wextra -O2 -Iinclude
LDFLAGS :=
# Source files and object files
SRCS := $(shell find $(SRC_DIR) -name '*.cpp')
OBJS := $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(SRCS))
# Default target
all: $(TARGET)
# Link final executable
$(TARGET): $(OBJS)
@mkdir -p $(dir $@)
$(CXX) $(OBJS) -o $@ $(LDFLAGS)
# Compile source files
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp
@mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) -c $< -o $@
# Clean build files
clean:
rm -rf $(BUILD_DIR)
# Print configuration (debugging)
print:
@echo "Compiler: $(CXX)"
@echo "Standard: $(STD)"
@echo "Sources: $(SRCS)"
@echo "Objects: $(OBJS)"

123
README.org Normal file
View File

@ -0,0 +1,123 @@
#+TITLE: Holst
#+AUTHOR: Charles Kralapp
#+OPTIONS: toc:nil num:nil
This project combines a raytracer and an N-body solar system simulation to learn modern C++ (C++03C++23) through practical implementation.
* ✅ Project Goals
- [ ] Simulate solar system using an N-body gravitational algorithm.
- [ ] Implement a raytracer for rendering bodies and backgrounds.
- [ ] Learn and demonstrate features from every major C++ standard.
- [ ] Use open-source tooling: GNU Emacs, Org-mode, GCC, GNU Make.
* 🚀 Toolchain
- Editor: Emacs + Org Mode
- Compiler: GCC/g++
- Build System: GNU Make (no CMake)
- Version Control: Git (optional but recommended)
* 📚 C++ Learning Checklist
** C++03 (Baseline)
- [ ] Classes & Constructors
- [ ] Operator Overloading (`+`, `*`, `[]`)
- [ ] Manual memory management (`new` / `delete`)
- [ ] STL containers: `std::vector`, `std::map`
- [ ] Function overloading
- [ ] Templates (vector math, utility classes)
- [ ] Pointers, references, and const correctness
- [ ] Namespaces
- [ ] RAII pattern with destructors
- [ ] `std::string`, `std::stringstream`
** C++11 (Modern C++ begins)
- [ ] `auto` type deduction
- [ ] Range-based for loops
- [ ] Lambda expressions
- [ ] `nullptr`
- [ ] `enum class`
- [ ] Smart pointers: `std::unique_ptr`, `std::shared_ptr`
- [ ] `override`, `final` specifiers
- [ ] `move` semantics and rvalue references
- [ ] `std::array`, `std::tuple`
- [ ] Thread support: `std::thread`
** C++14 (Polish & convenience)
- [ ] Generic lambdas (`auto` in lambda parameters)
- [ ] `decltype(auto)` and improved return type inference
- [ ] `std::make_unique`
- [ ] Binary literals and digit separators (`0b1010`, `1'000'000`)
- [ ] Relaxed constexpr functions
- [ ] Using `auto` in lambda captures
** C++17 (Simpler and more expressive)
- [ ] Structured bindings (`auto [x, y] = foo();`)
- [ ] `if constexpr`
- [ ] `std::optional`
- [ ] `std::variant`, `std::any`
- [ ] Inline variables
- [ ] `std::string_view`
- [ ] Filesystem support (`std::filesystem`)
- [ ] Parallel algorithms (`std::execution`)
** C++20 (Huge leap forward)
- [ ] Concepts (`template<typename T> requires`)
- [ ] Ranges library: views, filters, transforms
- [ ] `consteval` / `constinit`
- [ ] Coroutines (`co_yield`, `co_return`)
- [ ] Calendar and time utilities (`std::chrono::year_month_day`)
- [ ] Modules (if supported by compiler/toolchain)
- [ ] Expanded constexpr support (e.g., STL algorithms)
** C++23 (Final polish)
- [ ] `std::expected` (like Rust's Result<T, E>)
- [ ] `std::mdspan` for multidimensional array views
- [ ] `explicit` lambdas
- [ ] More constexpr in the standard library
- [ ] `[[assume]]` attribute
- [ ] Improved ranges (e.g., `views::repeat`, `zip`)
* 🛠 Project Milestones (use standards progressively)
** Milestone 1: Base Simulation Engine
- [ ] Build N-body simulation using raw pointers (C++03)
- [ ] Add `Vector3` class, `Body` class
- [ ] Use `std::vector` and manual memory management
** Milestone 2: Modernization Pass 1
- [ ] Convert raw pointers to smart pointers (C++11)
- [ ] Add lambda-driven physics update loop
- [ ] Use `enum class` for material types
** Milestone 3: Raytracer Core
- [ ] Add ray-object intersection logic
- [ ] Use `std::optional` for hit results (C++17)
- [ ] Structured bindings for clean code
** Milestone 4: Optimization Pass
- [ ] Parallel rendering with `std::execution::par` (C++17)
- [ ] Use ranges and views to process pixels (C++20)
** Milestone 5: Error Handling & Final Touches
- [ ] Use `std::expected` for config file errors or simulation errors (C++23)
- [ ] Add diagnostics/metrics via coroutines or logging views
- [ ] Final cleanup using `consteval`, `mdspan`, or advanced features
* 🧪 Testing Ideas
- [ ] Unit tests for vector math and physics (can use C++11 `assert`)
- [ ] Visual verification of orbits and raytraced scene
- [ ] Compare numerical stability over long time steps
* 📂 Directory Layout (suggested)
#+BEGIN_SRC
project-root/
├── Makefile
├── README.org (this file)
└─── src/
├── main.cpp
├── vec3.cpp / .h
├── body.cpp / .h
└─── raytracer/
└── ray.cpp / .h ...
#+END_SRC

19
src/main.cpp Normal file
View File

@ -0,0 +1,19 @@
#include "simulation.h"
#include <thread>
#include <chrono>
int main() {
auto state = std::make_shared<SimulationState>();
state->positions.push_back(Vec3(1.0, 2.0, 3.0));
std::thread sim(simulation_loop, state);
std::thread render(render_loop);
std::this_thread::sleep_for(std::chrono::seconds(2));
running = false;
sim.join();
render.join();
return 0;
}

51
src/ring_buffer.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef RING_BUFFER_H
#define RING_BUFFER_H
#include <array>
#include <atomic>
#include <cstddef>
template <typename T, size_t Capacity>
class RingBuffer {
static_assert((Capacity & (Capacity - 1)) == 0, "Capacity must be power of 2");
private:
std::array<T, Capacity> buffer;
std::atomic<size_t> head = 0; // write index
std::atomic<size_t> tail = 0; // read index
public:
bool push(const T& item) {
size_t current_head = head.load(std::memory_order_relaxed);
size_t next_head = (current_head + 1) & (Capacity - 1);
if (next_head == tail.load(std::memory_order_acquire)) {
return false; // buffer full
}
buffer[current_head] = item;
head.store(next_head, std::memory_order_release);
return true;
}
bool pop(T& item) {
size_t current_tail = tail.load(std::memory_order_relaxed);
if (current_tail == head.load(std::memory_order_acquire)) {
return false; // buffer empty
}
item = buffer[current_tail];
tail.store((current_tail + 1) & (Capacity - 1), std::memory_order_release);
return true;
}
bool empty() const {
return head.load() == tail.load();
}
bool full() const {
return ((head.load() + 1) & (Capacity - 1)) == tail.load();
}
};
#endif

36
src/simulation.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "simulation.h"
#include <chrono>
#include <iostream>
#include <thread>
std::atomic<bool> running(true);
RingBuffer<Vec3, 64> snapshot_buffer;
void simulation_loop(std::shared_ptr<SimulationState> state) {
Vec3 velocity(0.01, 0.02, 0.03);
while (running) {
// Update position
for (auto &p : state->positions) {
p += velocity;
}
// Push latest position to buffer
if (!snapshot_buffer.push(state->positions[0])) {
std::cerr << "Snapshot buffer full, dropping frame\n";
}
}
}
void render_loop() {
Vec3 latest;
while (running) {
while (snapshot_buffer.pop(latest)) {
std::cout << "[Render] ";
latest.print();
}
// Optional: add very short pause to avoid spinning too fast
std::this_thread::yield(); // cooperative multitasking
}
}

21
src/simulation.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef SIMULATION_H
#define SIMULATION_H
#include <vector>
#include <memory>
#include <mutex>
#include <atomic>
#include "vec3.h"
#include "ring_buffer.h"
struct SimulationState {
std::vector<Vec3> positions;
};
extern std::atomic<bool> running;
extern RingBuffer<Vec3, 64> snapshot_buffer;
void simulation_loop(std::shared_ptr<SimulationState> state);
void render_loop();
#endif

45
src/vec3.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef VEC3_H
#define VEC3_H
#include <array>
#include <iostream>
class Vec3 {
std::array<double, 3> data;
public:
// Constructors
Vec3() = default;
Vec3(double x, double y, double z) : data{x, y, z} {}
// Named accessors (mutable)
double& x() { return data[0]; }
double& y() { return data[1]; }
double& z() { return data[2]; }
// Named accessors (const)
double x() const { return data[0]; }
double y() const { return data[1]; }
double z() const { return data[2]; }
// Arithmetic operators
friend Vec3 operator+(const Vec3& a, const Vec3& b) {
return Vec3(a.x() + b.x(),
a.y() + b.y(),
a.z() + b.z());
}
Vec3& operator+=(const Vec3& other) {
x() += other.x();
y() += other.y();
z() += other.z();
return *this;
}
// Debug print
void print() const {
std::cout << "(" << x() << ", " << y() << ", " << z() << ")\n";
}
};
#endif // VEC3_H