Рисование к окну или представлению

Интерфейс программирования OpenGL обеспечивает сотни команд рисования то аппаратное обеспечение машинной графики диска. Это не обеспечивает команд, взаимодействующих через интерфейс с системой управления окнами операционной системы. Без системы управления окнами 3D графика программы OpenGL захватывается в GPU. Рисунок 2-1 показывает куб, нарисованный представлению Cocoa.

Рисунок 2-1  содержание OpenGL в представлении Cocoa
OpenGL content in a Cocoa view (left) and a Carbon window (right)

Эта глава показывает, как вывести на экран OpenGL, получающий экранное использование APIs, предоставленного OS X. (Эта глава не показывает, как использовать GLUT.) Первый раздел описывает общий подход к рисованию на экране и обеспечивает обзор функций и методов, используемых каждым API.

Общий подход

Для рисования содержания к представлению или уровню приложение использует NSOpenGL классы из среды разработки приложения Какао. В то время как API CGL используется Вашими приложениями только для создания полноэкранного содержания, каждого NSOpenGLContext объект содержит объект контекста CGL. Этот объект может быть получен от NSOpenGLContext когда Ваше приложение должно сослаться на него непосредственно. Для показа общих черт между этими двумя эта глава обсуждает обоих NSOpenGL классы и API CGL.

Нарисовать содержание OpenGL к окну или представлению с помощью NSOpenGL классы, необходимо выполнить эти задачи:

  1. Установите средство рендеринга и буферизуйте атрибуты, поддерживающие OpenGL, привлекающий Вас, хотят выполнить.

    Каждый OpenGL, APIs в OS X имеет его собственный набор констант, представляющих средство рендеринга и буферизующих атрибуты. Например, атрибут все-средств рендеринга представлен NSOpenGLPFAAllRenderers постоянный в Какао и kCGLPFAAllRenderers постоянный в API CGL.

  2. Запрос, от операционной системы, объект формата пикселя, инкапсулирующий пиксельную информацию о системах хранения и средство рендеринга и буферные атрибуты, требуемые Вашим приложением. Возвращенный объект формата пикселя содержит все возможные комбинации средств рендеринга и выводит на экран доступный в системе, на которой работает Ваша программа, и это удовлетворяет требования, указанные атрибутами. Комбинации упоминаются как виртуальные экраны. (См. Виртуальные Экраны.)

    Могут быть ситуации, для которых Вы хотите гарантировать, что Ваша программа использует определенное средство рендеринга. Выбор Renderer и Buffer Attributes обсуждает, как установить массив атрибутов, гарантирующий, что система пасует назад объект формата пикселя что использование только то средство рендеринга.

    Если ошибка происходит, Ваше приложение может получить a NULL объект формата пикселя. Ваше приложение должно обработать это условие.

  3. Создайте контекст рендеринга и свяжите объект формата пикселя с ним. Контекст рендеринга отслеживает информацию состояния, управляющую такими вещами как рисование цвета, представления и матриц проекции, характеристик света, и соглашения раньше упаковывали пиксели.

    Для Вашего приложения нужен объект формата пикселя создать контекст рендеринга.

  4. Выпустите объект формата пикселя. Как только объект формата пикселя связывается с контекстом рендеринга, его ресурсы больше не необходимы.

  5. Свяжите drawable объект с контекстом рендеринга. Для оконного контекста это обычно - представление Cocoa.

  6. Сделайте контекст рендеринга текущим контекстом. Система отправляет получение OpenGL в то, какой бы ни рендеринг контекста определяется как текущий. Для Вас возможно установить больше чем один контекст рендеринга, таким образом, необходимо удостовериться, что тот, к которому Вы хотите нарисовать, является текущим.

  7. Выполните свое получение.

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

Рисование к представлению какао

Существует два способа нарисовать содержание OpenGL к представлению Cocoa. Если Ваше приложение имеет умеренные требования получения, то можно использовать NSOpenGLView класс. См. Получение к Классу NSOpenGLView: Учебное руководство.

Если Ваше приложение более сложно и должно поддерживать получение к многократным контекстам рендеринга, можно хотеть рассмотреть разделение на подклассы NSView класс. Например, если Ваше получение поддержки приложений к многократным представлениям одновременно, необходимо установить пользовательское NSView класс. См. Получение Содержание OpenGL к Пользовательскому Представлению.

Рисование к классу NSOpenGLView: учебное руководство

NSOpenGLView класс является легким подклассом NSView класс, обеспечивающий удобные методы для установки получения OpenGL. NSOpenGLView объект поддерживает NSOpenGLPixelFormat возразите и NSOpenGLContext объект, в котором могут быть представлены вызовы OpenGL. Это обеспечивает методы для доступа и управления объектом формата пикселя и контекстом рендеринга, и обрабатывает уведомление о видимых изменениях области.

NSOpenGLView объект не поддерживает подпредставления. Можно, однако, разделить представление на многократные области рендеринга с помощью функции OpenGL glViewport.

Этот раздел обеспечивает поэтапные инструкции для создавания простого приложения Какао, рисующего содержание OpenGL к представлению. Учебное руководство предполагает, что Вы знаете, как использовать XCode и Интерфейсного Разработчика. Если Вы никогда не создавали приложение с помощью среды разработки XCode, посмотрите Начало работы с Инструментами.

  1. Создайте проект приложения Какао под названием Золотой Треугольник.

  2. Добавьте платформу OpenGL к своему проекту.

  3. Добавьте новый файл к своему проекту с помощью шаблона класса Objective C. Назовите файл MyOpenGLView.m и создайте заголовочный файл для него.

  4. Откройтесь MyOpenGLView.h файл и изменяет файл так, чтобы это было похоже на код, который, как показывают в Перечислении 2-1, объявил интерфейс.



    Перечисление 2-1  интерфейс для MyOpenGLView

    #import <Cocoa/Cocoa.h>
     
    @interface MyOpenGLView : NSOpenGLView
    {
    }
    - (void) drawRect: (NSRect) bounds;
    @end
  5. Сохраните и закройтесь MyOpenGLView.h файл.

  6. Откройтесь MyOpenGLView.m файл и включает gl.h файл, как показано в Перечислении 2-2.



    Перечисление 2-2  включает OpenGL/gl.h

    #import "MyOpenGLView.h"
    #include <OpenGL/gl.h>
     
    @implementation MyOpenGLView
    @end
  7. Реализуйте drawRect: метод как показано в Перечислении 2-3, добавляя код после @implementation оператор. Метод выбирает ясный цвет к черному цвету и очищает цветной буфер в подготовке к рисованию. Затем drawRect: вызывает Вашу подпрограмму получения, которую Вы добавите затем. Команда OpenGL glFlush рисует содержание, предоставленное Вашей подпрограммой для представления.



    Перечисление 2-3  drawRect: метод для MyOpenGLView

    -(void) drawRect: (NSRect) bounds
    {
        glClearColor(0, 0, 0, 0);
        glClear(GL_COLOR_BUFFER_BIT);
        drawAnObject();
        glFlush();
    }
  8. Добавьте код для выполнения получения. В Вашем собственном приложении Вы выполнили бы любое получение, является надлежащим. Но в целях изучения, как нарисовать содержание OpenGL к представлению, добавьте код, показанный в Перечислении 2-4. Этот код рисует 2D, треугольник золотого цвета, размерности которого являются не совсем размерностями истинного золотого треугольника, но достаточно хороший, чтобы показать, как выполнить получение OpenGL.

    Удостоверьтесь, что Вы вставляете эту подпрограмму перед drawRect: метод в MyOpenGLView.m файл.



      Код перечисления 2-4, рисующий треугольник с помощью команд OpenGL

    static void drawAnObject ()
    {
        glColor3f(1.0f, 0.85f, 0.35f);
        glBegin(GL_TRIANGLES);
        {
            glVertex3f(  0.0,  0.6, 0.0);
            glVertex3f( -0.2, -0.3, 0.0);
            glVertex3f(  0.2, -0.3 ,0.0);
        }
        glEnd();
    }
  9. Откройтесь MainMenu.xib в интерфейсном разработчике.

  10. Измените заголовок окна на Golden Triangle.

  11. Перетащите NSOpenGLView объект от Библиотеки до окна. Измените размеры представления для адаптации окну.

  12. Измените класс этого объекта к MyOpenGLView.

  13. Откройте область Attributes инспектора для представления, и смотрите на средство рендеринга и буферизуйте атрибуты, которые доступны установленному. Эти настройки спасают Вас от установки атрибутов программно.

    Когда представление инстанцируют, только те атрибуты, перечисленные в Интерфейсном инспекторе Разработчика, установлены. При необходимости в дополнительных атрибутах необходимо установить их программно.

  14. Сборка и запущенный Ваше приложение. Необходимо видеть содержание, подобное треугольнику, показанному на рисунке 2-2.

    Рисунок 2-2  вывод из Золотой Треугольной программы
    The output from the Golden Triangle program

Этот пример чрезвычайно прост. В более сложном приложении Вы хотели бы сделать следующее:

  • Замените команды рисования непосредственного режима командами, сохраняющими Ваши данные вершины в OpenGL. См. Стратегии Проектирования приложений OpenGL.

  • В интерфейсе для представления объявите переменную, указывающую, готово ли представление принять получение. Представление готово к рисованию, только если это связывается с контекстом рендеринга, и тот контекст установлен быть текущим.

  • Какао не вызывает подпрограммы инициализации для объектов, создаваемых в Интерфейсном Разработчике. Если необходимо выполнить какие-либо задачи инициализации, сделайте так в awakeFromNib метод для представления. Обратите внимание на то, что, потому что Вы устанавливаете атрибуты в инспекторе, нет никакой потребности установить их программно, если Вам не нужны дополнительные. Нет также никакой потребности создать объект формата пикселя программно; когда Какао загружает файл пера, это создается и загружается.

  • Ваш drawRect: метод должен протестировать, готово ли представление вовлечь. Необходимо обеспечить код, обрабатывающий случай, когда представление не готово вовлечь.

  • OpenGL в своих лучших проявлениях при выполнении и интерактивных графиков в реальном времени. Ваше приложение должно обеспечить таймер или поддерживать взаимодействие с пользователем. Для получения дополнительной информации о создании анимации в Вашем приложении OpenGL, посмотрите, Синхронизируются с Экранной Частотой обновления.

Рисование содержания OpenGL к пользовательскому представлению

Этот раздел обеспечивает обзор ключевых задач, которые необходимо выполнить для настройки NSView класс для получения OpenGL. Перед созданием пользовательского представления для получения OpenGL необходимо считать Создание Пользовательского Представления в поле зрения Руководство по программированию.

Когда Вы разделяете на подклассы NSView класс для создания пользовательского представления для получения OpenGL Вы переопределяете любое Кварцевое получение или другое содержание, которое находится в том представлении. Устанавливать пользовательское представление для получения OpenGL, подкласса NSView и создайте две частных переменные — та, которая является NSOpenGLContext возразите и другой NSOpenGLPixelFormat объект, как показано в Перечислении 2-5.

Перечисление 2-5  интерфейс для пользовательского представления OpenGL

@class NSOpenGLContext, NSOpenGLPixelFormat;
 
@interface CustomOpenGLView : NSView
{
  @private
    NSOpenGLContext*     _openGLContext;
    NSOpenGLPixelFormat* _pixelFormat;
}
+ (NSOpenGLPixelFormat*)defaultPixelFormat;
- (id)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat*)format;
- (void)setOpenGLContext:(NSOpenGLContext*)context;
- (NSOpenGLContext*)openGLContext;
- (void)clearGLContext;
- (void)prepareOpenGL;
- (void)update;
- (void)setPixelFormat:(NSOpenGLPixelFormat*)pixelFormat;
- (NSOpenGLPixelFormat*)pixelFormat;
@end

В дополнение к обычным методам для частных переменных (openGLContext, setOpenGLContext:, pixelFormat, и setPixelFormat:) необходимо реализовать следующие методы:

  • + (NSOpenGLPixelFormat*) defaultPixelFormat

    Используйте этот метод, чтобы выделить и инициализировать NSOpenGLPixelFormat объект.

  • - (void) clearGLContext

    Используйте этот метод, чтобы очистить и выпустить NSOpenGLContext объект.

  • - (void) prepareOpenGL

    Используйте этот метод для инициализации состояния OpenGL после создания NSOpenGLContext объект.

Необходимо переопределить update и initWithFrame: методы NSView класс.

  • update вызовы update метод NSOpenGLContext класс.

  • initWithFrame:pixelFormat сохраняет формат пикселя и устанавливает уведомление NSViewGlobalFrameDidChangeNotification. См. перечисление 2-6.

Перечисление 2-6  initWithFrame:pixelFormat: метод

- (id)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat*)format
{
    self = [super initWithFrame:frameRect];
    if (self != nil) {
        _pixelFormat   = [format retain];
    [[NSNotificationCenter defaultCenter] addObserver:self
                     selector:@selector(_surfaceNeedsUpdate:)
                     name:NSViewGlobalFrameDidChangeNotification
                     object:self];
    }
    return self;
}
 
- (void) _surfaceNeedsUpdate:(NSNotification*)notification
{
   [self update];
}

Если пользовательское представление, как гарантируют, не будет в окне, необходимо также переопределить lockFocus метод NSView класс. См. Перечисление 2-7. Этот метод удостоверяется, что представление заблокировано до рисования и что контекст является текущим.

Перечисление 2-7  lockFocus метод

- (void)lockFocus
{
    NSOpenGLContext* context = [self openGLContext];
 
    [super lockFocus];
    if ([context view] != self) {
        [context setView:self];
    }
    [context makeCurrentContext];
}

reshape метод не поддерживается NSView класс. Необходимо обновить границы в drawRect: метод, который должен принять форму, показанную в Перечислении 2-8.

Перечисление 2-8  drawRect метод для пользовательского представления

-(void) drawRect
{
    [context makeCurrentContext];
    //Perform drawing here
    [context flushBuffer];
}

Могут быть другие методы, которые Вы хотите добавить. Например, когда пользовательское представление перемещено из окна, как показано в Перечислении 2-9, Вы могли бы рассмотреть отсоединение контекста от drawable объекта.

Перечисление 2-9  , Отсоединяющее контекст от drawable объекта

-(void) viewDidMoveToWindow
{
    [super viewDidMoveToWindow];
    if ([self window] == nil)
        [context clearDrawable];
}