Запись потребительских патчей

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

  Потребитель рисунка 4-1 исправляет рендеринг месту назначения
Consumer patches render to a destinationConsumer patches render to a destination

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

Несмотря на то, что эти книги обеспечивают прочную основу в OpenGL, необходимо будет также считать Руководство по программированию OpenGL для Mac для подробных данных о том, как получить лучшую производительность на платформе Macintosh с помощью новых расширений OpenGL и OS X платформы OpenGL.

Используя OpenGL в пользовательском патче

Используя OpenGL в пользовательском патче требует немного большего количества работы установки, чем, что необходимо для патчей, не использующих OpenGL, но не очень. Необходимо установить контекст OpenGL в контекст выполнения пользовательского патча. Установка требует двух шагов:

  1. Включайте CGLMacro.h файл.

  2. Установите контекст OpenGL в контекст выполнения пользовательского патча с помощью этой строки кода:

    CGLContextObj cgl_ctx = [context CGLContextObj];

Первый шаг выполнен для Вас при использовании шаблона проекта XCode для Кварцевых плагинов Композитора. При включении макро-заголовочного файла CGL можно тогда использовать локальную переменную контекста для кэширования текущего средства рендеринга. Локальный кэш избавляет от необходимости OpenGL выполнять глобальный контекст и поиск средства рендеринга для каждой команды, которую это выполняет, таким образом сокращая наверху и улучшая производительность.

CGLContextObj метод QCPlugInContext протокол получает контекст OpenGL, к которому можно нарисовать из метода выполнения пользовательского патча. (См. Ссылку на протокол QCPlugInContext.) После установки контекста OpenGL (cgl_ctx), Кварцевый Композитор отправляет все команды OpenGL в контекст выполнения OpenGL пользовательского патча.

Код OpenGL в Вашем пользовательском патче получает преимущества от любых методов программирования, улучшающих производительность любого кода OpenGL. Другими словами, нет никаких особых требований для кода OpenGL, это - часть пользовательского патча. Однако Вы захотите сохранить и восстановить все изменения состояния кроме тех, которые являются частью GL_CURRENT_BIT (Цвет RGBA, индекс цвета, вектор нормали, координаты текстуры, и т.д). Можно также хотеть смотреть на главу “Улучшающаяся Производительность” в Руководстве по программированию OpenGL для Mac.

Вращение квадрата: рендеринг текстуры к четверке

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

Получающийся патч показан на рисунке 4-2.

Рисунок 4-2  Вращающийся Квадратный пользовательский патч
The Rotating Square custom patch

Выполните эти шаги для создания Вращающегося Квадратного пользовательского патча:

  1. Откройте Xcode и выберите File> New Project.

  2. В окне New Project выберите Standard Apple Plug-ins> Quartz Composer Plug-in и нажмите Далее.

  3. Войти RotatingSquare в текстовом поле Project Name и нажимают Далее.

  4. Откройтесь RotatingSquarePlugin.h файл.

    Измените интерфейсный файл так, чтобы он имел четыре динамических свойства Objective-C: значения x и y, цвет и входное изображение.

    #import <Quartz/Quartz.h>
     
    @interface RotatingSquarePlugIn : QCPlugIn
    {
    }
    // Declare four property input ports of type Number with the
    // keys inputX, inputY, inputZ, and inputAngle
    @property double inputX;
    @property double inputY;
    @property double inputZ;
    @property double inputAngle;
    // Declare a property input port of type Color with the key inputColor
    @property(assign) CGColorRef inputColor;
    // Declare a property input port of type Image with the key inputImage
    @property(assign) id<QCPlugInInputImageSource> inputImage;
    @end
  5. Сохраните и закройтесь RotatingSquarePlugIn.h файл.

  6. Откройтесь RotatingPlugin.m файл. Для обеспечения лучшей производительности OpenGL удостоверьтесь, что файл содержит следующее утверждение:

    #import <OpenGL/CGLMacro.h>

    Вы установите контекст OpenGL позже в выполнить методе.

  7. Сразу после оператора реализации, добавьте эту директиву так, чтобы Кварцевый Композитор обработал реализацию свойств:

    @dynamic inputX, inputY, inputZ, inputAngle, inputColor, inputImage;
  8. Добавьте пространство для разделения слов на имя. Тогда измените описание для пользовательского патча.

    Когда Вы сделаны, два #define операторы для взгляда следующим образом:

    #define    kQCPlugIn_Name @"Rotating Square"
    #define    kQCPlugIn_Description  @"Renders a colored square that you can animate."
  9. Затем Вы запишете, что методы должны были реализовать RotatingSquarePlugIn подкласс. attributes метод, предоставленный в шаблоне, должен уже быть похожим на это:

    + (NSDictionary*) attributes
    {
        return [NSDictionary dictionaryWithObjectsAndKeys:
                    kQCPlugIn_Name,QCPlugInAttributeNameKey,
                    kQCPlugIn_Description,QCPlugInAttributeDescriptionKey,
                    nil];
    }
  10. Измените attributesForPropertyPortWithKey: метод так, чтобы это возвратило словарь для каждого входного параметра. Ключевое имя атрибута порта - то, что появляется в Кварцевом Композиторе как метка для пользовательского порта патча.

    Метод должен посмотреть следующим образом:

    + (NSDictionary*) attributesForPropertyPortWithKey:(NSString*)key
    {
        if([key isEqualToString:@"inputX"])
            return [NSDictionary dictionaryWithObjectsAndKeys:
                    @"X Position", QCPortAttributeNameKey,
                    nil];
        if([key isEqualToString:@"inputY"])
            return [NSDictionary dictionaryWithObjectsAndKeys:
                    @"Y Position", QCPortAttributeNameKey,
                    nil];
        if([key isEqualToString:@"inputZ"])
            return [NSDictionary dictionaryWithObjectsAndKeys:
                    @"Z Position", QCPortAttributeNameKey,
                    nil];
        if([key isEqualToString:@"inputAngle"])
            return [NSDictionary dictionaryWithObjectsAndKeys:
                    @"Rotation Angle", QCPortAttributeNameKey,
                    nil];
        if([key isEqualToString:@"inputColor"])
            return [NSDictionary dictionaryWithObjectsAndKeys:
                    @"Color", QCPortAttributeNameKey,
                    nil];
        if([key isEqualToString:@"inputImage"])
            return [NSDictionary dictionaryWithObjectsAndKeys:
                @"Image", QCPortAttributeNameKey, nil];
     
        return nil;
    }
  11. Удостоверьтесь executionMode возвраты метода kQCPlugInExecutionModeConsumer указать, что пользовательский патч является потребителем. Среди прочего это заставляет Кварцевого Композитора добавлять Разрешать входной порт к получающемуся патчу.

    + (QCPlugInExecutionMode) executionMode
    {
        return kQCPlugInExecutionModeConsumer;
    }
  12. Удостоверьтесь что timeMode возвраты kQCPlugInTimeModeNone.

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

    Этот пользовательский патч выполняется только, когда изменяются входные значения.

    + (QCPlugInTimeMode) timeMode
    {
        return kQCPlugInTimeModeNone;
    }
  13. Реализуйте метод выполнения для контекста выполнения. Это - то, где определяется поток команды OpenGL. Необходимо определить контекст CGL здесь.

    - (BOOL) execute:(id<QCPlugInContext>)context
                atTime:(NSTimeInterval)time
                withArguments:(NSDictionary*)arguments
    {
        // Define a context and set it. This line causes OpenGL to use macros.
        CGLContextObj     cgl_ctx = [context CGLContextObj];
        id<QCPlugInInputImageSource>    image;
        GLuint            textureName;
        GLint             saveMode;
        const CGFloat*    colorComponents;
        GLenum      error;
     
        if(cgl_ctx == NULL)
            return NO;
        // Copy the image on the input port to a local variable.
        image = self.inputImage;
     
        // Get a texture from the image in the context color space
        if(image && [image lockTextureRepresentationWithColorSpace:([image shouldColorMatch] ? [context colorSpace] :
                            [image imageColorSpace])
                   forBounds:[image imageBounds]])
            textureName = [image textureName];
        else
            textureName = 0;
     
        // Save and set the modelview matrix.
        glGetIntegerv(GL_MATRIX_MODE, &saveMode);
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        // Translate the matrix
        glTranslatef(self.inputX, self.inputY, self.inputZ);
        // Rotate the matrix
        glRotatef(self.inputAngle, 0.0, 1.0, 0.0);
     
        // Bind the texture to a texture unit
        if(textureName) {
            [image bindTextureRepresentationToCGLContext:cgl_ctx
                                             textureUnit:GL_TEXTURE0
                                    normalizeCoordinates:YES];
       }
        // Get the color components (RGBA) from the input color port.
        colorComponents = CGColorGetComponents(self.inputColor);
        // Set the color.
        glColor4f(colorComponents[0], colorComponents[1], colorComponents[2], colorComponents[3]);
     
        // Render the textured quad by mapping the texture coordinates to the vertices
        glBegin(GL_QUADS);
            glTexCoord2f(1.0, 1.0);
            glVertex3f(0.5, 0.5, 0); // upper right
            glTexCoord2f(0.0, 1.0);
            glVertex3f(-0.5, 0.5, 0); // upper left
            glTexCoord2f(0.0, 0.0);
            glVertex3f(-0.5, -0.5, 0); // lower left
            glTexCoord2f(1.0, 0.0);
            glVertex3f(0.5, -0.5, 0); // lower right
        glEnd();
     
        // Unbind the texture from the texture unit.
        if(textureName)
            [image unbindTextureRepresentationFromCGLContext:cgl_ctx
                                                 textureUnit: GL_TEXTURE0];
     
        // Restore the modelview matrix.
        glMatrixMode(GL_MODELVIEW);
        glPopMatrix();
        glMatrixMode(saveMode);
     
        // Check for OpenGL errors and log them if there are errors.
        if(error = glGetError())
            [context logMessage:@"OpenGL error %04X", error];
     
        // Release the texture.
        if(textureName)
            [image unlockTextureRepresentation];
     
        return (error ? NO : YES);
    }
  14. Откройтесь Info.plist файл и удостоверяется, что следующий ключ является записью в словаре:

    <key>QCPlugInClasses</key>
    <array>
        <string>RotatingSquarePlugIn</string>
    </array>

    Если Вы хотите, настраиваете идентификатор пакета. Тогда сохраните и закройте файл.

  15. Под Целями выберите Build и Copy. Затем нажмите Build Build и Copy от всплывающего меню Действия.

    При создании использования этой опции XCode копирует успешно созданный плагин в ~/Library/Graphics/Quartz Composer Plug-Ins.

  16. Откройте Quartz Composer и ищите Вращающийся Квадратный пользовательский патч в Создателе Патча.

  17. Создайте состав для тестирования пользовательского патча. Попытайтесь выбрать цвет и позиции. Добавьте патч интерполяции для анимации квадрата. Для проверки ввода изображения можно перетащить изображение непосредственно редактору и затем подключить изображение к патчу, как показано ниже.

    missing graphic

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

    missing graphic