Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Основы работы c OpenGL в Delphi - инициализация в Windows

Автор: Саша Полозов
WEB-сайт: http://daddy.mirgames.ru

Всем привет, я начинаю серию статей непосредственно с самого простого, то есть инициализации, но для начала я хотел бы поговорить о самом o Delphi и С++. Сколько ужу сказано по этой теме, но все же. Существует такой стереотип что игры и программы пишутся только на Visual C++, а Делфи это не серьезная среда программирования, и на Делфи пишут только базы данных – это утверждение полная чушь, на самом деле все больше и больше программок пишется на Делфи, а Visual C++ подгоняемая старушкой Microsoft, задыхается, пытаясь догнать визуальную среду программирования ( собственно это и есть Делфи, и C++ Builder ), но все же большинство профессиональных игр пишется на Visual C++, в первую очередь из за скорости. Но это не значит что, нельзя использовать Делфи, в это среде теряется не намного больше в скорости работы. Собственно поэтому я выбрал Делфи , начинал я свое обучения сначала c C++ ( конечно же учась на статьях NEHE ), а потом перешел на Делфи. Так все с выбором среды программирования мы определились, теперь можно начать...

1. ( Для новичков) Начнем, первое что вы должны сделать это запустить Delphi ( 7 или 6 не имеет значения, возможно, подойдет даже 4 и 5), создаем новый проект ( File > New > Application ), закрываем форму, теперь жмем Project и там выбираем View Source. Выбираем закладку Unit на окне с кодом, и закрываем Unit, потом удаляем весь код. У вас на окне с кодом должна остаться только закладка Project1, и лист без кода.

2. Вот код который нужно вписать: program project1;

Начало программы и ее название

uses
  Windows,
  Messages,
  OpenGL;

Здесь мы подключаем библиотеки: стандартную библиотеку windows, библиотеку сообщений и конечно же OpenGl.

const
  WND_TITLE = 'OpenGL';
  FPS_TIMER = 1;
  FPS_INTERVAL = 1000;

Обьявляем константы. Надеюсь все кроме FPS_INTERVAL = 1000 понятно??!! FPS_INTERVAL = 1000 (секунда) это интервал времени через которое будет измерятся FPS ( кадры в секунду).

var
  h_Wnd: HWND;
  h_DC: HDC;
  h_RC: HGLRC;
  keys: array[0..255] of Boolean;
  FPSCount: Integer = 0;
  ElapsedTime: Integer;

Первые две строки после var устанавливают Контексты Рендеринга, которые связывает вызовы OpenGL с окном Windows. Контекст Рендеринга OpenGL определен как hRC. Для того чтобы рисовать в окне, вам необходимо создать Контекст Устройства Windows, который определен как hDC. DC соединяет окно с GDI. RC соединяет OpenGL с DC. keys : Array[0..255] of Boolean – это последняя переменная, в которой мы будем нуждаться , это массив, который мы используем для отслеживания нажатия клавиш на клавиатуре. Есть много путей следить за нажатиями на клавиатуре, но я использую этот путь. При этом можно отслеживать нажатие более чем одной клавиши одновременно ( не бойтесь что не чего не понятно, я и сам не до конца понимаю).

{$R *.RES}

procedure glBindTexture(target: GLenum; texture: GLuint);
  stdcall; external opengl32;

function IntToStr(Num: Integer): string;
begin
  Str(Num, result);
end;

procedure glDraw();
begin

end;

Вот это самое главное, после begin мы будем вставлять код который и будет рисовать всю сцену, но это не сейчас потом, пока ( в следующем уроке ) не чего не рисуем ( поэтому и экран серый ).

procedure glInit();
begin
  glClearColor(0.0, 0.0, 0.0, 0.0);
  glShadeModel(GL_SMOOTH);
  glClearDepth(1.0);
  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);
  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
end;

Здесь мы инициализируем OpenGl. GlClearColor (0.0, 0.0, 0.0, 0.0) – установка цвета фона ( с цветами мы разберемся пой же в следующей статье). Это единственное здесь что вам надо знать, ничего другого вам менять не понадобится, если кому то интересно пишите, объясню что это значит.

procedure glResizeWnd(Width, Height: Integer);
begin
  if (Height = 0) then
    Height := 1;

  glViewport(0, 0, Width, Height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, Width / Height, 1.0, 100.0);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
end;

Сейчас и далее я привожу части кода без объяснений, все равно менять что то здесь врятли вам понадобится, а понять что это делает на данном этапе будет сложно ( здесь идет восновно работа с нажатием клавиш )

function WndProc(hWnd: HWND; Msg: UINT; wParam: WPARAM;
  lParam: LPARAM): LRESULT; stdcall;
begin
  case (Msg) of
    WM_CREATE:
      begin
      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
        glResizeWnd(LOWORD(lParam), HIWORD(lParam));
        Result := 0;
      end;
    WM_TIMER:
      begin
        if wParam = FPS_TIMER then
        begin
          FPSCount := Round(FPSCount * 1000 / FPS_INTERVAL);
          SetWindowText(h_Wnd, PChar(WND_TITLE + '   [' + intToStr(FPSCount) +
            ' FPS]'));
          FPSCount := 0;
          Result := 0;
        end;
      end;
  else
    Result := DefWindowProc(hWnd, Msg, wParam, lParam);
  end;
end;

procedure glKillWnd(Fullscreen: Boolean);
begin
  if Fullscreen then
  begin
    ChangeDisplaySettings(devmode(nil^), 0);
    ShowCursor(True);
  end;

  if (not wglMakeCurrent(h_DC, 0)) then
    MessageBox(0, 'Release of DC and RC failed!', 'Error',
      MB_OK or MB_ICONERROR);

  if (not wglDeleteContext(h_RC)) then
  begin
    MessageBox(0, 'Release of rendering context failed!', 'Error',
      MB_OK or MB_ICONERROR);
    h_RC := 0;
  end;

  if ((h_DC > 0) and (ReleaseDC(h_Wnd, h_DC) = 0)) then
  begin
    MessageBox(0, 'Release of device context failed!', 'Error',
      MB_OK or MB_ICONERROR);
    h_DC := 0;
  end;

  if ((h_Wnd <> 0) and (not DestroyWindow(h_Wnd))) then
  begin
    MessageBox(0, 'Unable to destroy window!', 'Error',
      MB_OK or MB_ICONERROR);
    h_Wnd := 0;
  end;

  if (not UnRegisterClass('OpenGL', hInstance)) then
  begin
    MessageBox(0, 'Unable to unregister window class!', 'Error',
      MB_OK or MB_ICONERROR);
    hInstance := 0;
  end;
end;

А здесь создаются сообщения если что то пойдет не так при запуске файла.

function glCreateWnd(Width, Height: Integer; Fullscreen: Boolean;
  PixelDepth: Integer): Boolean;
var
  wndClass: TWndClass;
  dwStyle: DWORD;
  dwExStyle: DWORD;
  dmScreenSettings: DEVMODE;
  PixelFormat: GLuint;
  h_Instance: HINST;
  pfd: TPIXELFORMATDESCRIPTOR;
begin
  h_Instance := GetModuleHandle(nil);
  ZeroMemory(@wndClass, SizeOf(wndClass));

  with wndClass do
  begin
    style := CS_HREDRAW or
      CS_VREDRAW or
      CS_OWNDC;
    lpfnWndProc := @WndProc;
    hInstance := h_Instance;
    hCursor := LoadCursor(0, IDC_ARROW);
    lpszClassName := 'OpenGL';
  end;

  if (RegisterClass(wndClass) = 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 := PixelDepth;
      dmFields := DM_PELSWIDTH or DM_PELSHEIGHT or DM_BITSPERPEL;
    end;

    if (ChangeDisplaySettings(dmScreenSettings, CDS_FULLSCREEN)
      = DISP_CHANGE_FAILED) then
    begin
      MessageBox(0, 'Unable to switch to fullscreen!', 'Error',
        MB_OK or MB_ICONERROR);
      Fullscreen := False;
    end;
  end;

  if (Fullscreen) then
  begin
    dwStyle := WS_POPUP or
      WS_CLIPCHILDREN
      or WS_CLIPSIBLINGS;
    dwExStyle := WS_EX_APPWINDOW;
    ShowCursor(False);
  end
  else
  begin
    dwStyle := WS_OVERLAPPEDWINDOW or
      WS_CLIPCHILDREN or
      WS_CLIPSIBLINGS;
    dwExStyle := WS_EX_APPWINDOW or
      WS_EX_WINDOWEDGE;
  end;

  h_Wnd := CreateWindowEx(dwExStyle,
    'OpenGL',
    WND_TITLE,
    dwStyle,
    0, 0,
    Width, Height,
    0,
    0,
    h_Instance,
    nil);
  if h_Wnd = 0 then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to create window!', 'Error',
      MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  h_DC := GetDC(h_Wnd);
  if (h_DC = 0) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to get a device context!', 'Error',
      MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  with pfd do
  begin
    nSize := SizeOf(TPIXELFORMATDESCRIPTOR);
    nVersion := 1;
    dwFlags := PFD_DRAW_TO_WINDOW
      or PFD_SUPPORT_OPENGL
      or PFD_DOUBLEBUFFER;
    iPixelType := PFD_TYPE_RGBA;
    cColorBits := PixelDepth;
    cRedBits := 0;
    cRedShift := 0;
    cGreenBits := 0;
    cGreenShift := 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;

  PixelFormat := ChoosePixelFormat(h_DC, @pfd);
  if (PixelFormat = 0) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to find a suitable pixel format', 'Error',
      MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  if (not SetPixelFormat(h_DC, PixelFormat, @pfd)) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to set the pixel format', 'Error',
      MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  h_RC := wglCreateContext(h_DC);
  if (h_RC = 0) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to create an OpenGL rendering context', 'Error',
      MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  if (not wglMakeCurrent(h_DC, h_RC)) then
  begin
    glKillWnd(Fullscreen);
    MessageBox(0, 'Unable to activate OpenGL rendering context', 'Error',
      MB_OK or MB_ICONERROR);
    Result := False;
    Exit;
  end;

  SetTimer(h_Wnd, FPS_TIMER, FPS_INTERVAL, nil);
  ShowWindow(h_Wnd, SW_SHOW);
  SetForegroundWindow(h_Wnd);
  SetFocus(h_Wnd);

  glResizeWnd(Width, Height);
  glInit();

  Result := True;
end;

function WinMain(hInstance: HINST; hPrevInstance: HINST;
  lpCmdLine: PChar; nCmdShow: Integer): Integer; stdcall;
var
  msg: TMsg;
  finished: Boolean;
  DemoStart, LastTime: DWord;
begin
  finished := False;

  if not glCreateWnd(800, 600, FALSE, 32) then
  begin
    Result := 0;
    Exit;
  end;

  // Обратите внимание сюда!! Вот здесь находятся настройки окна.
  // 800, 600 – это разрешение экрана, False – отключение полноэкранного режима,
  // чтоб его включить, надо поменять на TRUE, 32 глубина цвета.

  DemoStart := GetTickCount();

  while not finished do
  begin
    if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then
    begin
      if (msg.message = WM_QUIT) then
        finished := True
      else
      begin
        TranslateMessage(msg);
        DispatchMessage(msg);
      end;
    end
    else
    begin
      Inc(FPSCount);

      LastTime := ElapsedTime;
      ElapsedTime := GetTickCount() - DemoStart;
      ElapsedTime := (LastTime + ElapsedTime) div 2;

      glDraw();
      SwapBuffers(h_DC);

      if (keys[VK_ESCAPE]) then
        finished := True
      else

    end;
  end;
  glKillWnd(FALSE);
  Result := msg.wParam;
end;

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

Вот и все, размер кода получился чуть длиннее, чем аналогичный на C++, в следующей статье мы научимся рисовать примитивные геометрические фигуры, разукрашивать их в разный цвета и научим их двигаться. Я собираюсь написать потом статьи о текстурирование, o bump mappinge, потом если все пойдет хорошо мы напишем заготовку трехмерного движка для стрелялки ( аля CS, Quake…….). Обязательно пишите, чем больше писем, тем больше вероятность что я напишу следующию статью, все таки я должен знать что то все кому то интересно. Если что то не получилось качайте исходник. Да и еще, чуть не забыл вот вам маленькое домашнее задание, измените режим окна на 1024,768, и сделайте полноэкранный режим.

Тут можно взять исходник и EXE

Проект Delphi World © Выпуск 2002 - 2024
Автор проекта: USU Software
Вы можете выкупить этот проект.