Показаны сообщения с ярлыком Pascal. Показать все сообщения
Показаны сообщения с ярлыком Pascal. Показать все сообщения

воскресенье, 2 февраля 2025 г.

Пример приложения печатающий текст в стиле терминала из фильма Matrix "Матрица"

Спустя 12 лет довел до ума пример приложения, который печатает текст в стиле терминала из фильма Матрица с DelphiX на OpenGL. Оригинальный пример, на основе которого сделан мой пример, взят с сайта Delphi-Graphics. Мой код базируется на Delphi, OpenGL, WinAPI. Код моего примера оставляю без комментарий, т. к. написание проводилось без детального разбора работы алгоритма оригинального приложения и осуществлялся банальный подбор функций OpenGL и их параметров. На рисунке 1 представлена работа моего примера в Windows 10. 

Рисунок 1. Пример приложения вывода текста в стиле терминала из фильма "Матрица"

program matrix;

uses
  Windows,
  Messages,
  OpenGL;

var
  h_Rc: HGLRC;
  h_Dc: HDC;
  h_Wnd: HWND;
  base: GLuint;

  keys: array [0..255] of BOOL;

  text: array[0..4] of String = ('Wake up, Neo.',
                                 'The Matrix has you.',
                                 'Follow the White Rabbit.',
                                 'Disconnecting...',
                                 '');

  Active: bool = true;
  FullScreen:bool = true;
  f,z: boolean;
  a,b: byte;
  sx: integer;
  cur: byte;
  all: string;

procedure ReSizeGLScene(Width: GLsizei; Height: GLsizei);
begin
  if (Height=0) then
     Height:=1;
  glViewport(0, 0, Width, Height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, Width, Height, 0, 1, -1);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;
end;

procedure BuildFont;
var
  font: HFONT;
  oldfont: HFONT;
begin

  base := glGenLists(96);

  font := CreateFont( -30,
                        0,
                        0,
                        0,
                        FW_BOLD,
                        0,
                        0,
                        0,
                        ANSI_CHARSET,
                        OUT_TT_PRECIS,
                        CLIP_DEFAULT_PRECIS,
                        ANTIALIASED_QUALITY,
                        FF_DONTCARE or DEFAULT_PITCH,
                        'Courier New');

  oldfont := SelectObject(h_DC, font);                       
  wglUseFontBitmaps(h_DC, 32, 96, base);
  SelectObject(h_DC, oldfont);
  DeleteObject(font);
end;

procedure KillFont;
begin
  glDeleteLists(base, 96);
end;

procedure glPrint(const Fmt: String);
begin

if Fmt = '' then
  Exit;

glPushAttrib(GL_LIST_BIT);
glListBase(base - 32);
glCallLists(Length(Fmt), GL_UNSIGNED_BYTE, Pointer(Fmt));
glPopAttrib();

end;

function IntToStr(Num: Integer) : String;
begin
  Str(Num, Result);  
end;

function InitGL:bool;
begin

  glClearColor(0.0, 0.0, 0.0, 0.0);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(0, 640, 480, 0, 0, 1);
  glDisable(GL_DEPTH_TEST);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  BuildFont();

  a:=0;
  b:=0;
  sx:=0;
  cur:=0;

  Result:=true;
end;

procedure addchar;
begin
  if length(all)=length(text[cur]) then
  begin
    inc(cur);
    sx:=0;
    z:=false;
    all:='';
    Exit;
  end;
  if cur<=5 then
  begin
    all := all + text[cur][length(all)+1];
  end
  else
  begin
    exit;
  end;
end;

function DrawGLScene():bool;
var
  i: integer;
  kk2:integer;
  kk: integer;
begin
  glClear(GL_COLOR_BUFFER_BIT);

  glEnable(GL_ALPHA_TEST);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  glLoadIdentity();

  if not z then
    inc(sx);
  if sx=200 then
    z:=true;

  if z then
  begin
    inc(B);
    if b=20 then addchar;
    if b>20 then b:=0;
  end;

  if not f then
    inc(a,5)
  else dec(a,5);

  if (a>=255)or(a=0) then f:=not f;

  glColor3f(0.196078, 0.8, 0.196078);
  for i := 0 to cur - 1 do
  begin
    glRasterPos2f(0.0, 20.0 + i*30);
    glPrint(text[i]);
  end;

  if i=5 then
  begin
    i:=0;
    cur:=0;
    a:=0;
    b:=0;
    sx:=0;
    z:=false;
    f:=False;
    all:='';
    glClearColor(0, 0, 0, 0);
    glClear(GL_COLOR_BUFFER_BIT);
  end;

  kk := 18*length(all);
  kk2 := cur*30;

  glRasterPos2f(0.0, 20.0 + cur*30);
  glPrint(all);

  glColor4f(0.196078, 0.8, 0.196078, a / 255); // Colour LimeGreen
  glRectf(0.0+kk, 0.0+kk2, 23.0+kk, 23.0+kk2);

  glDisable(GL_BLEND);
  glDisable(GL_ALPHA_TEST);

  Result := true;
end;


function WndProc(hWnd: HWND;
                 message: UINT;
                 wParam: WPARAM;
                 lParam: LPARAM):
                                  LRESULT; stdcall;
begin
  if message=WM_SYSCOMMAND then
  begin
      case wParam of
        SC_SCREENSAVE,SC_MONITORPOWER:
          begin
            result:=0;
            exit;
          end;
      end;
  end;
  
  case message of
    WM_ACTIVATE:
      begin
        if (Hiword(wParam)=0) then
          active:=true
        else
          active:=false;
        Result:=0;
      end;
    WM_CLOSE:
      Begin
        PostQuitMessage(0);
        result:=0
      end;
    WM_KEYDOWN:
      begin
        keys[wParam] := TRUE;
        result:=0;
      end;
    WM_KEYUP:
      begin
    	  keys[wParam] := FALSE;
        result:=0;
      end;
    WM_SIZe:
      begin
    	  ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));
        result:=0;
      end
    else

      begin
      	Result := DefWindowProc(hWnd, message, wParam, lParam);
      end;
    end;
end;


procedure KillGLWindow;
begin
  if FullScreen then
    begin
      ChangeDisplaySettings(devmode(nil^),0);
      showcursor(true);
    end;
  if h_rc<> 0 then
    begin
      if (not wglMakeCurrent(h_Dc,0)) then
        MessageBox(0,'Release of DC and RC failed.',' Shutdown Error',MB_OK or MB_ICONERROR);
      if (not wglDeleteContext(h_Rc)) then
        begin
          MessageBox(0,'Release of Rendering Context failed.',' Shutdown Error',MB_OK or MB_ICONERROR);
          h_Rc:=0;
        end;
    end;
  if (h_Dc=1) and (releaseDC(h_Wnd,h_Dc)<>0) then
    begin
      MessageBox(0,'Release of Device Context failed.',' Shutdown Error',MB_OK or MB_ICONERROR);
      h_Dc:=0;
    end;
  if (h_Wnd<>0) and (not destroywindow(h_Wnd))then
    begin
      MessageBox(0,'Could not release hWnd.',' Shutdown Error',MB_OK or MB_ICONERROR);
      h_Wnd:=0;
    end;
  if (not UnregisterClass('OpenGL',hInstance)) then
    begin
      MessageBox(0,'Could Not Unregister Class.','SHUTDOWN ERROR',MB_OK or MB_ICONINFORMATION);
    end;
end;


function CreateGlWindow(title:Pchar; width,height,bits:integer;FullScreenflag:bool):boolean stdcall;
var
  Pixelformat: GLuint;
  wc:TWndclass;
  dwExStyle:dword;
  dwStyle:dword;
  pfd: pixelformatdescriptor;
  dmScreenSettings: Devmode;
  h_Instance:hinst;
  WindowRect: TRect;
begin
  WindowRect.Left := 0;
  WindowRect.Top := 0;
  WindowRect.Right := width;
  WindowRect.Bottom := height;
  h_instance:=GetModuleHandle(nil);
  FullScreen:=FullScreenflag;
  with wc do
    begin
      style:=CS_HREDRAW or CS_VREDRAW or CS_OWNDC;
      lpfnWndProc:=@WndProc;
      cbClsExtra:=0;
      cbWndExtra:=0;
      hInstance:=h_Instance;
      hIcon:=LoadIcon(0,IDI_WINLOGO);
      hCursor:=LoadCursor(0,IDC_ARROW);
      hbrBackground:=0;
      lpszMenuName:=nil;
      lpszClassName:='OpenGl';
    end;
  if  RegisterClass(wc)=0 then
    begin
      MessageBox(0,'Failed To Register The Window Class.','Error',MB_OK or MB_ICONERROR);
      Result:=false;
      exit;
    end;
  if FullScreen then
    begin
      ZeroMemory( @dmScreenSettings, sizeof(dmScreenSettings) );
      with dmScreensettings do
        begin
          dmSize := sizeof(dmScreenSettings);
          dmPelsWidth  := width;
	        dmPelsHeight := height;
          dmBitsPerPel := bits;
          dmFields     := DM_BITSPERPEL or DM_PELSWIDTH or DM_PELSHEIGHT;
        end;

      if (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN))<>DISP_CHANGE_SUCCESSFUL THEN
        Begin

          if MessageBox(0,'This FullScreen Mode Is Not Supported. Use Windowed Mode Instead?'
                                             ,'Matrix',MB_YESNO or MB_ICONEXCLAMATION)= IDYES then
                FullScreen:=false
          else
            begin

              MessageBox(0,'Program Will Now Close.','Error',MB_OK or MB_ICONERROR);
              Result:=false;
              exit;
            end;
          end;
    end;
  if FullScreen then
    begin
      dwExStyle:=WS_EX_APPWINDOW;
      dwStyle:=WS_POPUP or WS_CLIPSIBLINGS or WS_CLIPCHILDREN;
      Showcursor(false);
    end
  else
    begin
      dwExStyle:=WS_EX_APPWINDOW or WS_EX_WINDOWEDGE;
      dwStyle:=WS_OVERLAPPEDWINDOW or WS_CLIPSIBLINGS or WS_CLIPCHILDREN;
    end;
  AdjustWindowRectEx(WindowRect,dwStyle,false,dwExStyle);

  H_wnd:=CreateWindowEx(dwExStyle,
                               'OpenGl',
                               Title,
                               dwStyle,
                               0,0,
                               WindowRect.Right-WindowRect.Left,
                               WindowRect.Bottom-WindowRect.Top,
                               0,
                               0,
                               hinstance,
                               nil);
  if h_Wnd=0 then
    begin
      KillGlWindow();
      MessageBox(0,'Window creation error.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  with pfd do
    begin
      nSize:= SizeOf( PIXELFORMATDESCRIPTOR );
      nVersion:= 1;
      dwFlags:= PFD_DRAW_TO_WINDOW
        or PFD_SUPPORT_OPENGL
        or PFD_DOUBLEBUFFER;
      iPixelType:= PFD_TYPE_RGBA;
      cColorBits:= bits;
      cRedBits:= 0;
      cRedShift:= 0;
      cGreenBits:= 0;
      cBlueBits:= 0;
      cBlueShift:= 0;
      cAlphaBits:= 0;
      cAlphaShift:= 0;
      cAccumBits:= 0;
      cAccumRedBits:= 0;
      cAccumGreenBits:= 0;
      cAccumBlueBits:= 0;
      cAccumAlphaBits:= 0;
      cDepthBits:= 16;
      cStencilBits:= 0;
      cAuxBuffers:= 0;
      iLayerType:= PFD_MAIN_PLANE;
      bReserved:= 0;
      dwLayerMask:= 0;
      dwVisibleMask:= 0;
      dwDamageMask:= 0;
    end;
  h_Dc := GetDC(h_Wnd);
  if h_Dc=0 then
    begin
      KillGLWindow();
      MessageBox(0,'Cant''t create a GL device context.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  PixelFormat := ChoosePixelFormat(h_Dc, @pfd);
  if (PixelFormat=0) then
    begin
      KillGLWindow();
      MessageBox(0,'Cant''t Find A Suitable PixelFormat.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  if (not SetPixelFormat(h_Dc,PixelFormat,@pfd)) then
    begin
      KillGLWindow();
      MessageBox(0,'Cant''t set PixelFormat.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  h_Rc := wglCreateContext(h_Dc);
  if (h_Rc=0) then
    begin
      KillGLWindow();
      MessageBox(0,'Cant''t create a GL rendering context.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  if (not wglMakeCurrent(h_Dc, h_Rc)) then
    begin
      KillGLWindow();
      MessageBox(0,'Cant''t activate the GL rendering context.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  ShowWindow(h_Wnd,SW_SHOW);
  SetForegroundWindow(h_Wnd);
  SetFOcus(h_Wnd);
  ReSizeGLScene(width,height);
  if (not InitGl()) then
    begin
      KillGLWindow();
      MessageBox(0,'initialization failed.','Error',MB_OK or MB_ICONEXCLAMATION);
      Result:=false;
      exit;
    end;
  Result:=true;
end;


function WinMain(hInstance: HINST;
		 hPrevInstance: HINST;
		 lpCmdLine: PChar;
		 nCmdShow: integer):
                        integer; stdcall;
var
  msg: TMsg;
  done: Bool;

begin
  done:=false;

  if MessageBox(0,'Would You Like To Run In FullScreen Mode?','Start FullScreen', MB_YESNO or MB_ICONQUESTION)=IDNO then
    FullScreen:=false
  else
    FullScreen:=true;

  if not CreateGLWindow('Matrix',640,480,16,FullScreen) then
  begin
    Result := 0;
    exit;
  end;

  while not done do
  begin
    if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then
    begin
      if msg.message=WM_QUIT then
        done:=true
      else
      begin
        TranslateMessage(msg);
        DispatchMessage(msg);
      end;
    end
    else
    begin

      if (Active and (not DrawGLScene()) or keys[VK_ESCAPE]) then
      begin
        done:=true;
      end;

      if (keys[VK_F1]) then
      begin
        Keys[VK_F1] := false;
        KillGLWindow();
        FullScreen := not FullScreen;

        if not CreateGLWindow('Matrix',640,480,16,fullscreen) then Result := 0;
      end;

      SwapBuffers(h_Dc);
    end;
  end;

  KillFont();
  killGLwindow();

  result:=msg.wParam;
end;

begin
  WinMain( hInstance, hPrevInst, CmdLine, CmdShow );
end.

вторник, 9 февраля 2016 г.

Lazarus World. Используем True Type Fonts шрифты при помощи библиотеки SDL_ttf



Внимание! Статья основна из статей посвященных SDL 1.2 с сайта http://www.freepascal-meets-sdl.net/


Давайте попробуем загрузить шрифт True Type Fonts и вывести текст в нашем SDL окне. Первое что нам понадобится, это создать SDL окно. Как это сделать я писал в статье Lazarus World. Подключаем библиотеку SDL 1.2. Вторым шагом будет найти и скачать True Type Fonts шрифт. Я скачал его отсюда. Третье, что нам необходимо сделать, это установить библиотеку SDL_TTF используя следующую команду в терминале:

sudo apt-get install libsdl-ttf2.0-0 libsdl-ttf2.0-dev

Создайте папку хранения нашего проекта, например ~/projects/lazarus/sdl/sdl_p2/. Сохраните проект под именем sdl_p2.lpr. Скопируйте шрифт в папку с проектом, файл шрифта называется cour.ttf. Нам осталось в редактор кода добавить код, собрать его и запустить на исполнение.

 Рисунок 1. Результат работы программы

program sdl_p2;

{$mode objfpc}{$H+}

uses sdl, sdl_ttf;
var
  screen :pSDL_SURFACE;
  fontface:pSDL_SURFACE;
  loaded_font: pointer;
  colour_font, colour_font2:pSDL_COLOR;
  i:BYTE;
  loopstop: boolean = FALSE;
  event: pSDL_EVENT;

begin
     SDL_Init(SDL_INIT_VIDEO);
     screen := SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
     if screen = NIL then Halt;

     if Ttf_Init = -1 then Halt;
     loaded_font := TTF_OPENFONT('cour.ttf', 60);

     new(colour_font);
     new(colour_font2);
     colour_font^.r:=255; colour_font^.g:=0; colour_font^.b:=0;
     colour_font2^.r:=0; colour_font2^.g:=255; colour_font2^.b:=255;

     fontface:=TTF_RENDERTEXT_SHADED(loaded_font
               'Hello World!', colour_font^, colour_font2^);

     new(event);

     while loopstop = FALSE do
     begin
          if SDL_PollEvent(event) = 1 then
          begin
               case event^.type_ of
                    SDL_KEYDOWN:
                    begin
                         if event^.key.keysym.sym = 27  
                         then loopstop := TRUE;
                    end;
                    SDL_QUITEV:
                    begin
                         loopstop := TRUE;
                    end;
               end;
          end;
          SDL_BLITSURFACE(fontface, NIL, screen, NIL);
          SDL_FLIP(screen);
     end;
     Dispose(colour_font);
     Dispose(colour_font2);
     Dispose(event);
     SDL_FreeSurface(screen);
     SDL_FreeSurface(fontface);
     TTF_CloseFont(loaded_font);
     TTF_QUIT;
     SDL_QUIT;
end.


syntax highlighted by Code2HTML, v. 0.9.1
 

Lazarus World. Подключаем библиотеку SDL 1.2


Внимание! Статья основна из статей посвященных SDL 1.2 с сайта http://www.freepascal-meets-sdl.net/

Для того чтобы начать работать с библиотекой SDL 1.2 нам с вами понадобятся заголовочные файлы переведенные в язык Pascal и файлы динамических библиотек (файлы запускаемого окружения), которые используется вместе с нашей программой в момент запуска.
Мне известны два проекта, в рамках которых осуществлен перевод заголовочных файлов на язык Pascal. Ниже я приведу названия этих проектов и ссылки на ресурсы, откуда их можно скачать.
Скачивать заголовочные файлы нам не придется, т.к. в составе компилятора freepascal они уже включены (начиная с версии fpc 2.2.2 http://wiki.freepascal.org/FPC_and_SDL ), т.е. если мы устанавливаем IDE Lazarus на Ubuntu 15.10, то все необходимые заголовочные файлы SDL 1.2 там уже есть. Расположены они по следующему пути:

/usr/share/fpcsrc/2.6.4/packages/sdl

Файлы динамических библиотек в Ubuntu 15.10 можно установить по следующей команде в терминале:

sudo apt-get install libsdl1.2debian libsdl1.2-dev

Ну и не помешает установить весь необходимый инструментарий для сборки проектов, в частности туда входит компиляторы gcc, g++ и т.д.

sudo apt-get install build-essential

Теперь можно перейти к созданию нового проекта и настройки проекта в среде Lazarus.

Запустите Lazarus и создайте новый проект. Для это выберите пункт меню «File» (Файл) – подпункт «New...» (Создать...). В открывшемся окне, с именем «New..» (Создать...), в левой части выберите раздел «Project» (Проект) и потом выберите подраздел «Program» (Программа), потом нажмите кнопку «OK».

Создайте папку хранения нашего проекта, например ~/projects/lazarus/sdl/sdl_p1/. Сохраните проект под именем sdl_p1.lpr. Для этого выберите пункт меню «File» (Файл) - подпункт меню «Save As...» (Сохранить как) и указать путь до папки хранения нашего проекта.

Настойка проекта завершена. Нам осталось в редактор кода добавить минимальный код SDL проекта, собрать его и запустить на исполнение.

program sdl_p1;

{$mode objfpc}{$H+}

uses sdl;
var
  screen :pSDL_SURFACE;
  loopstop: boolean = FALSE;
  event: pSDL_EVENT;

begin
     SDL_Init(SDL_INIT_VIDEO);
     screen := SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);

     new(event);

     while loopstop = FALSE do
     begin
          if SDL_PollEvent(event) = 1 then
          begin
               case event^.type_ of
                    SDL_KEYDOWN:
                    begin
                         if event^.key.keysym.sym = 27 
                         then loopstop := TRUE;
                    end;
                    SDL_QUITEV:
                    begin
                         loopstop := TRUE;
                    end;
               end;
          end;
     end;
     Dispose(event);
     SDL_FreeSurface(screen);
     SDL_QUIT;
end.  


syntax highlighted by Code2HTML, v. 0.9.1

воскресенье, 26 июля 2015 г.

Lazarus World. Порт приложения Particles "Частицы"

Очередная попытка порта приложения Particles "Частицы", которое было портировано с аналогичного приложения Particles "Частицы" написаного на языке программирование Delphi и с использованием библиотеки DelphiX (DirectX). Оригинальный код приложения, на основе которого сделан порт, взят сайта Delphi-Graphics. Код портирован на Lazarus с использованием OpenGL для отрисовки графики. Цель портирования - заставить работать приложение в операционной системе Ubuntu Linux. Код порта оставляю без комментарий, т. к. портирование проводилось без детального разбора работы алгоритма оригинального приложения и осуществлялся банальный подбор функций OpenGL и их параметров. На рисунке 1 предсталена работа портированного приложения в Ubuntu Linux.

Рисунок 1. Приложение «Частицы»

program lazarus_p2;

uses gl, glut, glu;

var
  ScreenWidth, ScreenHeight: Integer;
  SineMove : array[0..255] of integer; { Sine Table for Movement }
  CosineMove : array[0..255] of integer; { CoSine Table for Movement }
  SineTable : array[0..449] of integer; { Sine Table. 449 = 359 + 180 }
  CenterX, CenterY : Integer;
  LastUpdate: Integer;
const
  AppWidth = 640;
  AppHeight = 480;

procedure CalculateTables;
var
  wCount : Word;
begin
  { Precalculted Values for movement }

  for wCount := 0 to 255 do
  begin
    SineMove[wCount] := round( sin( pi*wCount/128 ) * 45 );
    CosineMove[wCount] := round( cos( pi*wCount/128 ) * 60 );
  end;

  { Precalculated Sine table. Only One table because cos(i) = sin(i + 90) }

  for wCount := 0 to 449 do
  begin
    SineTable[wCount] := round( sin( pi*wCount / 180 ) * 128);
  end;
end;



procedure PlotPoint(XCenter, YCenter, Radius, Angle: Word);
var
  X, Y : Word;

begin
  X := ( Radius * SineTable[90 + Angle]);

  {$ASMMODE intel}
  asm
     sar x, 7
  end;
  X := CenterX + XCenter + X;
  Y := ( Radius * SineTable[Angle] );
  asm
     sar y, 7
  end;

  Y := CenterY + YCenter + Y;
  if (X < AppWidth ) and ( Y < AppHeight ) then
  begin
  glBegin(GL_POINTS);
      glVertex2i(X, Y);
  glEnd;
  end;
end;



procedure DrawGLScene; cdecl;
const
  x : Word = 0;
  y : Word = 0;

  IncAngle = 12;

  XMove = 7;
  YMove = 8;

var
  CountAngle : Word;
  CountLong : Word;
  IncLong :Word;

begin
  glClear(GL_COLOR_BUFFER_BIT);

  IncLong := 2;
  CountLong := 20;

  { Draw Circle }

  repeat
    CountAngle := 0;
    repeat
      PlotPoint(CosineMove[( x + ( 200 - CountLong )) mod 255],
      SineMove[( y + ( 200 - CountLong )) mod 255], CountLong, CountAngle);
      inc(CountAngle, IncAngle);
    until CountAngle >= 360;

    { Another Circle, eventually another color }

    inc(CountLong, IncLong);

    if ( CountLong mod 3 ) = 0 then
    begin
      inc(IncLong);
    end;
  until CountLong >= 270;

  { move x and y co-ordinates}

  x := XMove + x mod 255;
  y := YMove + y mod 255;

  glutSwapBuffers;
end;

procedure ReSizeGLScene(Width, Height: Integer); cdecl;
begin
  glViewport(0, 0, Width, Height);
end;

procedure GLKeyboard(Key: Byte; X, Y: Longint); cdecl;
begin
  if Key = 27 then
    Halt(0);
end;

procedure InitializeGL;
begin
  glEnable( GL_POINT_SMOOTH );
  glColor3f(0, 0.3, 1);
  glPointSize(2);
  gluOrtho2D(0.0, 640.0, 0.0, 480.0);
  CenterX := AppWidth div 2;
  CenterY := AppHeight div 2;
  CalculateTables;
end;

begin
glutInit(@argc, argv);
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);
glutCreateWindow('ogl_p1');

InitializeGL;

glutDisplayFunc(@DrawGLScene);
glutIdleFunc(@DrawGLScene);
glutReshapeFunc(@ReSizeGLScene);
glutKeyboardFunc(@GLKeyboard);

glutMainLoop;
end.


syntax highlighted by Code2HTML, v. 0.9.1
 

среда, 8 июля 2015 г.

Lazarus World. Порт приложения Stars «Звёзды»



Представляю порт приложения Stars «Звёзды», которое было портировано с аналогичного приложения Stars «Звёзды» написаного на языке программирование Delphi и с использованием интерфейса GDI Windows. Оригинальный код приложения, на основе которого сделан порт, взят с сайта Delphi-Graphics. Код портирован на Lazarus с использованием OpenGL для отрисовки графики. Цель портирования - заставить работать приложение в операционной системе Ubuntu Linux. Код порта оставляю без комментарий, т. к. портирование проводилось без детального разбора работы алгоритма оригинального приложения и осуществлялся банальный подбор функций OpenGL и их параметров. На рисунке 1 предсталена работа портированного приложения в Ubuntu Linux. Так же рекомендую поиграться с параметрами OpenGL функций задания цвета звёзд и задания формы звёзд.


Рисунок 1. Приложение «Звезды»

program stars;

uses gl, glut, glu, SysUtils;

var
  Cmd: array of PChar;
  CmdCount: Integer;
  ScreenWidth, ScreenHeight: Integer;

const
  AppWidth = 800;
  AppHeight = 600;
  StarCount = 1000;

Type
  TStar = record
    x,y,z: integer;
    vx, vy, vc: integer;
  end;

var
  Star:array[0..StarCount - 1] of TStar;
  xcenter, ycenter: integer;
  starsize: integer;
  OldTick: GLuint;
  FramesCount: GLuint;
  StartTick: GLuint;


procedure InitStars;
var
s: integer;
begin
     for s:=0 to StarCount - 1 do
     begin
       With Star[s] do
       begin
         vx := -1;
         vy := -1;
         vc := 0;
         x := (Random(2 * xcenter) - xcenter) shl 7;
         y := (Random(2 * ycenter) - ycenter) shl 7;
         z := s + 1;
       end;
     end;
end;

procedure IdleFunc(); cdecl;
begin
     Sleep(1);

     OldTick := GlutGet(GLUT_ELAPSED_TIME);
     glutPostRedisplay;

end;

procedure DrawGLScene; cdecl;
var
   Title: array[0..80] of Char;
   s: integer;
begin
     glClear(GL_COLOR_BUFFER_BIT);

     for s := 0 to StarCount - 1 do
     begin
     with Star[s] do begin

         glColor3f(0.0, 0.0, 0.0);

         glBegin(GL_POINTS);
         glVertex2f(vx, vy);
         glEnd;

         vc := starsize div z;
         vx := x div z + xcenter - vc;
         vy := y div z + ycenter - vc;

         glPointSize(vc);

         glColor3f(1.0, 1.0, 1.0);

         glBegin(GL_POINTS);
         glVertex2f(vx, vy);
         glEnd;

         dec(Star[s].z,3);

         if z<1 then begin
            z:=StarCount;
            x:=(Random(2*xCenter)-xCenter) shl 7;
            y:=(Random(2*yCenter)-yCenter) shl 7;
         end;
     end;

     end;

     glutSwapBuffers;

     FramesCount := FramesCount + 1;
     if (GlutGet(GLUT_ELAPSED_TIME) <> StartTick) then
     begin
          Title := FloatToStrF(FramesCount*1000  
          div (GlutGet(GLUT_ELAPSED_TIME) - StartTick), ffFixed, 8, 0);
          Title := 'FPS: ' + Title;
          glutSetWindowTitle(Title);
     end;
end;

procedure ReSizeGLScene(Width, Height: Integer); cdecl;
begin
  glViewport(0, 0, Width, Height);
end;

procedure GLKeyboard(Key: Byte; X, Y: Longint); cdecl;
begin
  if Key = 27 then
    Halt(0);
end;

procedure InitializeGL;
begin
     glClearColor(0.0, 0.0, 0.0, 0.0);
     gluOrtho2D(0, AppWidth - 1, 0, AppHeight - 1);
end;

procedure InitApp;
begin
     OldTick := GlutGet(GLUT_ELAPSED_TIME);
     StartTick := OldTick;
     FramesCount := 0;

     xcenter := AppWidth div 2;
     ycenter := AppHeight div 2;
     starsize:=xcenter+ycenter;
end;

begin

CmdCount := 1;
SetLength(Cmd, CmdCount);
Cmd[CmdCount-1] := PChar(ParamStr(CmdCount-1));

glutInit(@CmdCount, @Cmd);

glutInitDisplayMode(GLUT_DOUBLE or GLUT_RGB);

glutInitWindowSize(AppWidth, AppHeight);

ScreenWidth := glutGet(GLUT_SCREEN_WIDTH);
ScreenHeight := glutGet(GLUT_SCREEN_HEIGHT);

glutInitWindowPosition((ScreenWidth - AppWidth) div 2,
   (ScreenHeight - AppHeight) div 2);

glutCreateWindow('stars');

InitApp;
InitStars;
InitializeGL;

glutDisplayFunc(@DrawGLScene);
glutIdleFunc(@DrawGLScene);
glutReshapeFunc(@ReSizeGLScene);
glutKeyboardFunc(@GLKeyboard);

glutMainLoop;

end.


syntax highlighted by Code2HTML, v. 0.9.1

суббота, 30 ноября 2013 г.

Lazarus World. Используем GLX расширение для связи OpenGL с X Window System


Для создания окна будем использовать библиотеку xlib. Запустите Lazarus и создайте новый проект, для этого выберите пункт меню File>New>Program и нажмите кнопку OK (Смотрите рисунок 1). Назовите его ogl_p3.lpr и сохраните проект в домашней директории пользователя /home/[имя пользователя]/Projects/lazarus/ogl_p3/.

Рисунок 1. Создание нового проекта

Чтобы сохранить проект под выбранным именем, нажмите пункт меню File>Save. В качестве пути сохранения проекта укажите каталог который вы создали ранее.

Если посмотреть в редактор кода среды Lazarus, то можно увидеть уже введенный стартовый код проекта. Удалим лишнее и оставим только то, что нам пригодится в дальнейшем:

program ogl_p3;
uses
begin
end.

Теперь в секции uses подключим необходимые модули:

1) для работы с функциями связывающие opengl с x window system (glx)
2) для работы с функциями создания окна x window system (x, xutil, xlib)
3) для работы с функциями OpenGL (gl, glu)

Таким образом секция uses у нас примит вид:

uses glx, x, xutil, xlib, gl, glu;

Выше секции uses укажите режим синтаксиса совместимый с delphi

{$MODE delphi}

После секции uses создадим секцию глобальных переменных var, в данной секции определим следующие переменные:

var
  dpy: PDisplay;
  visinfo: PXVisualInfo;
  Attr: Array[0..10] of integer =
   (GLX_DEPTH_SIZE, 16,
    GLX_RGBA,
    GLX_RED_SIZE, 1,
    GLX_GREEN_SIZE, 1,
    GLX_BLUE_SIZE, 1,
    GLX_DOUBLEBUFFER,
    none);
  cm: TColormap;
  winAttr: TXSetWindowAttributes;
  win :TWindow;
  glXCont: GLXContext;

1) Указатель на структуру Display с именем dpy, которая определена в xlib и содержит информацию о соединении с X-сервером.
2) Указатель на структуру XvisualInfo c именем visinfo, которая определена в xlib и содержит информацию о визуальных характеристиках поддерживаемых экраном X-сервера.
3) Attr, массив атрибутов визуальных характеристик, которые мы запрашиваем у X-сервера.
4) cm хранит информацию о новой цветовой палитре окна, тип Tcolormap.
5) Структура TXSetWindowAttributes с именем winAttr, хранит все необходимые атрибуты для создания нового окна.
6) Идентификатор, с именем win, созданного окна типа Twindow.
7) Переменная хранящая информацию о созданном контексте рендеринга OpenGL.

Для начала нам нужно определится, что мы будем рисовать с помощью функций OpenGL. В книге Эдварда Эйнджела «Интерактивная компьютерная графика. Вводный курс на базе OpenGL» 2-е издание 2001г. написан си код алгоритма построения треугольника Серпинского. Так что попробуем его нарисовать.

Далее определим новый тип:

type
  point2 = array[1..2] of GLfloat;

Этот новый тип point2, мы будем использовать для описания координат одной точки.

Далее определи секцию var, где определим одну точку (начальная точка, откуда идут все расчеты) и массив из трех точек (вершины большого треугольника):

var
  p: point2 = (0.0, 0.0);
  vertices: array[1..3] of point2 = 
     ((0.0, 0.0), (250.0, 500.0), (500.0, 0.0));

Ниже напишем код процедуры перерисовки окна:

procedure redraw();
var
  j,k: integer;
begin
  Randomize;

  glClear(GL_COLOR_BUFFER_BIT);

  for k:=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;

    glXSwapBuffers(dpy, win);
end;

В данной процедуре размещен кусок кода который рисует 250000 точек в определенных координатах согласно алгоритму, эти точки не выходя за пределы большого треугольника.
Здесь процедура glXSwapBuffers переключает сформировавшуюся картинку из буфера кадра на экран.
Ниже напишем процедуру инициализации обзора сцены:


procedure initgl();
begin
  glClearColor(1.0, 1.0, 1.0, 0.0);
  glColor3f(1.0, 0.0, 0.0);

  glMatrixMode(GL_PROJECTION);

  glLoadIdentity();

  gluOrtho2D(0.0, 500.0, 0.0, 500.0);

  glMatrixMode(GL_MODELVIEW);

end;

Ниже напишем процедуру, которая вызывается каждый раз при изменение размеров окна:

procedure resize(width, height: integer);
begin
  glViewport(0, 0, width, height);
end;

Ниже напишем процедуру, в которой находится бесконечный цикл обработки событий окна:

procedure loop();
var
  event: TXEvent;
begin
  while true do
  begin
   XNextEvent(dpy, @event);
   case event._type of
    Expose: redraw();
    ConfigureNotify: resize(event.xconfigure.width,
      event.xconfigure.height);
    KeyPress: halt(1);
   end;
  end;
end;

в данном случае обрабатываются событие перерисовки окна (Expose), событие изменения размеров окна (ConfigureNotify), события нажатия клавиши (KeyPress).

Ниже определим секцию var, в которой определены переменные необходимые для последующего кода проекта в главных операторных скобках (begin ... end.)

var
  errorBase, eventBase: integer;
  title: String;
  window_title_property: TXTextProperty;

1) Переменные с именами errorBase и eventBase нужны для хранения кода ошибок возвращаемые процедурой glXQueryExtension.
2) Переменная строка с именем title для хранения названия заголовка окна
3) Переменная window_title_property необходима для установки имени приложения

Ниже напишем код главных операторных скобок:

begin
  initGlx();

  dpy := XOpenDisplay( nil );

  if (dpy = nil) then
  writeLn('Error: Could not connect to X server');

  if not (glXQueryExtension(dpy, errorBase, eventBase)) then
  writeLn('Error: GLX extension not supported');

  visinfo := glXChooseVisual(dpy, DefaultScreen(dpy), Attr);
  if (visinfo = nil) then
  writeLn('Error: Could not find visual');

  cm := XCreateColormap(dpy, RootWindow(dpy, visinfo.screen),
  visinfo.visual, AllocNone);

  winAttr.colormap := cm;
  winAttr.border_pixel := 0;
  winAttr.background_pixel := 0;
  winAttr.event_mask := ExposureMask or
      ButtonPressMask or
      StructureNotifyMask or
      KeyPressMask;

  win := XCreateWindow(dpy, RootWindow(dpy, visinfo.screen),
  0, 0, 500, 500, 0, visinfo.depth, InputOutput, visinfo.visual,
  CWBorderPixel or CWColormap or CWEventMask, @winAttr);

  title := 'ogl_p3';
  XStringListToTextProperty(@title, 1, @window_title_property);
  XSetWMName(dpy, win, @window_title_property);

  glXCont := glXCreateContext(dpy, visinfo, none, true);
  if (glXCont = nil) then
  writeLn('Error: Could not create an OpenGL rendering context');

  glXMakeCurrent(dpy, win, glXCont);

  XMapWindow(dpy, win);

  initgl();

  loop();

end.


1) Функция initGlx производит инициализацию расширения GLX.
2) Функция XopenDisplay устанавливает соединение клиента с X-сервером.
3) Функция glXQueryExtension запрашивает у X-сервера поддерживает ли он GLX расширения.
4) Функция glXChooseVisual запрашивает у X-сервера возможные визуальные характеристики экрана.
5) Функция XcreateColormap создает новую цветовую палитру для нового окна
6) Далее мы задаем необходимые атрибуты создаваемого окна:

winAttr.colormap := cm;
winAttr.border_pixel := 0;
winAttr.background_pixel := 0;
winAttr.event_mask := ExposureMask or
   ButtonPressMask or
   StructureNotifyMask or
   KeyPressMask;

7) Функция XcreateWindow создает новое окно согласно заданным атрибутам и полученным характеристикам.
8) Следующими строчками кода мы устанавливаем заголовок окна:


 title := 'ogl_p3';
 XStringListToTextProperty(@title, 1, @window_title_property);
 XSetWMName(dpy, win, @window_title_property);

9) Функция glXCreateContext создает контекст OpenGL
10) Функция glXMakeCurrent привязывает созданный контекст OpenGL к созданному окну.
11) Функция XmapWindow делает окно видимым
12) Перед тем как передать управление обработчику событий окна, необходимо выполнить процедуру initgl инициализации обзора сцены.
13) Запускаем бесконечный цикл обработки событий окна.

Теперь давайте соберем проект. Результат работы программы представлен рисунком 2.
  
Рисунок 2. Треугольник Серпинского

Код полностью:
program ogl_p3;

{$MODE delphi}

uses glx, x, xutil, xlib, gl, glu;

var
  dpy: PDisplay;
  visinfo: PXVisualInfo;
  Attr: Array[0..10] of integer =
    (GLX_DEPTH_SIZE, 16,
     GLX_RGBA,
     GLX_RED_SIZE, 1,
     GLX_GREEN_SIZE, 1,
     GLX_BLUE_SIZE, 1,
     GLX_DOUBLEBUFFER,
     none);
  cm: TColormap;
  winAttr: TXSetWindowAttributes;
  win :TWindow;
  glXCont: GLXContext;

type
   point2 = array[1..2] of GLfloat;
var
   p: point2 = (0.0, 0.0);
   vertices: array[1..3] of point2 =  
           ((0.0, 0.0), (250.0, 500.0), (500.0, 0.0));

procedure redraw();
var
   j,k: integer;
begin
  Randomize;

  glClear(GL_COLOR_BUFFER_BIT);

  for k:=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;

  glXSwapBuffers(dpy, win);
end;

procedure initgl();
begin
  glClearColor(1.0, 1.0, 1.0, 0.0);
  glColor3f(1.0, 0.0, 0.0);

  glMatrixMode(GL_PROJECTION);

  glLoadIdentity();

  gluOrtho2D(0.0, 500.0, 0.0, 500.0);

  glMatrixMode(GL_MODELVIEW);

end;

procedure resize(width, height: integer);
begin
  glViewport(0, 0, width, height);
end;

procedure loop();
var
  event: TXEvent;
begin
  while true do
  begin
    XNextEvent(dpy, @event);
    case event._type of
         Expose: redraw();
         ConfigureNotify: resize(event.xconfigure.width,
                          event.xconfigure.height);
         KeyPress: halt(1);
    end;
  end;
end;

var
  errorBase, eventBase: integer;
  title: String;
  window_title_property: TXTextProperty;
begin
  initGlx();

  dpy := XOpenDisplay( nil );

  if (dpy = nil) then
  writeLn('Error: Could not connect to X server');

  if not (glXQueryExtension(dpy, errorBase, eventBase)) then
  writeLn('Error: GLX extension not supported');

  visinfo := glXChooseVisual(dpy, DefaultScreen(dpy), Attr);
  if (visinfo = nil) then
  writeLn('Error: Could not find visual');

  cm := XCreateColormap(dpy, RootWindow(dpy, visinfo.screen),
  visinfo.visual, AllocNone);

     winAttr.colormap := cm;
     winAttr.border_pixel := 0;
     winAttr.background_pixel := 0;
     winAttr.event_mask := ExposureMask or
                           ButtonPressMask or
                           StructureNotifyMask or
                           KeyPressMask;

  win := XCreateWindow(dpy, RootWindow(dpy, visinfo.screen),
  0, 0, 500, 500, 0, visinfo.depth, InputOutput, visinfo.visual,
  CWBorderPixel or CWColormap or CWEventMask, @winAttr);

  title := 'ogl_p3';
  XStringListToTextProperty(@title, 1, @window_title_property);
  XSetWMName(dpy, win, @window_title_property);

  glXCont := glXCreateContext(dpy, visinfo, none, true);
  if (glXCont = nil) then
  writeLn('Error: Could not create an OpenGL rendering context');

  glXMakeCurrent(dpy, win, glXCont);

  XMapWindow(dpy, win);

  initgl();

  loop();

end.


syntax highlighted by Code2HTML, v. 0.9.1