Logo

MacOS X, OpenGL и FreePascal: Часть Первая.
11.01.09

IT-индустрия не стоит на месте, и рост популярности ОС, отличных от Windows, все больше заставляет разработчиков задумываться о расширении списка поддерживаемых платформ. Т.к. о разработке OpenGL-приложений для Linux я уже писал, в этом цикле постараюсь описать разработку OpenGL-приложений для MacOS X. Данная статья(и следующие планируемые) не претендует на "серьезную" техническую документацию, а лишь является изложением собственных мыслей "по поводу" :) Поэтому всё рассмотренное желательно подкреплять ознакомлением с официальной документацией на http://developer.apple.com/

Немного о требуемом инструментарии

Разработка приложений для MacOS X сопряжена не только проблемой наличия этой ОС, и ее работоспособности только на "избранных железках", а и размером инструментария, что все еще может оказаться проблематичным моментом для некоторых. Так, помимо самого FreePascal(для архитектуры x86) для этой ОС, потребуется еще и XCode, для скачивания которого нужно пройти регистрацию на сайте Apple и обзавестись хорошим интернет-каналом или знакомыми :) Правда не все так плохо - на диске с оригинальными MacOS X 10.5.x XCode уже идет в комплекте, а для обладателей 10.4.x тоже есть выход - скачать только FreePascal, и вот этот архив, где я собрал всё необходимое(отдельное спасибо XProger'у :)). В этот архив входит ассемблер для архитектуры x86, линковщик(ld и libtool), strip'ер, make-утилита(gnumake) и еще два необходимых обьектных файла - crt1.o и dylib1.o. Разместить все файлы нужно в корневой директории("/") также, как соблюдена иерархия директорий в самом архиве. Для размещения можно воспользоваться как файловым менеджером, так и консольной командой "sudo cp"(в обеих случаях потребуется пароль администратора). Собственно это все, если у вас уже есть сама ОС и MacBook/etc. :)

Вместо введения

Модель программирования OpenGL-приложений для MacOS X довольно похожа на таковую для Linux, за исключением особенностей X-Server'а в последней. Посему список действий сводиться к созданию окна, выбору формата пикселей и связыванию OpenGL-контекста с окном. Хотя последовательность первых двух действий не имеет значения, но я оставил их в такой последовательности, чтобы свести в одну функцию выбор формата пикселей и связывание OpenGL-контекста с окном.

Создание окна

Тут все довольно просто. Сперва нужно определиться с атрибутами окна и его размером, а потом вызвать функцию CreateNewWindow, и проследить не возвратила ли она ошибку.


      size.Left   := X;
      size.Top    := Y;
      size.Right  := X + Width;
      size.Bottom := Y + Height;
      wnd_Attr    := kWindowCloseBoxAttribute or kWindowCollapseBoxAttribute or kWindowStandardHandlerAttribute;
      status      := CreateNewWindow( kDocumentWindowClass, wnd_Attr, size, wnd_Handle );

      if ( status <> noErr ) or ( not Assigned( wnd_Handle ) ) Then
        begin
          // Ошибка
          exit;
        end;
      

Для отображения окна, следует "выбрать" его(функция SelectWindow) и "показать" функцией ShowWindow. Касательно используемых атрибутов для окна - kWindowStandardHandlerAttribute требуется для возможности закрепить за окном обработку сообщений, ну а kWindowCloseBoxAttribute и kWindowCollapseBoxAttribute, как следует из названия, указывают на наличие кнопок закрытия и сворачивания окна. Передаваемый аргумент kDocumentWindowClass в функцию создания окна указывает на создание стандартного окна(подробное описание других видов окон есть в модуле MacOSAll.pas).

Выбор формата пикселей

Также как в Linux существует glxChooseVisual, в Windows - wglChoosePixelFormat, так и тут есть свой аналог - aglChoosePixelFormat. Вызов этой функции, как и её "сородичей", сводиться к заполнению массива атрибутов, и передачи его функции.


      ogl_Attr[ 0 ] := AGL_RGBA;
      ogl_Attr[ 1 ] := AGL_DOUBLEBUFFER;
      ogl_Attr[ 2 ] := AGL_DEPTH_SIZE;
      ogl_Attr[ 3 ] := 24;
      ogl_Attr[ 4 ] := AGL_NONE;

      ogl_Format := aglChoosePixelFormat( nil, 0, @ogl_Attr[ 0 ] );

      if not Assigned( ogl_Format ) Then
        begin
          // Ошибка
          exit;
        end;
      

Атрибуты приведенные выше являются необходимым минимумом(описание думаю давать не требуется? :)). Первых два параметра функции aglChoosePixelFormat принимают указатель на список графических устройств и номер устройства, что будет использовано, но можно обойтись передачей значений по умолчанию - nil и 0. Детальнее со всем можно ознакомится в AGL Reference.

Создание контекста OpenGL

Как и в других ОС, этот шаг требует выполнения команд, связанных с самим созданием контекста(aglCreateContext), и установкой его текущим(aglSetCurrentContext). Но в MacOS X есть одно отличие - нужно "связать" окно с контекстом посредством функции aglSetDrawable. В итоге все выглядит следующим образом:


      ogl_Context := aglCreateContext( ogl_Format, nil );
      if not Assigned( ogl_Context ) Then
        begin
          // Ошибка
          exit;
        end;
      if aglSetDrawable( ogl_Context, GetWindowPort( wnd_Handle ) ) = GL_FALSE Then
        begin
          // Ошибка
          exit;
        end;
      if aglSetCurrentContext( ogl_Context ) = GL_FALSE Then
        begin
          // Ошибка
          exit;
        end;
      aglDestroyPixelFormat( ogl_Format );
      
В заключение

Обработка событий будет рассмотрена в следующей части, но т.к. без функции GetNextEvent приложение корректно работать не будет, ее я добавлю в исходный код, но без описания. На таком моменте как Swap буферов думаю останавливаться не надо, разве что упомянуть что для этого есть функция aglSwapBuffers. Ах да, заголовок окна "Hello, World!" :) Тут все просто:


      SetWTitle( wnd_Handle, 'Hello, World!' );
      

В общем из всего этого можно сделать вывод, что API MacOS довольно простое и логичное. Хотя некоторые операции можно выполнить несколькими способами, что может сбить с толку, да и наличие deprecated(запрещенных и устаревших) функций тоже не радует, но они в модуле MacOSAll.pas помечены как таковые.

Несколько слов о компиляции

Во-первых, по каким-то непонятным причинам в FreePascal не включен модуль AGL.pas, его пришлось брать из svn-репозитария IDE Lazarus, и немного переделать для динамической загрузки функций, т.к. линковщик не знал откуда брать их, и сыпал ошибками. Во-вторых, компиляцию придется выполнять в консоле. Используя примерно следующую команду:


      /usr/local/lib/fpc/2.2.2/ppc386 demo01.pas -Sd -XsX -CX
      

Правда этим все не заканчивается, т.к. созданный бинарный файл по двойному клику будет запускаться из консоли(т.е. появится консоль и выполнит команду вида "/Users/andru/Documents/demo01/demo01; exit"), и на сообщения приложение откликаться не будет. Решается это созданием Bundle'а, описание можно получить тут. В двух словах, выглядит это так: создается директория с именем "demo01.app", в ней Contenst и внутри неё - MacOS. Туда помещается бинарный файл(название главной директории должно совпадать с названием бинарного файла), и вуаля :) В архиве с примером лежит такая "сборка".


MIRGames