Что ж, я придумал, как это сделать максимально кратко. Ниже я объясню, как этого добиться, и перечислю весь необходимый код :)
Чтобы разрешить сенсорное взаимодействие для выбора пикселя, сначала добавьте UITapGestureRecognizer
в свой GLKViewController
подкласс (при условии, что вы хотите выбрать пиксель касанием) со следующим целевым методом внутри этого класса. Вы должны сделать свой GLKViewController
подкласс UIGestureRecognizerDelegate
:
@interface GLViewController : GLKViewController <GLKViewDelegate, UIGestureRecognizerDelegate>
После создания экземпляра распознавателя жестов добавьте его в свойство view
(которое в GLKViewController
на самом деле является GLKView
):
// Inside GLKViewController subclass init/awakeFromNib:
[[self view] addGestureRecognizer:[self tapRecognizer]];
[[self tapRecognizer] setDelegate:self];
Установите целевое действие для распознавателя жестов; вы можете сделать это при его создании с использованием определенного init...
, однако я создал свой с помощью Storyboard (он же «новый интерфейсный конструктор в Xcode 4.2») и подключил его таким образом.
В любом случае, вот мое целевое действие для распознавателя жестов касания:
-(IBAction)onTapGesture:(UIGestureRecognizer*)recognizer {
const CGPoint loc = [recognizer locationInView:[self view]];
[self pickAtX:loc.x Y:loc.y];
}
Вызывается метод выбора, который я определил в своем подклассе GLKViewController
:
-(void)pickAtX:(GLuint)x Y:(GLuint)y {
GLKView *glkView = (GLKView*)[self view];
UIImage *snapshot = [glkView snapshot];
[snapshot pickPixelAtX:x Y:y];
}
При этом используется удобный новый метод snapshot
, который Apple любезно включила в GLKView
для создания UIImage
из базового EAGLContext
.
Важно отметить комментарий в snapshot
документации API, в котором говорится:
Этот метод следует вызывать всякий раз, когда вашему приложению явно требуется содержимое представления; никогда не пытайтесь напрямую прочитать содержимое нижележащего буфера кадра с помощью функций OpenGL ES.
Это дало мне ключ к пониманию того, почему мои более ранние попытки вызвать glReadPixels
при попытках доступа к данным пикселей генерировали EXC_BAD_ACCESS
и индикатор, который вместо этого отправил меня по правильному пути.
Вы заметите, что в моем методе pickAtX:Y:
, определенном минуту назад, я вызываю pickPixelAtX:Y:
на UIImage
. Это метод, который я добавил в UIImage
в настраиваемой категории:
@interface UIImage (NDBExtensions)
-(void)pickPixelAtX:(NSUInteger)x Y:(NSUInteger)y;
@end
Вот реализация; это последний обязательный листинг кода. Код взят из этого вопроса и имеет были изменены согласно полученному там ответу:
@implementation UIImage (NDBExtensions)
- (void)pickPixelAtX:(NSUInteger)x Y:(NSUInteger)y {
CGImageRef cgImage = [self CGImage];
size_t width = CGImageGetWidth(cgImage);
size_t height = CGImageGetHeight(cgImage);
if ((x < width) && (y < height))
{
CGDataProviderRef provider = CGImageGetDataProvider(cgImage);
CFDataRef bitmapData = CGDataProviderCopyData(provider);
const UInt8* data = CFDataGetBytePtr(bitmapData);
size_t offset = ((width * y) + x) * 4;
UInt8 b = data[offset+0];
UInt8 g = data[offset+1];
UInt8 r = data[offset+2];
UInt8 a = data[offset+3];
CFRelease(bitmapData);
NSLog(@"R:%i G:%i B:%i A:%i",r,g,b,a);
}
}
@end
Первоначально я пробовал некоторый связанный код, найденный в документе Apple API под названием: «Получение данных пикселей из контекста CGImage», для которого требовалось 2 определения метода вместо этого 1, но требуется гораздо больше кода, и есть данные типа void *
, для которых я не удалось реализовать правильную интерпретацию.
Вот и все! Добавьте этот код в свой проект, а затем, нажав на пиксель, он выведет его в форме:
R:24 G:46 B:244 A:255
Конечно, вы должны написать некоторые средства для извлечения этих значений RGBA int (которые будут в диапазоне от 0 до 255) и использования их по своему усмотрению. Один из подходов - вернуть UIColor
из вышеуказанного метода, созданный следующим образом:
UIColor *color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];
person
KomodoDave
schedule
23.10.2011