Warning: opendir(/var/www/html/wp-content/mu-plugins): Failed to open directory: Permission denied in /var/www/html/wp-includes/load.php on line 981
[button url=’https://github.com/sewonist/ScreenWakeUp’ target=’_blank’ size=’large’]Sources in GitHub[/button] 드디어 연재 마지막 시간입니다. 앞시간에 만든 파일들을 모두 모아 ane 를 만들어 보도록 하겠습니다. 사실 ane 빌드 자체는 한줄 명령어로 끝날 정도로 단순하지만 실제로 ane 를 만들려고 시도 할 때 많이 어려워하는 부분입니다. 그중 가장 큰이유는 GUI에 익숙해 있는 개발자가 커맨드라인을 이용해서 빌드 해야 하기 때문입니다. 그래서 많은 개발자들이 build.bat 이나 build.xml 을 이용해서 빌드를 하지만 커맨드라인을 수정해야 한다는 점은 변함이 없습니다. 그러므로 이번 기회에 adt를 이용한 빌드를 익혀 두는 것도 좋을 것 같습니다. 위의 디렉토리에 지금까지 만든 라이브러리와 SWC 를 모아 두었습니다. libScreenWakeUp.a 는 iOS용 라이브러리 에서 SecreenWakeUp.jar 는 Android용 라이브러리에서 마지막으로 ScreenWakeUp.swc는 연결 SWC 입니다. 그리고 나머지 2개의 xml 지금부터 차례대로 알아보겠습니다. [xml] xml 의 정확한 구조와 명세는 다음의 링크에서 확인 할 수 있습니다. Native extension descriptor files 여기서는 중요한 몇가지만 설명하겠습니다. id platform nativeLibrary initializer AIR런타임은 위와 같이 extension.xml 에 정의된 값을 토대로 context 를 생성하는 것 입니다. [xml] <property name="name" value="ScreenWakeUp"/> <target name="package" description="Create the extension package"> build.xml 은 빌드 자동화를 위한 ANT 설정 파일입니다. ANT 에 대해서는 위키에서 간단히 알아볼 수 있습니다. 예시로든 build.xml 은 단순히 ane 빌드만 하고 있으므로 딱히 ant 를 사용 할 필요 없어 보이지만 사실은 그렇지 않습니다. ane 개발은 네이티브 라이브러리, 연결 SWC 그리고 테스트 애플리케이션 까지 빌드가 되야 비로서 테스트가 가능합니다. 그런데 이런 일련의 과정을 일일이 빌드하려면 쓸데 없이 낭비되는 시간도 많을 뿐더러 불편하기 그지 없습니다. 그래서 보통 build.xml 에는 각 네이티브 라이브러리의 빌드, 연결 SWC의 빌드, 파일의 복사 및 압축 해제, ane 빌드 등이 모두 포함 되어 있습니다. 여기서 인자로 들어가는 -platform 은 extension.xml 에 정의된 platform 과 동일 해야 합니다. 그리고 시작점에서 보았던 폴더에 없던 파일이 보이는 바로 library.swf 입니다. 이는 ScreenWakeUp.swc 의 library.swf 입니다. ScreenWakeUp.swc 를 압축해제하고 같은 폴더에 library.swf 를 넣어두면 됩니다. 이제 모든 파일이 준비 되었다면 빌드를 해보겠습니다. 2초만에 빌드에 성공하였습니다. ㅎㅎㅎ 그리고 ScreenWakeUp.ane가 생성 된 것도 확인 할 수 있습니다. 이렇게 우리가 필요한 ane 제작이 완료 되었습니다. 그럼 제작한 ane가 잘 작동하는지 테스트 앱을 만들어 보겠습니다. 프로젝트명을 입력하고 SDK는 AIR3.3 이상으로 합니다. ScreenWakeUp.ane 는 iOS 와 Android 는 지원하니 두 플렛폼만 선택 합니다. build 폴더에서 빌드된 ScreenWakeUp.ane 를 프로젝트 폴더에 복사합니다. 연결 SWC 를 이용하기 위해 Library path 를 설정합니다. ane는 ane파일안에 연결 SWC 를 포함하고 있으므로 따로 SWC 를 넣을 필요 없이 ane 파일 하나로 같이 사용 할 수 있습니다. Native Extensions 탭에서 ANE 파일을 추가합니다. ane의 각종 정보를 확인 할 수 있습니다. [as3] import flash.display.Sprite; import it.ane.ScreenWakeUp; public class ScreenWakeUpTester extends Sprite public function ScreenWakeUpTester() stage.align = StageAlign.TOP_LEFT; _buttonOn = new PushButton(this, 100, 20, "ScreenWakeUp ON", onClick); _screenWakeUp = new ScreenWakeUp; } protected function onClick(event:MouseEvent):void 위와 같인 간단히 테스트 코드를 작성 합니다. [as3] ScreenWakeUp.ane 의 연결 SWC 인스턴스인 _screenWakeUp 을 이용하여 화면 잠금 해제를 할 수 있습니다. 마지막으로 아래와 같이 ane 파일을 패키지에 포함 시켜고 테스트 앱 프로젝트를 빌드합니다. 총 5회에 걸쳐 ANE에 대해서 알아보고 iOS, Android 각 플렛폼용 라이브러리와 연결 SWC 를 만들어 보았습니다. 그리고 ANE를 빌드하여 테스트앱을 통해 정상 작동하는지도 살펴보았습니다. 사실 지금까지는 제가 미리 테스트한 샘플을 가지고 예제로 보여 드렸기 때문에 별 문제 없이 모든게 진행 되었습니다. 하지만 실제 개발에서는 지금 부터가 문제 입니다. 막상 ANE 개발을 해보면 여기까지 와서 테스트를 하면 안되는 경우가 상당히 많기 때문입니다. ANE의 태생적인 단점으로 여러 레이어층을 가진다는게 문제 입니다. 정확히 어느 부분에서 문제가 발생 했는데 파악하기가 어렵습니다. 디버그도 쉽지 않구요. 이를 해결 하기 위해서는 최대한 초기에 계획을 잘 세우고 중간중간 가능한 많은 테스트슈트를 만들어 테스트를 하면 진행 하여야 하겠습니다. 이번 연재에 사용된 모든 소스는 아래의 Github에 공유 되어 있으니 소스를 보시고 테스트해보시기 바랍니다. 긴글 끝까지 읽어 주셔서 대단히 감사합니다.^^ [button url=’https://github.com/sewonist/ScreenWakeUp’ target=’_blank’ size=’large’]Sources in GitHub[/button] 제가 연결 SWC 라고 부르는 이 부분의 호칭이 참 모호합니다. 다른 외국문서는 대부분 ActionScript3 Code 로 하는 것 같은데 그건 그냥 언어 이름이라서 헷갈릴 소지가 있습니다. 일단 앞으로 공통된 호칭이 나오기 전까지 저는 그냥 연결 SWC 라고 부르겠습니다. 제가 이 파트를 연결 SWC 라고 부르는 이유는 이 SWC가 네이티브 라이브러리와 앞으로 개발할 다른 플래시들과의 연결점이 되어주기 때문입니다. 위의 그림은 연결 SWC 가 실제로 어떻게 작동하는 지를 보여주고 있습니다. 연결 SWC는 extension.xml 을 참조하여 각 OS에 맞는 context 를 생성합니다. 그리고 이 context 를 통해 네이티브 라이브러리와 통신하게 됩니다. 새로운 Flex Library Project 를 생성합니다. 프로젝트 이름을 입력하고 Flex SDK 는 AIR3.3 이상이 적용된 버전을 선택합니다. 이번 ScreenWakeUp ANE에서는 이벤트를 발생 하지 않지만 대부분의 ANE가 연결 SWC에서 이벤트를 사용하고 있습니다. 이를 대비해서 EventDispatcher를 확장했습니다. ANE 에서의 이벤트는 비동기로 이루어지기 때문에 약간의 처리가 필요합니다. ANE 에서의 이벤트 처리에 대해서 다음에 알아보도록 하고 이번에는 일단 지나가도록 하겠습니다. [as3] public class ScreenWakeUp extends EventDispatcher private var context:ExtensionContext; public function ScreenWakeUp(target:IEventDispatcher=null) try{ protected function onStatusHandler(event:Event):void } public function get isSupported():Boolean{ public function lock($flag:Boolean):void } 오~~~ 드디어 고향에 돌아왔습니다. 그동안 외계어를 보느라 고생 많았습니다. 이제 다시 안방으로 돌아왔습니다. 심지어 코드도 짧습니다. 특별히 설명이 없어도 다 이해할 수 있는 수준이지만 포스팅을 길게 하기 위해서 약간의 설명을 하겠습니다.^^ [as3] EXTENSION_ID는 extension.xml 에 정의되어 있는 ANE의 id 입니다. 이 id를 통해서 ANE를 구별하고 context를 생성 합니다. [as3] ExtensionContext 의 createExtensionContext 함수를 통해 실제 context를 생성 합니다. createExtensionContext 의 첫번째 인자는 extensionId 두번째 인자는 contextType 입니다. extensionId 를 참조하여 context를 생성하고 contextType을 인자로 넘겨 하나의 extension 에서 원하는 context를 생성 할 수 있게 합니다. 다만 보통은 단일 기능만 제공하므로 일반적으로 null을 넘기고 있습니다. 바로 이 시점에서 iOS의 경우 ExtInitializer를 통한 ContextInitializer 함수가 Android의 경우 ScreenWakeUpExtension 의 createContext 함수가 실행 되면서 context 가 생성 됩니다. [as3] 그리고 ExtensionContext 의 call(functionName:String, … args) 함수를 통해 네이티브 라이브러리의 함수를 실행하게 됩니다. functionName은 우리가 지난시간에 만든 각 라이브러리에서 함수이름으로 등록된 이름 입니다. 이제 ANE 를 만들기 위한 거의 모든 준비가 되었습니다. 첫 시간 ANE 살펴보기에서 알아본 ANE 구조 처럼 ANE는 네이티브 라이브러리 + 연결 SWC + extension.xml 의 압축파일입니다. 네이티브 라이브러리에서는 context를 만들 준비를 하고 실제 네이티브 함수를 구현합니다. 연결 SWC 는 context 를 만들고 context 와 플래시가 실행 할 수 있는 전역함수를 제공 합니다 그리고 마지막으로 extension.xml 은 AIR런타임이 연결 SWC 와 네이티브 라이브러리 사이의 연결을 정의 합니다. 다음 시간에는 지금까지 만든 파일들을 모두 build 폴더에 넣고 실제 ScreenWakeUp.ane 를 빌드 해 보도록 하겠습니다. Android용 네이티브 라이브러리를 만들기 위해서는 ADT 즉 Android Development Toolkit이 필요합니다. 최신 이클립스를 설치하시고 플러그인으로 ADT를 설치하시면 됩니다. 자세한 설치방법은 다음의 링크를 참고하세요. ADT 설치하기, 안드로이드 SDK 설치하기, AVD 추가하기 [button url=’https://github.com/sewonist/ScreenWakeUp’ target=’_blank’ size=’large’]Sources in GitHub[/button] Android 용 네이티브 라이브러리는 작성은 iOS용과 약간의 차이가 있습니다. iOS용이 C 의 구조체를 이용한 방식이라면 Android는 Java의 클래스를 이용하고 있습니다. 이는 단순히 언어의 문법적 차이일뿐 실제 작동 방식은 거의 유사합니다. [java] import android.util.Log; import com.adobe.fre.FREContext; public class ScreenWakeUpExtension implements FREExtension { @Override Log.e("ScreenWakeUp", "call createContext"); return new ScreenWakeUpContext(); @Override @Override } 이 ScreenWakeUpExtension 은 extension.xml 에 정의 되어 있습니다. 그래서 AIR런타임 실행시 extension.xml을 참조하여 ScreenWakeUpExtension 의 createContext을 실행하여 context를 반환 받습니다. 인자 arg0은 ExtensionContext.createExtensionContext([extensionId], [contextTyoe]); 실행시 전달되는 contextType 입니다. import java.util.HashMap; import com.adobe.fre.FREContext; public class ScreenWakeUpContext extends FREContext { @Override } @Override map.put("isSupported", new IsSupportedFunction()); return map; } [java] import android.app.Activity; import com.adobe.fre.FREContext; public class LockFunction implements FREFunction { protected PowerManager.WakeLock mWakeLock; @Override if(mWakeLock==null){ try { if(flag==true && isLock==false){ isLock = flag; return null; } 위의 리스트는 FREObject의 경우이며 추가적으로 FREObject의 자식인 FREArray, FREBitmapData, FREByteArray 클래스도 사용할 수 있습니다. [java] 참고로 Android 에서 이 기능을 사용하기 위해서는 아래의 퍼미션이 필요하므로 제작한 AIR앱의 -App.xml 에 아래의 퍼미션을 추가해야 합니다. Android 용 네이티브 라이브러리 만드는 법을 살펴 보았습니다. iOS와는 문법적으로 조금 다르나 기본적으로 context를 생성하고 함수 목록을 반환하야 사용하는 구조는 유사하다는 걸 알 수 있었습니다. 즉, extension.xml 에 의해 ScreenWakeUpExtension 이 실행되고 이어 각 기능 함수가 포함되어 있는 ScreenWakeUpContext가 반환되는 것 입니다. 함수들은 FREFunction 인터페이스만 정의 하고 있으면 내부적으로는 어떻게 작성되어도 무방합니다. 또한 예제에서는 편의를 위해 모든 파일을 따로 만들었지만 한파일에 모두 정의 되어 작성되어도 잘 작동하니 참고 하시기 바랍니다. 이제 다음 시간에는 앞서 만든 각 네이티브 라이브러리를 실제 플래시와 연결해 줄 연결 SWC 를 만들어 보도록 하겠습니다. 자 이제 본격적으로 ScreenWakeUp ANE 용 iOS 네이티브 라이브러리를 만들어 보도록 하겠습니다. 제 작업 환경은 아래와 같습니다. 저는 주로 모바일용을 만들고 있기 때문에 위와 같은 환경입니다. 사용자 마다 환경은 조금씩 다를 수 있는데 AIR3.3 이상의 Flex SDK만 있다면 ANE 를 만드는데 크게 상관은 없습니다. 일단 제가 가지고 있는 시스템이 맥이다 보니 맥을 기준으로 글을 작성 할 예정입니다. [button url=’https://github.com/sewonist/ScreenWakeUp’ target=’_blank’ size=’large’]Sources in GitHub[/button] 그럼 Xcode 프로젝트를 생성해 보도록 하겠습니다. 이제 iOS용 ANE 라이브러리를 만들 준비가 전부 되었으므로 실제 코드를 살펴 보도록 하겠습니다. 지난 시간에 광고한대로 이번 시간부터는 ScreenWakeUp 이라는 ANE를 직접 만들고 소스를 분석해 보도록 하겠습니다. ScreenWakeUp 은 스마트폰의 화면자동 잠금 기능을 무효화 하고 화면이 계속 켜져 있도록 해주는 ANE 입니다. [c] @interface ScreenWakeUp : NSObject @end Xcode 프로젝트를 생성하고 나면 자동으로 생성되는 ScreenWakeUp.h 파일에 FlashRuntimeExtensions.h 파일을 임포트 합니다. 이제 앞으로 ScreenWakeUp.h 를 임포트하는 ScreenWakeUp.m 파일에서 FlashRuntimeExtensions.h 에 정의된 모든 기능을 사용 할 수 있습니다. 그럼 바로 ScreenWakeUp.m 전체소스를 보고 부분씩 살펴 보겠습니다. [c] @implementation ScreenWakeUp @end FREObject isSupported(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[] ){ FREObject lock(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[] ){ //Turn our actionscrpt code into native code. if(boolean){ void ContextInitializer(void* extData, const uint8_t * ctxType, FREContext ctx, *numFunctionsToTest = count; func[0].name = (const uint8_t *) "isSupported"; func[1].name = (const uint8_t *) "lock"; *functionsToSet = func; void ContextFinalizer(FREContext ctx) { void ExtInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet, void ExtFinalizer(void* extData) { 처음 보면 다소 복잡해 보이는 코드이지만 하나하나 나눠서 보면 그리 어렵지 않습니다. 먼저 확인해햐 하는 함수는 ExtInitializer 입니다. [c] [c] *numFunctionsToTest = count; func[0].name = (const uint8_t *) "isSupported"; func[1].name = (const uint8_t *) "lock"; *functionsToSet = func; 위의 코드에서 주의깊게 봐야 할 부분은 먼저 int count=2 입니다. 소스를 잘 보시면 count는 numFunctionsToTest 와 functionsToSet 을 위한 func 생성시 메모리 크기 또한 지정해 주고 있습니다. 메모리 관리에 대한 개념이 별로 없는 플래시 개발자들이 C언어에서 가장 많이 힘들어 하는 부분입니다. count를 2로 생성했으면 이후에 오는 배열크기도 이와 반드시 동일 해야 합니다. 즉 func[3] 와 같이는 사용 할 수 없습니다. func 구조체의 name 인자는 플래시에서 ExtensionContext call() 호출시 사용 하는 이름 입니다. functionData 는 function 실행시 전달되는 데이터 입니다. 그닥 사용 할 일은 많지 않을 것 같습니다. function은 실제로 호출될 함수에 대한 참조 입니다. 그리고 추가적으로 함수인자로 넘어오는 ctxType 은 연결 연결 SWC 에서 context를 생성하는 함수인 ExtensionContext.createExtensionContext([extensionId], [contextTyoe]); 실행시 contextType 에 들어가는 인자로 하나의 ANE 에서 다른 종류의 기능인 있는 context 를 만들 수 있게 해줍니다. [c] //Turn our actionscrpt code into native code. if(boolean){ [c] //Turn our actionscrpt code into native code. 타입에 따라 사용법은 조금씩 상이 합니다. 그리고 함수에서 결과 값을 반환 받는 방식이 아닌 인자로 들어간 포인터에 값이 저장 되는 형식이 특이해 보입니다. 여담으로 dieBuster 를 방문해 보시면 함수와 인자에 대한 좋을 글을 보실 수 있습니다. [c] 참고로 제가 테스트 해본결과 ANE 용 라이브러리를 만들때 C, C++ 그리고 Object-C가 위의 코드 처럼 섞여 있어도 문제없이 잘 작동하였습니다. 간혹 빌드를 한 파일이 안보이는 경우가 있는데 제 경우에는 빌드 설정에서 빌드 패스를 위의 이미지 처럼 상대경로로 설정해 줍니다. 그럼 아래의 이미지 처럼 프로젝트 폴더의 한단계 상위에서 최종적으로 빌드된 파일을 확인 할 수 있습니다. 지금까지 iOS 용 ANE 네이티브 라이브러리를 만드는 과정에 대해서 알아보았습니다. 간단히 순서를 요약하면 Xcode 에서 Cocoa Touch Static Library 프로젝트를 만든다. FlashRuntimeExtenshion.h 를 프로젝트에 추가한다. ExtInitializer -> ContextInitializer -> 함수 순으로 등록하여 사용한다. 정도로 정리 할 수 있을 겁니다. 이제 ANE를 만들기 위한 첫발을 내딛었습니다. 다음 시간에는 iOS용과는 또다른 구조로 되어있는 Android 용 라이브러리를 만들어 보도록 하겠습니다. – 참고 – p.s. 우야꼬님도 ANE에 대한 연재를 시작하셨네요. 같이 보시면 더욱 좋을 것 같습니다. Native Extension for iOS 만들기 Part.1 – iOS 개발 ANE 란 AIR Native Extensions 의 약자로 이름 그대로 AIR 에서 네이티브 코드를 사용 할 수 있게 해주는 AIR 확장 툴입니다. 저는 앞으로 5회에 걸쳐 ANE 에 대해서 알아보고 어떻게 만들고 사용 할 수 있는지 알아 보려고 합니다. 오늘은 그 첫시간으로 ANE 에 대해서 간략 하게 알아 보도록 하겠습니다. ANE는 Adobe AIR 와 운영체제의 네이티브 라이브러리를 서로 연결 해 주는 연결점(context) 라고 생각하시면 이해하기 편합니다.주로 AIR가 네이티브 라이브러리의 함수를 호출하고 데이터를 주고 받는 형태로 이루어져 있습니다. 흔히들 AIR3.0 에서 모바일을 지원하며 대대적으로 알려졌지만 실제로는 AIR2.5 for TV에서 처음 등장하였습니다. ANE는 다음의 두 가지 방법 중 하나로 작동 할 수 있습니다. 디바이스 번들링 디바이스 번들링은 네이티브 코드가 디바이스에 포함되는 경우로 AIR2.5 for TV 의 ANE가 대표적입니다. 주로 네이티브코드를 TV제작업체에서 제공합니다. 아래의 표는 애플리케이션 번들링과 디바이스 번들링이 지원하는 디바이스를 보여 줍니다. ANE 는 시스템에 특화된 기능들을 사용 할 수 있게 해줍니다. 예를 들어 핸드폰에 있는 진동이라던가 안드로이드의 알람과 같이 기본 AIR API에 없는 기능을 사용 할 수 있습니다. 이러한 시스템 특화된 기능을 Adobe 에서 지원해 주기를 기대하는 것은 어렵습니다. Adobe는 당연하겠지만 범용으로 사용 할 수 있는 API 업데이트에 중점을 두고 있으니까요. 그래서 ANE라는 중간역활을 두어 개발자들에게 필요한 것들을 개발 할 수 있는 문을 열어 주었습니다. 어떻게 보면 인터넷 생태계가 급속도록 모바일로 이동하면서 Adobe가 내놓은 궁여지책 일 수도 있습니다. 하지만 실제로 ANE가 AIR2.5 for TV 부터 지원했다는 사실을 보면 내부적으로 이러한 상황을 염두하고 있었던 것 같습니다. 좀더 현실적으로 보면 이로서 시스템의 자원을 AIR에서 바로 사용할 수 있게 된것입니다. 예를 들어 기존에는 특정 드라이버를 이용해야 하는 경우 AIR에서 직접 접근 할 방법이 없으므로 중간에 프록시서버등을 통해서 소켓으로 통신하곤 하였습니다. 하지만 이제 더 이상 그럴 필요 없이 ANE 를 통해 바로 연결 할 수 있습니다. 전통적인 C, C++ 그리고 Java와 같은 언어를 사용 할 수 있게 됨으로서 기존의 검증된 훌륭한 코드들을 빠르고 쉽게 사용 할 수 있습니다. ANE를 통해 이러한 코드를 랩핑하여 앞으로 ActionScript 통해 만들 어플리케이션에서도 이러한 코드를 사용 할 수 있게 되었습니다. ANE 는 가장 높은 수준의 최적화를 구현 할 수 있습니다. ANE를 사용함으로서 기대 할 수 있는 성능 향상은 첫째 컴파일된 C 코드를 통한 최고의 퍼포먼스, 두번째로 병렬 알고리즘으로 큰 효과를 볼 수 있는 멀티코어의 사용, 마지막으로 GPU 가속을 통한 성능 향상을 기대 할 수 있습니다. 제가 만든 앱을 통해서 테스트 해 본 결과 암호화와 같은 특정상황에서는 엄청난 성능의 차이를 체감 할 수 있었습니다. ANE의 시스템에 특화된 기능을 사용 할 수 있는 특징은 결국 시스템에 종속적으로 만들어 버립니다. ANE를 도입하는 순간 플래시의 큰장점인 원소스 멀티플렛폼을 포기해야 하는 상황이 발생합니다. 물론 ANE를 도입해야 하는 시점에서 이미 어느정도 멀티플랫폼을 포기해야 할 컨테츠라는 점이 조금은 다행이긴 합니다만 예를 들어 무료컨텐츠에 광고 솔루션을 붙힌 어플리케이션의 경우 보통 ANE로 작성된 광고 솔루션을 사용하게 되는데 AdMob을 붙힌 어플리케이션은 iOS에 사용 할 수 없게되는 상황이 발생 하게 된다는 점입니다. 심지어 iOS용으로 만든 라이브러리의 경우 ARM용으로 빌드한 것은 x86으로 돌아가는 아이폰 시뮬레이션에서는 작동 하지 않습니다. 뒤에 좀 더 자세히 알아보겠지만 ANE 가 최종적으로 실행 되는 모습을 보기 위해서는 다음의 세 레이어층이 필요합니다. 1.네이티브 코드 2.연결 SWC 3.어플리케이션 입니다. 실제로 우리가 ANE 라고 부르는 영역은 1번과 2번 까지 입니다. 하지만 실제로 ANE 를 만들고 테스트 하기 위해서는 디바이스에서 돌아가는 3번 어플리케이션 까지 작성해야 합니다. 그리고 ANE와 어플리케이션이 전혀 다른 루트로 디버그툴을 제공하므로 디버그가 상당히 불편한 편입니다. 가장 좋은 솔루션은 네이티브코드를 작성할때 테스트 케이스를 만들어 네이티브코드에 대한 무결성을 보장하는 겁니다. 이제 ANE 파일의 실제구조를 알아보겠습니다. ANE는 단순히 네이티브코드와 연결SWC의 libaray.swf 그리고 이들의 관계를 정의한 extension.xml 의 압축파일입니다. 파일트리는 다음 과 같습니다. [xml] 앞으로 연제를 하며 만들어 볼 ScreenWakeUp의 ANE 트리구조 입니다. AIR는 시스템을 확인 후 extension.xml을 토대로 context를 생성 하게 됩니다. extension.xml을 한번 보겠습니다. [xml] … </platforms> 여기서 주의깊게 봐야 할 부분은 <id> 와 <initializer> 입니다. 다음 ANE만들기에서 다시 자세히 살펴보겠지만 간단히 살펴보면 <id>는 연결SWC 에서 다음의 코드로 context를 만들때 사용하는 아이디 입니다. [as3] 그리고 <initializer> 의 값은 네이티브코드에 정의된 함수로 FlashRuntimeExtensions.h 에 의해 전달된 context에 함수를 등록하는 함수입니다. 이렇게 함으로서 연결SWC 와 네이티브코드가 context를 통해 연결되게 됩니다. Adobe가 ANE를 처음(?)소개 했을 때 많은 플래시 개발자들이 열광했습니다. 저도 그들 중 한명이었구요. 모바일시대에 들어서면 플래시의 입지가 줄어들대로 줄어든 상황에서 ANE는 마치 한줄기 구원의 빛과 같았습니다. 하지만 ANE는 장점만큼이나 신경써야할게 많은 기술입니다. 특히 ANE의 핵심인 네이티브코드 부분은 일반 플래시개발자에게는 너무나 생소한 영역입니다. 그러다 보니 많은 분들이 ANE 에 관심은 있지만 실제로 쉽게 접근하기 힘든게 사실입니다. 하지만 차근차근 살펴보면 생각보다 어렵지 않습니다. 가능한 쉽게 설명하려 했으나 조금 뜬구름 잡는 느낌이 있는데 이후 연제에서 실제로 샘플을 만들어 보면 더 쉽게 이해 할 수 있으리라 생각 됩니다. 다음 시간 부터는 ScreenWakeUp 이라는 이름의 ANE를 실제로 만들어 보도록 하겠습니다. 이 ANE는 스마트폰의 화면을 켬 상태로 잠궈주는 기능을 합니다. 만약 AIR를 이용해 비디오 플레이어 같은 어플을 만들경우 유용하게 사용 할 수 있을 겁니다. – 참고 –작업환경
소스 다운로드
시작점 만들기

extension.xml
<extension xmlns="http://ns.adobe.com/air/extension/3.1">
<id>it.ane.ScreenWakeUp</id>
<versionNumber>1.1</versionNumber>
<platforms>
<platform name="iPhone-ARM">
<applicationDeployment>
<nativeLibrary>libScreenWakeUp.a</nativeLibrary>
<initializer>ExtInitializer</initializer>
<finalizer>ExtFinalizer</finalizer>
</applicationDeployment>
</platform>
<platform name="Android-ARM">
<applicationDeployment>
<nativeLibrary>ScreenWakeUp.jar</nativeLibrary>
<initializer>it.ane.screenwakeup.ScreenWakeUpExtension</initializer>
</applicationDeployment>
</platform>
</platforms>
</extension>
[/xml]
ANE의 고유 id 입니다. 이 아이디는 연결 SWC 가 context를 만들 때 사용하는 id와 동일합니다.
각 플렛폼을 정의하는 노드 입니다. 플렛폼에 사용 할 수 있는 name 속성은 다음과 같습니다.
해당 플렛폼에서 사용한 라이브러리 파일명입니다.
미리 정의된 initializer 함수 또는 클래스명입니다.build.xml
<?xml version="1.0" encoding="UTF-8"?>
<project name="Air Native Extension Build Scripts" default="package">
<property name="sdk.home" value="/Applications/Adobe Flash Builder 4.6/sdks/4.6.0_AIR3.3"/>
<property name="bin.ext" value=""/>
<exec executable="${sdk.home}/bin/adt${bin.ext}" failonerror="true" dir="./">
<arg value="-package"/>
<arg value="-target"/>
<arg value="ane"/>
<arg value="${name}.ane"/>
<arg value="./extension.xml"/>
<arg line="-swc ${name}.swc"/>
<arg line="-platform iPhone-ARM library.swf libScreenWakeUp.a"/>
<arg line="-platform Android-ARM library.swf ScreenWakeUp.jar"/>
</exec>
</target>
</project>
[/xml]
테스트 하기






package
{
import com.bit101.components.Label;
import com.bit101.components.PushButton;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.MouseEvent;
{
private var _buttonOn:PushButton;
private var _buttonOff:PushButton;
private var _status:Label;
private var _screenWakeUp:ScreenWakeUp;
private var _isSupported:Boolean;
{
super();
stage.scaleMode = StageScaleMode.NO_SCALE;
_buttonOff = new PushButton(this, 100, 50, "ScreenWakeUp OFF", onClick);
_status = new Label(this, 100, 80, "status : OFF");
_isSupported = _screenWakeUp.isSupported;
{
if(event.currentTarget == _buttonOn){
if(_isSupported){
_screenWakeUp.lock(true);
_status.text = "status : ON";
}
} else if (event.currentTarget == _buttonOff) {
if(_isSupported){
_screenWakeUp.lock(false);
_status.text = "status : OFF";
}
}
}
}
}
[/as3]
_screenWakeUp.lock(true); //화면 잠금 설정
…
_screenWakeUp.lock(false); //화면 잠금 해제
[/as3]
정리
작업환경
소스 다운로드
연결 SWC

시작점 만들기



코드작성
package it.ane
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.StatusEvent;
import flash.external.ExtensionContext;
{
private static const EXTENSION_ID : String = "it.ane.ScreenWakeUp";
{
super(target);
context = ExtensionContext.createExtensionContext(EXTENSION_ID, null);
context.addEventListener(StatusEvent.STATUS, onStatusHandler);
}catch(e:Error){
trace(e.message, e.errorID);
}
}
{
var result:Boolean = context.call("isSupported");
return result;
}
{
context.call("lock", $flag);
}
}
[/as3]
private static const EXTENSION_ID : String = "it.ane.ScreenWakeUp";
[/as3]
context = ExtensionContext.createExtensionContext(EXTENSION_ID, null);
[/as3]
public function lock($flag:Boolean):void
{
context.call("lock", $flag);
}
[/as3]정리
작업환경
소스 다운로드
시작점 만들기

이클립스에 정상적으로 안드로이드 SDK 설치 되었다면 위의 이미지와 같이 신규 프로젝트에 Android 가 추가된 것을 확인 할 수 있습니다. Android Application Project를 선택합니다.
어플리케이션 이름을 지정해 줍니다. Build SDK는 설치된 SDK 이고 Minimum Required SDK는 최소 필요 SDK입니다. 이 최소SDK 에 따라 사용 할 수 있는 기능에 차이가 있을 수 있습니다.
Create Activity 는 일반 안드로이드앱을 만들 때를 위한 기본 템플릿 입니다. ANE를 위한 라이브러리에서는 필요 없는 기능이므로 체크를 해제 하고 프로젝트 생성을 완료 합니다.
플래시와 네이티브 라이브러리를 연결하기 위해 사용 할 각종 함수와 정의가 있는 FlashRuntimeExtenshion.jar 파일을 복사합니다. 이 파일은 일반적으로 {Flash Builder 설치 경로}/sdks/{SDK 버전}/lib/android 폴더 안에 위치 합니다.
FlashRuntimeExtenshion.jar 을 좀전에 만든 프로젝트 폴더의 libs폴더에 복사 합니다. Android 의 경우에는 libs 폴더안의 jar 파일은 자동으로 참조하니 따로 프로젝트에 등록 할 필요는 없습니다.코드작성

package it.ane.screenwakeup;
import com.adobe.fre.FREExtension;
public FREContext createContext(String arg0) {
}
public void dispose() {
}
public void initialize() {
}
[/java]
ScreenWakeUpExtension 클래스는 FREExtension 인터페이스를 정의하고 있습니다. 저는 처음 Android용 ANE를 라이브러리를 만들 때 당연히 전부 클래스를 상속하려니 extends 를 했던 아픈 기억이 있습니다. 클래스 확장인 아닌 인터페이스 정의에 주의 하시기 바랍니다.
[java]
package it.ane.screenwakeup;
import java.util.Map;
import com.adobe.fre.FREFunction;
public void dispose() {
// TODO Auto-generated method stub
public Map<String, FREFunction> getFunctions() {
Map<String, FREFunction> map = new HashMap<String, FREFunction>();
map.put("lock", new LockFunction());
}
[/java]
FREContext 를 확장하는 ScreenWakeUpContext 를 만듭니다. getFunctions() 함수를 통해 함수목록이 있는 map을 반환 합니다. map에 AIR에서 함수 호출시 사용할 이름과 함수의 인스턴스를 넣어 줍니다. C의 경우 함수에 대한 포인터 참조이나 Java의 경우 객체라는 점이 다릅니다. Java문법과 유사한 ActionScript에 익숙한 플래시 개발자들에게 좀더 익숙한 문법이 아닌 가 싶습니다.
package it.ane.screenwakeup;
import android.content.Context;
import android.os.PowerManager;
import android.util.Log;
import com.adobe.fre.FREFunction;
import com.adobe.fre.FREInvalidObjectException;
import com.adobe.fre.FREObject;
import com.adobe.fre.FRETypeMismatchException;
import com.adobe.fre.FREWrongThreadException;
private Boolean isLock;
public FREObject call(FREContext ctx, FREObject[] args) {
Activity activity = ctx.getActivity();
final PowerManager pm = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
this.mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "ScreenWakeUp");
isLock = false;
}
Boolean flag = args[0].getAsBool();
this.mWakeLock.acquire();
} else if (flag==false && isLock == true) {
this.mWakeLock.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (FRETypeMismatchException e) {
e.printStackTrace();
} catch (FREInvalidObjectException e) {
e.printStackTrace();
} catch (FREWrongThreadException e) {
e.printStackTrace();
}
}
[/java]
실제 기능을 할 함수클래스를 작성합니다. LockFunction은 FREFunction 인터페이스를 정의하고 있는 것에 주의 하시기 바랍니다. 함수 인자를 살펴보면 ctx 는 context, args는 플래시에서 함수 호출신 전달되는 인자입니다. Android도 iOS와 마찬가지로 인자를 바로 사용하는 것이 아니라 getAsBool() 등의 함수를 통해 네이티브 변수로 변환 해야 합니다. 사용 할 수 있는 인자 타입은 아래와 같습니다.
Activity activity = ctx.getActivity();
final PowerManager pm = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
this.mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "ScreenWakeUp");
…
this.mWakeLock.acquire();
…
this.mWakeLock.release();
[/java]
실제로 화면잠금 구현부입니다. 여기서 재미난게 있습니다. PowerManager를 사용하기 위해서는 Activity 가 있어햐 하는데 우리는 이 Activity를 만든 적이 없습니다. 하지만 이미 AIR에 의해서 기본적으로 Activity가 만들어져 있기 때문에 ctx.getActivity(); 를 통해 바로 사용 할 수 있습니다.
[xml]
<uses-permission android:name="android.permission.WAKE_LOCK" />
[/xml]빌드

Package Explorer 에서 프로젝트의 src 폴더를 우클릭해서 Export 합니다. 물론 다른 방법으로도 Export 할 수 있지만 이렇게 하는게 가장 깔끔하게 Export 됩니다.
Export 는 Java 의 JAR file 을 선택 합니다.
Export generated class files and resources 가 체크 활성화 되어 있는지 확인합니다. JAR 파일이 저장될 곳을 선택하고 완료합니다.정리
작업환경
소스 다운로드
시작점 만들기

위의 개발 폴더 구조는 제가 다른 여러 ANE 제작자들의 폴더구조를 보고 만든 방법입니다. Android 와 Xcode 는 각 네이티브 라이브러리를 만들 프로젝트 폴더이고 SWC는 연결 SWC, Flash 폴더는 테스트 플래시 프로젝트 폴더입니다 마지막으로 build는 각 네이티브 라이브러리, SWC 그리고 extension.xml 을 넣어서 빌드를 하는 폴더 입니다. 위의 구조는 임의 이므로 편하신대로 다시 세팅하여도 무방합니다.
File -> New -> Project… 메뉴를 통해서 Cocoa Touch Static Library 프로젝트를 생성합니다.
프로젝트 이름을 입력하고 프로젝트 생성을 완료 합니다.
플래시와 네이티브 라이브러리를 연결하기 위해 사용 할 각종 함수와 정의가 있는 FlashRuntimeExtenshion 헤더 파일을 복사합니다. 이 파일은 보통 {Flash Builder 설치 경로}/sdks/{SDK 버전}/include 폴더 안에 위치 합니다.
FlashRuntimeExtenshion.h 파일을 좀전에 만든 프로젝트 하위 폴더에 복사 합니다.

Xcode 프로젝트는 폴더에 파일을 복사해도 프로젝트에서 자동으로 인식 하지 않으므로 위와 같은 방법을 프로젝트에 복사한 FlashRuntimeExtenshion.h 을 등록합니다.코드작성
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "FlashRuntimeExtensions.h"
[/c]
#import "ScreenWakeUp.h"
FREObject retVal;
if(FRENewObjectFromBool(YES, &retVal) == FRE_OK){
return retVal;
}else{
return nil;
}
}
//Temporary values to hold our actionscript code.
uint32_t boolean;
FREGetObjectAsBool(argv[0], &boolean);
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
} else {
[[UIApplication sharedApplication] setIdleTimerDisabled:NO];
}
return nil;
}
uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet)
{
int count=2;
FRENamedFunction* func = (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * count);
func[0].functionData = NULL;
func[0].function = &isSupported;
func[1].functionData = NULL;
func[1].function = &lock;
}
return;
}
FREContextFinalizer* ctxFinalizerToSet) {
*extDataToSet = NULL;
*ctxInitializerToSet = &ContextInitializer;
*ctxFinalizerToSet = &ContextFinalizer;
}
return;
}
[/c]
void ExtInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet,
FREContextFinalizer* ctxFinalizerToSet) {
*extDataToSet = NULL;
*ctxInitializerToSet = &ContextInitializer;
*ctxFinalizerToSet = &ContextFinalizer;
}
[/c]
이는 extension.xml 에 명시되어진 함수로 처음 context 가 만들어지면서 호출 되는 함수 입니다. 인자로 extDataToSet, ctxInitializerToSet, ctxFinalizerToSet 의 포인터를 받습니다. 시작하자마자 멘붕이 오기 시작합니다. * 은 뭐고 & 는 뭐고 심지어 ** 은 뭔가요? *을 저리 많이 쓴걸 보니 뭔가 중요한건가 봅니다. ㅎㅎㅎ 이걸 제대로 이해하기 위해서는 직업을 c 개발자로 전향 해야 될지도 모르니 의미 만 간단히 살펴보면 걍 ContextInitializer 와 ContextFinalizer 를 참조하겠다 입니다. 그리고 당연하게 필요한 시기에 호출해서 사용하겠지요. 그 시기란 AIR런타임이 context 를 만드는 시점 일 겁니다. 여튼 이 함수를 통해서 AIR와 네이티브간의 첫 접선이 이루어졌고 우리는 자연스럽게 ContextInitializer 함수가 실행 될 것이라는 걸 추측 할 수 있습니다.
void ContextInitializer(void* extData, const uint8_t * ctxType, FREContext ctx,
uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet)
{
int count=2;
FRENamedFunction* func = (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * count);
func[0].functionData = NULL;
func[0].function = &isSupported;
func[1].functionData = NULL;
func[1].function = &lock;
}
[/c]
ContextInitializer 함수의 주기능은 실제로 사용하게 될 함수를 등록하는 일입니다. 이 시점에 우리는 네이티브 코드를 위해 context 를 변수에 저장 해 둘 수 도 있습니다.
FREObject lock(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[] ){
//Temporary values to hold our actionscript code.
uint32_t boolean;
FREGetObjectAsBool(argv[0], &boolean);
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
} else {
[[UIApplication sharedApplication] setIdleTimerDisabled:NO];
}
return nil;
}
[/c]
실제로 우리가 원하는 기능을 구현할 함수부 입니다. 먼저 전달 인자 부터 보겠습니다. ctx는 계속 나오고 있는 context 입니다. funcData는 좀전에 ContextInitializer 에서 func 생성시 지정한 funcData 입니다. argc는 플래시로부터 넘어오는 인자 argv 배열의 갯수 입니다. argv는 플래시에서 실제로 넘어노는 인자값 배열 입니다.
//Temporary values to hold our actionscript code.
uint32_t boolean;
FREGetObjectAsBool(argv[0], &boolean);
[/c]
플래시에서 넘어온 인자를 네이티브에서 사용하기 위해서는 위의 코드와 같이 지정된 함수를 통해서 네이티브용 값으로 변환해 주어야 합니다. 현재 가져올 수 있는 데이터 타입은 아래의 표와 같습니다.
if(boolean){
[[UIApplication sharedApplication] setIdleTimerDisabled:YES];
} else {
[[UIApplication sharedApplication] setIdleTimerDisabled:NO];
}
[/c]
드디어 정말 우리가 필요로 하는 코드가 나왔습니다. 뭔가 거창하게 시작했는데 너무 싱겁나요? ㅎㅎㅎ iOS에서는 기본적으로 위와 같은 메소드를 제공 하고 있으므로 setIdleTimerDisabled 을 호출 하는 것 많으로 아주 간단하게 우리가 원하는 화면잠금 기능을 구현 할 수 있습니다. 다음 연제에 나올 Android 버전은 조금 더 복잡하니 너무 실망하지 마세요~^^빌드


정리
http://help.adobe.com/en_US/air/extensions/WSb464b1207c184b14-62b8e11f12937b86be4-8000.htmlANE 란?
애플리케이션 번들링 애플리케이션 번들링이 앞으로 저희가 주로 알아볼 방식으로 제작된 AIR 애플리케이션에 네이티브코드가 포함되어 실행되는 방식을 말합니다. ANE에 따라서 멀티플렛폼을 지원하도록 만들 수도 있고 경우에 따라서는 네이티브코드를 지원하지 않는 경우를 위해 액션스크립트만 포함 할 수도 있습니다.ANE 로 할 수 있는 것들
특화된 기능

훌륭한 코드들
성능
ANE 단점
시스템 종속성
불편한 디버그
ANE 구조
mimetype
META-INF/ANE/extension.xml
catalog.xml
library.swf
META-INF/ANE/Android-ARM/library.swf
META-INF/ANE/Android-ARM/ScreenWakeUp.jar
META-INF/ANE/iPhone-ARM/library.swf
META-INF/ANE/iPhone-ARM/libScreenWakeUp.a
[/xml]
<extension xmlns="http://ns.adobe.com/air/extension/3.1">
<id>it.ane.ScreenWakeUp</id>
<versionNumber>1.1</versionNumber>
<platforms>
<platform name="iPhone-ARM">
<applicationDeployment>
<nativeLibrary>libScreenWakeUp.a</nativeLibrary>
<initializer>ExtInitializer</initializer>
<finalizer>ExtFinalizer</finalizer>
</applicationDeployment>
</platform>
</extension>
[/xml]
private static const EXTENSION_ID:String = "it.ane.ScreenWakeUp";
ExtensionContext.createExtensionContext(EXTENSION_ID, null);
[/as3]정리
http://www.adobe.com/devnet/air/articles/extending-air.html
http://help.adobe.com/en_US/air/extensions/air_extensions.pdf
최근 나온 포토샵CS5 앱 3종 입니다. 모두 아이패드 전용입니다.
Color Lava는 칼라믹서 입니다. 마치 자신의 손가락에 정말 물감이 묻어 있는 것 처럼 믹서 할 수 있습니다. 좌측 상단의 물통이 아주아주 인상 적입니다. 기존의 유저경험(붓은 물통에 빤다)을 그대로 옮겨 온 듯한 인터페이스가 맘에 드네요. 믹스해서 만들어진 칼라 차트는 다른 유저와 쉽게 공유 할 수 있습니다.
Eazel 은 수채화 효과 앱입니다. 기존의 페인터와는 전혀 다른 느낌으로 수채화를 표현하는군요. 영상만 보면 정말 물로 그림을 그리는 느낌이 드는군요. 아이패드에서 그린 그림은 바로 포토샵으로 전송 할 수 있습니다. 5손가락을 이용한하는 멀티터치 인터페이스도 인상적입니다.
위의 두 앱과는 다르게 Nav 는 포토샵이 반드시 필요합니다. 포토샵의 툴을 선택하고 열려있는 도큐먼트를 살펴 볼 수 있는 앱이기 때문 입니다. 오픈되어 있는 도큐먼트가 많을 경우 찾기가 쉽지 않았는데 (특히 윈도우에서.. 맥은 익스포제가 있어서 쉽지요.ㅎㅎㅎ) 이 앱이 있다면 아주 빠르고 쉽게 찾을 수 있을 것 같습니다.
이번에 출시된 3개의 앱 모두 포토샵과 연동되며 포토샵과 연동하기 위해서는 Photoshop 12.0.4 update 해야 합니다. 그리고 이와 함께 Photoshop Touch SDK 으로 안드로이드, 블랙베리, iOS, MacOS, 윈도우 에서 포토샵CS5 와 연동 가능한 어플을 만들 수 있습니다. 아! 그리고 가장 중요한 플래시에서도 연동 할 수 있습니다. 근데 사실 제 개인적인 생각으로 플래시에서 연동되는것보다 외부 디바이스에서 포토샵을 연동 할 수 있다는게 매우 좋은 것 같습니다. 이게 가능하게 됨으로 아직까지 소비위주인 타블렛PC나 모바일 디바이스가 생산적인 디바이스로 거듭 날 수 있을 것 같습니다. 아마 모르긴 몰라도 앞으로 이런한 여러 하드웨어와 소프트웨어의 재미난 융합이 많이 만들어 질 것 같습니다.
주말에는 저 SDK 로 아이폰용 심플NAV 를 만들어 볼 생각 입니다. Coming soon.
]]>단순히 새버전이 나온다고 무작정 따라가는 것도 답은 아니라고 생각합니다. 회사입장에서는 프로그램 구입비도 만만치 않을테니까요. 더군다나 현재 사용하고 있는 제품이 업무에 전혀 문제가 없다면 특히 그럴 것 입니다. 하지만 버전업으로 인해 얻는게 많다면 당연히 시도해 볼 가치는 있겠지요.
Flash CS4 로 버전 업 하면서 주목할 만한 변화는 개인적으로 PixelBender 의 사용과 Vector 가 아닐가 생각됩니다. 두기능 모두 Flash 의 성능과 가능성을 비약적으로 높혀 주지요. 다만 두 기능 모두 Flash Player 10 이상을 요구합니다. CS4 가 나온 초기 시점에는 클라이언트 환경이 대부분 Flash Player 9 였으므로 무리해서 두기능을 추가하기가 어려웠습니다. 하지만 그건 이미 2년이나 지난 이야기이지요. 현재 Flash Player 최상위 버전은 10.1 입니다. 또 대부분의 클라이언트 환경도 업그레이드 되었으므로 여지껏 아껴두었던 위의 기능들을 충분히 사용해도 좋을 것 같습니다.
오늘은 두 기능 중 PixelBender 를 테스트 해 보았습니다. PixelBender 는 다들 아시다시피 Adobe 의 이미지,비디오 프로세싱 기술입니다. 해서 당연히 Flash 외에 Photoshop, AfterEffect 등에서도 함께 사용 할 수 있습니다. 저는 이런 PixelBender 를 Flash 에서 어떻게 효과적으로 사용 할 까? 를 생각해보았습니다. 제 개인적으로 Flash는 인터렉티브 입니다. 그 어떤 환경보다도 유저와 상호작용하기 좋은 환경이죠. 그러므로 PixelBender 도 이러한 용도로 사용하고 싶었습니다. 물론 가장 기본적인 이미지프로세싱 (레벨, 컨트라스트 등)도 가능하겠지만 이건 별로 임팩트가 없어서 Mac OS X 의 기능중 Dashboard 의 있는 효과를 흉내내 봤습니다. 쉽게 말해 물결효과 입니다.
물결파는 아래 이미지의 공식으로 만들어 집니다.
이를 PixelBender 언어로 바꾸면 다음과 같습니다.
kernel HorizontalAverage < namespace: "com.impossiblearts"; vendor: "Hannes Moser"; version: 1; description: "damped sin-wave depending on time"; > { input image4 source; output pixel4 result; const float PI = 3.14159265358979323846264338327950288; parameter float2 pos < minValue:float2(0.0, 0.0); maxValue:float2(2880.0, 2880.0); defaultValue:float2(400.0, 400.0); >; parameter float amount < minValue:0.0; maxValue:10000.0; defaultValue:5000.0; >; parameter float wavelength < minValue:1.0; maxValue:2500.0; defaultValue:150.0; >; parameter float t < minValue:0.0; maxValue:1000.0; defaultValue:0.0; >; parameter float overlay < minValue:0.0; maxValue:100.0; defaultValue:10.0; >; void evaluatePixel() { float2 coord = outCoord(); float dist = distance(pos, coord); float curve = (1.0 / sqrt(1000.0 * PI)) * exp((-1.0/wavelength) * pow(-t + dist, 2.0)) * sin(dist / overlay) * amount; float2 cw; cw = coord + curve; result = sample(source, cw); } }
출처 : http://impossiblearts.com/blog/2008/10/pixelbender-damped-sin-waves-gauss-curve/
위의 Effect 를 Flash 로 가져와 인터렉션과 애니메이션을 추가해서 다음과 같이 완성 했습니다. PixelBender의 Effect 는 DisplayObject 의 filters 에 적용 되므로 아래에서 보는 것과 같이 다이나믹텍스트나 인풋텍스트에도 아주 잘 적용 됩니다.(플래시 영역을 클릭하세요.)
아래의 사이트에 방문해 보면 좀 더 흥미롭고 재밌는 PixelBender 예제들을 만나 볼 수 있습니다.
]]>NVIDIA & Adobe: Creatively Partnered
Together, NVIDIA® and Adobe®
are transforming the way the world engages with ideas and information
through visual computing. From rich images in print, video, and film,
to dynamic digital content for a variety of media, NVIDIA
GPU-accelerated Adobe solutions can be enjoyed by anyone who creates
and interacts with visual information.Unleash your creativity with NVIDIA graphics
solutions designed for the artistically inclined home user to the
highly trained professional video and digital artist.“A critical element of CS4 was to capture the enormous power of the
GPU. The difference is astounding. Performance is important to creative
professionals and with the NVIDIA GPU, they are assured to be able to
interact with images and videos in a much faster, smoother, more
engaging way.”– John Loiacono, senior vice president of Creative Solutions at Adobe
이러한 멋진 일이 가능하게 된것은 Adobe가 NVIDA 의 CUDA 를 지원함으로서 가능하게 되었다. CUDA는 GPU의 다양한 능력을 활용 할 수 있게 해주는 언어이다. 자세한 정보는 http://kr.nvidia.com/object/cuda_what_is_kr.html 에서 확인 할 수 있다.
위의 인용구에서 존 로아이코너 Adobe 수석 부사장은 CS4를 다음과 같이 평가 하고 있다.
CS4의 중요한 점은 GPU의 막대한 힘을 잡았다는 것입니다. 차이점은 정말 놀랍습니다. 창의력 있는 전문가에게 성능은 중요하고, NVIDA와 GPU로 이미지와 동영상을 훨씬 빠르고, 부드럽고, 더 매력적인 방법으로 상호 작용할 수 있을 것입니다.
하지만 더이상 GPU를 3D 게임이나 돌리는데 사용하지 않아도 되어서 너무나 기쁘다. 그러기에 GPU의 성능은 너무나 뛰어나다.
한동안은 아무래도 Adobe CS4 에 관한 글을 올릴 것 같다. 그중 첫탄으로 CS4에서 새롭게 업그레이든 된 Media Encodr를 살펴보자. 본래 Media Encoder 는 Flash Video Ender라는 이름으로 기존부터 존재해 왔다. 이 Flash Video Encoder 가 생기면서 Flash에서는 flv라는 새로운 비디오포멧을 사용 할 수 있게 되었고 이를 통해 플래쉬는 영상작업의 플랫폼으로 한걸음 발전 할 수 있었다. 지금의 YouTUBE나 대부분의 UCC들이 flv로 만들어 지는 것을 보면 flv의 힘이 어느정도 였는지 단적으로 알 수 있다.
이러한 Flash Video 가 CS4 를 통해 또 한번 큰 발전을 했다. 이제는 Adobe Media Encoder 라는 새로운 이름으로 어엿한 Adobe 제품군이 되었다.
전체적인 인터페이스는 기존의 것과 유사하지만 스킨이 완전히 바뀌었다. 의외인것은 이번 CS4 제품들이 전부 새로운 CS4 인터페이스를 하고 있는데 Media Encoder는 이전 CS3 의 AfterEffect 인터페이스와 거의 유사하다는 것이다.
실제로 사용해보면 확실히 AfterEffect의 느낌이난다.
그래서 인지 새롭게 추가할 수 있는 것들에 After Effects Composition 과 Premiere Pro Sequence 가 생겨났다. 확실히 Adobe의 제품전략을 다시 한번 느낄 수 있는 대목이다. 거의 대부분의 CS 제품들은 이러한 방법 처럼 유기적으로 연동이 되고 있다.
무비속성 창이다. 많이 복잡해 진 것 처럼 보이나 인터페이스 면에서는 실제로는 기존의 것과 큰 차이는 없다. 다만 더 쉽게 간단한 편집들을 바로 할 수 있으며 Ouput 탭에서는 Ouput을 미리 체크 할 수 도 있다.
속성 중 가장 눈이 뛰는 변화는 역시 H.264 지원일 것이다. Formate 탭에서 flv와 f4v 를 선택 할 수 있으며 f4v를 선택하면 H.264를 쓸 수 있다. 개인적으로는 기존 flv의 On2 VP6 코덱도 매우 만족 스럽게 써왔으므로 H.264가 얼만큼 더 좋을지는 잘 모르겠다. 이 부분은 좀더 많은 테스트와 연구가 필요 할 것 같다.
아래 리치왕의 분노 인트로로 flv와 f4v 테스트 해보았다. 재미난 것은 f4v를 Flash Player 9 에서도 재생 할 수 있다는 것이다. 다만 FlvplayBack을 Flash CS4에서 추가해줘야 한다. 아래 샘플의 flv는 Flash CS3로 f4v는 Flash CS4로 퍼블리싱 하였다.
FLV 파일정보
File – width : 520, height : 222, size : 10.2 Mb
Video – codec : On2 VP6, bitrate : CBR 700 Kbps
Audio – codec : MP3, bitrate : 96 Kbps
F4V 파일정보
File – width : 520, height : 222, size : 9.87 Mb
Video – codec : H.264, bitrate : VBR 700 Kbps ~ 1000 Kbps
Audio – codec : AAC, bitrate : 96 Kbps
bitrate 700은 최근 플래쉬로 영상을 넣을 때 가장 많이 사용한 수치이다. 이 수치에서 두 동영상의 큰 차이를 발견하기는 쉽지 않다. F4V쪽이 좀더 샤프해 보이기는 하나 미미한 수준이다. 두 포멧의 차이를 확실하게 비교하기 위해서는 더 큰 화면이나 더 작은 용량 처럼 좀 더 극닥적인 환경이여야지 싶다.
추가적으로 더이상 FLV를 플레이 하기 위해서 따로 FLVPlayer를 설치 할 필요 없다. 물론 사용가능하겠으나 기본적으로 Adobe Media Player 가 함께 설치 되므로 바로 재생 가능하다.

http://www.adobe.com/kr/products/creativesuite/
너무나 방대한 양의 새로운 기능들이 있지만 다행스럽게도 대부분이 한글화 되어 설명 되어져 있다. 이중 Flash 의 신기능만 살짝 살펴보자.
1. 객체 기반 모션

객체 기반의 애니메이션 툴을 사용하면 키프레임이 아닌 객체 자체에 직접 트윈을 적용할 수 있으므로 각각의 애니메이션 속성을 완벽하게 제어할 수 있습니다. 또한 베지어 핸들을 사용해 모션 패스를 손쉽게 변경할 수 있습니다
2. 3D 변형

x, y, z 축을 따라 움직임을 조정할 수 있는 새로운 3D 평행 이동 툴과 회전 툴을 사용하면 3D 공간에서 2D 객체에 애니메이션을 적용할 수 있습니다. 객체의 일부 또는 전체에 변형을 적용할 수 있습니다.
3. 뼈툴을 이용한 역기구학

여러 개의 연결된 객체로 체인과 같은 애니메이션 효과를 만들거나 새로운 뼈 툴을 사용하여 하나의 모양만 신속하게 왜곡시킬 수 있습니다.
4. 장식 및 스프레이툴을 이용한 절차적 모델링

심볼을 인스턴트 디자인 툴로 변환할 수 있습니다. 이때 다양한 방법으로 심볼을 적용할 수 있습니다. 장식 툴을 사용하여 만화경과
같은 효과를 내거나 채우기를 적용할 수 있고 스프레이 브러시를 사용하여 정의된 전체 영역에 임의로 심볼을 뿌릴 수 있습니다.
5. 모션편집기

새롭게 제공되는 모션 편집기를 사용하면 회전, 크기, 크기 조절, 위치, 필터 등 키프레임 매개 변수를 세부적으로 제어하고
Adobe After Effects® 소프트웨어와 유사하게 완전한 그래픽 방식으로 보여주는 여유 값을 세밀하게 제어할 수 있습니다
6. 메타데이터(XMP) 지원

새로운 XMP 패널을 사용하여 SWF 파일에 메타데이터를 추가할 수 있습니다. 공동 작업 강화와 보다 나은 모바일 경험을 위해 신속하게 태그를 지정할 수 있습니다.
7. 모션 프리셋

모든 객체에 적용할 수 있는 미리 만들어진 애니메이션을 사용하면 프로젝트를 바로 시작할 수 있습니다. 다양한 프리셋 중에서
선택하거나 직접 만들어 저장할 수도 있습니다. 또한 다른 사람과 프리셋을 공유하면 애니메이션 제작 시간을 단축할 수 있습니다.
이 외 더 많은 신기능들이 추가되었다. http://www.adobe.com/kr/products/flash/features/?view=new 에서 확인 할 수 있다.
사실 기대했던 것 이상으로 많은 업데이트와 신기능이 추가되었다. Flash Player 10 의 출시 만 해도 큰 이슈인데 이 정도로 메이져 업데이트 일 줄은 몰랐다. 의외의 점은 Flash 에 신기능중 많은 부분이 모션에 관련 된 것들이라는 점이다. 사실 최근 Flash의 경향은 어플리케이션 쪽으로 기우는게 아닌가 싶었다. 하지만 Adobe의 생각은 다른 것 같다. 이렇게 되면 확실히 모션은 Flash 어플리케이션은 Flex 라는 구도가 형성 되는 것 같다.
이 새로운 툴로 또 얼마나 창의적은 작품들이 쏟아질지 벌써 부터 흥분된다.
참고사이트
http://blogs.zdnet.com/BTL/?p=10127
http://blog.digitalbackcountry.com/?p=1654