{$reference System.Windows.Forms.dll} {$reference System.Drawing.dll} // Данный пример демонстрирует запуск простейшей программы с модулем OpenGL // Примите во внимание, что методы из gl_gdi. - могут служить только временной заменой в серьёзной программе // (По крайней мере в данной версии. В будущем, возможно, gl_gdi будет улучшено) // Они использованы тут, чтоб пример был проще uses System.Windows.Forms; uses System.Drawing; uses System; uses OpenGL; {$apptype windows} // убирает консоль var gl: OpenGL.gl; {$region Shader} function InitShader(fname: string; st: ShaderType): gl_shader; begin Result := gl.CreateShader(st); var source := ReadAllText(fname); gl.ShaderSource(Result, 1, new string[](source), new integer[](source.Length) ); gl.CompileShader(Result); // получаем состояние успешности компиляции // 1=успешно // 0=ошибка var comp_ok: integer; gl.GetShaderiv(Result, ShaderParameterName.COMPILE_STATUS, comp_ok); if comp_ok = 0 then begin // узнаём нужную длинную строки var l: integer; gl.GetShaderiv(Result, ShaderParameterName.INFO_LOG_LENGTH, l); // выделяем достаточно памяти чтоб сохранить строку var ptr := System.Runtime.InteropServices.Marshal.AllocHGlobal(l); // получаем строку логов gl.GetShaderInfoLog(Result, l, IntPtr.Zero, ptr); // преобразовываем в управляемую строку var log := System.Runtime.InteropServices.Marshal.PtrToStringAnsi(ptr); Writeln(log); // и в конце обязательно освобождаем памяти, чтобы не было утечек памяти System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr); end; end; {$endregion Shader} {$region Program} function InitProgram(vertex_shader, fragment_shader: gl_shader): gl_program; begin Result := gl.CreateProgram; gl.AttachShader(Result, vertex_shader); if fragment_shader<>gl_shader.Zero then gl.AttachShader(Result, fragment_shader); gl.LinkProgram(Result); // всё то же самое что и у шейдеров var link_ok: integer; gl.GetProgramiv(Result, ProgramPropertyARB.LINK_STATUS, link_ok); if link_ok = 0 then begin var l: integer; gl.GetProgramiv(Result, ProgramPropertyARB.INFO_LOG_LENGTH, l); var ptr := System.Runtime.InteropServices.Marshal.AllocHGlobal(l); gl.GetProgramInfoLog(Result, l, IntPtr.Zero, ptr); var log := System.Runtime.InteropServices.Marshal.PtrToStringAnsi(ptr); Writeln(log); System.Runtime.InteropServices.Marshal.FreeHGlobal(ptr); end; end; {$endregion Program} const dy = -Sin(Pi / 6) / 2; begin // Создаёт и настраиваем окно var f := new Form; f.StartPosition := FormStartPosition.CenterScreen; f.ClientSize := new Size(500, 500); f.FormBorderStyle := FormBorderStyle.Fixed3D; // Если окно закрылось - надо сразу завершить программу f.Closed += (o,e)->Halt(); // Настраиваем поверхность рисования var hdc := gl_gdi.InitControl(f); // Настраиваем перерисовку gl_gdi.SetupControlRedrawing(f, hdc, EndFrame-> begin {$region Настройка глобальных параметров OpenGL} // При создании экземпляра OpenGL.gl инициализируются некоторые функции // Это необходимо для всех функций из OpenGL1.2 и выше, потому что они локальны для контекста OpenGL gl := new OpenGL.gl; {$endregion Настройка глобальных параметров OpenGL} {$region Инициализация переменных} var vertex_pos_buffer: gl_buffer; gl.CreateBuffers(1, vertex_pos_buffer); gl.NamedBufferData( vertex_pos_buffer, new IntPtr(3*sizeof(Vec2f)), ArrGen(3, i-> begin var rot := i * Pi * 2 / 3; Result := new Vec2f( Sin(rot), Cos(rot) + dy ); end), VertexBufferObjectUsage.STATIC_DRAW ); var vertex_clr_buffer: gl_buffer; gl.CreateBuffers(1, vertex_clr_buffer); gl.NamedBufferData( vertex_clr_buffer, new IntPtr(3*sizeof(Vec3f)), new Vec3f[]( new Vec3f(1,0,0), new Vec3f(0,1,0), new Vec3f(0,0,1) ), VertexBufferObjectUsage.STATIC_DRAW ); var element_buffer: gl_buffer; gl.CreateBuffers(1, element_buffer); gl.NamedBufferData( element_buffer, new IntPtr(3*sizeof(byte)), new byte[]( 0,1,2 ), VertexBufferObjectUsage.STATIC_DRAW ); var vertex_shader := InitShader('Rot Triangle 1.vertex.glsl', ShaderType.VERTEX_SHADER); // var fragment_shader := InitShader('fragment.glsl', ShaderType.FRAGMENT_SHADER); var sprog := InitProgram(vertex_shader, gl_shader.Zero {fragment_shader}); var uniform_rot_k := gl.GetUniformLocation(sprog, 'rot_k'); var attribute_position := gl.GetAttribLocation(sprog, 'position'); var attribute_color := gl.GetAttribLocation(sprog, 'color'); var t := new System.Diagnostics.Stopwatch; t.Start; {$endregion Инициализация переменных} while true do begin // очищаем окно в начале перерисовки gl.Clear(ClearBufferMask.COLOR_BUFFER_BIT); gl.UseProgram(sprog); gl.Uniform1f(uniform_rot_k, Cos( t.Elapsed.Ticks * 0.0000002 ) ); gl.BindBuffer(BufferTargetARB.ARRAY_BUFFER, vertex_pos_buffer); gl.VertexAttribPointer( attribute_position, 2, VertexAttribPointerType.FLOAT, false, 8, IntPtr.Zero ); gl.EnableVertexAttribArray(attribute_position); gl.BindBuffer(BufferTargetARB.ARRAY_BUFFER, vertex_clr_buffer); gl.VertexAttribPointer( attribute_color, 3, VertexAttribPointerType.FLOAT, false, 12, IntPtr.Zero ); gl.EnableVertexAttribArray(attribute_color); gl.BindBuffer(BufferTargetARB.ELEMENT_ARRAY_BUFFER, element_buffer); gl.DrawElements( PrimitiveType.TRIANGLES, 3, DrawElementsType.UNSIGNED_BYTE, IntPtr.Zero ); gl.DisableVertexAttribArray(attribute_position); gl.DisableVertexAttribArray(attribute_color); // получаем тип последней ошибки var err := gl.GetError; // и если ошибка есть - выводим её if err<>ErrorCode.NO_ERROR then Writeln(err); gl.Finish; // EndFrame меняет местами буферы и ждёт vsync EndFrame; end; end); Application.Run(f); end.