|
|
|
@ -5,7 +5,12 @@ unit UDraw;
|
|
|
|
|
interface
|
|
|
|
|
|
|
|
|
|
uses
|
|
|
|
|
Classes, SysUtils, gl, UColor3f;
|
|
|
|
|
Classes, SysUtils, gl, UGLTypes;
|
|
|
|
|
|
|
|
|
|
const
|
|
|
|
|
// The number of sections per corner must be at least 1.
|
|
|
|
|
CCornerSectionCount = 4;
|
|
|
|
|
CCornerSectionAngle = Pi / (2 * CCornerSectionCount);
|
|
|
|
|
|
|
|
|
|
type
|
|
|
|
|
|
|
|
|
@ -13,78 +18,80 @@ type
|
|
|
|
|
|
|
|
|
|
TDraw = class
|
|
|
|
|
public
|
|
|
|
|
class procedure Clear; static;
|
|
|
|
|
class procedure AddBox(AWidth, AHeight, ACornerSize: Single); static;
|
|
|
|
|
class procedure AddRoundedCornerVertices(AHalfWidth, AHalfHeight,
|
|
|
|
|
ACornerSize: Single; AIndex: Integer); static;
|
|
|
|
|
class constructor Create;
|
|
|
|
|
class procedure AddRoundBox(ACenterX, ACenterY, AWidth, AHeight,
|
|
|
|
|
ACornerSize: Single); static;
|
|
|
|
|
private
|
|
|
|
|
FCornerSectionVertices: array[0..CCornerSectionCount + 1] of TVertex3f; static;
|
|
|
|
|
class procedure MakeVertexList; static;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
const
|
|
|
|
|
CBackgroundColor: TColor3f = (R: 0.27; G: 0.53; B: 0.71);
|
|
|
|
|
CRoundedCornerVertexCount = 4;
|
|
|
|
|
CRoundedCornerVertexAngle = Pi / (2 * CRoundedCornerVertexCount + 2);
|
|
|
|
|
|
|
|
|
|
implementation
|
|
|
|
|
|
|
|
|
|
{ TDraw }
|
|
|
|
|
|
|
|
|
|
class procedure TDraw.Clear;
|
|
|
|
|
class constructor TDraw.Create;
|
|
|
|
|
begin
|
|
|
|
|
glClearColor(CBackgroundColor.R, CBackgroundColor.G, CBackgroundColor.B, 0);
|
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
|
MakeVertexList;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
class procedure TDraw.AddBox(AWidth, AHeight, ACornerSize: Single);
|
|
|
|
|
class procedure TDraw.AddRoundBox(ACenterX, ACenterY, AWidth, AHeight,
|
|
|
|
|
ACornerSize: Single);
|
|
|
|
|
var
|
|
|
|
|
i: Integer;
|
|
|
|
|
halfWidth, halfHeight: Single;
|
|
|
|
|
i, flip: Integer;
|
|
|
|
|
begin
|
|
|
|
|
halfWidth := 0.5 * AWidth;
|
|
|
|
|
halfHeight := 0.5 * AHeight;
|
|
|
|
|
|
|
|
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
|
|
|
glColor3f(1, 1, 1);
|
|
|
|
|
if ACornerSize > TSingleHelper.Epsilon then
|
|
|
|
|
glPushMatrix;
|
|
|
|
|
// Draws a cross from two quads: the panel without the corners.
|
|
|
|
|
glTranslatef(ACenterX, ACenterY, 0);
|
|
|
|
|
glPushMatrix;
|
|
|
|
|
glTranslatef(-0.5 * AWidth, -0.5 * AHeight, 0);
|
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
|
glColor3f(1, 1, 1);
|
|
|
|
|
glVertex2f(AWidth - ACornerSize, AHeight);
|
|
|
|
|
glVertex2f(ACornerSize, AHeight);
|
|
|
|
|
glVertex2f(ACornerSize, 0);
|
|
|
|
|
glVertex2f(AWidth - ACornerSize, 0);
|
|
|
|
|
glVertex2f(AWidth, AHeight - ACornerSize);
|
|
|
|
|
glVertex2f(0, AHeight - ACornerSize);
|
|
|
|
|
glVertex2f(0, ACornerSize);
|
|
|
|
|
glVertex2f(AWidth, ACornerSize);
|
|
|
|
|
glEnd;
|
|
|
|
|
glPopMatrix;
|
|
|
|
|
|
|
|
|
|
// Draws the four corners by mirroring one fan of triangles. Its vertex
|
|
|
|
|
// coordinates are precalculated in 'FCornerSectionVertices'.
|
|
|
|
|
for i := 0 to 3 do
|
|
|
|
|
begin
|
|
|
|
|
// With round corners, the fan's origin is the center of the panel.
|
|
|
|
|
glVertex2f(0.0, 0.0);
|
|
|
|
|
for i := 0 to 4 do
|
|
|
|
|
AddRoundedCornerVertices(halfWidth, halfHeight, ACornerSize, i);
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
// Without round corners, the panel is just two triangles.
|
|
|
|
|
glVertex2f(halfWidth, halfHeight);
|
|
|
|
|
glVertex2f(-halfWidth, halfHeight);
|
|
|
|
|
glVertex2f(-halfWidth, -halfHeight);
|
|
|
|
|
glVertex2f(halfWidth, -halfHeight);
|
|
|
|
|
glPushMatrix;
|
|
|
|
|
glTranslatef(0.5 * AWidth - ACornerSize, 0.5 * AHeight - ACornerSize, 0);
|
|
|
|
|
glScalef(ACornerSize, ACornerSize, 1);
|
|
|
|
|
glEnableClientState(GL_VERTEX_ARRAY);
|
|
|
|
|
glVertexPointer(3, GL_FLOAT, 0, @FCornerSectionVertices[0]);
|
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, Length(FCornerSectionVertices));
|
|
|
|
|
glDisableClientState(GL_VERTEX_ARRAY);
|
|
|
|
|
glPopMatrix;
|
|
|
|
|
flip := 2 * (i and 1);
|
|
|
|
|
glScalef(flip - 1, 1 - flip, 1);
|
|
|
|
|
end;
|
|
|
|
|
glEnd;
|
|
|
|
|
glPopMatrix;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
class procedure TDraw.AddRoundedCornerVertices(AHalfWidth, AHalfHeight, ACornerSize:
|
|
|
|
|
Single; AIndex: Integer);
|
|
|
|
|
class procedure TDraw.MakeVertexList;
|
|
|
|
|
var
|
|
|
|
|
i, signX, signY, cornerSign: Integer;
|
|
|
|
|
borderX, borderY, phi: Single;
|
|
|
|
|
i, last: Integer;
|
|
|
|
|
begin
|
|
|
|
|
signX := 1 - (AIndex + 1) and 2;
|
|
|
|
|
borderX := signX * AHalfWidth;
|
|
|
|
|
signY := 1 - AIndex and 2;
|
|
|
|
|
borderY := signY * AHalfHeight;
|
|
|
|
|
cornerSign := AIndex and 1;
|
|
|
|
|
|
|
|
|
|
glVertex2f(borderX - signX * cornerSign * ACornerSize, borderY + signY * (cornerSign - 1) * ACornerSize);
|
|
|
|
|
|
|
|
|
|
// For the last call only the first vertex is added to close the loop.
|
|
|
|
|
if AIndex >= 4 then
|
|
|
|
|
Exit;
|
|
|
|
|
|
|
|
|
|
for i := 1 to CRoundedCornerVertexCount do
|
|
|
|
|
FCornerSectionVertices[0].X := 0;
|
|
|
|
|
FCornerSectionVertices[0].Y := 0;
|
|
|
|
|
FCornerSectionVertices[1].X := 1;
|
|
|
|
|
FCornerSectionVertices[1].Y := 0;
|
|
|
|
|
last := Length(FCornerSectionVertices) - 1;
|
|
|
|
|
for i := 2 to last - 1 do
|
|
|
|
|
begin
|
|
|
|
|
phi := (i + AIndex * (CRoundedCornerVertexCount + 1)) * CRoundedCornerVertexAngle;
|
|
|
|
|
glVertex2f(borderX + (Cos(phi) - signX) * ACornerSize, borderY + (Sin(phi) - signY) * ACornerSize);
|
|
|
|
|
FCornerSectionVertices[i].X := Cos(CCornerSectionAngle * (i - 1));
|
|
|
|
|
FCornerSectionVertices[i].Y := Sin(CCornerSectionAngle * (i - 1));
|
|
|
|
|
end;
|
|
|
|
|
glVertex2f(borderX + signX * (cornerSign - 1) * ACornerSize, borderY - signY * cornerSign * ACornerSize);
|
|
|
|
|
FCornerSectionVertices[last].X := 0;
|
|
|
|
|
FCornerSectionVertices[last].Y := 1;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
end.
|
|
|
|
|