Move wideband OpenGL background to primitives

This commit is contained in:
2026-05-26 18:26:13 +03:00
parent daa8043a23
commit aa252cb741
+196 -40
View File
@@ -24,6 +24,7 @@ type
TWidebandView = class TWidebandView = class
private private
FBitmap: TBitmap; FBitmap: TBitmap;
FLabelBitmap: TBitmap;
FRulerBitmap: TBitmap; FRulerBitmap: TBitmap;
FTheme: TAppTheme; FTheme: TAppTheme;
FData: array of Single; FData: array of Single;
@@ -57,6 +58,8 @@ type
procedure PaintCPU(C: TCanvas); procedure PaintCPU(C: TCanvas);
procedure PaintGL(C: TOpenGLControl); procedure PaintGL(C: TOpenGLControl);
procedure ColorToGL(AColor: TColor; out R, G, B: GLFloat); procedure ColorToGL(AColor: TColor; out R, G, B: GLFloat);
procedure DrawBackgroundGL(W, H, PlotW: Integer);
procedure DrawGridGL(W, H, PlotW: Integer);
procedure DrawSpectrumGL(PlotW, H: Integer); procedure DrawSpectrumGL(PlotW, H: Integer);
procedure DrawHamBandGL(PlotW, H: Integer; F1, F2: Double; AColor: TColor); procedure DrawHamBandGL(PlotW, H: Integer; F1, F2: Double; AColor: TColor);
procedure DrawHamBandsGL(PlotW, H: Integer); procedure DrawHamBandsGL(PlotW, H: Integer);
@@ -71,7 +74,9 @@ type
const Name: string; AColor: TColor); const Name: string; AColor: TColor);
procedure DrawFrequencyMarker(C: TCanvas; PlotW, H: Integer); procedure DrawFrequencyMarker(C: TCanvas; PlotW, H: Integer);
procedure DrawSpectrumGradient(const SpPts: array of TPoint; PlotW, H: Integer); procedure DrawSpectrumGradient(const SpPts: array of TPoint; PlotW, H: Integer);
procedure UploadBitmapToGL; procedure DrawGLLabels(W, H, PlotW: Integer);
procedure UploadLabelTextureToGL;
procedure DrawLabelTextureGL(W, H: Integer);
public public
constructor Create; constructor Create;
destructor Destroy; override; destructor Destroy; override;
@@ -107,6 +112,8 @@ begin
inherited Create; inherited Create;
FBitmap := TBitmap.Create; FBitmap := TBitmap.Create;
FBitmap.PixelFormat := pf32bit; FBitmap.PixelFormat := pf32bit;
FLabelBitmap := TBitmap.Create;
FLabelBitmap.PixelFormat := pf32bit;
FRulerBitmap := TBitmap.Create; FRulerBitmap := TBitmap.Create;
FRulerBitmap.PixelFormat := pf32bit; FRulerBitmap.PixelFormat := pf32bit;
FTheme := DarkTheme; FTheme := DarkTheme;
@@ -137,6 +144,7 @@ begin
if FGLTex <> 0 then if FGLTex <> 0 then
glDeleteTextures(1, @FGLTex); glDeleteTextures(1, @FGLTex);
FRulerBitmap.Free; FRulerBitmap.Free;
FLabelBitmap.Free;
FBitmap.Free; FBitmap.Free;
inherited Destroy; inherited Destroy;
end; end;
@@ -230,6 +238,11 @@ begin
FBitmap.SetSize(W, H); FBitmap.SetSize(W, H);
FGLBackgroundDirty := True; FGLBackgroundDirty := True;
end; end;
if (FLabelBitmap.Width <> W) or (FLabelBitmap.Height <> H) then
begin
FLabelBitmap.SetSize(W, H);
FGLBackgroundDirty := True;
end;
end; end;
procedure TWidebandView.SetBitmapSize(W, H: Integer); procedure TWidebandView.SetBitmapSize(W, H: Integer);
@@ -666,8 +679,6 @@ begin
DrawHamBands(C, PlotW, H); DrawHamBands(C, PlotW, H);
C.Font.Color := FTheme.Text;
C.TextOut(6, 4, 'Wideband');
if IncludeSpectrum then if IncludeSpectrum then
FDirty := False FDirty := False
else else
@@ -742,6 +753,67 @@ begin
B := ((AColor shr 16) and $FF) / 255.0; B := ((AColor shr 16) and $FF) / 255.0;
end; end;
procedure TWidebandView.DrawBackgroundGL(W, H, PlotW: Integer);
var
R1, G1, B1, R2, G2, B2: GLFloat;
begin
ColorToGL(FTheme.SpecGradTop, R1, G1, B1);
ColorToGL(FTheme.SpecGradBot, R2, G2, B2);
glBegin(GL_QUADS);
glColor3f(R1, G1, B1); glVertex2f(0, H);
glColor3f(R1, G1, B1); glVertex2f(W, H);
glColor3f(R2, G2, B2); glVertex2f(W, 0);
glColor3f(R2, G2, B2); glVertex2f(0, 0);
glEnd;
ColorToGL(FTheme.SpecLabelBand, R1, G1, B1);
glColor3f(R1, G1, B1);
glBegin(GL_QUADS);
glVertex2f(PlotW, 0);
glVertex2f(W, 0);
glVertex2f(W, H);
glVertex2f(PlotW, H);
glEnd;
end;
procedure TWidebandView.DrawGridGL(W, H, PlotW: Integer);
var
X, Y, TopH: Integer;
DB, DBMin, InvRange, StepHz, FreqHz: Double;
R, G, B: GLFloat;
begin
DBMin := FRefLevel - FRange;
InvRange := 1.0 / Max(1.0, FRange);
TopH := Max(1, H - 1);
ColorToGL(FTheme.SpecGrid, R, G, B);
glColor4f(R, G, B, 0.78);
glBegin(GL_LINES);
FLabelBitmap.Canvas.Font.Name := 'Courier New';
FLabelBitmap.Canvas.Font.Size := 7;
StepHz := RulerGridStepHz(FLabelBitmap.Canvas, PlotW);
FreqHz := Ceil(FViewStartHz / StepHz) * StepHz;
while FreqHz <= FViewEndHz + 0.5 do
begin
X := FreqToX(FreqHz, PlotW);
glVertex2f(X, 0);
glVertex2f(X, H);
FreqHz := FreqHz + StepHz;
end;
DB := FRefLevel - 20.0;
while DB >= DBMin do
begin
Y := Round((FRefLevel - DB) * InvRange * TopH);
glVertex2f(0, H - Y);
glVertex2f(W, H - Y);
DB := DB - 20.0;
end;
glVertex2f(PlotW, 0);
glVertex2f(PlotW, H);
glEnd;
end;
procedure TWidebandView.DrawSpectrumGL(PlotW, H: Integer); procedure TWidebandView.DrawSpectrumGL(PlotW, H: Integer);
var var
I: Integer; I: Integer;
@@ -826,66 +898,158 @@ begin
DrawHamBandGL(PlotW, H, 50000000, 51990000, TColor($003C729A)); DrawHamBandGL(PlotW, H, 50000000, 51990000, TColor($003C729A));
end; end;
procedure TWidebandView.UploadBitmapToGL; procedure TWidebandView.DrawGLLabels(W, H, PlotW: Integer);
var
C: TCanvas;
X1, X2, LabelX, LabelY, TW, TH, Y, TopH, ScaleX: Integer;
DB, DBMin, InvRange: Double;
procedure BandLabel(F1, F2: Double; const Name: string);
begin
X1 := FreqToX(F1, PlotW);
X2 := FreqToX(F2, PlotW);
if (X2 <= 0) or (X1 >= PlotW) then Exit;
X1 := EnsureRange(X1, 0, PlotW - 1);
X2 := EnsureRange(X2, 0, PlotW - 1);
if X2 <= X1 then Exit;
TW := C.TextWidth(Name);
TH := C.TextHeight(Name);
LabelX := EnsureRange(((X1 + X2) div 2) - TW div 2, 2, Max(2, PlotW - TW - 5));
LabelY := Max(1, Min(H - TH - 1, 2));
C.TextOut(LabelX, LabelY, Name);
end;
begin
if (W <= 0) or (H <= 0) then Exit;
if (FLabelBitmap.Width <> W) or (FLabelBitmap.Height <> H) then
FLabelBitmap.SetSize(W, H);
C := FLabelBitmap.Canvas;
C.Brush.Style := bsSolid;
C.Brush.Color := clBlack;
C.FillRect(Rect(0, 0, W, H));
C.Brush.Style := bsClear;
DBMin := FRefLevel - FRange;
InvRange := 1.0 / Max(1.0, FRange);
TopH := Max(1, H - 1);
ScaleX := PlotW;
C.Font.Name := 'Courier New';
C.Font.Quality := fqDefault;
C.Font.Size := 7;
C.Font.Color := FTheme.SpecLabelText;
DB := FRefLevel - 20.0;
while DB >= DBMin do
begin
Y := Round((FRefLevel - DB) * InvRange * TopH);
C.TextOut(ScaleX + 2, Y - 9, Format('%4.0f', [DB]));
DB := DB - 20.0;
end;
C.Font.Name := 'Sans';
C.Font.Quality := fqDefault;
C.Font.Size := 7;
C.Font.Color := TColor($00EAF7D7);
BandLabel(1810000, 2000000, '160m');
BandLabel(3500000, 3800000, '80m');
BandLabel(5258500, 5403500, '60m');
BandLabel(7000000, 7300000, '40m');
BandLabel(10100000, 10150000, '30m');
BandLabel(14000000, 14350000, '20m');
BandLabel(18068000, 18168000, '17m');
BandLabel(21000000, 21450000, '15m');
BandLabel(24890000, 24990000, '12m');
BandLabel(28000000, 29700000, '10m');
BandLabel(50000000, 51990000, '6m');
end;
procedure TWidebandView.UploadLabelTextureToGL;
var var
X, Y, I: Integer; X, Y, I: Integer;
Src: PByte; Src: PByte;
Buf: array of Byte; Buf: array of Byte;
A: Byte;
begin begin
if (FBitmap.Width <= 0) or (FBitmap.Height <= 0) then Exit; if (FLabelBitmap.Width <= 0) or (FLabelBitmap.Height <= 0) then Exit;
if FGLTex = 0 then if FGLTex = 0 then
glGenTextures(1, @FGLTex); glGenTextures(1, @FGLTex);
SetLength(Buf, FBitmap.Width * FBitmap.Height * 4); SetLength(Buf, FLabelBitmap.Width * FLabelBitmap.Height * 4);
FBitmap.BeginUpdate(False); FLabelBitmap.BeginUpdate(False);
try try
I := 0; I := 0;
for Y := 0 to FBitmap.Height - 1 do for Y := 0 to FLabelBitmap.Height - 1 do
begin begin
Src := PByte(FBitmap.ScanLine[Y]); Src := PByte(FLabelBitmap.ScanLine[Y]);
for X := 0 to FBitmap.Width - 1 do for X := 0 to FLabelBitmap.Width - 1 do
begin begin
Buf[I] := Src[2]; A := Max(Src[0], Max(Src[1], Src[2]));
Buf[I + 1] := Src[1]; if A < 6 then A := 0;
Buf[I + 2] := Src[0]; if A > 0 then
Buf[I + 3] := $FF; begin
Buf[I] := Byte(Min(255, Src[2] * 255 div A));
Buf[I + 1] := Byte(Min(255, Src[1] * 255 div A));
Buf[I + 2] := Byte(Min(255, Src[0] * 255 div A));
A := Byte(Min(255, A + (255 - A) div 3));
end
else
begin
Buf[I] := 0;
Buf[I + 1] := 0;
Buf[I + 2] := 0;
end;
Buf[I + 3] := A;
Inc(Src, 4); Inc(Src, 4);
Inc(I, 4); Inc(I, 4);
end; end;
end; end;
finally finally
FBitmap.EndUpdate(False); FLabelBitmap.EndUpdate(False);
end; end;
glBindTexture(GL_TEXTURE_2D, FGLTex); glBindTexture(GL_TEXTURE_2D, FGLTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, FBitmap.Width, FBitmap.Height, 0, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, FLabelBitmap.Width, FLabelBitmap.Height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, @Buf[0]); GL_RGBA, GL_UNSIGNED_BYTE, @Buf[0]);
end; end;
procedure TWidebandView.DrawLabelTextureGL(W, H: Integer);
begin
if FGLTex = 0 then Exit;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, FGLTex);
glColor4f(1, 1, 1, 1);
glBegin(GL_QUADS);
glTexCoord2f(0, 1); glVertex2f(0, 0);
glTexCoord2f(1, 1); glVertex2f(W, 0);
glTexCoord2f(1, 0); glVertex2f(W, H);
glTexCoord2f(0, 0); glVertex2f(0, H);
glEnd;
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
end;
procedure TWidebandView.PaintGL(C: TOpenGLControl); procedure TWidebandView.PaintGL(C: TOpenGLControl);
var var
W, H, PlotW, X: Integer; W, H, PlotW, X: Integer;
NeedUpload: Boolean;
begin begin
if C = nil then Exit; if C = nil then Exit;
W := Max(1, C.Width); W := Max(1, C.Width);
H := Max(1, C.Height); H := Max(1, C.Height);
if not C.MakeCurrent then Exit; if not C.MakeCurrent then Exit;
NeedUpload := False;
if (FBitmap.Width <> W) or (FBitmap.Height <> H) then if (FBitmap.Width <> W) or (FBitmap.Height <> H) then
begin
SetBitmapSize(W, H); SetBitmapSize(W, H);
NeedUpload := True;
end;
if FGLBackgroundDirty then if FGLBackgroundDirty then
begin begin
DrawCPU(W, H, False); PlotW := Max(1, W - WB_DB_SCALE_W);
NeedUpload := True; DrawGLLabels(W, H, PlotW);
UploadLabelTextureToGL;
FGLBackgroundDirty := False;
end; end;
if FGLTex = 0 then
NeedUpload := True;
if NeedUpload then
UploadBitmapToGL;
glViewport(0, 0, W, H); glViewport(0, 0, W, H);
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glLoadIdentity; glLoadIdentity;
@@ -895,21 +1059,13 @@ begin
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glClearColor(0, 0, 0, 1.0); glClearColor(0, 0, 0, 1.0);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, FGLTex);
glColor3f(1, 1, 1);
glBegin(GL_QUADS);
glTexCoord2f(0, 1); glVertex2f(0, 0);
glTexCoord2f(1, 1); glVertex2f(W, 0);
glTexCoord2f(1, 0); glVertex2f(W, H);
glTexCoord2f(0, 0); glVertex2f(0, H);
glEnd;
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
PlotW := Max(1, W - WB_DB_SCALE_W); PlotW := Max(1, W - WB_DB_SCALE_W);
DrawBackgroundGL(W, H, PlotW);
DrawGridGL(W, H, PlotW);
DrawSpectrumGL(PlotW, H); DrawSpectrumGL(PlotW, H);
DrawHamBandsGL(PlotW, H); DrawHamBandsGL(PlotW, H);
DrawLabelTextureGL(W, H);
FDirty := False; FDirty := False;
if (FMarkerHz >= FViewStartHz) and (FMarkerHz <= FViewEndHz) then if (FMarkerHz >= FViewStartHz) and (FMarkerHz <= FViewEndHz) then