OpenGL в игре изменить вид


Я работаю над проектом какао, которое использует OpenGL. Я пытаюсь держать вещи легко крест-platformable на потом (что является главной причиной для моего ГЛ синглтон; я надеюсь, реализации Linux версии Иргл методов, которые в настоящее время используют NSOpenGL...). Когда делаю какао и OpenGL вещи, хотя, я не уверен, что я делать вещи "правильно". Что я мог бы сделать лучше здесь? Я опустил методов, не связанных с GL или рисунок.

Вот мой NSView подкласса:

//
//  IRLevelViewView
//  Iris
//
//  Created by Andy Van Ness on 3/15/11.
//  Copyright 2011 Andy Van Ness. All rights reserved.
//

#import "IRGameEditView.h"
#import <OpenGL/gl.h>
#import "IRGL.h"
//snip

@implementation IRGameEditView

- (id)initWithFrame:(NSRect)frameRect
{
    self = [super initWithFrame:frameRect];
    if (self != nil)
    {
        //snip

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(surfaceNeedsUpdate:) name:NSViewGlobalFrameDidChangeNotification object:self];
    }
    return self;
}

- (void)initDisplayLink
{
    GLint swapInt = 1;
    [[[IRGL gl] glContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; 

    CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
    CVDisplayLinkSetOutputCallback(displayLink, &MyDisplayLinkCallback, self);

    CGLContextObj cglContext = [[[IRGL gl] glContext] CGLContextObj];
    CGLPixelFormatObj cglPixelFormat = [[NSOpenGLView defaultPixelFormat] CGLPixelFormatObj];
    CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat);

    CVDisplayLinkStart(displayLink);
}

- (void)initGL
{   
    glDisable(GL_DEPTH_TEST);
    glDepthMask(GL_FALSE);

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

    [[IRGL gl] initShaders];
    [self reshape];

    [self setReadyForGL:YES];
}

static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
{
    NSAutoreleasePool* pool = [NSAutoreleasePool new];

    [(id)displayLinkContext setNeedsDisplay:YES];

    [pool drain];

    return kCVReturnSuccess;
}

- (void)lockFocus
{
    [super lockFocus];
    [[IRGL gl] activateContextForView:self];
}

- (void)drawRect:(NSRect)dirtyRect
{
    if (![self isReadyForGL]) [self initGL];

    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    [[self clock] updateTime];
    CGFloat animator = (CGFloat)([[self clock] time] % 100000)/100000.0;

    [[IRGL gl] setCurrentShader:IRIrisShader];
    [[IRGL gl] setUniformGLVariable:@"animator" toFloat:animator];
    [[IRGL gl] setUniformGLVariable:@"cameraCenter" toPoint:[[self camera] center]];
    [[IRGL gl] setUniformGLVariable:@"cameraTileAspectRatio" toFloat:[[self camera] tileAspectRatio]];
    [[IRGL gl] setUniformGLVariable:@"cameraZoom" toFloat:[[self camera] zoom]];
    [[IRGL gl] setUniformGLVariable:@"cameraSize" toSize:[[self camera] size]];
    [[self camera] loadCameraMatrix];

    @synchronized([[self level] tileMap])
    {
        for (IRTileStack* currentStack in [[[self level] tileMap] tileStacksInIrisRect:[[self camera] irisFrame]])
        {
            [currentStack draw];
        }
    }

    glFlush();
}

- (void)reshape
{
    glViewport(0, 0, (GLsizei)[self frame].size.width, (GLsizei)[self frame].size.height);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0, [self frame].size.width, [self frame].size.height, 0, -2, 0);

    glMatrixMode(GL_MODELVIEW);
}

- (BOOL)isOpaque  { return YES; }
- (BOOL)isFlipped { return YES; }

- (void)setFrame:(NSRect)frameRect
{
    [super setFrame:frameRect];

    [[IRGL gl] activateContextForView:self];
    [self reshape];

    [self setNeedsDisplay:YES];
}

@synthesize automaticallyRedraws;
- (void)setAutomaticallyRedraws:(BOOL)newAutomaticallyRedraws
{
    if (newAutomaticallyRedraws != automaticallyRedraws)
    {
        automaticallyRedraws = newAutomaticallyRedraws;
        if (automaticallyRedraws)
        {
            [self initDisplayLink];
        }
        else
        {
            CVDisplayLinkRelease(displayLink);
        }
    }
}

- (void)surfaceNeedsUpdate:(NSNotification*)notification
{
    [[[IRGL gl] glContext] update];
}

//snip

@end

И вот одноэлементный класс GL:

//
//  IRGL.m
//  Iris
//
//  Created by Andy Van Ness on 8/9/11.
//  Copyright 2011 Andy Van Ness. All rights reserved.
//

#import "IRGL.h"

@implementation IRGL

//snip

@synthesize currentShader;
- (void)setCurrentShader:(NSString *)newCurrentShader
{
    if (![currentShader isEqualToString:newCurrentShader])
    {
        [currentShader release];
        currentShader = [newCurrentShader copy];
    }

    if (!newCurrentShader)
    {
        glUseProgramObjectARB(0);
    }
    else
    {
        glUseProgramObjectARB([self shaderForKey:currentShader]);
    }
}

- (void)initShaders
{
    for (NSString* currentID in [NSArray arrayWithObjects:IRAllShaders])
    {
        [self addShaderWithID:currentID];
    }

    [self setInitialized:YES];
}

- (void)addShaderWithID:(NSString*)key
{
    NSString* shaderSource = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:key ofType:@"fs"] encoding:NSUTF8StringEncoding error:nil];

    if ([shaderSource length] > 0)
    {
        GLhandleARB shaderProgram = glCreateProgramObjectARB();

        GLchar const* source = [shaderSource UTF8String];
        GLint const length = [shaderSource length];
        GLhandleARB shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
        glShaderSourceARB(shader, 1, &source, &length);

        glCompileShaderARB(shader);
        glAttachObjectARB(shaderProgram, shader);

        glLinkProgramARB(shaderProgram);
        MOGLShaderInfoLog(shaderProgram);

        [[self shaders] setObject:[NSValue valueWithPointer:shaderProgram] forKey:key];
        [[self uniformVariablesByShader] setObject:[NSMutableDictionary dictionary] forKey:key];
    }
    else
    {
        MOLogWarning(@"Shader not found.");
    }
}

- (GLhandleARB)shaderForKey:(NSString *)shaderKey
{
    if (shaderKey == nil) return 0;

    NSValue* shaderValue = [[self shaders] objectForKey:shaderKey];

    if (!shaderValue) MOLogError(@"Shader %@ not found.",shaderKey);

    return [shaderValue pointerValue];
}

- (GLint)uniformLocationForName:(NSString*)varName
{
    NSNumber* uniformLocation = [[[self uniformVariablesByShader] objectForKey:[self currentShader]] objectForKey:varName];

    if (!uniformLocation)
    {
        GLint var = glGetUniformLocationARB([self shaderForKey:[self currentShader]],[varName UTF8String]);
        uniformLocation = [NSNumber numberWithInteger:var];
        MOGLError();
        if (var == -1)
        {
            MOLogError(@"Uniform %@ could not be found.",varName);
        }
        else
        {
            [[[self uniformVariablesByShader] objectForKey:[self currentShader]] setObject:uniformLocation forKey:varName]; 
        }
    }

    return (GLint)[uniformLocation integerValue];
}

- (void)setUniformGLVariable:(NSString*)varName toFloat:(CGFloat)varValue
{
    if ([self isInitialized])
    {
        glUniform1f([self uniformLocationForName:varName], varValue);
        MOGLError();
    }
}

//snip; bunches more methods like that one

- (void)activateContext
{
    if (![self glContext])
    {
        NSOpenGLContext* newContext = [[NSOpenGLContext alloc] initWithFormat:[NSOpenGLView defaultPixelFormat] shareContext:nil];
        [self setGLContext:newContext];
        [newContext release];
        MOGLError();
    }

    [[self glContext] makeCurrentContext];
    MOGLError();
}

- (void)activateContextForView:(NSView*)view
{
    [self activateContext];
    [[self glContext] setView:view];
}

@end


742
5
задан 14 августа 2011 в 07:08 Источник Поделиться
Комментарии
1 ответ


  1. CVDisplayLink является асинхронным и вообще AppKit не ориентирована на многопотоковое исполнение.

  2. Используя setNeedsDisplay, который получает вас обновить в какой-то момент в будущем, в розыгрыше обратного вызова не попадает в точку отображения ссылок, который рисует что-то синхронно с обновлением экрана.

  3. Вы можете оставить АРБ, верно? Это почти 2012.

3
ответ дан 4 декабря 2011 в 07:12 Источник Поделиться