diff --git a/Makefile b/Makefile index 9c13dc3..ec025b4 100644 --- a/Makefile +++ b/Makefile @@ -32,4 +32,8 @@ $(TARGET): $(OBJS) clean: rm -f $(OBJS) $(TARGET) +run: + make + ./engine_sim + .PHONY: clean diff --git a/engine/engine.cpp b/engine/engine.cpp index 0e5d68d..a3cb78f 100644 --- a/engine/engine.cpp +++ b/engine/engine.cpp @@ -1,4 +1,5 @@ #include "engine.h" +#include "iostream" void Engine::step(double dt, double load_torque_nm) { // TODO: replace with real combustion/friction torque model driven @@ -17,6 +18,16 @@ double Engine::torque_nm() const { return m_torque_nm; } +void Engine::set_throttle(double throttle) { + m_throttle = throttle; +} + +double Engine::get_throttle() { + return m_throttle; +} + void Engine::reset() { m_rpm = 0; + m_oil_temp = 0; + m_coolant_capacity = 0; } diff --git a/engine/engine.h b/engine/engine.h index b66f966..49e4bab 100644 --- a/engine/engine.h +++ b/engine/engine.h @@ -11,12 +11,24 @@ public: double rpm() const; double torque_nm() const; // net torque produced this step + void set_throttle(double throttle); + double get_throttle(); void reset(); private: double m_rpm = 0.0; double m_torque_nm = 0.0; - static constexpr double kIdleRpm = 900.0; + // Fluids + double m_oil_capacity = 0.0; + double m_coolant_capacity = 0.0; + + double m_oil_temp = 0.0; + double m_coolant_temp = 0.0; + + // User Input + double m_throttle = 0.0; + + static constexpr double kIdleRpm = 1700.0; static constexpr double kCrankInertiaKgm2 = 0.15; // placeholder }; diff --git a/engine/engine.o b/engine/engine.o index c083d20..2a4f1b9 100644 Binary files a/engine/engine.o and b/engine/engine.o differ diff --git a/engine_sim b/engine_sim index 733232b..40ea136 100755 Binary files a/engine_sim and b/engine_sim differ diff --git a/gui/gui.cpp b/gui/gui.cpp index f6e702d..4690ff7 100644 --- a/gui/gui.cpp +++ b/gui/gui.cpp @@ -136,17 +136,41 @@ void Gui::render(const EngineStats& stats) { ImGui::Columns(2, "main_columns"); - // --- Left column: primary live readouts --- + // --- (0,0): primary live readouts — tach + throttle lever side by side --- DrawTachGauge(static_cast(stats.rpm), static_cast(stats.max_rpm), static_cast(stats.redline_rpm), 220.0f); + ImGui::SameLine(); + ImGui::VSliderFloat("##throttle_lever", ImVec2(40, 160), &m_throttle_lever, 0.0f, 1.0f, ""); + // VSliderFloat is only "active" while the mouse is down on it, so + // this is the spring-back: anything other than an active drag + // resets the lever to closed, including on release. + if (!ImGui::IsItemActive()) { + m_throttle_lever = 0.0f; + } + ImGui::SameLine(); + ImGui::Text("Throttle\n%.0f%%", m_throttle_lever * 100.0f); + + // Row 1 starts here in both columns, so column 1's content below + // lines up with column 0's regardless of which column is taller. + float row1_y = ImGui::GetCursorPosY(); + + // --- (1,0): fuel/power readouts + accessory toggles --- ImGui::Text("Fuel Consumption: %.2f L/h", stats.fuel_consumption_lph); ImGui::Text("Crank Power: %.2f kW", stats.crank_power_kw); ImGui::Text("Output Heat: %.1f J", stats.output_heat_j); + ImGui::Spacing(); + ImGui::Separator(); + ImGui::Text("Accessories"); + ImGui::Checkbox("Alternator", &m_accessories.alternator); + ImGui::Checkbox("A/C", &m_accessories.ac); + ImGui::Checkbox("Power Steering", &m_accessories.power_steering); + ImGui::NextColumn(); - // --- Right column: extensible stats list (oil temp, coolant temp, ...) --- + // --- (1,1): extensible stats list (oil temp, coolant temp, ...) --- + ImGui::SetCursorPosY(row1_y); ImGui::Text("Stats"); ImGui::Separator(); for (const StatEntry& s : stats.extra_stats) { diff --git a/gui/gui.h b/gui/gui.h index 7016093..15f763c 100644 --- a/gui/gui.h +++ b/gui/gui.h @@ -28,6 +28,15 @@ struct EngineStats { std::vector extra_stats; }; +// Which parasitic-load accessories are toggled on, via checkboxes drawn +// in the left column by render(). Placeholders (Alternator, A/C, Power +// Steering) until there's an actual load model behind them. +struct AccessoryState { + bool alternator = false; + bool ac = false; + bool power_steering = false; +}; + class Gui { public: bool init(); // create window + ImGui context @@ -36,6 +45,20 @@ public: void end_frame(); // swap buffers void shutdown(); + // Reflects the throttle lever as of the most recent render() call. + // Spring-loaded: holds whatever value the drag left it at only + // while the mouse is down, and snaps back to 0 the instant it's + // released. Read it any time after render() this frame, or before + // render() next frame, to feed it into the engine. + double throttle() const { return static_cast(m_throttle_lever); } + + // Reflects the checkbox state as of the most recent render() call — + // read it any time after render() this frame, or before render() + // next frame, to feed accessory load into the engine. + const AccessoryState& accessories() const { return m_accessories; } + private: GLFWwindow* m_window = nullptr; + float m_throttle_lever = 0.0f; + AccessoryState m_accessories; }; diff --git a/gui/gui.o b/gui/gui.o index d8fee10..70d2c20 100644 Binary files a/gui/gui.o and b/gui/gui.o differ diff --git a/imgui.ini b/imgui.ini index 188241f..f2ea7fd 100644 --- a/imgui.ini +++ b/imgui.ini @@ -1,10 +1,15 @@ [Window][Debug##Default] Pos=60,60 Size=400,400 -LastUsed=20260828 +LastUsed=20260831 [Window][Engine Sim] Pos=0,0 Size=900,600 -LastUsed=20260828 +LastUsed=20260831 + +[Window][Throttle] +Pos=20,20 +Size=78,195 +LastUsed=20260831 diff --git a/main.cpp b/main.cpp index fe37c7c..d6f4f49 100644 --- a/main.cpp +++ b/main.cpp @@ -40,9 +40,15 @@ int main() { stats.extra_stats.push_back({"Oil Temp", 0.0, "C"}); stats.extra_stats.push_back({"Coolant Temp", 0.0, "C"}); + stats.extra_stats.push_back({"Throttle Position", sim.engine().get_throttle(), "%"}); gui.render(stats); gui.end_frame(); + + // The lever now lives inline in render()'s window, so it's read + // after drawing — this frame's drag feeds next frame's step, + // same one-frame lag as gui.accessories(). + sim.engine().set_throttle(gui.throttle()); } gui.shutdown(); diff --git a/main.o b/main.o index c2b83d0..a10babd 100644 Binary files a/main.o and b/main.o differ