Enables GL_CULL_FACE by default (user-toggleable in Settings) so
closed solids skip shading their back halves. The catch is that
IFC placements can contain reflections (mat4 with det<0 — mirrored
families, symmetric instances). Naively culling would make every
mirrored instance vanish because the rasterizer sees its screen-space
winding as backwards.
Fix: detect reflections at upload time via determinant sign, bucket
visible instances into forward (det>=0) and reverse (det<0) per mesh
during culling, and issue two glMultiDrawElementsIndirect calls per
model with glFrontFace toggled CCW/CW between them. The indirect
buffer is still one buffer — just split into a forward slice followed
by a reverse slice, with m.indirect_forward_count recording the split.
Vertex shader flips the normal when the transform has negative
determinant, keeping lighting correct on mirrored instances. The
fragment shader keeps the gl_FrontFacing fallback as a safety net
when culling is disabled (e.g. for files with open shells).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Show FPS, frame time, visible/total objects, and visible/total
triangles in the status bar. Toggled via Settings > Show Performance
Stats, persisted in app settings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>