Expand GAL native test harness from 24 to 28 scenarios covering all 70 GAL methods. New scenarios: - scenario_text_attrs.cpp (24): Text attribute APIs (SetGlyphSize, SetFontBold/Italic/Underlined, SetTextMirrored, justification) - scenario_glyphs.cpp (25): DrawGlyph/DrawGlyphs with stroke glyphs - scenario_bitmap.cpp (26): DrawBitmap with test patterns - scenario_transform.cpp (27): Transform() API documentation Additional API coverage in existing scenarios: - Flush() in test harness - SetFlip(), SetRotation() in screen-transform - SetDepthRange() in depth-testing - GetGridPoint() in grid-native New stub files: - kifont_stub.h: STROKE_GLYPH factory functions for letter glyphs - bitmap_base_stub.h: Test pattern generators (checkerboard, gradient) Note: Bitmap scenario shows empty panels - DrawBitmap uses legacy OpenGL immediate mode (glBegin/glEnd) which doesn't work while shader is active. This is a known limitation when testing outside KiCad's VIEW rendering flow. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
200 lines
6.8 KiB
C++
200 lines
6.8 KiB
C++
/**
|
|
* Depth Testing Scenario
|
|
*
|
|
* Tests GAL::EnableDepthTest() - explicit depth test control
|
|
*
|
|
* Depth testing determines whether fragments are drawn based on their
|
|
* depth value. When enabled with GL_LESS, closer fragments overwrite
|
|
* farther ones. This test demonstrates depth ordering with overlapping shapes.
|
|
*/
|
|
|
|
#include <gal/graphics_abstraction_layer.h>
|
|
#include <cmath>
|
|
|
|
#ifndef M_PI
|
|
#define M_PI 3.14159265358979323846
|
|
#endif
|
|
|
|
namespace GALTest {
|
|
|
|
using KIGFX::COLOR4D;
|
|
using KIGFX::GAL;
|
|
|
|
void RenderDepthTesting(GAL* gal, int width, int height) {
|
|
// Enable depth testing
|
|
gal->EnableDepthTest(true);
|
|
|
|
// Test SetDepthRange() API - sets the near/far depth range for rendering
|
|
// x = near, y = far - this maps layer depths to NDC z-values
|
|
// Default is typically VECTOR2D(0.1, 100) for KiCad
|
|
gal->SetDepthRange(VECTOR2D(0.1, 100));
|
|
|
|
gal->SetIsFill(true);
|
|
gal->SetIsStroke(false);
|
|
|
|
// Section 1: Overlapping circles with explicit depth ordering
|
|
// Using SetLayerDepth - lower values are closer to camera
|
|
|
|
// Background reference
|
|
gal->SetLayerDepth(100);
|
|
gal->SetFillColor(COLOR4D(0.15, 0.15, 0.18, 1.0));
|
|
gal->DrawRectangle(VECTOR2D(20, 20), VECTOR2D(280, 200));
|
|
|
|
// Draw circles from back to front
|
|
gal->SetLayerDepth(80);
|
|
gal->SetFillColor(COLOR4D(0.8, 0.2, 0.2, 0.9));
|
|
gal->DrawCircle(VECTOR2D(100, 100), 50);
|
|
|
|
gal->SetLayerDepth(60);
|
|
gal->SetFillColor(COLOR4D(0.2, 0.8, 0.2, 0.9));
|
|
gal->DrawCircle(VECTOR2D(140, 110), 50);
|
|
|
|
gal->SetLayerDepth(40);
|
|
gal->SetFillColor(COLOR4D(0.2, 0.2, 0.8, 0.9));
|
|
gal->DrawCircle(VECTOR2D(180, 100), 50);
|
|
|
|
gal->SetLayerDepth(20);
|
|
gal->SetFillColor(COLOR4D(0.8, 0.8, 0.2, 0.9));
|
|
gal->DrawCircle(VECTOR2D(220, 90), 50);
|
|
|
|
// Section 2: Depth ordering with rectangles
|
|
gal->SetLayerDepth(100);
|
|
gal->SetFillColor(COLOR4D(0.15, 0.15, 0.18, 1.0));
|
|
gal->DrawRectangle(VECTOR2D(300, 20), VECTOR2D(560, 200));
|
|
|
|
// Stack of rectangles
|
|
for (int i = 0; i < 5; i++) {
|
|
double t = (double)i / 4.0;
|
|
gal->SetLayerDepth(90 - i * 15);
|
|
gal->SetFillColor(COLOR4D(0.3 + t * 0.5, 0.3 + t * 0.2, 0.8 - t * 0.3, 0.9));
|
|
gal->DrawRectangle(
|
|
VECTOR2D(320 + i * 25, 40 + i * 20),
|
|
VECTOR2D(420 + i * 25, 120 + i * 20)
|
|
);
|
|
}
|
|
|
|
// Section 3: Complex depth scene (PCB-like)
|
|
gal->SetLayerDepth(100);
|
|
gal->SetFillColor(COLOR4D(0.1, 0.2, 0.1, 1.0));
|
|
gal->DrawRectangle(VECTOR2D(580, 20), VECTOR2D(780, 200));
|
|
|
|
// Traces at depth 70
|
|
gal->SetLayerDepth(70);
|
|
gal->SetFillColor(COLOR4D(0.7, 0.5, 0.2, 1.0));
|
|
gal->DrawSegment(VECTOR2D(600, 60), VECTOR2D(760, 60), 8);
|
|
gal->DrawSegment(VECTOR2D(600, 110), VECTOR2D(760, 110), 8);
|
|
gal->DrawSegment(VECTOR2D(600, 160), VECTOR2D(760, 160), 8);
|
|
|
|
// Pads at depth 50 (above traces)
|
|
gal->SetLayerDepth(50);
|
|
gal->SetFillColor(COLOR4D(0.85, 0.65, 0.25, 1.0));
|
|
gal->DrawCircle(VECTOR2D(620, 60), 15);
|
|
gal->DrawCircle(VECTOR2D(680, 60), 15);
|
|
gal->DrawCircle(VECTOR2D(740, 60), 15);
|
|
gal->DrawCircle(VECTOR2D(620, 110), 15);
|
|
gal->DrawCircle(VECTOR2D(680, 110), 15);
|
|
gal->DrawCircle(VECTOR2D(740, 110), 15);
|
|
gal->DrawCircle(VECTOR2D(620, 160), 15);
|
|
gal->DrawCircle(VECTOR2D(680, 160), 15);
|
|
gal->DrawCircle(VECTOR2D(740, 160), 15);
|
|
|
|
// Holes at depth 30 (above pads)
|
|
gal->SetLayerDepth(30);
|
|
gal->SetFillColor(COLOR4D(0.1, 0.1, 0.1, 1.0));
|
|
gal->DrawCircle(VECTOR2D(620, 60), 6);
|
|
gal->DrawCircle(VECTOR2D(680, 60), 6);
|
|
gal->DrawCircle(VECTOR2D(740, 60), 6);
|
|
gal->DrawCircle(VECTOR2D(620, 110), 6);
|
|
gal->DrawCircle(VECTOR2D(680, 110), 6);
|
|
gal->DrawCircle(VECTOR2D(740, 110), 6);
|
|
gal->DrawCircle(VECTOR2D(620, 160), 6);
|
|
gal->DrawCircle(VECTOR2D(680, 160), 6);
|
|
gal->DrawCircle(VECTOR2D(740, 160), 6);
|
|
|
|
// Section 4: Interleaved depths
|
|
gal->SetLayerDepth(100);
|
|
gal->SetFillColor(COLOR4D(0.18, 0.15, 0.18, 1.0));
|
|
gal->DrawRectangle(VECTOR2D(20, 220), VECTOR2D(280, 400));
|
|
|
|
// Create a checkerboard-like depth pattern
|
|
for (int row = 0; row < 3; row++) {
|
|
for (int col = 0; col < 3; col++) {
|
|
int depth = ((row + col) % 2 == 0) ? 60 : 40;
|
|
double t = (row * 3 + col) / 8.0;
|
|
gal->SetLayerDepth(depth);
|
|
gal->SetFillColor(COLOR4D(0.8 * t + 0.2, 0.3 + 0.5 * (1 - t), 0.5, 0.9));
|
|
gal->DrawCircle(VECTOR2D(70 + col * 70, 270 + row * 50), 25);
|
|
}
|
|
}
|
|
|
|
// Section 5: AdvanceDepth demonstration
|
|
gal->SetLayerDepth(100);
|
|
gal->SetFillColor(COLOR4D(0.15, 0.18, 0.15, 1.0));
|
|
gal->DrawRectangle(VECTOR2D(300, 220), VECTOR2D(560, 400));
|
|
|
|
// Use AdvanceDepth to automatically increment depth
|
|
gal->SetLayerDepth(90);
|
|
double cx = 430;
|
|
double cy = 310;
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
double angle = i * M_PI / 4;
|
|
double r = 60;
|
|
double x = cx + cos(angle) * r;
|
|
double y = cy + sin(angle) * r;
|
|
|
|
double t = (double)i / 7.0;
|
|
gal->SetFillColor(COLOR4D(1.0 - t * 0.5, 0.3 + t * 0.4, 0.3 + t * 0.5, 0.9));
|
|
gal->DrawCircle(VECTOR2D(x, y), 30);
|
|
gal->AdvanceDepth(); // Each subsequent circle is closer
|
|
}
|
|
|
|
// Center circle (closest)
|
|
gal->SetFillColor(COLOR4D(1.0, 1.0, 1.0, 0.95));
|
|
gal->DrawCircle(VECTOR2D(cx, cy), 25);
|
|
|
|
// Section 6: Depth test off comparison
|
|
// This section shows what happens without proper depth ordering
|
|
gal->SetLayerDepth(100);
|
|
gal->SetFillColor(COLOR4D(0.18, 0.18, 0.15, 1.0));
|
|
gal->DrawRectangle(VECTOR2D(580, 220), VECTOR2D(780, 400));
|
|
|
|
// All at same depth - draw order determines visibility
|
|
gal->SetLayerDepth(50);
|
|
|
|
gal->SetFillColor(COLOR4D(0.8, 0.2, 0.2, 0.9));
|
|
gal->DrawCircle(VECTOR2D(640, 300), 40);
|
|
|
|
gal->SetFillColor(COLOR4D(0.2, 0.8, 0.2, 0.9));
|
|
gal->DrawCircle(VECTOR2D(680, 310), 40);
|
|
|
|
gal->SetFillColor(COLOR4D(0.2, 0.2, 0.8, 0.9));
|
|
gal->DrawCircle(VECTOR2D(720, 300), 40);
|
|
|
|
// Labels/frames
|
|
gal->SetLayerDepth(10);
|
|
gal->SetIsFill(false);
|
|
gal->SetIsStroke(true);
|
|
gal->SetLineWidth(2.0);
|
|
|
|
gal->SetStrokeColor(COLOR4D(0.4, 0.4, 0.5, 0.8));
|
|
gal->DrawRectangle(VECTOR2D(20, 20), VECTOR2D(280, 200));
|
|
gal->DrawRectangle(VECTOR2D(300, 20), VECTOR2D(560, 200));
|
|
gal->DrawRectangle(VECTOR2D(580, 20), VECTOR2D(780, 200));
|
|
gal->DrawRectangle(VECTOR2D(20, 220), VECTOR2D(280, 400));
|
|
gal->DrawRectangle(VECTOR2D(300, 220), VECTOR2D(560, 400));
|
|
gal->DrawRectangle(VECTOR2D(580, 220), VECTOR2D(780, 400));
|
|
|
|
// Bottom info bar
|
|
gal->SetLayerDepth(100);
|
|
gal->SetIsFill(true);
|
|
gal->SetFillColor(COLOR4D(0.12, 0.12, 0.15, 1.0));
|
|
gal->DrawRectangle(VECTOR2D(20, 420), VECTOR2D(780, 480));
|
|
|
|
gal->SetIsFill(false);
|
|
gal->SetStrokeColor(COLOR4D(0.3, 0.3, 0.4, 0.8));
|
|
gal->SetLineWidth(1.0);
|
|
gal->DrawRectangle(VECTOR2D(20, 420), VECTOR2D(780, 480));
|
|
}
|
|
|
|
} // namespace GALTest
|