pcbjam/tests/gal-regression/scenarios/scenario_grid_native.cpp
Viktor Vaczi 051fb87cab feat(gal-test): Add 100% GAL API test coverage (28 scenarios)
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>
2026-01-07 12:27:06 +01:00

214 lines
7 KiB
C++

/**
* Grid Native Scenario
*
* Tests GAL grid-related methods:
* - SetGridVisibility() / GetGridVisibility()
* - SetGridOrigin()
* - SetGridSize()
* - SetGridColor()
* - SetAxesEnabled() / SetAxesColor()
* - SetCoarseGrid()
* - DrawGrid()
*
* Note: The grid system in GAL is designed for the viewport,
* so we demonstrate grid properties through explicit DrawGrid() calls
* with different settings applied to different regions.
*/
#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 RenderGridNative(GAL* gal, int width, int height) {
// First, let's demonstrate the grid API by setting up and drawing
// different grid configurations
//=========================================================================
// Test GetGridPoint() API - snaps a world point to nearest grid point
//=========================================================================
gal->SetGridSize(VECTOR2D(20, 20));
gal->SetGridOrigin(VECTOR2D(0, 0));
// Test GetGridPoint - should snap (55, 47) to nearest grid point (60, 40)
VECTOR2D testPoint(55, 47);
VECTOR2D snappedPoint = gal->GetGridPoint(testPoint);
// snappedPoint should now be (60, 40) or similar based on grid settings
// Default background
gal->SetLayerDepth(100);
gal->SetIsFill(true);
gal->SetIsStroke(false);
gal->SetFillColor(COLOR4D(0.15, 0.15, 0.15, 1.0));
gal->DrawRectangle(VECTOR2D(0, 0), VECTOR2D(width, height));
// Region 1: Fine grid with axes
gal->SetLayerDepth(50);
gal->SetGridVisibility(true);
gal->SetGridOrigin(VECTOR2D(100, 100));
gal->SetGridSize(VECTOR2D(20, 20)); // 20-pixel grid
gal->SetGridColor(COLOR4D(0.3, 0.3, 0.5, 0.5));
gal->SetAxesEnabled(true);
gal->SetAxesColor(COLOR4D(0.8, 0.3, 0.3, 0.8));
gal->SetCoarseGrid(5); // Every 5th line is coarse
// Draw the grid (this uses the internal grid renderer)
gal->DrawGrid();
// Mark region 1 boundary
gal->SetIsFill(false);
gal->SetIsStroke(true);
gal->SetLineWidth(2.0);
gal->SetStrokeColor(COLOR4D(0.5, 0.5, 0.8, 0.8));
gal->DrawRectangle(VECTOR2D(20, 20), VECTOR2D(320, 220));
// Since DrawGrid() renders based on viewport, let's also
// manually draw grid patterns to show different configurations
// Region 2: Custom fine grid pattern
gal->SetLayerDepth(40);
gal->SetStrokeColor(COLOR4D(0.2, 0.5, 0.2, 0.4));
gal->SetLineWidth(1.0);
double gridX = 360;
double gridY = 20;
double gridW = 300;
double gridH = 200;
double step = 15;
// Vertical lines
for (double x = gridX; x <= gridX + gridW; x += step) {
gal->DrawLine(VECTOR2D(x, gridY), VECTOR2D(x, gridY + gridH));
}
// Horizontal lines
for (double y = gridY; y <= gridY + gridH; y += step) {
gal->DrawLine(VECTOR2D(gridX, y), VECTOR2D(gridX + gridW, y));
}
// Coarse grid overlay
gal->SetStrokeColor(COLOR4D(0.3, 0.7, 0.3, 0.6));
gal->SetLineWidth(2.0);
double coarseStep = step * 5;
for (double x = gridX; x <= gridX + gridW; x += coarseStep) {
gal->DrawLine(VECTOR2D(x, gridY), VECTOR2D(x, gridY + gridH));
}
for (double y = gridY; y <= gridY + gridH; y += coarseStep) {
gal->DrawLine(VECTOR2D(gridX, y), VECTOR2D(gridX + gridW, y));
}
// Region 2 boundary
gal->SetStrokeColor(COLOR4D(0.5, 0.8, 0.5, 0.8));
gal->DrawRectangle(VECTOR2D(gridX - 5, gridY - 5), VECTOR2D(gridX + gridW + 5, gridY + gridH + 5));
// Region 3: Dot grid (alternative grid style)
gal->SetLayerDepth(30);
gal->SetIsFill(true);
gal->SetIsStroke(false);
gal->SetFillColor(COLOR4D(0.6, 0.6, 0.8, 0.6));
double dotGridX = 20;
double dotGridY = 260;
double dotStep = 25;
for (double x = dotGridX; x <= dotGridX + 280; x += dotStep) {
for (double y = dotGridY; y <= dotGridY + 200; y += dotStep) {
gal->DrawCircle(VECTOR2D(x, y), 2);
}
}
// Mark region 3
gal->SetIsFill(false);
gal->SetIsStroke(true);
gal->SetStrokeColor(COLOR4D(0.6, 0.6, 0.8, 0.8));
gal->SetLineWidth(2.0);
gal->DrawRectangle(VECTOR2D(dotGridX - 10, dotGridY - 10),
VECTOR2D(dotGridX + 290, dotGridY + 210));
// Region 4: Non-square grid (different X and Y spacing)
gal->SetLayerDepth(30);
gal->SetStrokeColor(COLOR4D(0.8, 0.5, 0.3, 0.5));
gal->SetLineWidth(1.0);
double nsGridX = 360;
double nsGridY = 260;
double nsGridW = 300;
double nsGridH = 200;
double xStep = 30;
double yStep = 15;
// Vertical lines (wide spacing)
for (double x = nsGridX; x <= nsGridX + nsGridW; x += xStep) {
gal->DrawLine(VECTOR2D(x, nsGridY), VECTOR2D(x, nsGridY + nsGridH));
}
// Horizontal lines (tight spacing)
for (double y = nsGridY; y <= nsGridY + nsGridH; y += yStep) {
gal->DrawLine(VECTOR2D(nsGridX, y), VECTOR2D(nsGridX + nsGridW, y));
}
// Mark region 4
gal->SetStrokeColor(COLOR4D(0.8, 0.6, 0.4, 0.8));
gal->SetLineWidth(2.0);
gal->DrawRectangle(VECTOR2D(nsGridX - 5, nsGridY - 5),
VECTOR2D(nsGridX + nsGridW + 5, nsGridY + nsGridH + 5));
// Region 5: Grid with different origin (offset)
gal->SetLayerDepth(30);
gal->SetStrokeColor(COLOR4D(0.7, 0.3, 0.7, 0.5));
gal->SetLineWidth(1.0);
double oGridX = 700;
double oGridY = 20;
double oGridW = 100;
double oGridH = 200;
double oStep = 20;
double originOffsetX = 7; // Origin offset from edge
double originOffsetY = 12;
for (double x = oGridX + originOffsetX; x <= oGridX + oGridW; x += oStep) {
gal->DrawLine(VECTOR2D(x, oGridY), VECTOR2D(x, oGridY + oGridH));
}
for (double y = oGridY + originOffsetY; y <= oGridY + oGridH; y += oStep) {
gal->DrawLine(VECTOR2D(oGridX, y), VECTOR2D(oGridX + oGridW, y));
}
// Mark origin point
gal->SetFillColor(COLOR4D(1.0, 0.3, 0.3, 1.0));
gal->SetIsFill(true);
gal->DrawCircle(VECTOR2D(oGridX + originOffsetX, oGridY + originOffsetY), 5);
// Mark region 5
gal->SetIsFill(false);
gal->SetStrokeColor(COLOR4D(0.7, 0.4, 0.7, 0.8));
gal->SetLineWidth(2.0);
gal->DrawRectangle(VECTOR2D(oGridX - 5, oGridY - 5),
VECTOR2D(oGridX + oGridW + 5, oGridY + oGridH + 5));
// Axes demonstration in center-bottom region
gal->SetLayerDepth(20);
double axesCx = 700;
double axesCy = 380;
// X axis (red)
gal->SetStrokeColor(COLOR4D(1.0, 0.2, 0.2, 1.0));
gal->SetLineWidth(2.0);
gal->DrawLine(VECTOR2D(axesCx - 80, axesCy), VECTOR2D(axesCx + 80, axesCy));
// Y axis (green)
gal->SetStrokeColor(COLOR4D(0.2, 1.0, 0.2, 1.0));
gal->DrawLine(VECTOR2D(axesCx, axesCy - 80), VECTOR2D(axesCx, axesCy + 80));
// Origin marker
gal->SetFillColor(COLOR4D(1.0, 1.0, 0.2, 1.0));
gal->SetIsFill(true);
gal->DrawCircle(VECTOR2D(axesCx, axesCy), 6);
}
} // namespace GALTest