Updated drawing method to use proper gl methods and added TView to handle OpenGL initialization

main
Stefan Müller 2 months ago
parent 4c2d4713cd
commit 4b3b57d710

@ -44,12 +44,16 @@
<HasResources Value="True"/>
<ResourceBaseClass Value="Form"/>
</Unit>
<Unit>
<Filename Value="UView.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="UDraw.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="utils\UColor3f.pas"/>
<Filename Value="utils\UGLTypes.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units>
@ -81,6 +85,7 @@
</CodeGeneration>
<Linking>
<Debugging>
<DebugInfoType Value="dsDwarf2"/>
<UseHeaptrc Value="True"/>
</Debugging>
<Options>

@ -10,7 +10,7 @@ uses
athreads,
{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, lazopenglcontext, UMainForm, UDraw, UColor3f;
Forms, lazopenglcontext, UMainForm, UView, UDraw, UGLTypes;
{$R *.res}

@ -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.

@ -6,6 +6,8 @@ object MainForm: TMainForm
Caption = 'MainForm'
ClientHeight = 480
ClientWidth = 640
OnCreate = FormCreate
OnDestroy = FormDestroy
LCLVersion = '2.2.4.0'
object OpenGLControl: TOpenGLControl
Left = 0
@ -13,6 +15,7 @@ object MainForm: TMainForm
Top = 0
Width = 640
Align = alClient
OnClick = OpenGLControlClick
OnPaint = OpenGLControlPaint
end
end

@ -6,7 +6,7 @@ interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, OpenGLContext, gl,
UDraw;
UView, UDraw;
type
@ -14,17 +14,22 @@ type
TMainForm = class(TForm)
OpenGLControl: TOpenGLControl;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure OpenGLControlClick(Sender: TObject);
procedure OpenGLControlPaint(Sender: TObject);
private
FView: TView;
public
end;
const
CWidth = 0.4;
CHeight = 0.5;
CCornerSize = 0.1;
CCenterX = 250;
CCenterY = 200;
CWidth = 200;
CHeight = 300;
CCornerSize = 30;
var
MainForm: TMainForm;
@ -35,11 +40,33 @@ implementation
{ TMainForm }
procedure TMainForm.FormCreate(Sender: TObject);
begin
FView := TView.Create(OpenGLControl);
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
FView.Free;
end;
procedure TMainForm.OpenGLControlClick(Sender: TObject);
begin
// TODO: This is just a workaround until we find a better place for the init.
FView.OpenGLInit(True);
OpenGLControl.Repaint;
end;
procedure TMainForm.OpenGLControlPaint(Sender: TObject);
begin
TDraw.Clear;
// Prepares drawing.
FView.Clear;
glLoadIdentity;
TDraw.AddBox(CWidth, CHeight, CCornerSize);
// Draws everything.
TDraw.AddRoundBox(CCenterX, CCenterY, CWidth, CHeight, CCornerSize);
// Finishes drawing.
OpenGLControl.SwapBuffers;
end;

@ -0,0 +1,59 @@
unit UView;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils, OpenGLContext, gl, glu, UGLTypes;
type
{ TView }
TView = class
public
constructor Create(AOpenGLControl: TOpenGLControl);
procedure OpenGLInit(AResetModelView: Boolean);
procedure Clear;
private
FOpenGLControl: TOpenGLControl;
end;
const
CBackgroundColor: TColor3f = (R: 0.27; G: 0.53; B: 0.71);
implementation
{ TView }
constructor TView.Create(AOpenGLControl: TOpenGLControl);
begin
FOpenGLControl := AOpenGLControl;
FScale := 1;
end;
// TODO: Do we need 'AResetModelView'?
procedure TView.OpenGLInit(AResetModelView: Boolean);
begin
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
glViewport(0, 0, FOpenGLControl.Width, FOpenGLControl.Height);
gluOrtho2D(0, FOpenGLControl.Width, 0, FOpenGLControl.Height);
glMatrixMode(GL_MODELVIEW);
if AResetModelView then
glLoadIdentity;
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
end;
procedure TView.Clear;
begin
glClearColor(CBackgroundColor.R, CBackgroundColor.G, CBackgroundColor.B, 0);
glClear(GL_COLOR_BUFFER_BIT);
end;
end.

@ -1,4 +1,4 @@
unit UColor3f;
unit UGLTypes;
{$mode ObjFPC}{$H+}
@ -8,6 +8,10 @@ uses
Classes, SysUtils;
type
TVertex3f = record
X, Y, Z: Single;
end;
TColor3f = record
R, G, B: Single;
end;
Loading…
Cancel
Save