program Glut_01;
{$mode objfpc}{$H+}
{.$Define CORE_GL}
uses
dynlibs, sysutils,
GL, glu, Glut, FreeGlut, GLext;
const
AppWidth = 800;
AppHeight = 600;
type
point = array[1..2] of GLfloat;
{$IfDef CORE_GL}
TShader = record
vbo_point, vao_point, shaderProgram, vertexArrayObject: GLuint;
uniform_viewportSize: GLint;
end;
TAAPLVertex = record
position: array [0..1] of single;
color: array [0..2] of single;
end;
{$EndIf}
var
{$IfnDef CORE_GL}
p: point = (0.0, 0.0);
vertices: array[1..3] of point = ((0.0, 0.0), (400.0, 600.0),(800.0, 0.0));
{$Else}
gOffsetXY: point = (0, 0);
gSize: Single = 100;
gShader: TShader;
verts: array[0..2] of TAAPLVertex;
GLErrorStr: string = '';
{$EndIf}
{$IFDEF CORE_GL}
const
//Simple Vertex Shader
kVert = '#version 330'
+#10'layout(location = 0) in vec2 position;'
+#10'layout(location = 1) in vec3 color;'
+#10'out vec3 fClr;'
+#10'uniform vec2 viewportSize;'
+#10'void main() {'
+#10' gl_Position = vec4((position / (viewportSize/2)), 0.0, 1.0);'
+#10' fClr = color;'
+#10'}';
//Simple Fragment Shader
kFrag = '#version 330'
+#10'in vec3 fClr;'
+#10'out vec4 color;'
+#10'void main() {'
+#10' color = vec4(fClr, 1);'
+#10'}';
procedure ReportErrorsGL(glObjectID: GLuint);
var
s : string;
maxLength : GLint;
begin
glGetShaderiv(glObjectID, GL_INFO_LOG_LENGTH, @maxLength);
if (maxLength < 2) then exit;
setlength(s, maxLength);
glGetShaderInfoLog(glObjectID, maxLength, @maxLength, @s[1]);
s:=trim(s);
if GLErrorStr = '' then begin
GLErrorStr := 'GLSL error '+s;
{$IFDEF UNIX}writeln(GLErrorStr); {$ENDIF}
end;
end;
procedure GetError(p: integer; str: string = ''); //report OpenGL Error
var
Error: GLenum;
s: string;
begin
Error := glGetError();
if Error = GL_NO_ERROR then exit;
s := inttostr(p)+'->';
if Error = GL_INVALID_ENUM then
s := s+'GL_INVALID_ENUM'
else if Error = GL_INVALID_VALUE then
s := s+'GL_INVALID_VALUE' //out of range https://www.khronos.org/registry/OpenGL-Refpages/es2.0/xhtml/glGetError.xml
else
s := s + inttostr(Error);
if GLErrorStr = '' then begin
GLErrorStr := 'GLSL error '+str+s;
{$IFDEF UNIX}writeln(GLErrorStr);{$ENDIF}
end;
end;
function compileShaderOfType (shaderType: GLEnum; shaderText: string): GLuint;
var
status: GLint;
begin
result := glCreateShader(shaderType);
glShaderSource(result, 1, PChar(@shaderText), nil);
glCompileShader(result);
ReportErrorsGL(result);
status := 0;
glGetShaderiv(result, GL_COMPILE_STATUS, @status);
if (status = 0) and (GLErrorStr = '') then begin //report compiling errors.
GLErrorStr := 'GLSL shader compile failure';
end;
end;
procedure ReportCompileProgramError(glObjectID: GLuint);
var
s : string;
maxLength : GLint;
begin
glGetProgramiv(glObjectID, GL_LINK_STATUS, @maxLength);
//if (maxLength = GL_TRUE) then exit;
if (maxLength = 1) then exit; //DGL GL_TRUE
maxLength := 4096;
setlength(s, maxLength);
glGetProgramInfoLog(glObjectID, maxLength, @maxLength, @s[1]);
if maxLength < 1 then begin
if GLErrorStr = '' then
GLErrorStr := ('Program compile error (unspecified)');
exit
end;
s:=trim(s);
if (length(s) < 2) then exit;
if GLErrorStr = '' then
GLErrorStr := ('Program compile error '+s);
end;
function initVertFrag(vert, frag: string): GLuint;
var
fs, vs: GLuint;
begin
result := 0;
vs := 0;
glGetError();
result := glCreateProgram();
if (length(vert) > 0) then begin
vs := compileShaderOfType(GL_VERTEX_SHADER, vert);
if (vs = 0) then exit;
glAttachShader(result, vs);
end;
fs := compileShaderOfType(GL_FRAGMENT_SHADER, frag);
if (fs = 0) then exit;
glAttachShader(result, fs);
glLinkProgram(result);
ReportCompileProgramError(result);
if (length(vert) > 0) then begin
glDetachShader(result, vs);
glDeleteShader(vs);
end;
glDetachShader(result, fs);
glDeleteShader(fs);
GetError(123,'newShader');
glGetError();
end;
function initVertFragX(vert, frag: string): GLuint;
var
fr, vt: GLuint;
begin
result := 0;
glGetError(); //<- ignore proior errors
vt := compileShaderOfType(GL_VERTEX_SHADER, vert);
fr := compileShaderOfType(GL_FRAGMENT_SHADER, frag);
if (fr = 0) or (vt = 0) then exit;
result := glCreateProgram();
glAttachShader(result, vt);
glAttachShader(result, fr);
glBindFragDataLocation(result, 0, 'FragColor');
glLinkProgram(result);
glDeleteShader(vt);
glDeleteShader(fr);
GetError(1,'initX');
glGetError(); //<- ignore proior errors
end;
procedure LoadBufferData (isInit: boolean);
const
kATTRIB_POINT = 0;
kATTRIB_COLOR = 1;
var
verts: array[0..2] of TAAPLVertex;
begin
verts[0].position[0] := gOffsetXY[1] + gSize;
verts[0].position[1] := gOffsetXY[2] - gSize;
verts[0].color[0] := 1;
verts[0].color[1] := 0;
verts[0].color[2] := 0;
verts[1].position[0] := gOffsetXY[1] - gSize;
verts[1].position[1] := gOffsetXY[2] - gSize;
verts[1].color[0] := 0;
verts[1].color[1] := 1;
verts[1].color[2] := 0;
verts[2].position[0] := gOffsetXY[1];
verts[2].position[1] := gOffsetXY[2] + gSize;
verts[2].color[0] := 0;
verts[2].color[1] := 0;
verts[2].color[2] := 2;
if (not isInit) then begin
glBindBuffer(GL_ARRAY_BUFFER, gShader.vbo_point);
glBufferSubData(GL_ARRAY_BUFFER,0,sizeof(verts), @verts[0]);
glBindBuffer(GL_ARRAY_BUFFER, 0);
exit;
end;
glGenBuffers(1, @gShader.vbo_point);
glBindBuffer(GL_ARRAY_BUFFER, gShader.vbo_point);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), @verts[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Prepare vertrex array object (VAO)
// glGenVertexArrays intoduced with OpenGL 3.0
glGenVertexArrays(1, @gShader.vao_point);
glBindVertexArray(gShader.vao_point);
glBindBuffer(GL_ARRAY_BUFFER, gShader.vbo_point);
glVertexAttribPointer(kATTRIB_POINT, 2, GL_FLOAT, GL_FALSE, 5*4, PChar(0));
glEnableVertexAttribArray(kATTRIB_POINT);
glVertexAttribPointer(kATTRIB_COLOR, 3, GL_FLOAT, GL_FALSE, 5*4, PChar(sizeof(single)*2));
glEnableVertexAttribArray(kATTRIB_COLOR);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
gShader.uniform_viewportSize := glGetUniformLocation(gShader.shaderProgram, pAnsiChar('viewportSize'));
end;
{$ENDIF}
procedure MyGlutInit(ParseCmdLine: Boolean); // у меня уже создана, скопирую
var
Cmd: array of PChar;
CmdCount, i: Integer;
begin
if ParseCmdLine then
CmdCount := ParamCount + 1
else
CmdCount := 1;
SetLength(Cmd, CmdCount);
for i := 0 to CmdCount - 1 do
Cmd[i] := PChar(ParamStr(i));
GlutInit(@CmdCount, @Cmd);
end;
procedure MyDrawScene; cdecl;
{$IfnDef CORE_GL}
var
i, j: Integer;
{$EndIf}
begin
{$IfnDef CORE_GL}
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glLoadIdentity;
glColor3f(0, 0, 0);
for i := 1 to 250000 do
begin
j := Random(3) + 1;
p[1] := (p[1] + vertices[j, 1]) / 2;
p[2] := (p[2] + vertices[j, 2]) / 2;
glBegin(GL_POINTS);
glVertex2fv(@p);
glEnd;
end;
{$Else}
LoadBufferData(false);
glClearColor(0.0, 0.0, 0.7, 1.0); //Set blue background
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glUseProgram(gShader.shaderProgram);
glUniform2f(gShader.uniform_viewportSize, AppWidth, AppHeight);
glBindVertexArray(gShader.vao_point);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
glBindVertexArray(0);
glUseProgram(0);
{$ENDIF}
glutSwapBuffers;
end;
procedure MyResizeScene(width, height: Integer); cdecl;
begin
if height = 0 then height := 1;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity;
gluOrtho2D(0, width, 0, height);
// gluPerspective(45, width / height, 0.1, 1000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
end;
procedure GLKeyboard(Key: Byte; x, y: LongInt); cdecl;
begin
if Key = 27 then halt(0);
end;
var
ScreenWidth, ScreenHeight: Integer;
begin
{$IfDef MacOSAll}
// для MacOS вручную прописываем путь, куда установили FreeGlut
// for MacOS, manually write the path where FreeGlut was installed
LoadFreeGlut(LoadLibrary('/usr/local/Cellar/freeglut/3.2.1/lib/libglut.dylib'));
// у меня был путь "/usr/local/Cellar/freeglut/3.2.1" оставшуюся часть
// надо добавить (не знаю, может у кого другой путь будет) !!! "lib/libglut.dylib" !!!!
{$EndIf}
Randomize;
MyGlutInit(True);
glutInitDisplayMode(GLUT_DOUBLE or GLUT_RGB or GLUT_DEPTH);
glutInitWindowSize(AppWidth, AppHeight);
ScreenWidth := glutGet(GLUT_SCREEN_WIDTH);
ScreenHeight := glutGet(GLUT_SCREEN_HEIGHT);
glutInitWindowPosition((ScreenWidth - AppWidth) div 2, (ScreenHeight - AppHeight) div 2);
// запрос контекста!!! В Glut нет.
// context request!!! In Glut no.
{$IfDef CORE_GL}
glutInitContextProfile(GLUT_CORE_PROFILE);
glutInitContextVersion(3, 3);
{$Else}
glutInitContextProfile(GLUT_CORE_PROFILE);
glutInitContextVersion(2, 1);
{$EndIf}
glutCreateWindow('OpenGL - Glut');
{$IfDef CORE_GL}
Load_GL_version_3_3_CORE();
gShader.shaderProgram := initVertFrag(kVert, kFrag);
LoadBufferData(true);
{$EndIf}
glClearColor(0.18, 0.20, 0.66, 0);
glutDisplayFunc(@MyDrawScene);
glutReshapeFunc(@MyResizeScene);
glutKeyboardFunc(@GLKeyboard);
glutMainLoop;
end.