Project Brief
- Purpose: A small playground for projection-mapped 2D/2.5D level rendering in Python, experimenting with tiled walls/floors, simple lighting, and player-centric controls. It ships two ModernGL demos (isometric and orthographic) and a pygame-only viewer for quick iteration.
Key Features
- Level loading: Reads
src/level/level1.json
withvertices
andlines
(edges) into an embedded planar graph. Faces are discovered from the graph to generate floor polygons. - Meshing: Walls are extruded as quads per edge; floors are triangulated (ear clipping or simple fan depending on demo) with per-vertex world-space UVs for stable tiling.
- Rendering (ModernGL):
gl_main.py
(isometric shader projection) renders floors then walls, with point-light Lambert shading and adjustable texture tiling.gl_main_ortho.py
(true view/projection) adds a visibility mask pass for the floor (cheap 3x3 soften) and per-edge wall visibility using a shadowcasting-like visibility polygon.
- Controls:
- Movement:
W/A/S/D
or left-click to set a move target; optional follow. - Camera: mouse wheel zoom; middle-drag orbit; Shift+middle pan (GL demos).
- Tuning: change tile sizes, light radius, culling/sight toggles (see below).
- Movement:
- Assets: Textures under
projection_mapping_test/src/img/
(stone.png
,dirt.png
). Uses relative paths; replace with your own as needed.
Run It
- Install deps (uv):
uv sync
- Pygame viewer:
python -m projection_mapping_test
- GL isometric demo:
python projection_mapping_test/src/gl_main.py
- GL orthographic demo:
python projection_mapping_test/src/gl_main_ortho.py
Note: Python >= 3.13 is required. If ModernGL context creation fails, ensure your GPU/driver supports OpenGL 3.3 core (macOS requires a forward-compatible core context).
Controls (Summary)
- Common:
W/A/S/D
: Move player.Shift
: sprint.Left Click
: Click-to-move target.Mouse Wheel
: Zoom (anchored at cursor in GL demos).P
: Toggle follow player.9/0
: Decrease/increase light radius.C/V/B/N
: Adjust wall texture tiling (width/height).1/2/3/4
: Adjust floor texture tiling (width/height).
- GL demos:
MMB drag
: Orbit.Shift+MMB
: Pan.- Ortho only:
F
: Toggle face culling,O
: Toggle “sight” (backface black). - Window resize automatically updates viewport (and the mask in ortho).
Data Format
level1.json
contains:vertices
: array of{ "x": float, "y": float }
.lines
: array of{ "a": int, "b": int, "two_sided": bool }
indices intovertices
.
Repo Layout
- Runtime:
projection_mapping_test/src/
- Demos:
gl_main.py
,gl_main_ortho.py
- Viewer:
main.py
(python -m projection_mapping_test
) - Assets:
src/img/
, Levels:src/level/
- Demos:
Notes & Limitations
- Geometry is simple; no collision. Floor triangulation assumes simple faces.
- Visibility in the ortho demo is approximate (softened mask + midpoint checks) and intended for prototyping, not final gameplay logic.
- Textures are expected to be reasonably sized; large binaries should not be committed.
Dev Tips
- Style: PEP 8, 4 spaces, line length ~88–100. Consider Ruff/Black:
uvx ruff format . && uvx ruff check .
- Tests (pytest):
uvx pytest -q
— focus on geometry (face building, triangulation) and JSON parsing if you add tests.