// Basic animation variables
static float
time = 0
.0f
;static float trainPosition = 0.0f;
const float TRAIN_SPEED = 150.0f;
static float moonGlow = 0.0f;
static float moonY = 0.0f;
void RenderScene(); {
time += ImGui
::GetIO().DeltaTime
; trainPosition += TRAIN_SPEED * ImGui::GetIO().DeltaTime;
// Update moon animations
moonGlow
= 0
.5f
+ 0
.5f
* sinf
(time * 0
.5f
); moonY
= 5
.0f
* sinf
(time * 0
.2f
);
// Reset train position
if (trainPosition > ImGui::GetWindowSize().x + 400.0f) {
trainPosition = -800.0f; // Increased negative value to account for bogies
}
ImDrawList* pDrawList = ImGui::GetWindowDrawList();
ImVec2 windowPos = ImGui::GetWindowPos();
ImVec2 windowSize = ImGui::GetWindowSize();
// Draw moon
float moonRadius = 40.0f;
ImVec2 moonCenter(
windowPos.x + windowSize.x * 0.8f,
windowPos.y + windowSize.y * 0.2f + moonY
);
// Moon glow effect
for (float r = moonRadius + 30.0f; r >= moonRadius; r -= 1.0f) {
float alpha = moonGlow * (1.0f - (r - moonRadius) / 30.0f) * 0.3f;
pDrawList->AddCircleFilled(
moonCenter,
r,
ImGui::GetColorU32(ImVec4(0.9f, 0.9f, 0.7f, alpha))
);
}
// Main moon
pDrawList->AddCircleFilled(
moonCenter,
moonRadius,
ImGui::GetColorU32(ImVec4(0.95f, 0.95f, 0.8f, 1.0f))
);
// Moon craters
const ImVec2 craters[] = {
ImVec2(-15, -10), ImVec2(10, -15), ImVec2(5, 5),
ImVec2(-5, 15), ImVec2(15, 10), ImVec2(-20, 5)
};
for (const auto& crater : craters) {
pDrawList->AddCircleFilled(
ImVec2(moonCenter.x + crater.x, moonCenter.y + crater.y),
4.0f,
ImGui::GetColorU32(ImVec4(0.85f, 0.85f, 0.7f, 1.0f))
);
}
// Add stars around moon
const int NUM_STARS = 50;
static std::vector<ImVec2> stars;
static bool starsInitialized = false;
// Initialize star positions once
if (!starsInitialized) {
stars.clear();
for (int i = 0; i < NUM_STARS; i++) {
float angle = (float)i / NUM_STARS * 2 * 3.14159f;
float distance
= 100
.0f
+ rand() % 200; stars.push_back(ImVec2(
moonCenter.x + cosf(angle) * distance,
moonCenter.y + sinf(angle) * distance
));
}
starsInitialized = true;
}
// Draw stars with twinkling effect
for (size_t i = 0; i < stars.size(); i++) {
float starGlow
= 0
.3f
+ 0
.7f
* sinf
(time * 2
.0f
+ i
* 1
.5f
); float starSize
= 2
.0f
+ sinf
(time * 3
.0f
+ i
) * 0
.5f
;
pDrawList->AddCircleFilled(
stars[i],
starSize,
ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 1.0f, starGlow))
);
}
// Draw railway tracks
float trackY = windowPos.y + windowSize.y * 0.7f;
// Draw track base
pDrawList->AddRectFilled(
ImVec2(windowPos.x, trackY - 5),
ImVec2(windowPos.x + windowSize.x, trackY + 15),
ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.3f, 1.0f))
);
// Draw railroad ties
float tieSpacing = 50.0f;
float tieOffset
= fmodf
(time * TRAIN_SPEED
, tieSpacing
);
for (float x = -tieSpacing + tieOffset; x < windowSize.x; x += tieSpacing) {
pDrawList->AddRectFilled(
ImVec2(windowPos.x + x, trackY - 10),
ImVec2(windowPos.x + x + 30, trackY + 20),
ImGui::GetColorU32(ImVec4(0.4f, 0.2f, 0.1f, 1.0f))
);
}
// Draw rails
pDrawList->AddRectFilled(
ImVec2(windowPos.x, trackY - 2),
ImVec2(windowPos.x + windowSize.x, trackY),
ImGui::GetColorU32(ImVec4(0.7f, 0.7f, 0.7f, 1.0f))
);
pDrawList->AddRectFilled(
ImVec2(windowPos.x, trackY + 10),
ImVec2(windowPos.x + windowSize.x, trackY + 12),
ImGui::GetColorU32(ImVec4(0.7f, 0.7f, 0.7f, 1.0f))
);
// Draw Train
ImVec2 trainPos(windowPos.x + trainPosition, trackY - 60);
// Add train bogies (compartments) BEHIND the locomotive
const int NUM_BOGIES = 3;
float bogieWidth = 180.0f;
float bogieGap = 20.0f;
float bogieStartX = trainPos.x - bogieWidth - bogieGap;
for (int i = 0; i < NUM_BOGIES; i++) {
float bogieX = bogieStartX - (bogieWidth + bogieGap) * i;
// Bogie body
pDrawList->AddRectFilled(
ImVec2(bogieX, trainPos.y),
ImVec2(bogieX + bogieWidth, trainPos.y + 60),
ImGui::GetColorU32(ImVec4(0.7f, 0.2f, 0.2f, 1.0f))
);
// Glowing windows
float windowGlow
= 0
.5f
+ 0
.5f
* sinf
(time * 2
.0f
+ i
* 1
.5f
); for (float wx = bogieX + 20; wx < bogieX + bogieWidth - 20; wx += 40) {
// Window glow effect
for (float r = 20.0f; r >= 0.0f; r -= 1.0f) {
float alpha = windowGlow * (1.0f - r / 20.0f) * 0.3f;
pDrawList->AddRectFilled(
ImVec2(wx - r, trainPos.y + 10 - r),
ImVec2(wx + 30 + r, trainPos.y + 40 + r),
ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 0.8f, alpha))
);
}
// Actual window
pDrawList->AddRectFilled(
ImVec2(wx, trainPos.y + 10),
ImVec2(wx + 30, trainPos.y + 40),
ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 0.8f, 1.0f))
);
}
// Wheels for each bogie
float wheelRadius = 15.0f;
float wheelSpacing = 50.0f;
for (float x = bogieX + 30; x < bogieX + bogieWidth - 30; x += wheelSpacing) {
pDrawList->AddCircleFilled(
ImVec2(x, trainPos.y + 55),
wheelRadius,
ImGui::GetColorU32(ImVec4(0.1f, 0.1f, 0.1f, 1.0f))
);
}
}
// Locomotive body
pDrawList->AddRectFilled(
ImVec2(trainPos.x, trainPos.y),
ImVec2(trainPos.x + 200, trainPos.y + 60),
ImGui::GetColorU32(ImVec4(0.2f, 0.3f, 0.8f, 1.0f))
);
// Locomotive front
pDrawList->AddRectFilled(
ImVec2(trainPos.x + 200, trainPos.y + 10),
ImVec2(trainPos.x + 240, trainPos.y + 60),
ImGui::GetColorU32(ImVec4(0.2f, 0.2f, 0.7f, 1.0f))
);
// Cabin
pDrawList->AddRectFilled(
ImVec2(trainPos.x + 140, trainPos.y - 30),
ImVec2(trainPos.x + 200, trainPos.y),
ImGui::GetColorU32(ImVec4(0.2f, 0.2f, 0.7f, 1.0f))
);
// Windows
for (float x = trainPos.x + 20; x < trainPos.x + 120; x += 40) {
pDrawList->AddRectFilled(
ImVec2(x, trainPos.y + 10),
ImVec2(x + 30, trainPos.y + 40),
ImGui::GetColorU32(ImVec4(0.8f, 0.8f, 1.0f, 1.0f))
);
}
// Chimney
pDrawList->AddRectFilled(
ImVec2(trainPos.x + 180, trainPos.y - 50),
ImVec2(trainPos.x + 195, trainPos.y),
ImGui::GetColorU32(ImVec4(0.2f, 0.2f, 0.2f, 1.0f))
);
// Locomotive wheels
float wheelRadius = 15.0f;
float wheelSpacing = 50.0f;
for (float x = trainPos.x + 30; x < trainPos.x + 220; x += wheelSpacing) {
pDrawList->AddCircleFilled(
ImVec2(x, trainPos.y + 55),
wheelRadius,
ImGui::GetColorU32(ImVec4(0.1f, 0.1f, 0.1f, 1.0f))
);
}
// Smoke animation
for (int i = 0; i < 5; i++) {
float smokeOffset
= sinf
(time * 2
.0f
+ i
) * 10
.0f
; float smokeSize = 10.0f + i * 5.0f;
float smokeAlpha = 0.6f - (i * 0.1f);
pDrawList->AddCircleFilled(
ImVec2(trainPos.x + 187 + smokeOffset, trainPos.y - 60 - (i * 20)),
smokeSize,
ImGui::GetColorU32(ImVec4(0.7f, 0.7f, 0.7f, smokeAlpha))
);
}
}
Ci8vIEJhc2ljIGFuaW1hdGlvbiB2YXJpYWJsZXMKc3RhdGljIGZsb2F0IHRpbWUgPSAwLjBmOwpzdGF0aWMgZmxvYXQgdHJhaW5Qb3NpdGlvbiA9IDAuMGY7CmNvbnN0IGZsb2F0IFRSQUlOX1NQRUVEID0gMTUwLjBmOwpzdGF0aWMgZmxvYXQgbW9vbkdsb3cgPSAwLjBmOwpzdGF0aWMgZmxvYXQgbW9vblkgPSAwLjBmOwoKdm9pZCBSZW5kZXJTY2VuZSgpOyB7CiAgICB0aW1lICs9IEltR3VpOjpHZXRJTygpLkRlbHRhVGltZTsKICAgIHRyYWluUG9zaXRpb24gKz0gVFJBSU5fU1BFRUQgKiBJbUd1aTo6R2V0SU8oKS5EZWx0YVRpbWU7CiAgICAKICAgIC8vIFVwZGF0ZSBtb29uIGFuaW1hdGlvbnMKICAgIG1vb25HbG93ID0gMC41ZiArIDAuNWYgKiBzaW5mKHRpbWUgKiAwLjVmKTsKICAgIG1vb25ZID0gNS4wZiAqIHNpbmYodGltZSAqIDAuMmYpOwoKICAgIC8vIFJlc2V0IHRyYWluIHBvc2l0aW9uCiAgICBpZiAodHJhaW5Qb3NpdGlvbiA+IEltR3VpOjpHZXRXaW5kb3dTaXplKCkueCArIDQwMC4wZikgewogICAgICAgIHRyYWluUG9zaXRpb24gPSAtODAwLjBmOyAgLy8gSW5jcmVhc2VkIG5lZ2F0aXZlIHZhbHVlIHRvIGFjY291bnQgZm9yIGJvZ2llcwogICAgfQoKICAgIEltRHJhd0xpc3QqIHBEcmF3TGlzdCA9IEltR3VpOjpHZXRXaW5kb3dEcmF3TGlzdCgpOwogICAgSW1WZWMyIHdpbmRvd1BvcyA9IEltR3VpOjpHZXRXaW5kb3dQb3MoKTsKICAgIEltVmVjMiB3aW5kb3dTaXplID0gSW1HdWk6OkdldFdpbmRvd1NpemUoKTsKCiAgICAvLyBEcmF3IG1vb24KICAgIGZsb2F0IG1vb25SYWRpdXMgPSA0MC4wZjsKICAgIEltVmVjMiBtb29uQ2VudGVyKAogICAgICAgIHdpbmRvd1Bvcy54ICsgd2luZG93U2l6ZS54ICogMC44ZiwKICAgICAgICB3aW5kb3dQb3MueSArIHdpbmRvd1NpemUueSAqIDAuMmYgKyBtb29uWQogICAgKTsKCiAgICAvLyBNb29uIGdsb3cgZWZmZWN0CiAgICBmb3IgKGZsb2F0IHIgPSBtb29uUmFkaXVzICsgMzAuMGY7IHIgPj0gbW9vblJhZGl1czsgciAtPSAxLjBmKSB7CiAgICAgICAgZmxvYXQgYWxwaGEgPSBtb29uR2xvdyAqICgxLjBmIC0gKHIgLSBtb29uUmFkaXVzKSAvIDMwLjBmKSAqIDAuM2Y7CiAgICAgICAgcERyYXdMaXN0LT5BZGRDaXJjbGVGaWxsZWQoCiAgICAgICAgICAgIG1vb25DZW50ZXIsCiAgICAgICAgICAgIHIsCiAgICAgICAgICAgIEltR3VpOjpHZXRDb2xvclUzMihJbVZlYzQoMC45ZiwgMC45ZiwgMC43ZiwgYWxwaGEpKQogICAgICAgICk7CiAgICB9CgogICAgLy8gTWFpbiBtb29uCiAgICBwRHJhd0xpc3QtPkFkZENpcmNsZUZpbGxlZCgKICAgICAgICBtb29uQ2VudGVyLAogICAgICAgIG1vb25SYWRpdXMsCiAgICAgICAgSW1HdWk6OkdldENvbG9yVTMyKEltVmVjNCgwLjk1ZiwgMC45NWYsIDAuOGYsIDEuMGYpKQogICAgKTsKCiAgICAvLyBNb29uIGNyYXRlcnMKICAgIGNvbnN0IEltVmVjMiBjcmF0ZXJzW10gPSB7CiAgICAgICAgSW1WZWMyKC0xNSwgLTEwKSwgSW1WZWMyKDEwLCAtMTUpLCBJbVZlYzIoNSwgNSksCiAgICAgICAgSW1WZWMyKC01LCAxNSksIEltVmVjMigxNSwgMTApLCBJbVZlYzIoLTIwLCA1KQogICAgfTsKCiAgICBmb3IgKGNvbnN0IGF1dG8mIGNyYXRlciA6IGNyYXRlcnMpIHsKICAgICAgICBwRHJhd0xpc3QtPkFkZENpcmNsZUZpbGxlZCgKICAgICAgICAgICAgSW1WZWMyKG1vb25DZW50ZXIueCArIGNyYXRlci54LCBtb29uQ2VudGVyLnkgKyBjcmF0ZXIueSksCiAgICAgICAgICAgIDQuMGYsCiAgICAgICAgICAgIEltR3VpOjpHZXRDb2xvclUzMihJbVZlYzQoMC44NWYsIDAuODVmLCAwLjdmLCAxLjBmKSkKICAgICAgICApOwogICAgfQoKICAgIC8vIEFkZCBzdGFycyBhcm91bmQgbW9vbgogICAgY29uc3QgaW50IE5VTV9TVEFSUyA9IDUwOwogICAgc3RhdGljIHN0ZDo6dmVjdG9yPEltVmVjMj4gc3RhcnM7CiAgICBzdGF0aWMgYm9vbCBzdGFyc0luaXRpYWxpemVkID0gZmFsc2U7CgogICAgLy8gSW5pdGlhbGl6ZSBzdGFyIHBvc2l0aW9ucyBvbmNlCiAgICBpZiAoIXN0YXJzSW5pdGlhbGl6ZWQpIHsKICAgICAgICBzdGFycy5jbGVhcigpOwogICAgICAgIGZvciAoaW50IGkgPSAwOyBpIDwgTlVNX1NUQVJTOyBpKyspIHsKICAgICAgICAgICAgZmxvYXQgYW5nbGUgPSAoZmxvYXQpaSAvIE5VTV9TVEFSUyAqIDIgKiAzLjE0MTU5ZjsKICAgICAgICAgICAgZmxvYXQgZGlzdGFuY2UgPSAxMDAuMGYgKyByYW5kKCkgJSAyMDA7CiAgICAgICAgICAgIHN0YXJzLnB1c2hfYmFjayhJbVZlYzIoCiAgICAgICAgICAgICAgICBtb29uQ2VudGVyLnggKyBjb3NmKGFuZ2xlKSAqIGRpc3RhbmNlLAogICAgICAgICAgICAgICAgbW9vbkNlbnRlci55ICsgc2luZihhbmdsZSkgKiBkaXN0YW5jZQogICAgICAgICAgICApKTsKICAgICAgICB9CiAgICAgICAgc3RhcnNJbml0aWFsaXplZCA9IHRydWU7CiAgICB9CgogICAgLy8gRHJhdyBzdGFycyB3aXRoIHR3aW5rbGluZyBlZmZlY3QKICAgIGZvciAoc2l6ZV90IGkgPSAwOyBpIDwgc3RhcnMuc2l6ZSgpOyBpKyspIHsKICAgICAgICBmbG9hdCBzdGFyR2xvdyA9IDAuM2YgKyAwLjdmICogc2luZih0aW1lICogMi4wZiArIGkgKiAxLjVmKTsKICAgICAgICBmbG9hdCBzdGFyU2l6ZSA9IDIuMGYgKyBzaW5mKHRpbWUgKiAzLjBmICsgaSkgKiAwLjVmOwogICAgICAgIAogICAgICAgIHBEcmF3TGlzdC0+QWRkQ2lyY2xlRmlsbGVkKAogICAgICAgICAgICBzdGFyc1tpXSwKICAgICAgICAgICAgc3RhclNpemUsCiAgICAgICAgICAgIEltR3VpOjpHZXRDb2xvclUzMihJbVZlYzQoMS4wZiwgMS4wZiwgMS4wZiwgc3Rhckdsb3cpKQogICAgICAgICk7CiAgICB9CgogICAgLy8gRHJhdyByYWlsd2F5IHRyYWNrcwogICAgZmxvYXQgdHJhY2tZID0gd2luZG93UG9zLnkgKyB3aW5kb3dTaXplLnkgKiAwLjdmOwogICAgCiAgICAvLyBEcmF3IHRyYWNrIGJhc2UKICAgIHBEcmF3TGlzdC0+QWRkUmVjdEZpbGxlZCgKICAgICAgICBJbVZlYzIod2luZG93UG9zLngsIHRyYWNrWSAtIDUpLAogICAgICAgIEltVmVjMih3aW5kb3dQb3MueCArIHdpbmRvd1NpemUueCwgdHJhY2tZICsgMTUpLAogICAgICAgIEltR3VpOjpHZXRDb2xvclUzMihJbVZlYzQoMC4zZiwgMC4zZiwgMC4zZiwgMS4wZikpCiAgICApOwoKICAgIC8vIERyYXcgcmFpbHJvYWQgdGllcwogICAgZmxvYXQgdGllU3BhY2luZyA9IDUwLjBmOwogICAgZmxvYXQgdGllT2Zmc2V0ID0gZm1vZGYodGltZSAqIFRSQUlOX1NQRUVELCB0aWVTcGFjaW5nKTsKICAgIAogICAgZm9yIChmbG9hdCB4ID0gLXRpZVNwYWNpbmcgKyB0aWVPZmZzZXQ7IHggPCB3aW5kb3dTaXplLng7IHggKz0gdGllU3BhY2luZykgewogICAgICAgIHBEcmF3TGlzdC0+QWRkUmVjdEZpbGxlZCgKICAgICAgICAgICAgSW1WZWMyKHdpbmRvd1Bvcy54ICsgeCwgdHJhY2tZIC0gMTApLAogICAgICAgICAgICBJbVZlYzIod2luZG93UG9zLnggKyB4ICsgMzAsIHRyYWNrWSArIDIwKSwKICAgICAgICAgICAgSW1HdWk6OkdldENvbG9yVTMyKEltVmVjNCgwLjRmLCAwLjJmLCAwLjFmLCAxLjBmKSkKICAgICAgICApOwogICAgfQoKICAgIC8vIERyYXcgcmFpbHMKICAgIHBEcmF3TGlzdC0+QWRkUmVjdEZpbGxlZCgKICAgICAgICBJbVZlYzIod2luZG93UG9zLngsIHRyYWNrWSAtIDIpLAogICAgICAgIEltVmVjMih3aW5kb3dQb3MueCArIHdpbmRvd1NpemUueCwgdHJhY2tZKSwKICAgICAgICBJbUd1aTo6R2V0Q29sb3JVMzIoSW1WZWM0KDAuN2YsIDAuN2YsIDAuN2YsIDEuMGYpKQogICAgKTsKICAgIAogICAgcERyYXdMaXN0LT5BZGRSZWN0RmlsbGVkKAogICAgICAgIEltVmVjMih3aW5kb3dQb3MueCwgdHJhY2tZICsgMTApLAogICAgICAgIEltVmVjMih3aW5kb3dQb3MueCArIHdpbmRvd1NpemUueCwgdHJhY2tZICsgMTIpLAogICAgICAgIEltR3VpOjpHZXRDb2xvclUzMihJbVZlYzQoMC43ZiwgMC43ZiwgMC43ZiwgMS4wZikpCiAgICApOwoKICAgIC8vIERyYXcgVHJhaW4KICAgIEltVmVjMiB0cmFpblBvcyh3aW5kb3dQb3MueCArIHRyYWluUG9zaXRpb24sIHRyYWNrWSAtIDYwKTsKCgovLyBBZGQgdHJhaW4gYm9naWVzIChjb21wYXJ0bWVudHMpIEJFSElORCB0aGUgbG9jb21vdGl2ZQogICAgY29uc3QgaW50IE5VTV9CT0dJRVMgPSAzOwogICAgZmxvYXQgYm9naWVXaWR0aCA9IDE4MC4wZjsKICAgIGZsb2F0IGJvZ2llR2FwID0gMjAuMGY7CiAgICBmbG9hdCBib2dpZVN0YXJ0WCA9IHRyYWluUG9zLnggLSBib2dpZVdpZHRoIC0gYm9naWVHYXA7CgogICAgZm9yIChpbnQgaSA9IDA7IGkgPCBOVU1fQk9HSUVTOyBpKyspIHsKICAgICAgICBmbG9hdCBib2dpZVggPSBib2dpZVN0YXJ0WCAtIChib2dpZVdpZHRoICsgYm9naWVHYXApICogaTsKICAgICAgICAKICAgICAgICAvLyBCb2dpZSBib2R5CiAgICAgICAgcERyYXdMaXN0LT5BZGRSZWN0RmlsbGVkKAogICAgICAgICAgICBJbVZlYzIoYm9naWVYLCB0cmFpblBvcy55KSwKICAgICAgICAgICAgSW1WZWMyKGJvZ2llWCArIGJvZ2llV2lkdGgsIHRyYWluUG9zLnkgKyA2MCksCiAgICAgICAgICAgIEltR3VpOjpHZXRDb2xvclUzMihJbVZlYzQoMC43ZiwgMC4yZiwgMC4yZiwgMS4wZikpCiAgICAgICAgKTsKCiAgICAgICAgLy8gR2xvd2luZyB3aW5kb3dzCiAgICAgICAgZmxvYXQgd2luZG93R2xvdyA9IDAuNWYgKyAwLjVmICogc2luZih0aW1lICogMi4wZiArIGkgKiAxLjVmKTsKICAgICAgICBmb3IgKGZsb2F0IHd4ID0gYm9naWVYICsgMjA7IHd4IDwgYm9naWVYICsgYm9naWVXaWR0aCAtIDIwOyB3eCArPSA0MCkgewogICAgICAgICAgICAvLyBXaW5kb3cgZ2xvdyBlZmZlY3QKICAgICAgICAgICAgZm9yIChmbG9hdCByID0gMjAuMGY7IHIgPj0gMC4wZjsgciAtPSAxLjBmKSB7CiAgICAgICAgICAgICAgICBmbG9hdCBhbHBoYSA9IHdpbmRvd0dsb3cgKiAoMS4wZiAtIHIgLyAyMC4wZikgKiAwLjNmOwogICAgICAgICAgICAgICAgcERyYXdMaXN0LT5BZGRSZWN0RmlsbGVkKAogICAgICAgICAgICAgICAgICAgIEltVmVjMih3eCAtIHIsIHRyYWluUG9zLnkgKyAxMCAtIHIpLAogICAgICAgICAgICAgICAgICAgIEltVmVjMih3eCArIDMwICsgciwgdHJhaW5Qb3MueSArIDQwICsgciksCiAgICAgICAgICAgICAgICAgICAgSW1HdWk6OkdldENvbG9yVTMyKEltVmVjNCgxLjBmLCAxLjBmLCAwLjhmLCBhbHBoYSkpCiAgICAgICAgICAgICAgICApOwogICAgICAgICAgICB9CgogICAgICAgICAgICAvLyBBY3R1YWwgd2luZG93CiAgICAgICAgICAgIHBEcmF3TGlzdC0+QWRkUmVjdEZpbGxlZCgKICAgICAgICAgICAgICAgIEltVmVjMih3eCwgdHJhaW5Qb3MueSArIDEwKSwKICAgICAgICAgICAgICAgIEltVmVjMih3eCArIDMwLCB0cmFpblBvcy55ICsgNDApLAogICAgICAgICAgICAgICAgSW1HdWk6OkdldENvbG9yVTMyKEltVmVjNCgxLjBmLCAxLjBmLCAwLjhmLCAxLjBmKSkKICAgICAgICAgICAgKTsKICAgICAgICB9CgogICAgICAgIC8vIFdoZWVscyBmb3IgZWFjaCBib2dpZQogICAgICAgIGZsb2F0IHdoZWVsUmFkaXVzID0gMTUuMGY7CiAgICAgICAgZmxvYXQgd2hlZWxTcGFjaW5nID0gNTAuMGY7CiAgICAgICAgCiAgICAgICAgZm9yIChmbG9hdCB4ID0gYm9naWVYICsgMzA7IHggPCBib2dpZVggKyBib2dpZVdpZHRoIC0gMzA7IHggKz0gd2hlZWxTcGFjaW5nKSB7CiAgICAgICAgICAgIHBEcmF3TGlzdC0+QWRkQ2lyY2xlRmlsbGVkKAogICAgICAgICAgICAgICAgSW1WZWMyKHgsIHRyYWluUG9zLnkgKyA1NSksCiAgICAgICAgICAgICAgICB3aGVlbFJhZGl1cywKICAgICAgICAgICAgICAgIEltR3VpOjpHZXRDb2xvclUzMihJbVZlYzQoMC4xZiwgMC4xZiwgMC4xZiwgMS4wZikpCiAgICAgICAgICAgICk7CiAgICAgICAgfQogICAgfQogICAgCiAgICAvLyBMb2NvbW90aXZlIGJvZHkKICAgIHBEcmF3TGlzdC0+QWRkUmVjdEZpbGxlZCgKICAgICAgICBJbVZlYzIodHJhaW5Qb3MueCwgdHJhaW5Qb3MueSksCiAgICAgICAgSW1WZWMyKHRyYWluUG9zLnggKyAyMDAsIHRyYWluUG9zLnkgKyA2MCksCiAgICAgICAgSW1HdWk6OkdldENvbG9yVTMyKEltVmVjNCgwLjJmLCAwLjNmLCAwLjhmLCAxLjBmKSkKICAgICk7CgogICAgLy8gTG9jb21vdGl2ZSBmcm9udAogICAgcERyYXdMaXN0LT5BZGRSZWN0RmlsbGVkKAogICAgICAgIEltVmVjMih0cmFpblBvcy54ICsgMjAwLCB0cmFpblBvcy55ICsgMTApLAogICAgICAgIEltVmVjMih0cmFpblBvcy54ICsgMjQwLCB0cmFpblBvcy55ICsgNjApLAogICAgICAgIEltR3VpOjpHZXRDb2xvclUzMihJbVZlYzQoMC4yZiwgMC4yZiwgMC43ZiwgMS4wZikpCiAgICApOwoKICAgIC8vIENhYmluCiAgICBwRHJhd0xpc3QtPkFkZFJlY3RGaWxsZWQoCiAgICAgICAgSW1WZWMyKHRyYWluUG9zLnggKyAxNDAsIHRyYWluUG9zLnkgLSAzMCksCiAgICAgICAgSW1WZWMyKHRyYWluUG9zLnggKyAyMDAsIHRyYWluUG9zLnkpLAogICAgICAgIEltR3VpOjpHZXRDb2xvclUzMihJbVZlYzQoMC4yZiwgMC4yZiwgMC43ZiwgMS4wZikpCiAgICApOwoKICAgIC8vIFdpbmRvd3MKICAgIGZvciAoZmxvYXQgeCA9IHRyYWluUG9zLnggKyAyMDsgeCA8IHRyYWluUG9zLnggKyAxMjA7IHggKz0gNDApIHsKICAgICAgICBwRHJhd0xpc3QtPkFkZFJlY3RGaWxsZWQoCiAgICAgICAgICAgIEltVmVjMih4LCB0cmFpblBvcy55ICsgMTApLAogICAgICAgICAgICBJbVZlYzIoeCArIDMwLCB0cmFpblBvcy55ICsgNDApLAogICAgICAgICAgICBJbUd1aTo6R2V0Q29sb3JVMzIoSW1WZWM0KDAuOGYsIDAuOGYsIDEuMGYsIDEuMGYpKQogICAgICAgICk7CiAgICB9CgogICAgLy8gQ2hpbW5leQogICAgcERyYXdMaXN0LT5BZGRSZWN0RmlsbGVkKAogICAgICAgIEltVmVjMih0cmFpblBvcy54ICsgMTgwLCB0cmFpblBvcy55IC0gNTApLAogICAgICAgIEltVmVjMih0cmFpblBvcy54ICsgMTk1LCB0cmFpblBvcy55KSwKICAgICAgICBJbUd1aTo6R2V0Q29sb3JVMzIoSW1WZWM0KDAuMmYsIDAuMmYsIDAuMmYsIDEuMGYpKQogICAgKTsKCiAgICAvLyBMb2NvbW90aXZlIHdoZWVscwogICAgZmxvYXQgd2hlZWxSYWRpdXMgPSAxNS4wZjsKICAgIGZsb2F0IHdoZWVsU3BhY2luZyA9IDUwLjBmOwogICAgCiAgICBmb3IgKGZsb2F0IHggPSB0cmFpblBvcy54ICsgMzA7IHggPCB0cmFpblBvcy54ICsgMjIwOyB4ICs9IHdoZWVsU3BhY2luZykgewogICAgICAgIHBEcmF3TGlzdC0+QWRkQ2lyY2xlRmlsbGVkKAogICAgICAgICAgICBJbVZlYzIoeCwgdHJhaW5Qb3MueSArIDU1KSwKICAgICAgICAgICAgd2hlZWxSYWRpdXMsCiAgICAgICAgICAgIEltR3VpOjpHZXRDb2xvclUzMihJbVZlYzQoMC4xZiwgMC4xZiwgMC4xZiwgMS4wZikpCiAgICAgICAgKTsKICAgIH0KCiAgICAvLyBTbW9rZSBhbmltYXRpb24KICAgIGZvciAoaW50IGkgPSAwOyBpIDwgNTsgaSsrKSB7CiAgICAgICAgZmxvYXQgc21va2VPZmZzZXQgPSBzaW5mKHRpbWUgKiAyLjBmICsgaSkgKiAxMC4wZjsKICAgICAgICBmbG9hdCBzbW9rZVNpemUgPSAxMC4wZiArIGkgKiA1LjBmOwogICAgICAgIGZsb2F0IHNtb2tlQWxwaGEgPSAwLjZmIC0gKGkgKiAwLjFmKTsKICAgICAgICAKICAgICAgICBwRHJhd0xpc3QtPkFkZENpcmNsZUZpbGxlZCgKICAgICAgICAgICAgSW1WZWMyKHRyYWluUG9zLnggKyAxODcgKyBzbW9rZU9mZnNldCwgdHJhaW5Qb3MueSAtIDYwIC0gKGkgKiAyMCkpLAogICAgICAgICAgICBzbW9rZVNpemUsCiAgICAgICAgICAgIEltR3VpOjpHZXRDb2xvclUzMihJbVZlYzQoMC43ZiwgMC43ZiwgMC43Ziwgc21va2VBbHBoYSkpCiAgICAgICAgKTsKICAgIH0KfQ==
// Basic animation variables
static float time = 0.0f;
static float trainPosition = 0.0f;
const float TRAIN_SPEED = 150.0f;
static float moonGlow = 0.0f;
static float moonY = 0.0f;
void RenderScene(); {
time += ImGui::GetIO().DeltaTime;
trainPosition += TRAIN_SPEED * ImGui::GetIO().DeltaTime;
// Update moon animations
moonGlow = 0.5f + 0.5f * sinf(time * 0.5f);
moonY = 5.0f * sinf(time * 0.2f);
// Reset train position
if (trainPosition > ImGui::GetWindowSize().x + 400.0f) {
trainPosition = -800.0f; // Increased negative value to account for bogies
}
ImDrawList* pDrawList = ImGui::GetWindowDrawList();
ImVec2 windowPos = ImGui::GetWindowPos();
ImVec2 windowSize = ImGui::GetWindowSize();
// Draw moon
float moonRadius = 40.0f;
ImVec2 moonCenter(
windowPos.x + windowSize.x * 0.8f,
windowPos.y + windowSize.y * 0.2f + moonY
);
// Moon glow effect
for (float r = moonRadius + 30.0f; r >= moonRadius; r -= 1.0f) {
float alpha = moonGlow * (1.0f - (r - moonRadius) / 30.0f) * 0.3f;
pDrawList->AddCircleFilled(
moonCenter,
r,
ImGui::GetColorU32(ImVec4(0.9f, 0.9f, 0.7f, alpha))
);
}
// Main moon
pDrawList->AddCircleFilled(
moonCenter,
moonRadius,
ImGui::GetColorU32(ImVec4(0.95f, 0.95f, 0.8f, 1.0f))
);
// Moon craters
const ImVec2 craters[] = {
ImVec2(-15, -10), ImVec2(10, -15), ImVec2(5, 5),
ImVec2(-5, 15), ImVec2(15, 10), ImVec2(-20, 5)
};
for (const auto& crater : craters) {
pDrawList->AddCircleFilled(
ImVec2(moonCenter.x + crater.x, moonCenter.y + crater.y),
4.0f,
ImGui::GetColorU32(ImVec4(0.85f, 0.85f, 0.7f, 1.0f))
);
}
// Add stars around moon
const int NUM_STARS = 50;
static std::vector<ImVec2> stars;
static bool starsInitialized = false;
// Initialize star positions once
if (!starsInitialized) {
stars.clear();
for (int i = 0; i < NUM_STARS; i++) {
float angle = (float)i / NUM_STARS * 2 * 3.14159f;
float distance = 100.0f + rand() % 200;
stars.push_back(ImVec2(
moonCenter.x + cosf(angle) * distance,
moonCenter.y + sinf(angle) * distance
));
}
starsInitialized = true;
}
// Draw stars with twinkling effect
for (size_t i = 0; i < stars.size(); i++) {
float starGlow = 0.3f + 0.7f * sinf(time * 2.0f + i * 1.5f);
float starSize = 2.0f + sinf(time * 3.0f + i) * 0.5f;
pDrawList->AddCircleFilled(
stars[i],
starSize,
ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 1.0f, starGlow))
);
}
// Draw railway tracks
float trackY = windowPos.y + windowSize.y * 0.7f;
// Draw track base
pDrawList->AddRectFilled(
ImVec2(windowPos.x, trackY - 5),
ImVec2(windowPos.x + windowSize.x, trackY + 15),
ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.3f, 1.0f))
);
// Draw railroad ties
float tieSpacing = 50.0f;
float tieOffset = fmodf(time * TRAIN_SPEED, tieSpacing);
for (float x = -tieSpacing + tieOffset; x < windowSize.x; x += tieSpacing) {
pDrawList->AddRectFilled(
ImVec2(windowPos.x + x, trackY - 10),
ImVec2(windowPos.x + x + 30, trackY + 20),
ImGui::GetColorU32(ImVec4(0.4f, 0.2f, 0.1f, 1.0f))
);
}
// Draw rails
pDrawList->AddRectFilled(
ImVec2(windowPos.x, trackY - 2),
ImVec2(windowPos.x + windowSize.x, trackY),
ImGui::GetColorU32(ImVec4(0.7f, 0.7f, 0.7f, 1.0f))
);
pDrawList->AddRectFilled(
ImVec2(windowPos.x, trackY + 10),
ImVec2(windowPos.x + windowSize.x, trackY + 12),
ImGui::GetColorU32(ImVec4(0.7f, 0.7f, 0.7f, 1.0f))
);
// Draw Train
ImVec2 trainPos(windowPos.x + trainPosition, trackY - 60);
// Add train bogies (compartments) BEHIND the locomotive
const int NUM_BOGIES = 3;
float bogieWidth = 180.0f;
float bogieGap = 20.0f;
float bogieStartX = trainPos.x - bogieWidth - bogieGap;
for (int i = 0; i < NUM_BOGIES; i++) {
float bogieX = bogieStartX - (bogieWidth + bogieGap) * i;
// Bogie body
pDrawList->AddRectFilled(
ImVec2(bogieX, trainPos.y),
ImVec2(bogieX + bogieWidth, trainPos.y + 60),
ImGui::GetColorU32(ImVec4(0.7f, 0.2f, 0.2f, 1.0f))
);
// Glowing windows
float windowGlow = 0.5f + 0.5f * sinf(time * 2.0f + i * 1.5f);
for (float wx = bogieX + 20; wx < bogieX + bogieWidth - 20; wx += 40) {
// Window glow effect
for (float r = 20.0f; r >= 0.0f; r -= 1.0f) {
float alpha = windowGlow * (1.0f - r / 20.0f) * 0.3f;
pDrawList->AddRectFilled(
ImVec2(wx - r, trainPos.y + 10 - r),
ImVec2(wx + 30 + r, trainPos.y + 40 + r),
ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 0.8f, alpha))
);
}
// Actual window
pDrawList->AddRectFilled(
ImVec2(wx, trainPos.y + 10),
ImVec2(wx + 30, trainPos.y + 40),
ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 0.8f, 1.0f))
);
}
// Wheels for each bogie
float wheelRadius = 15.0f;
float wheelSpacing = 50.0f;
for (float x = bogieX + 30; x < bogieX + bogieWidth - 30; x += wheelSpacing) {
pDrawList->AddCircleFilled(
ImVec2(x, trainPos.y + 55),
wheelRadius,
ImGui::GetColorU32(ImVec4(0.1f, 0.1f, 0.1f, 1.0f))
);
}
}
// Locomotive body
pDrawList->AddRectFilled(
ImVec2(trainPos.x, trainPos.y),
ImVec2(trainPos.x + 200, trainPos.y + 60),
ImGui::GetColorU32(ImVec4(0.2f, 0.3f, 0.8f, 1.0f))
);
// Locomotive front
pDrawList->AddRectFilled(
ImVec2(trainPos.x + 200, trainPos.y + 10),
ImVec2(trainPos.x + 240, trainPos.y + 60),
ImGui::GetColorU32(ImVec4(0.2f, 0.2f, 0.7f, 1.0f))
);
// Cabin
pDrawList->AddRectFilled(
ImVec2(trainPos.x + 140, trainPos.y - 30),
ImVec2(trainPos.x + 200, trainPos.y),
ImGui::GetColorU32(ImVec4(0.2f, 0.2f, 0.7f, 1.0f))
);
// Windows
for (float x = trainPos.x + 20; x < trainPos.x + 120; x += 40) {
pDrawList->AddRectFilled(
ImVec2(x, trainPos.y + 10),
ImVec2(x + 30, trainPos.y + 40),
ImGui::GetColorU32(ImVec4(0.8f, 0.8f, 1.0f, 1.0f))
);
}
// Chimney
pDrawList->AddRectFilled(
ImVec2(trainPos.x + 180, trainPos.y - 50),
ImVec2(trainPos.x + 195, trainPos.y),
ImGui::GetColorU32(ImVec4(0.2f, 0.2f, 0.2f, 1.0f))
);
// Locomotive wheels
float wheelRadius = 15.0f;
float wheelSpacing = 50.0f;
for (float x = trainPos.x + 30; x < trainPos.x + 220; x += wheelSpacing) {
pDrawList->AddCircleFilled(
ImVec2(x, trainPos.y + 55),
wheelRadius,
ImGui::GetColorU32(ImVec4(0.1f, 0.1f, 0.1f, 1.0f))
);
}
// Smoke animation
for (int i = 0; i < 5; i++) {
float smokeOffset = sinf(time * 2.0f + i) * 10.0f;
float smokeSize = 10.0f + i * 5.0f;
float smokeAlpha = 0.6f - (i * 0.1f);
pDrawList->AddCircleFilled(
ImVec2(trainPos.x + 187 + smokeOffset, trainPos.y - 60 - (i * 20)),
smokeSize,
ImGui::GetColorU32(ImVec4(0.7f, 0.7f, 0.7f, smokeAlpha))
);
}
}