wip: integrating threaded decoupled physics

Current Issues:
- HUGE memory leak
- HUGE amount of needles copying
- FillGraph() does thousands of lock_guards instead of one
- Can no longer rely on new states appearing immediately - have to check
each access
- Physics run as fast as possible, no constant sim speed`
- Irregular long freezes
This commit is contained in:
2026-02-24 02:00:15 +01:00
parent 39c0b58f3f
commit 550970f8a1
7 changed files with 140 additions and 87 deletions

View File

@ -33,7 +33,7 @@ auto Renderer::UpdateTextureSizes() -> void {
menu_target = LoadRenderTexture(width * 2, MENU_HEIGHT);
}
auto Renderer::AllocateGraphInstancing(const MassSpringSystem &mass_springs)
auto Renderer::AllocateGraphInstancing(const std::vector<Mass> &masses)
-> void {
cube_instance = GenMeshCube(VERTEX_SIZE, VERTEX_SIZE, VERTEX_SIZE);
@ -48,38 +48,40 @@ auto Renderer::AllocateGraphInstancing(const MassSpringSystem &mass_springs)
vertex_mat.maps[MATERIAL_MAP_DIFFUSE].color = VERTEX_COLOR;
vertex_mat.shader = instancing_shader;
transforms = (Matrix *)MemAlloc(mass_springs.masses.size() * sizeof(Matrix));
transforms_size = mass_springs.masses.size();
transforms = (Matrix *)MemAlloc(masses.size() * sizeof(Matrix));
transforms_size = masses.size();
}
auto Renderer::ReallocateGraphInstancingIfNecessary(
const MassSpringSystem &mass_springs) -> void {
if (transforms_size != mass_springs.masses.size()) {
transforms = (Matrix *)MemRealloc(transforms, mass_springs.masses.size() *
sizeof(Matrix));
transforms_size = mass_springs.masses.size();
const std::vector<Mass> &masses) -> void {
if (transforms_size != masses.size()) {
transforms =
(Matrix *)MemRealloc(transforms, masses.size() * sizeof(Matrix));
transforms_size = masses.size();
}
}
auto Renderer::DrawMassSprings(const MassSpringSystem &mass_springs,
const State &current_state,
const State &starting_state,
const std::unordered_set<State> &winning_states,
const std::unordered_set<State> &visited_states)
-> void {
auto Renderer::DrawMassSprings(
const std::vector<Mass> &masses,
const std::unordered_map<State, int> &state_masses,
const std::vector<Spring> &springs,
const std::unordered_map<std::pair<State, State>, int> state_springs,
const State &current_state, const State &starting_state,
const std::unordered_set<State> &winning_states,
const std::unordered_set<State> &visited_states) -> void {
ZoneScoped;
// Prepare cube instancing
{
ZoneNamedN(prepare_masses, "PrepareMasses", true);
if (mass_springs.masses.size() < DRAW_VERTICES_LIMIT) {
if (masses.size() < DRAW_VERTICES_LIMIT) {
if (transforms == nullptr) {
AllocateGraphInstancing(mass_springs);
AllocateGraphInstancing(masses);
}
ReallocateGraphInstancingIfNecessary(mass_springs);
ReallocateGraphInstancingIfNecessary(masses);
int i = 0;
for (const auto &mass : mass_springs.masses) {
for (const auto &mass : masses) {
transforms[i] =
MatrixTranslate(mass.position.x, mass.position.y, mass.position.z);
++i;
@ -96,10 +98,10 @@ auto Renderer::DrawMassSprings(const MassSpringSystem &mass_springs,
{
ZoneNamedN(draw_springs, "DrawSprings", true);
rlBegin(RL_LINES);
for (const auto &spring : mass_springs.springs) {
for (const auto &spring : springs) {
// We have to do a lookup of the actual mass object, which is slow :(
const Mass &a = mass_springs.masses.at(spring.mass_a);
const Mass &b = mass_springs.masses.at(spring.mass_b);
const Mass &a = masses.at(spring.mass_a);
const Mass &b = masses.at(spring.mass_b);
rlColor4ub(EDGE_COLOR.r, EDGE_COLOR.g, EDGE_COLOR.b, EDGE_COLOR.a);
rlVertex3f(a.position.x, a.position.y, a.position.z);
rlVertex3f(b.position.x, b.position.y, b.position.z);
@ -110,20 +112,19 @@ auto Renderer::DrawMassSprings(const MassSpringSystem &mass_springs,
// Draw masses (instanced)
{
ZoneNamedN(draw_masses, "DrawMasses", true);
if (mass_springs.masses.size() < DRAW_VERTICES_LIMIT) {
if (masses.size() < DRAW_VERTICES_LIMIT) {
// NOTE: I don't know if drawing all this inside a shader would make it
// much faster... The amount of data sent to the GPU would be
// reduced (just positions instead of matrices), but is this
// noticable for < 100000 cubes?
DrawMeshInstanced(cube_instance, vertex_mat, transforms,
mass_springs.masses.size());
DrawMeshInstanced(cube_instance, vertex_mat, transforms, masses.size());
}
}
// Mark winning states
if (mark_solutions || connect_solutions) {
for (const auto &state : winning_states) {
const Mass &winning_mass = mass_springs.GetMass(state);
const Mass &winning_mass = masses.at(state_masses.at(state));
if (mark_solutions) {
DrawCube(winning_mass.position, 2 * VERTEX_SIZE, 2 * VERTEX_SIZE,
2 * VERTEX_SIZE, BLUE);
@ -131,26 +132,26 @@ auto Renderer::DrawMassSprings(const MassSpringSystem &mass_springs,
if (connect_solutions) {
DrawLine3D(winning_mass.position,
mass_springs.GetMass(current_state).position, PURPLE);
masses.at(state_masses.at(current_state)).position, PURPLE);
}
}
}
// Mark visited states
for (const auto &state : visited_states) {
const Mass &visited_mass = mass_springs.GetMass(state);
const Mass &visited_mass = masses.at(state_masses.at(state));
DrawCube(visited_mass.position, VERTEX_SIZE * 1.5, VERTEX_SIZE * 1.5,
VERTEX_SIZE * 1.5, PURPLE);
}
// Mark starting state
const Mass &starting_mass = mass_springs.GetMass(starting_state);
const Mass &starting_mass = masses.at(state_masses.at(starting_state));
DrawCube(starting_mass.position, VERTEX_SIZE * 2, VERTEX_SIZE * 2,
VERTEX_SIZE * 2, ORANGE);
// Mark current state
const Mass &current_mass = mass_springs.GetMass(current_state);
const Mass &current_mass = masses.at(state_masses.at(current_state));
DrawCube(current_mass.position, VERTEX_SIZE * 2, VERTEX_SIZE * 2,
VERTEX_SIZE * 2, RED);
@ -250,8 +251,9 @@ auto Renderer::DrawKlotski(const State &state, int hov_x, int hov_y, int sel_x,
EndTextureMode();
}
auto Renderer::DrawMenu(const MassSpringSystem &mass_springs,
int current_preset, const State &current_state,
auto Renderer::DrawMenu(const std::vector<Mass> &masses,
const std::vector<Spring> &springs, int current_preset,
const State &current_state,
const std::unordered_set<State> &winning_states)
-> void {
ZoneScoped;
@ -277,8 +279,7 @@ auto Renderer::DrawMenu(const MassSpringSystem &mass_springs,
draw_btn(0, 0,
std::format("States: {}, Transitions: {}, Winning: {}",
mass_springs.masses.size(), mass_springs.springs.size(),
winning_states.size()),
masses.size(), springs.size(), winning_states.size()),
DARKGREEN);
draw_btn(
0, 1,