unit uMainForm; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls, uglcContext, uglcShader, uglcArrayBuffer, uglcTypes, uglcBitmap; type TMainForm = class(TForm) ApplicationProperties: TApplicationProperties; LogLB: TListBox; RenderPanel: TPanel; procedure ApplicationPropertiesIdle(Sender: TObject; var Done: Boolean); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure RenderPanelResize(Sender: TObject); private fContext: TglcContext; fShader: TglcShaderProgram; fVBO: TglcArrayBuffer; fTexture: TglcBitmap2D; procedure Log(aSender: TObject; const aMsg: String); procedure Render; public { public declarations } end; var MainForm: TMainForm; implementation {$R *.lfm} uses dglOpenGL, ugluVector; const SHADER_FILE = 'shader.glsl'; TEXTURE_FILE = 'data\texture.png'; LAYOUT_LOCATION_POS = 0; LAYOUT_LOCATION_TEX = 1; UNIFORM_NAME_TEXTURE = 'uTexture'; type TVertex = packed record pos: TgluVector3f; tex: TgluVector2f; end; PVertex = ^TVertex; procedure TMainForm.FormCreate(Sender: TObject); var pf: TglcContextPixelFormatSettings; p: PVertex; texData: TglcBitmapData; begin pf := TglcContext.MakePF(); fContext := TglcContext.GetPlatformClass.Create(RenderPanel, pf); fContext.BuildContext; fShader := TglcShaderProgram.Create(@Log); fShader.LoadFromFile(ExtractFilePath(Application.ExeName) + SHADER_FILE); fShader.Compile; fShader.Uniform1i(UNIFORM_NAME_TEXTURE, 0); fVBO := TglcArrayBuffer.Create(TglcBufferTarget.btArrayBuffer); fVBO.BufferData(4, sizeof(TVertex), TglcBufferUsage.buStaticDraw, nil); p := fVBO.MapBuffer(TglcBufferAccess.baWriteOnly); try p^.pos := gluVector3f(-0.5, -0.5, 0); p^.tex := gluVector2f( 0.0, 1.0); inc(p); p^.pos := gluVector3f( 0.5, -0.5, 0); p^.tex := gluVector2f( 1.0, 1.0); inc(p); p^.pos := gluVector3f( 0.5, 0.5, 0); p^.tex := gluVector2f( 1.0, 0.0); inc(p); p^.pos := gluVector3f(-0.5, 0.5, 0); p^.tex := gluVector2f( 0.0, 0.0); inc(p); finally fVBO.UnmapBuffer; end; fTexture := TglcBitmap2D.Create; texData := TglcBitmapData.Create; try texData.LoadFromFile(ExtractFilePath(Application.ExeName) + TEXTURE_FILE); fTexture.UploadData(texData); finally FreeAndNil(texData); end; end; procedure TMainForm.ApplicationPropertiesIdle(Sender: TObject; var Done: Boolean); begin Render; Done := false; end; procedure TMainForm.FormDestroy(Sender: TObject); begin FreeAndNil(fVBO); FreeAndNil(fShader); FreeAndNil(fContext); end; procedure TMainForm.RenderPanelResize(Sender: TObject); begin if Assigned(fContext) then begin glViewport(0, 0, RenderPanel.ClientWidth, RenderPanel.ClientHeight); end; end; procedure TMainForm.Log(aSender: TObject; const aMsg: String); begin LogLB.Items.Add(aMsg); end; procedure TMainForm.Render; begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); fVBO.Bind; fTexture.Bind; fShader.Enable; glEnableVertexAttribArray(LAYOUT_LOCATION_POS); glVertexAttribPointer(LAYOUT_LOCATION_POS, 3, GL_FLOAT, False, SizeOf(TVertex), @PVertex(nil)^.pos); glEnableVertexAttribArray(LAYOUT_LOCATION_TEX); glVertexAttribPointer(LAYOUT_LOCATION_TEX, 2, GL_FLOAT, False, SizeOf(TVertex), @PVertex(nil)^.tex); glDrawArrays(GL_QUADS, 0, fVBO.DataCount); glDisableVertexAttribArray(LAYOUT_LOCATION_POS); glDisableVertexAttribArray(LAYOUT_LOCATION_TEX); fShader.Disable; fTexture.Unbind; fVBO.Unbind; fContext.SwapBuffers; end; end.