| cmake | ||
| docs | ||
| examples | ||
| include/fxFPM | ||
| pc | ||
| src | ||
| tests | ||
| .gitignore | ||
| CMakeLists.txt | ||
| compile_flags.txt | ||
| README.md | ||
fxcgFPM !!
Fixed-Point Math Library & 3D Rendering Engine for Casio fx-CG50
Overview
The Casio fx-CG50 is driven by a Renesas SH4A processor that has no floating-point hardware unit. Every float calculation silently falls back to a slow software emulation — fast enough for a few matrix operations, but completely unacceptable for real-time 3D graphics or any tight inner loop where trigonometry is involved.
fxcgFPM solves this by replacing floating-point entirely with a Q16.16 fixed-point arithmetic system. Every value is an int32_t where the upper 16 bits are the integer part and the lower 16 bits are the fractional part, giving a precision of 1/65536 ≈ 0.000015. All multiplications reduce to DMULS.L, the SH4A's native 32×32→64 instruction — dramatically faster than the FPU emulation.
On top of the arithmetic library, fxcgFPM includes a complete 3D rendering engine (r3d). It handles the full pipeline from model matrices to rasterised triangles: backface culling, near-plane clipping, perspective projection, and a painter's-algorithm sort — all in Q16.16 arithmetic, at interactive frame rates on the stock clock.
Two example programs are included: engine3d, a multi-mesh showcase of all six render modes, and flightsim, a mountain flight simulator with a full flight model, procedural terrain, trees, and houses.
fxcgFPM is based on:
- gint 2.11+ --- gitea.planet-casio.com/Lephenixnoir/gint
- fxSDK --- gitea.planet-casio.com/Lephenixnoir/fxsdk
Compatibility and Requirements
| Model | Supported |
|---|---|
| fx-CG50 | ✔ Yes |
| fx-CG90 | ✔ Yes |
| PC (Linux x86) | ✔ Arithmetic library only (pc/ build) |
| fx-CG10 / 20 | ❌ No |
Minimum gint version: 2.11 Build system: fxSDK (calculator) or CMake 3.15+ (PC)
What fxcgFPM Contains
Q16.16 Fixed-Point Arithmetic
The fp16 C++ class wraps an int32_t and provides operator overloads and math functions. The real value represented is raw / 65536.0.
fp16::from_int(n)/fp16::from_float(f)--- construct from integer or float literal (build-time only)fp16::mul_raw(a, b)--- raw Q16.16 multiply usingDMULS.L; no overflow for values under ±32768fp16_sin(x)/fp16_cos(x)/fp16_sincos(x, &s, &c)--- trigonometry via LUT;sincoscomputes both at oncefp16_sqrt(x)--- fast integer square rootfp16_atan2(y, x)--- four-quadrant arctangentR3D_Q = 65536--- the unit constant; one world unit equalsR3D_Qraw
3D Engine (r3d)
A complete single-header software rasteriser running entirely in Q16.16:
| Stage | Implementation |
|---|---|
| Model matrix | mat4_model(pos, rx, ry, scale) — Ry then Rx, no roll |
| View matrix | mat4_view(pos, yaw, pitch) — camera look-at |
| Transform | mat4_pt() — 4×4 matrix × vec3, homogeneous divide |
| Backface culling | dot(face_normal_view, face_centre_view) >= 0 → skip |
| Near-plane clipping | Sutherland-Hodgman at configurable g_ctx.near_z |
| Projection | Perspective divide; focal length ≈ 110 px; int16_t screen coords |
| Sorting | Painter's algorithm — stable insertion sort by z_avg |
| Fill | fill_triangle() — scanline rasteriser with Gouraud lerp |
Engine limits:
| Parameter | Value | Notes |
|---|---|---|
R3D_MAX_VERTS |
64 | Vertices per mesh |
R3D_MAX_FACES |
128 | Faces per mesh |
R3D_MAX_ITEMS |
512 | Painter's sort buffer (≈28 KB) |
Render Modes
Six modes selectable at runtime via g_ctx.mode:
| Mode | Key | Description |
|---|---|---|
R3D_WIRE |
0 | Wireframe — edges drawn with dline() |
R3D_FLAT |
1 | Flat shading — one colour per face, lit by light_dir |
R3D_FLATWIRE |
2 | Flat shading + wireframe overlay |
R3D_GOURAUD |
3 | Per-vertex lighting interpolated across each face |
R3D_TEXLIN |
4 | Affine texture mapping (fast, slight warp on oblique) |
R3D_TEXPERSP |
5 | Perspective-correct texture mapping |
Mesh Primitives
Ready-to-use procedural mesh generators:
r3d_cube(mesh, half)--- axis-aligned cube, 8 verts / 12 facesr3d_pyramid(mesh, half, height)--- square-base pyramid, 5 verts / 6 facesr3d_icosphere(mesh, radius)--- icosahedron, 12 verts / 20 facesr3d_mesh_normals(mesh)--- recompute all face normals from winding order
Included Examples
engine3d
A static scene with three meshes (cube, pyramid, icosphere) rotating under a directional light. All six render modes are available. The TexPersp mode uses a procedural checker texture mapped with a +8192 boundary offset to eliminate 1-ULP FPU rounding glitches at checker cell edges.
Controls:
- [F1] : cycle render mode (Wire → Flat → F+W → Gouraud → TexLin → TexPersp)
- [EXIT] : quit
flightsim
A mountain flight simulator. The terrain is generated each frame from a sum of four sine waves, producing a plausible infinite-looking mountain landscape. A centered four-quadrant chunk layout ensures the terrain is always visible in all directions — including after U-turns. Trees (green pyramids) and houses (cream cubes) are scattered across the landscape and distance-culled.
Controls:
- [UP / DOWN] : pitch (nose up / nose down)
- [LEFT / RIGHT] : yaw (bank left / right)
- [SHIFT + UP / DOWN] : throttle up / down
- [F1] : cycle render mode
- [EXIT] : quit
HUD shows current altitude, speed (×0.1 world units/frame), and compass heading.
Build & Install
Library
cd fxcgFPM
fxsdk build-cg -B
Examples
cd fxcgFPM/examples/engine3d
fxsdk build-cg -B
# Transfer engine3d.g3a to your calculator
cd fxcgFPM/examples/flightsim
fxsdk build-cg -B
# Transfer flightsim.g3a to your calculator
TODO List
Short-Term (High Priority)
- Q16.16 arithmetic (
fp16C++ class,R3D_Qconstant) - Trigonometry via LUT (
fp16_sin,fp16_cos,fp16_sincos) - 4×4 matrix operations (
mat4_model,mat4_view,mat4_mul,mat4_pt) - 3D engine — all 6 render modes
- Near-plane Sutherland-Hodgman clipping
- Painter's algorithm sort buffer
- Mesh primitives: cube, pyramid, icosphere
engine3ddemo — multi-mesh scene with all render modesflightsimdemo — terrain, flight model, props, HUD- Z-buffer rasteriser (correct depth for self-intersecting geometry)
- Fog — depth-based colour blending
Long-Term (Possible Future Work)
- Clipping against all six frustum planes (not just near)
- Normal mapping in fixed-point
- Multiple dynamic light sources
- Model loader from fxSDK asset pipeline
Version History
Version 0.1
- Initial Q16.16 arithmetic library (
fp16class, operator overloads) fp16_sin,fp16_cosvia LUTfp16_sqrt,fp16_atan2- Basic test suite
Version 0.2
- 4×4 matrix operations:
mat4_model,mat4_view,mat4_mul,mat4_pt vec3_t,v3_dot,v3_cross,v3_len,v3_normalisefp16_sincos(simultaneous sin/cos in one LUT lookup)
Version 0.3
- 3D rendering engine (
r3d) — first release - Wireframe and flat shading modes
- Backface culling and near-plane Sutherland-Hodgman clipping
- Painter's algorithm sort (insertion, stable)
- Mesh primitives: cube, pyramid, icosphere
engine3ddemo
Version 0.4
- Gouraud shading mode (
R3D_GOURAUD) - Affine texture mapping (
R3D_TEXLIN) - Perspective-correct texture mapping (
R3D_TEXPERSP) with+8192boundary fix flightsimdemo — four-quadrant centered terrain, flight model, props, HUD
Documentation
Full documentation is available in the docs/ directory:
Disclaimer
This software is a Work in Progress and is provided "as is", without warranty of any kind. The rendering engine is a software rasteriser — no GPU acceleration is possible on the fx-CG50. Performance varies significantly with scene complexity and chosen render mode.
Please:
- Keep mesh vertex and face counts within the documented engine limits
- Set
g_ctx.near_zlarge enough to avoidint16_tscreen-coordinate overflow - Report rendering artefacts with a minimal mesh and camera position
The author cannot be held responsible for any issues caused by the use of this library.
Credits
Thanks to Lephenixnoir for gint, fxSDK, and for the SH4 low-level insights that made the DMULS.L fixed-point path possible.
Thanks to the Planète Casio community.



