검색결과 리스트
아이폰에 해당되는 글 19건
- 2011.04.29 NSNotification (1)
- 2011.04.07 푸시 메시지 포맷
- 2011.04.07 애플 푸시 서비스
- 2011.03.16 Sprite Sheet 제작툴 Zwoptex
- 2011.03.15 애플리케이션 응답성 향상을 위해 동시성 사용하기
- 2011.02.14 OpenGL ES 게임 프레임웍
- 2011.02.14 OpenGL ES 사용
- 2011.02.13 OpenGL ES 사용설정
- 2010.12.21 [iPhone] 로깅 프레임웍 cocoalumberjack
글
NSNotification
Cocoa 와 Cocoa Touch 프레임웍의 이벤트 통지 메커니즘인 NSNotification 에 대해서 간략하게 알아보자.
1. NSNotification 이란?
집중화시켜서 서로 간에 결합도를 느슨하게 할 수 있다. NSNotificationCenter, NSNotification, Observer 로 구성된다.
NSNotificationCenter는 객체들 사이에 이벤트 전달을 중계하는 역할을 하며, Observer는 이벤트가 발생하기를 기다리는 대상을
나타낸다. Observer 가 기다리는 이벤트에 대한 정보와 부가적인 데이터를 전달하기 위한 객체가 Notification 이다.
Notification 사용예
있던지 이벤트를 수신하는 클래스에서는 연쇄적으로 Notification을 다음화면으로 전달하여 (화면1 > 화면2 > 화면3) 의 순서를 유지하며 화면 전환을 할 수 있다. (화면1 > 화면3으로 바로 전환해버리면 네비게이션 순서가 틀어져버림)
사용하면 클래스간에 참조를 가지고 있지 않아도 데이터를 쉽게 전달할 수 있다.
② Notification 포스팅
④ NSNotificationCenter 에서 Observer 와 Notification 제거
NSNotificationCenter *notifCenter = [NSNotificationCenterdefaultCenter];
[notifCenter addObserver:self
selector:@selector(viewTrasitionToMyLostArticleList:)
name:@"moveToPushList" object:nil];
에러가 발생한다.
(void)viewTrasitionToMyLostArticleList:(NSNotification*)notif {
NSString *pushSeq = [[notif userInfo] objectForKey:@"pushSeq"];
// 의심분실물 목록뷰로 전환
}
2.3 이벤트 발생시키기
* Notification을 직접 생성하여 전달 - 데이터 전달이 필요없을 경우
(void)postNotification:(NSNotification*)notification;
* 부가적으로 전달해야할 데이터가 있을 경우 사용
(void)postNotification:(NSString*)notificationName
object:(id)anObject
userInfo:(NSDictionary*)userInfo
2.4 등록된 observer와 Notification 제거
// notificationObserver와 동일한 참조의 모든 observer를 제거
(void)removeObserver:(id)notificationObserver
// 송신자가 notificationSender로 등록된 notificationName으로 등록된 모든 observer 제거
(void)removeObserver:(id)notificationObserver
name:(NSString *)notificationName
object:(id)notificationSender
'아이폰' 카테고리의 다른 글
| [번역] 사용자 인터페이스 설계의 원리 (0) | 2012.06.24 |
|---|---|
| 수동으로 UI 컨트롤에 이벤트 전달 (0) | 2011.11.13 |
| NSNotification (1) | 2011.04.29 |
| 푸시 메시지 포맷 (0) | 2011.04.07 |
| 애플 푸시 서비스 (0) | 2011.04.07 |
| Sprite Sheet 제작툴 Zwoptex (0) | 2011.03.16 |
설정
트랙백
댓글
글
푸시 메시지 포맷
요구사항이 존재한다. 다음은 Local, Remote Notification Programming Guide 문서에서 일부 발췌한 내용이다.
자세한 내용은 실제 문서를 참고하자.
1. Provider가 APNS와 통신하기 위한 요구사항
Simple 포맷은 실제로 푸시 메시지가 전송됐는지를 보장하지 않기 때문에, 푸시 메시지에 대한 전송 신뢰성이 보장되야 할경우엔는
Enhanced 포맷을 사용하자. Enhanced 포맷에서는 메시지 전송 실패시 에러를 반환하기 때문에, Provider가 주기적으로 APNS에서
이 값을 체크하여 실패시 다시 전송을 요청할 수 있다.
Local, Remote Notification Programming Guide 문서에 나와있는 샘플 코드이다. 실제 메시지 전송을 구현해야할 경우 참고하자
static bool sendPayload(SSL *sslPtr, char *deviceTokenBinary, char *payloadBuff, size_t payloadLength)
{
bool rtn = false;
if (sslPtr && deviceTokenBinary && payloadBuff && payloadLength) {
uint8_t command = 1; /* command number */
char binaryMessageBuff[sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t)
+ sizeof(uint16_t) + DEVICE_BINARY_SIZE + sizeof(uint16_t) + MAXPAYLOAD_SIZE];
/* message format is, |COMMAND|ID|EXPIRY|TOKENLEN|TOKEN|PAYLOADLEN|PAYLOAD| */
char *binaryMessagePt = binaryMessageBuff;
uint32_t whicheverOrderIWantToGetBackInAErrorResponse_ID = 1234;
uint32_t networkOrderExpiryEpochUTC = htonl(time(NULL)+86400);
// expire message if not delivered in 1 day
uint16_t networkOrderTokenLength = htons(DEVICE_BINARY_SIZE);
uint16_t networkOrderPayloadLength = htons(payloadLength);
/* command */
*binaryMessagePt++ = command;
/* provider preference ordered ID */
memcpy(binaryMessagePt, &whicheverOrderIWantToGetBackInAErrorResponse_ID, sizeof
(uint32_t));
binaryMessagePt += sizeof(uint32_t);
/* expiry date network order */
memcpy(binaryMessagePt, &networkOrderExpiryEpochUTC, sizeof(uint32_t));
binaryMessagePt += sizeof(uint32_t);
/* token length network order */
memcpy(binaryMessagePt, &networkOrderTokenLength, sizeof(uint16_t));
binaryMessagePt += sizeof(uint16_t);
/* device token */
memcpy(binaryMessagePt, deviceTokenBinary, DEVICE_BINARY_SIZE);
binaryMessagePt += DEVICE_BINARY_SIZE;
/* payload length network order */
memcpy(binaryMessagePt, &networkOrderPayloadLength, sizeof(uint16_t));
binaryMessagePt += sizeof(uint16_t);
/* payload */
memcpy(binaryMessagePt, payloadBuff, payloadLength);
binaryMessagePt += payloadLength;
if (SSL_write(sslPtr, binaryMessageBuff, (binaryMessagePt -binaryMessageBuff)) > 0)
rtn = true;
}
return rtn;
}
반환해주어 에러의 원인을 확인할 수 있다. Provider 에서는 주기적으로 APNS의 에러응답에 접근하여 결과를 확인할 수 있다.
역시 실제 구현시에 참고하자.
static bool sendPayload(SSL *sslPtr, char *deviceTokenBinary, char *payloadBuff, size_t payloadLength)
{
bool rtn = false;
if (sslPtr && deviceTokenBinary && payloadBuff && payloadLength) {
uint8_t command = 1; /* command number */
char binaryMessageBuff[sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint32_t)
+ sizeof(uint16_t) + DEVICE_BINARY_SIZE + sizeof(uint16_t) + MAXPAYLOAD_SIZE];
/* message format is, |COMMAND|ID|EXPIRY|TOKENLEN|TOKEN|PAYLOADLEN|PAYLOAD| */
char *binaryMessagePt = binaryMessageBuff;
uint32_t whicheverOrderIWantToGetBackInAErrorResponse_ID = 1234;
uint32_t networkOrderExpiryEpochUTC = htonl(time(NULL)+86400);
// expire message if not delivered in 1 day
uint16_t networkOrderTokenLength = htons(DEVICE_BINARY_SIZE);
uint16_t networkOrderPayloadLength = htons(payloadLength);
/* command */
*binaryMessagePt++ = command;
/* provider preference ordered ID */
memcpy(binaryMessagePt, &whicheverOrderIWantToGetBackInAErrorResponse_ID, sizeof(uint32_t));
binaryMessagePt += sizeof(uint32_t);
/* expiry date network order */
memcpy(binaryMessagePt, &networkOrderExpiryEpochUTC, sizeof(uint32_t));
binaryMessagePt += sizeof(uint32_t);
/* token length network order */
memcpy(binaryMessagePt, &networkOrderTokenLength, sizeof(uint16_t));
binaryMessagePt += sizeof(uint16_t);
/* device token */
memcpy(binaryMessagePt, deviceTokenBinary, DEVICE_BINARY_SIZE);
binaryMessagePt += DEVICE_BINARY_SIZE;
/* payload length network order */
memcpy(binaryMessagePt, &networkOrderPayloadLength, sizeof(uint16_t));
binaryMessagePt += sizeof(uint16_t);
/* payload */
memcpy(binaryMessagePt, payloadBuff, payloadLength);
binaryMessagePt += payloadLength;
if (SSL_write(sslPtr, binaryMessageBuff, (binaryMessagePt -binaryMessageBuff)) > 0)
rtn = true;
}
return rtn;
}5. Error 응답 포맷
반환하지 않는다. 에러 응답의 포맷은 다음과 같다.
'아이폰' 카테고리의 다른 글
| 수동으로 UI 컨트롤에 이벤트 전달 (0) | 2011.11.13 |
|---|---|
| NSNotification (1) | 2011.04.29 |
| 푸시 메시지 포맷 (0) | 2011.04.07 |
| 애플 푸시 서비스 (0) | 2011.04.07 |
| Sprite Sheet 제작툴 Zwoptex (0) | 2011.03.16 |
| 애플리케이션 응답성 향상을 위해 동시성 사용하기 (0) | 2011.03.15 |
설정
트랙백
댓글
글
애플 푸시 서비스
라는 앱을 개발했다. 서울 분실물 센터에 수거되어 있는 분실물 목록을 조회할 수 있고, 등록된 분실물과 유사한 분신물 목록을
사용자 아이폰으로 알리는 앱이었다. 이때 유사 분실물 발견유무를 푸시 기능을 통해 구현하였다. 당시에 푸시와 관련된
자료가 별로 없어서(내가 못찾았겠지만...) 애플 개발자 가이드 문서를 참고하여 구현하였다. 그 때 정리한 내용을 올려본다.
(사진 캡처를 안해서 이해가 잘 안될 수도....-_-;; )
"분실물 다나와" 프로젝트로 예를 들면...Provider는 "분실물 다나와" 서버가 되고, Client App 은 "분실물 다나와" 아이폰 앱,
푸시할 데이터만을 가공하여 APNS에 푸시를 요청한다. Provider가 APNS에 접속하여 푸시데이터를 전송하려 할 때, APNS는
푸시요청을 할수 있는 권한을 SSL 인증을 통해 검사하게 된다. 그래서 Provider는 사전에 이 인증을 위한 암호화 파일을 사전에
등록시킨다. 이 파일을 p12 파일로 export 하여, 파일, 비밀번호와 함께 Provider 에게 사전에 전달해야 한다.
되기 때문에 Provider가 보유하고 있어야 하는 데이터이다. DeviceToken은 거의 변하지 않지만, 애플리케이션이 삭제되고 다시
설치될 때 변할 수도 있기 때문에 애플리케이션이 실행될 때마다, Provider에게 전송하여 갱신여부를 확인하는 것이 좋다. Development용과 Product용의 DeviceToken 값은 다르다는 것에 주의한다.
DeviceToken와 함께 다음의 주소로 push를 요청할 수 있다. 개발환경과 실제 서비스를 위한 APNS 의 주소가 다르다.
Local, Remote Notification Programming Guide 를 참고하자.
JSON 형태로 생성된 메시지 형태는 다음과 같다.
{"aps":{"sound":"default","alert":"My alert message","badge":45}}
참고하자. 이 메시지 포맷과 APNS 의 요구사항에 맞게 구현한 javapns라는 오픈소스 라이브러리를 사용하여 APNS에 푸시를
요청해보자
다음은 javapns 라이브러리를 사용하여 Provider 에서 APNS 에 푸시를 요청하는 예이다.
String password = "1q2w3e4r";
String certicatePath = "/home/CertificateSR/Interesting_Dev_Cert_pass.p12";
String apnsAddress = "gateway.sandbox.push.apple.com";
String apnsPort = "2195";
try {
PayLoad payload = new PayLoad();
payload.addAlert(pushMessage.getAlert());
payload.addBadge(pushMessage.getBadge());
payload.addSound(pushMessage.getSound());
HashMap customMap = (HashMap) pushMessage.getCustomData();
Iterator iterator = customMap.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
payload.addCustomDictionary(key, customMap.get(key));
}
PushNotificationManager manager = PushNotificationManager.getInstance();
manager.addDevice("myIphone", pushMessage.getDeviceToken());
Device device = PushNotificationManager.getInstance().getDevice("myIphone");
manager.initializeConnection( apnsAddress,
Integer.parseInt(apnsPort),
certicatePath,
password,
SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);
manager.sendNotification(device, payload);
manager.stopConnection();
manager.removeDevice("myIphone");
} catch (Exception e) {
e.printStackTrace();
}
⑦ 애플리케이션측에서 Push를 수신하기 위해서 UIApplicationDelegate 프로토콜의 메소드를 구현
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 배지넘버 초기화
application.applicationIconBadgeNumber = 0;
NSDictionary *aps =
[launchOptionsobjectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
// 애플리케이션을 처음실행 : RemoteNotification을 등록함
if (aps == nil) {
[[UIApplication sharedApplication]
registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeSound |
UIRemoteNotificationTypeBadge)
];
} else {
// 애플리케이션이 원격 통보에 의해 실행됐음
// alert 추출
NSString *alert = [aps objectForKey:@"alert"];
// custom 데이터 추출
NSString *pushSeq = [userInfo objectForKey:@"pushSeq"];
}
return YES;
}
// RemoteNotification 등록 성공. deviceToken을 수신
(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
// Provider에게 DeviceToken 전송
//[service registDeviceToken:[deviceToken description]];
}
// APNS 에 RemoteNotification 등록 실패
(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(@"fail RemoteNotification Registration: %@", [error description]);
}
// 애플리케이션 실행 중에 RemoteNotification 을 수신
(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// push 메시지 추출
NSDictionary *aps = [userInfo objectForKey:@"aps"];
// alert 추출
NSString *alert = [aps objectForKey:@"alert"];
// custom 데이터 추출
NSString *pushSeq = [userInfo objectForKey:@"pushSeq"];
}
<12345678 12345678 12345678 12345678 50cfb1 3f5febbe497df>
푸시 서비스 권한을 설정하고, 키체인에서 인증파일을 생성하는 과정이 번거롭고... 푸시를 받을 앱이 실행중일 때와 실행중이지
않을 때 푸시 수신 시 동작방식을 달리 처리해줘야 하는 것이 조금 번거로울 뿐이다. 다음 포스팅에서는 실제 푸시메시지 포맷에
대해서 좀더 자세히 알아보자.
'아이폰' 카테고리의 다른 글
| NSNotification (1) | 2011.04.29 |
|---|---|
| 푸시 메시지 포맷 (0) | 2011.04.07 |
| 애플 푸시 서비스 (0) | 2011.04.07 |
| Sprite Sheet 제작툴 Zwoptex (0) | 2011.03.16 |
| 애플리케이션 응답성 향상을 위해 동시성 사용하기 (0) | 2011.03.15 |
| OpenGL ES 게임 프레임웍 (0) | 2011.02.14 |
설정
트랙백
댓글
글
Sprite Sheet 제작툴 Zwoptex
2. Zwoptext의 특징
3. Zwoptex 다운받기
클릭해서, 변경사항을 적용시켜야 한다.
되는데, 이때 width, height 값을 조정하고, Apply 를 클릭하여 배경의 크기를 변경할 수 있다.
'아이폰' 카테고리의 다른 글
| 푸시 메시지 포맷 (0) | 2011.04.07 |
|---|---|
| 애플 푸시 서비스 (0) | 2011.04.07 |
| Sprite Sheet 제작툴 Zwoptex (0) | 2011.03.16 |
| 애플리케이션 응답성 향상을 위해 동시성 사용하기 (0) | 2011.03.15 |
| OpenGL ES 게임 프레임웍 (0) | 2011.02.14 |
| OpenGL ES 사용 (0) | 2011.02.14 |
설정
트랙백
댓글
글
애플리케이션 응답성 향상을 위해 동시성 사용하기
1. 애플리케이션에서의 응답성
아이폰, 아이패드를 포함한 모든 애플리케이션의 사용자 인터페이스에 있어서 응답성은 중요한 요소중에 하나이다.
많은 시간을 소비하는 태스크를 사용자 인터페이스가 동작하는 쓰레드에서 수행하면, 해당 태스크가 종료하기 까지
사용자는 어떠한 인터렉션도 행할 수가 없기 때문이다. 트위터의 글목록을 가져와서 보여주는 앱을 생각해보자.
최신글 목록과 사용자 프로필 이미지를 가져오는 동안, 버벅이 되며 먹통이 되면 누가 이 앱을 사용하겠는가?
이 포스팅에서는 Cocoa Touch에서 지원하는 동시성 향상을 방법에 대해서 알아보겠다.
MacOsX와 iOS에서 지원하는 사용자 인터렉션 응답성을 향상시키기 위한 다음과 같은 동시성 방법들이 있다.
NSThread / NSObject가 지원하는 백그라운드/메인 쓰레드, C기반의 POSIX 쓰레드, 비동기 기반의 메소드, NSOperation /NSOperationQueue 등이 있다. 각각의 추상화 수준(사용 용이성)과 복잡성이 다르다. 추상화 수준이 높은 방법일 수록
하드웨어 의존적인 부분을 감추어주고 쉽게 사용할 수 있어서, 비지니스 로직에 더 집중 할 수 있다. 좀더 세밀한 컨트롤과
뛰어난 성능을 원한다면 C 기반의 동시성 API 를 사용하자.
2. NSOperation / NSOperationQueue
웹에서 사진들의 목록을 받아와 이미지와 함께 사진의 이름을 출력하는 플리커 애플리케이션을 생각해보자.
사진들의 목록을 받아오고, 목록에 해당하는 이미지 각각을 로딩하는데 상당한 시간이 소모될 것이다. 이러한 작업을
아이폰 애플리케이션의 메인쓰레드에서 수행할 경우, 애플리케이션은 상당히 버벅거리게 된다. 백그라운드 쓰레드로
이미지를 가져오는 방법을 선택하더라도 성능의 향상은 있겠지만 그 효과는 미미하다.
하나의 이미지를 가져오는 작업에 하나의 쓰레드를 할당하여 완료되면 이미지를 목록을 추가하는 방식이 자연스러운
애플리케이션이 될 것이지만, 몇 개의 쓰레드를 할당하는 것이 성능의 저하를 가져오지 않고 최적의 성능을 낼 것인지는
하드웨어에 의존적이어서 정확히 알 수가 없다. 아이폰에서 제공하는 비동기 방식의 메소드를 사용하여 해결 할 수 있지만,
좀더 추상화 수준이 높으면서 하드웨어 변경에도 코드의 변경이 거의 없는 NSOperation/NSOperationQueue 를 사용해보자.
NSOperatinoQueue 는 내부적으로 최적의 성능을 낼 수는 쓰레드의 개수를 생성하고 관리해 준다.
NSOperation은 NSObject를 상속하고, 하나의 작업단위를 캡슐화하는 추상클래스이다.
3. NSBlockOperation
NSBlockOperation은 Lisp, Ruby와 같은 언어의 클로져와 유사한 Block 이라는 요소를 사용한다. Block은 마치
데이터 스콥을 공유하는 함수와 유사하며, Block으로 지정한 코드를 캡슐화하여 별도 쓰레드로 동작시킨다.
NSOperation / NSInvocationOperation 과 NSOperationQueue를 사용하는 방법도 훌륭하다. 하지만 NSBlockOperation을
사용하면 동일한 성능의 장접을 갖되, 연관된 코드를 한곳에 집중 시킬수 있는 부수적인 장점이 생긴다.
그러나 아이폰 운영체제의 하위 호환성이 떨어지는 것이 단점이다.
블럭은 사용하는 코드는 아래와 같다.
NSBlockOperation의 blockOperationWithBlock 메시지의 인자로 블럭을 정의하여 인자로 전달하였다.
블럭 ^{} 의 내부에서 긴 시간이 소모되는 코드를 수행하고, 작업이 완료되면 MainThread 에서 GUI를 변경하도록 하고 있다.
블럭 내 코드는 별도의 쓰레드에서 실행되기 때문에 자체적인 릴리지 풀을 생성하여 사용해야한다. 마지막으로 블럭에 정의한
작업을 수행하기 위해 NSOperationQueue(workQueue)에 추가하고 있다.
NSBlockOperation *fetchImageOp = [NSBlockOperationblockOperationWithBlock:^{
NSAutoreleasePool *localPool;
@try {
// Autorelease pool 생성
localPool = [[NSAutoreleasePool alloc] init];
// 시간이 소요되는 작업 수행
[selfperformSelectorOnMainThread:@selector(storeImageForURL:) // 메인쓰레드에서 GUI 변경
withObject:result
waitUntilDone:NO];
}
@catch (NSException * exception) {
NSLog(@"Exception: %@", [exception reason]);
}
@finally {
// Autorelease pool 해제
[localPool release];
}
}];
// NSOperationQueue에 추가
[workQueue addOperation:fetchImageOp];
4. 블럭 선언 및 정의하기
다음과 같이 익명으로 정의되어, 메시지의 파라미터로 전달될 수 있다.
int (^cubeIt)(int);// 블럭변수 선언
cubeIt = ^(int num) { return num * num * num; };// 블럭정의
다음과 같이 익명으로 정의되어, 메시지의 파라미터로 전달될 수 있다.
(returnDataType (^) ( parameterType1, parameterType2, ...))blockName
'아이폰' 카테고리의 다른 글
| 애플 푸시 서비스 (0) | 2011.04.07 |
|---|---|
| Sprite Sheet 제작툴 Zwoptex (0) | 2011.03.16 |
| 애플리케이션 응답성 향상을 위해 동시성 사용하기 (0) | 2011.03.15 |
| OpenGL ES 게임 프레임웍 (0) | 2011.02.14 |
| OpenGL ES 사용 (0) | 2011.02.14 |
| OpenGL ES 사용설정 (0) | 2011.02.13 |
설정
트랙백
댓글
글
OpenGL ES 게임 프레임웍
이 포스트는 작성중... -_-;; 음 마무리 지어야 하는데 이런 저런 일들로 정리를 못하고 있네;;;
-(CGRect)screenRectFromMeshRect:(CGRect)rect atPoint:(CGPoint)meshCenter
{
// find the point on the screen that is the center of the rectangle
// and use that to build a screen-space rectangle
CGPoint screenCenter = CGPointZero;
CGPoint rectOrigin = CGPointZero;
// since our view is rotated, then our x and y are flipped
screenCenter.x = meshCenter.y + 160.0; // need to shift it over
screenCenter.y = meshCenter.x + 240.0; // need to shift it up
rectOrigin.x = screenCenter.x - (CGRectGetHeight(rect)/2.0); // height and width
rectOrigin.y = screenCenter.y - (CGRectGetWidth(rect)/2.0); // are flipped
return CGRectMake(rectOrigin.x, rectOrigin.y, CGRectGetHeight(rect), CGRectGetWidth(rect));
}
SceneObject 업데이트 메소드
-(void)update
{
glPushMatrix();
glLoadIdentity();
// move to my position
glTranslatef(translation.x, translation.y, translation.z);
// rotate
glRotatef(rotation.x, 1.0f, 0.0f, 0.0f);
glRotatef(rotation.y, 0.0f, 1.0f, 0.0f);
glRotatef(rotation.z, 0.0f, 0.0f, 1.0f);
//scale
glScalef(scale.x, scale.y, scale.z);
// save the matrix transform
glGetFloatv(GL_MODELVIEW_MATRIX, matrix);
//restore the matrix
glPopMatrix();
if (collider != nil) [collider updateCollider:self];
}
SceneObject 렌더메소드
-(void)render
{
if (!mesh || !active) return; // if we do not have a mesh, no need to render
// clear the matrix
glPushMatrix();
glLoadIdentity();
glMultMatrixf(matrix);
[mesh render];
glPopMatrix();
}
'아이폰' 카테고리의 다른 글
| Sprite Sheet 제작툴 Zwoptex (0) | 2011.03.16 |
|---|---|
| 애플리케이션 응답성 향상을 위해 동시성 사용하기 (0) | 2011.03.15 |
| OpenGL ES 게임 프레임웍 (0) | 2011.02.14 |
| OpenGL ES 사용 (0) | 2011.02.14 |
| OpenGL ES 사용설정 (0) | 2011.02.13 |
| [iPhone] 로깅 프레임웍 cocoalumberjack (0) | 2010.12.21 |
설정
트랙백
댓글
글
OpenGL ES 사용
-(CGSize)loadTextureImage:(NSString*)imageName materialKey:(NSString*)materialKey
{
CGContextRef spriteContext; //context ref for the UIImage
GLubyte *spriteData; // a temporary buffer to hold our image data
size_t width, height;
GLuint textureID; // the ultimate ID for this texture
// grab the image off the file system, jam it into a CGImageRef
UIImage* uiImage = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:imageName ofType:nil]];
CGImageRef spriteImage = [uiImage CGImage];
// Get the width and height of the image
width = CGImageGetWidth(spriteImage);
height = CGImageGetHeight(spriteImage);
CGSize imageSize = CGSizeMake(width, height);
// Texture dimensions must be a power of 2. If you write an application that allows users to supply an image,
// you'll want to add code that checks the dimensions and takes appropriate action if they are not a power of 2.
if (spriteImage) {
// Allocated memory needed for the bitmap context
spriteData = (GLubyte *) malloc(width * height * 4);
memset(spriteData, 0, (width * height * 4));
// Uses the bitmatp creation function provided by the Core Graphics framework.
spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width * 4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
// After you create the context, you can draw the sprite image to the context.
CGContextDrawImage(spriteContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), spriteImage);
// You don't need the context at this point, so you need to release it to avoid memory leaks.
CGContextRelease(spriteContext);
// Use OpenGL ES to generate a name for the texture.
glGenTextures(1, &textureID);
// Bind the texture name.
glBindTexture(GL_TEXTURE_2D, textureID);
// Specidfy a 2D texture image, provideing the a pointer to the image data in memory
//Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGBBBBAAAA"
// this will make your images take up half as much space in memory
// but you will lose half of your color depth.
if (BB_CONVERT_TO_4444) {
void* tempData;
unsigned int* inPixel32;
unsigned short* outPixel16;
tempData = malloc(height * width * 2);
inPixel32 = (unsigned int*)spriteData;
outPixel16 = (unsigned short*)tempData;
NSUInteger i;
for(i = 0; i < width * height; ++i, ++inPixel32)
*outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 4) << 12) | ((((*inPixel32 >> 8) & 0xFF) >> 4) << 8) | ((((*inPixel32 >> 16) & 0xFF) >> 4) << 4) | ((((*inPixel32 >> 24) & 0xFF) >> 4) << 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, tempData);
free(tempData);
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
}
free(spriteData);
// Release the image data
// Set the texture parameters to use a minifying filter and a linear filer (weighted average)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Enable use of the texture
glEnable(GL_TEXTURE_2D);
// Set a blending function to use
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Enable blending
glEnable(GL_BLEND);
} else {
return CGSizeZero;
}
[uiImage release];
if (materialLibrary == nil) materialLibrary = [[NSMutableDictionary alloc] init];
// now put the texture ID into the library
[materialLibrary setObject:[NSNumber numberWithUnsignedInt:textureID] forKey:materialKey];
return imageSize;
}
-(void)render
{
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
// load arrays into the engine
glVertexPointer(vertexSize, GL_FLOAT, 0, vertexes);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(colorSize, GL_FLOAT, 0, colors);
glEnableClientState(GL_COLOR_ARRAY);
//render
glDrawArrays(renderStyle, 0, vertexCount);
}
-(void)render
{
glVertexPointer(vertexSize, GL_FLOAT, 0, vertexes);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(colorSize, GL_FLOAT, 0, colors);
glEnableClientState(GL_COLOR_ARRAY);
if (materialKey != nil) {
[[BBMaterialController sharedMaterialController] bindMaterial:materialKey];
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, uvCoordinates);
}
//render
glDrawArrays(renderStyle, 0, vertexCount);
}
'아이폰' 카테고리의 다른 글
| Sprite Sheet 제작툴 Zwoptex (0) | 2011.03.16 |
|---|---|
| 애플리케이션 응답성 향상을 위해 동시성 사용하기 (0) | 2011.03.15 |
| OpenGL ES 게임 프레임웍 (0) | 2011.02.14 |
| OpenGL ES 사용 (0) | 2011.02.14 |
| OpenGL ES 사용설정 (0) | 2011.02.13 |
| [iPhone] 로깅 프레임웍 cocoalumberjack (0) | 2010.12.21 |
설정
트랙백
댓글
글
OpenGL ES 사용설정
#import <UIKit/UIKit.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
@interface EAGLView : UIView {
@private
// 백버퍼의 넓이, 높이
GLint backingWidth;
GLint backingHeight;
EAGLContext *context;
// 렌더버퍼, 프레임버퍼 식별자
GLuint viewRenderbuffer, viewFramebuffer;
// 깊이 버퍼, 사용하지 않으면 0
GLuint depthRenderbuffer;
}
- (void)beginDraw;
- (void)finishDraw;
- (void)setupViewLandscape;
- (void)setupViewPortrait;
+ (Class)layerClass {
return [CAEAGLLayer class];
}
- (id)initWithFrame:(CGRect)rect {
if ((self = [super initWithFrame:rect])) {
// Get the layer
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = YES;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!context || ![EAGLContext setCurrentContext:context]) {
[self release];
return nil;
}
self.multipleTouchEnabled = YES;
}
return self;
}
- (void)layoutSubviews
{
[EAGLContext setCurrentContext:context];
[self destroyFramebuffer];
[self createFramebuffer];
[self setupViewLandscape];
}
- (BOOL)createFramebuffer {
// 프레임버퍼와, 렌더버퍼를 위한 식별자 값 얻기 (식별자는 GLuint 형 타입)
glGenFramebuffersOES(1, &viewFramebuffer);
glGenRenderbuffersOES(1, &viewRenderbuffer);
// 파이프라인에 바인딩
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
// 렌더버퍼 메모리 할당
[context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(CAEAGLLayer*)self.layer];
// 렌더버퍼를 프레임버퍼에 연결
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
// 깊이 버퍼도 사용한다면, 위와 동일한 과정으로 생성후 프레임버퍼에 연결
if (USE_DEPTH_BUFFER) {
glGenRenderbuffersOES(1, &depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, backingWidth, backingHeight);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);
}
if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
return NO;
}
return YES;
}
- (void)destroyFramebuffer {
glDeleteFramebuffersOES(1, &viewFramebuffer);
viewFramebuffer = 0;
glDeleteRenderbuffersOES(1, &viewRenderbuffer);
viewRenderbuffer = 0;
if(depthRenderbuffer) {
glDeleteRenderbuffersOES(1, &depthRenderbuffer);
depthRenderbuffer = 0;
}
}
- (void)setupViewLandscape
{
// Sets up matrices and transforms for OpenGL ES
glViewport(0, 0, backingWidth, backingHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
// set up the viewport so that it is analagous to the screen pixels
glOrthof(-backingHeight/2.0, backingHeight/2.0, -backingWidth/2.0, backingWidth/2.0, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
// Clears the view with black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
}
-(void)perspectiveFovY:(GLfloat)fovY
aspect:(GLfloat)aspect
zNear:(GLfloat)zNear
zFar:(GLfloat)zFar
{
const GLfloat pi = 3.1415926;
// Half of the size of the x and y clipping planes.
// - halfWidth = left, halfWidth = right
// - halfHeight = bottom, halfHeight = top
GLfloat halfWidth, halfHeight;
// Calculate the distance from 0 of the y clipping plane. Basically trig to calculate
// position of clip plane at zNear.
halfHeight = tan( (fovY / 2) / 180 * pi ) * zNear;
// Calculate the distance from 0 of the x clipping plane based on the aspect ratio.
halfWidth = halfHeight * aspect;
// Finally call glFrustum with our calculated values.
glFrustumf( -halfWidth, halfWidth, -halfHeight, halfHeight, zNear, zFar );
}
-(void)beginDraw
{
// Make sure that you are drawing to the current context
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
// make sure we are in model matrix mode and clear the frame
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT);
// set a clean transform
glLoadIdentity();
}
-(void)finishDraw
{
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
'아이폰' 카테고리의 다른 글
| Sprite Sheet 제작툴 Zwoptex (0) | 2011.03.16 |
|---|---|
| 애플리케이션 응답성 향상을 위해 동시성 사용하기 (0) | 2011.03.15 |
| OpenGL ES 게임 프레임웍 (0) | 2011.02.14 |
| OpenGL ES 사용 (0) | 2011.02.14 |
| OpenGL ES 사용설정 (0) | 2011.02.13 |
| [iPhone] 로깅 프레임웍 cocoalumberjack (0) | 2010.12.21 |
설정
트랙백
댓글
글
[iPhone] 로깅 프레임웍 cocoalumberjack
아이폰에서 사용할 수 있는 Log4j 같은 로깅 프레임웍을 찾아 구글링을 하다,
cocoalumberjack 이라는 프레임웍을 찾게 되었다. 사용법도 log4j 와 유사하면서,
설정하기 쉽고, NSLog 보다 빠른속도와 커스텀 로거를 작성할 수 있는 유연성도 제공한다.
실제로 사용해보고, 유용성에 대해서는 추후 포스팅 해야겠다.
아래 주소에서 프레임웍 소스를 다운받자. (svn 으로 체크아웃하자)
http://code.google.com/p/cocoalumberjack/
1 소스를 아이폰 프로젝트에 복사한다 (logging이라는 폴더를 만들고, lumberjack 폴더를 통째로 복사했다)
2 프레임웍 사용을 위한 설정을 한다. 사용할 로거의 종류를 결정하는 부분으로 초기화하는 부분에 들어간다
( 예를 들면 applicationDidFinishingLaunching...)
DDLog : 프레임웍의 기초가 되는 부분
DDASLogger : 로그메시지를 Apple System 로거인 Console.app 으로 출력한다
DDTTYLogger : 로그메시지를 Xcode 터미널로 출력한다.
DDFileLogger : 로그메시지를 파일로 출력한다.
다음과 같이 사용할 로거의 인스턴스를 생성하여 DDLog에 추가한다
#import "DDLog.h" #import "DDTTYLogger.h" #import "DDASLLogger.h"
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[DDLog addLogger:[DDASLLogger sharedInstance]];
[DDLog addLogger:[DDTTYLogger sharedInstance]];
// ...
}
3 기존 NSLog 문을 프레임웍에서 제공하는 로깅 메서드로 대체한다.
로깅 레벨은 error < warn < info < verbose 가 지원된다. 해당 로깅레벨은 설정하면, 자신과 하위레벨의
로깅메시지만을 출력한다. 레벨별 로깅 메서드는 다음과 같다.
DDLogError(@""); DDLogWarn(@""); DDLogInfo(@""); DDLogVerbose(@"");
로깅 레벨은 전역으로 설정 할 수도 있으며, 파일별로 설정할 수도 있다. 로깅 레벨은 상수로 정의되어 진다.
LOG_LEVEL_ERROR : 에러레벨의 로깅메시지 출력 LOG_LEVEL_WARN : 에러, 경고레벨의 로깅메시지 출력 LOG_LEVEL_INFO : 에러, 경고, 인포 레벨의 로깅메시지 출력 LOG_LEVEL_VERBOSE : 모든 로깅메시지 출력 LOG_LEVEL_OFF : 모든 로깅메시지를 출력하지 않음
이제 파일의 상단에 헤더파일과 로깅 레벨을 선언하고, 로깅메서드를 사용한다
#import "DDLog.h" // 모든 로깅메시지 출력하도록 레벨 설정 static const int ddLogLevel = LOG_LEVEL_VERBOSE; // 에러 레벨 로깅메시지 출력 DDLogError(@"fail!!");커스텀 로거를 작성하는 방법 또는 파일로거를 작성하는 방법은 프로젝트 사이트를 참고하자~
'아이폰' 카테고리의 다른 글
| Sprite Sheet 제작툴 Zwoptex (0) | 2011.03.16 |
|---|---|
| 애플리케이션 응답성 향상을 위해 동시성 사용하기 (0) | 2011.03.15 |
| OpenGL ES 게임 프레임웍 (0) | 2011.02.14 |
| OpenGL ES 사용 (0) | 2011.02.14 |
| OpenGL ES 사용설정 (0) | 2011.02.13 |
| [iPhone] 로깅 프레임웍 cocoalumberjack (0) | 2010.12.21 |