CRISTIAN RENOSTO← All projects

Project

CalcC

A hardware-accelerated calculator written entirely in C, rendered with signed-distance fields in GLSL.

What it does

Run it locally

Build (CMake ≥ 4.0, from the repository root)

cmake -S . -B build && cmake --build build -j

Run

./build/calcC

Documentation

CalcC is a desktop calculator written entirely in C, built on raylib with signed-distance-field rendering in GLSL and a native Wayland window. Transparent, resizable, fully proportional layout, light/dark theme detected from the operating system, spring animations on the buttons.

Requirements

Component Version
CMake ≥ 4.0 (the policy version is set explicitly, 3.x fails)
Session An active Wayland session
Toolchain C11 + pthreads
Network Only at first configure — raylib is downloaded by FetchContent

raylib 5.0 is fetched automatically at configure time; GLFW 3.4 ships inside it. System libraries (libGL, freetype, fontconfig) are resolved by the platform packages.

Build

cmake -S . -B build
cmake --build build -j
./build/calcC

Run from the repository root: the font is loaded by relative path (assets/Comfortaa.ttf), and launched from anywhere else the app falls back to raylib's default font without an error message.

CMAKE_BUILD_TYPE defaults to Release (-O3 -DNDEBUG). If build/ already exists with an empty cache, delete it and reconfigure — otherwise the build silently compiles at -O0.

Tests

eval_test.c covers the arithmetic engine without opening a window:

gcc -O2 -o /tmp/eval_test eval_test.c logic/eval.c -lm && /tmp/eval_test

Exit code 0 on success. It covers operator precedence, left associativity, negative numbers and unary minus, eight syntax errors, overflow edge cases, ten exact formatting contracts, and the absence of node-pool leaks. It is not wired into CMake: there is no ctest.

How it is built

  • A static node pool, not malloc: 4096 nodes with a free list, O(1), no fragmentation. When the pool runs out the expression is truncated silently — a known limit, recorded in the README.
  • Two fragment shaders (GLSL 330): one for the SDF panel, one for the background. If the shaders fail to compile the renderer falls back to flat rounded rectangles on the CPU and the app stays usable.
  • One source of truth for the keymap: the KEYS[5][4] table in main.c generates both the layout and the key lookup, so mouse and keyboard cannot disagree.
  • Theme detection on its own thread: DetectSystemThemeDark() used to run 19 times per frame (570 ms/frame); bench_baseline.c measures the fix.

What it does — and what it deliberately does not

Present: the four operations, modulo (binary fmod, not a percentage), decimals with both . and ,, Ans to chain the result, navigable history with ↑/↓, backspace, C, one pending operation (5++3 → 5+3), spring and ripple animations, proportional layout, system theme.

Absent, by choice: no parentheses, no √, no 1/x, no ±, no memory keys, no clipboard, no scientific input notation, no localization (the string Errore and the comments are in Italian).

Known limits

  • 1/0 and 5%0 both produce Errore, with no indication of where the problem is.
  • ExprPop is O(n): it walks to the penultimate node instead of holding a pointer to it. Irrelevant with the 160-token ceiling.
  • Pool exhaustion truncates silently.
  • shoot.sh stays tied to niri for the floating placement.

Full detail in docs.md inside the repository.