오랜만에 네이버 오픈케스트에 케스팅했습니다. 이만저만 하는게 많다보니 여기에 신경을 전혀 못쓰고 있었네요. 요즘에는 AIR분야를 좀 해보려고 하고 있습니다. 항상 눈팅만하다가 본격적으로 결과물을 내어야할 것이 생겨서 이것저것 해보는 중입니다. 이런걸 정리하다 보면 저 자신도 너무 모르는게 많고 항상 부족함을 느낍니다. 아무튼 혼자 아는 것보다 함께 알아서 서로 공유해 서로 커나가는 것이 제 생각입니다. 좋은 정보가 되길 바랍니다.
Adobe AIR는 다양한 OS(Windows, Mac, Linux)에 구동될 수 있는 애플리케이션을 만드는데 사용하는 일종의 Flash Platfom기술이다. Flash ActionScript 3.0이나 Ajax만으로도 AIR 애플리케이션을 만들 수 있기 때문에 기존에 웹개발자들이 다른 언어를 배우지 않고 일반 데스크탑용 애플리케이션을 만드는데 있어서 접근성이 좋다. 앞으로 AIR는 데스크탑뿐 아니라 모바일등과 같은 다양한 기기에도 적용될 예정이다.
하지만 AIR외에 다른 데스크탑용 애플리케이션과 비교해 그 적용범위가 아직까지 많은 부분 부족하고 복잡한 UI를 다루는데 있어서 성능문제가 걸릴 수 있다. 하지만 AIR 2.0 Beta 버전이 오픈된 것을 볼 수 있었듯이 계속 발전해나갈 것이다. 물론 성능면에서도 마찬가지 일 것이다. 그래도 약간은 부족하다. 기능은 그렇다 쳐도 지금의 성능을 개발자가 조금만 신경을 쓴다면 획기적으로 향상시킬 수 있다.
이 방법이 퍼포먼스를 올리기 위한 방법의 하나의 예시는 될 수 있지만 그 전부는 아니라는 점은 밝혀둔다.
(이 글을 완벽히 이해하기 위해서는 ActionScript 3.0과 AIR에 대한 전반적 이해가 요구됩니다.)
FrameRate를 줄임
Framerate를 줄임(Framerate throttling)은 애플리케이션의 휴면(idle)이 있을때 자원 사용을 줄여 퍼포먼스를 증가시키는 기술을 의미한다. 이를 구현하기 위해 ActionScript 3.0에서 매우 유용한 속성으로 Stage.frameRate가 있다. 이것을 이용하면 런타임시에 애플리케이션의 framerate를 변경시킬 수 있다.
여기서 보여지는 예제는 Reducing CPU usage in Adobe AIR에서 소개한 글에 나온 예제를 조금더 실용적으로 만들었다.(실제로 실행해 볼 수 있도록) Flash Builder 4와 AIR 2.0 SDK를 설치한 사람들이라면 이 예제를 실제로 테스트 해볼 수 있다. 아래 순서대로 개발/테스트 환경을 구축하면 된다.
(MS Windows의 경우)SDK는 압축을 풀고 그안에 있는 내용을 Flash builder가 설치된 sdks/4.0.0과 sdks/3.4.1 폴더에 각각 덮어씌웁니다. 제 경우는 C:\Program Files\Adobe\Adobe Flash Builder Plug-in Beta 2\sdks\4.0.0
Flash Builder를 실행합니다.
메뉴에서 File > New > Flex Project를 선택합니다.
프로젝트 이름을 적고 Application Type은 AIR를 선택합니다.
Next버튼을 두번 클릭후 Main Application file이름이 프로젝트명.mxml로 되어 있다면 Novice.as로 바꾸세요. 그리고 Finish 버튼을 누릅니다.
아래 첫번째 초급 코드를 복사해서 Novice클래스를 열어 붙힙니다.
디버그 모드로 테스트합니다.
두번째, 세번째의 경우 만들어진 프로젝트의 소스폴더에 해당 클래스 이름으로 Class를 만듭니다. File > New > ActionScript Class를 선택한뒤 아래 소스를 복사해 붙여넣으면 되겠죠?
초급
Framerate를 줄일때의 시점을 선택하는데 가장 쉽고 유용한 방법은 NativeApplication에서 Event.ACTIVATE 와 Event.DEACTIVATE 이벤트를 사용하는 것이다. AIR로 만들어진 빈윈도우를 선택해서 사용할때 CPU사용율이 1.8%라면 다른 윈도우를 선택해 그 윈도우의 CPU 사용율이 0.4%까지 떨여졌다고 한다. 또한 framerate를 0.01로 지정하면 0.2%까지 떨어진다고 한다. 이에 대한 예제는 다음과 같다. 예제가 이해하기 쉬우므로 따로 설명하지 않겠다.
package {
import flash.desktop.NativeApplication;
import flash.display.NativeWindow;
import flash.display.NativeWindowInitOptions;
import flash.display.NativeWindowType;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.utils.getTimer;
/**
* CPU 사용 줄이기 예제 1
* @author Yongho, Ji
* @since 2009.12.1
* @see http://blog.jidolstar.com/622
*/
public class Novice extends Sprite {
private var __isActive:Boolean = false;
private var __window:NativeWindow;
private var __textField:TextField;
public function Novice() {
__init();
var options:NativeWindowInitOptions = new NativeWindowInitOptions();
options.type = NativeWindowType.UTILITY;
__window = new NativeWindow(options);
__window.width = 200;
__window.height = 200;
__window.title = "Novice";
__textField = new TextField();
__textField.autoSize = TextFieldAutoSize.LEFT;
__textField.text = "";
__window.stage.scaleMode = StageScaleMode.NO_SCALE;
__window.stage.align = StageAlign.TOP_LEFT;
__window.stage.addChild(__textField);
__window.activate();
__window.addEventListener(Event.CLOSING,__onClosing);
}
private function __init():void {
NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, __onActive );
NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, __onDeactive );
stage.addEventListener(Event.ENTER_FRAME,__onEnterFrame);
}
private function __onActive($event:Event):void {
stage.frameRate = 50;
__isActive = true;
}
private function __onDeactive($event:Event):void {
stage.frameRate = 1;
__isActive = false;
}
private function __onEnterFrame($event:Event):void {
__textField.text = "active:" + __isActive + " " + getTimer();
}
private function __onClosing($event:Event):void {
NativeApplication.nativeApplication.exit();
}
}
}
중급
위의 예제보다 조금더 고급적으로 framerate를 조절할 필요가 있다. 가령, 마우스 휠 이벤트에 따라 스크롤이 되는 컨텐츠가 있는 경우가 그것인데 평소에는 작은 framerate를 유지하다가 스크롤시에 빠른 렌더링이 필요하므로 framerate를 올려주는 것이다. 구체적으로 MouseEvent.MOUSE_WHEEL이 발생시 framerate를 올려주고 Event.ENTER_FRAME 이벤트에서 스크롤링후 500ms이 지난 다음 다시 framerate를 줄이는 것이다. 이도 휴면(idle)상태에서 쓸데없이 렌더링되는 것을 방지하고 필요한 동작할 때만 빠른 렌더링을 요구하도록 함으로써 CPU 사용율을 줄여주는 것이다.
package {
import flash.desktop.NativeApplication;
import flash.display.NativeWindow;
import flash.display.NativeWindowInitOptions;
import flash.display.NativeWindowType;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.utils.getTimer;
/**
* CPU 사용 줄이기 예제 2
* @author Yongho, Ji
* @since 2009.12.1
* @see http://blog.jidolstar.com/622
*/
public class Intermediate extends Sprite {
private static const ACTIVE:int = 50;
private static const INACTIVE:int = 1;
private var __isActive:Boolean = false;
private var __isScrolling:Boolean = false;
private var __buffer:int;
private var __window:NativeWindow;
public function Intermediate() {
__init();
var options:NativeWindowInitOptions = new NativeWindowInitOptions();
options.type = NativeWindowType.UTILITY;
__window = new NativeWindow(options);
__window.width = 200;
__window.height = 200;
__window.title = "Intermediate";
var textField:TextField = new TextField();
textField.y = 20;
textField.width = 195;
textField.height = 175;
textField.multiline = true;
textField.wordWrap = true;
textField.border = true;
textField.borderColor = 0xff0000;
textField.text = "Adobe AIR는 다양한 OS(Windows, Mac, Linux)에 구동될 수 있는 애플리케이션을 만드는데 사용하는 일종의 Flash Platfom기술이다. Flash ActionScript 3.0이나 Ajax만으로도 AIR 애플리케이션을 만들 수 있기 때문에 기존에 웹개발자들이 다른 언어를 배우지 않고 일반 데스크탑용 애플리케이션을 만드는데 있어서 접근성이 좋다. 앞으로 AIR는 데스크탑뿐 아니라 모바일등과 같은 다양한 기기에도 적용될 예정이다.하지만 원천적으로 데스크탑용 애플리케이션과 비교해 그 적용범위가 아직까지 많은 부분 부족하고 복잡한 UI를 다루는데 있어서 성능문제가 걸릴 수 있다. 적용되는 범위는 AIR 2.0 Beta 버전이 오픈된 것을 볼 수 있었듯이 계속 발전해나갈 것이다. 또한 성능면에서도 마찬가지 일 것이다. 그래도 성능면에 있어서 개발자가 조금만 신경을 쓴다면 어떤 부분에 있어서 획기적으로 AIR 애플리케이션의 성능을 향상시킬 수 있다. 일전에 Reducing CPU usage in Adobe AIR라는 글을 보았다. 여기서는 매우 단순하고 쉬운 방법으로 framerate를 줄임으로서 CPU 사용율을 현격히 줄이는 방법을 소개하고 있다. ";
__window.stage.scaleMode = StageScaleMode.NO_SCALE;
__window.stage.align = StageAlign.TOP_LEFT;
__window.stage.addChild(textField);
__window.activate();
__window.addEventListener(Event.CLOSING,__onClosing);
}
private function __init():void {
NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, __onActive );
NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, __onDeactive );
stage.addEventListener(MouseEvent.MOUSE_WHEEL, __onMouseWheel, true);
}
private function __onActive($event:Event):void {
stage.frameRate = ACTIVE;
__isActive = true;
trace( "active" );
}
private function __onDeactive($event:Event):void {
stage.frameRate = INACTIVE;
__isActive = false;
trace( "deactive" );
}
private function __onMouseWheel($event:MouseEvent):void {
if( !__isActive ) {
if ( !__isScrolling ) {
stage.addEventListener(Event.ENTER_FRAME, __onEnterFrame, true);
}
stage.frameRate = ACTIVE;
__isScrolling = true;
__buffer = getTimer()+500;
}
}
private function __onEnterFrame($event:Event):void {
if( __buffer < getTimer() ) {
stage.frameRate = INACTIVE;
__isScrolling = false;
}
}
private function __onClosing($event:Event):void {
NativeApplication.nativeApplication.exit();
}
}
}
고급
위에서 소개한 경우보다 약간더 어려운 주제로 넘어가보자. 먼저 창이 보이지 않을때와 보일때에 어떻게 처리할 것인가이다. 보이는 경우라면 일단 최소한의 framerate를 5로 주고 안보인다면 1로 준다. 이 경우는 MS Windows에서는 Tray Icon으로 바뀌며 창이 안보여질 때나 Mac에서 Dock으로만 표시될 필요가 있을때 사용될 수 있을 것이다. 굳이 보여지지 않는데 지나친 framerate를 줄 필요가 없기 때문이다. 평상시 Active한 상태에서는 24 framerate를 유지하지면 때에 따라서 부드럽게 운동하는 모습을 렌더링할 필요가 있을 때가 있다. 상태변화에 따라 Tweener 기능을 사용하는 경우가 그것인데 이때는 평소보다 framerate를 올려줄 필요가 있을 수 있다.
아래 AIR 애플리케이션 소스코드는 두개의 버튼이 있다. 한개는 창의 visible을 false로 지정했다가 1초후 다시
true로 해주는 것이고 또 하나는 가상의 애니메이션이 있다고 가정하고 1초정도 여분을 둔다. 각 상태가 변할때마다
framerate를 Dubugging 시에 콘솔창에서 상태변화를 확인할 수 있도록 짜여있다.
package {
import flash.desktop.NativeApplication;
import flash.display.NativeWindow;
import flash.display.NativeWindowInitOptions;
import flash.display.NativeWindowType;
import flash.display.Shape;
import flash.display.SimpleButton;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.BevelFilter;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.utils.getTimer;
import flash.utils.setTimeout;
/**
* CPU 사용 줄이기 예제 3
* @author Yongho, Ji
* @since 2009.12.1
* @see http://blog.jidolstar.com/622
*/
public class Expert extends Sprite {
public static const ANIMATING:int = 50;
public static const ACTIVE:int = 24;
public static const INACTIVE_VISIBLE:int = 5;
public static const INACTIVE_INVISIBLE:int = 1;
private var __isActive:Boolean = false;
private var __isAnimating:Boolean = false;
private var __window:NativeWindow;
private var __buffer:int;
public function Expert() {
__init();
var options:NativeWindowInitOptions = new NativeWindowInitOptions();
options.type = NativeWindowType.UTILITY;
__window = new NativeWindow(options);
__window.width = 200;
__window.height = 200;
__window.title = "Expert";
__window.stage.scaleMode = StageScaleMode.NO_SCALE;
__window.stage.align = StageAlign.TOP_LEFT;
//창을 감추기 버튼
var buttonSkin:Sprite = new Sprite;
buttonSkin.graphics.beginFill( 0xff0000, 1.0 );
buttonSkin.graphics.drawRect(0,0,100,50);
buttonSkin.graphics.endFill();
buttonSkin.filters = [new BevelFilter()];
var textFormat:TextFormat = new TextFormat();
textFormat.color = 0xffffff;
textFormat.align = "center";
var textField:TextField = new TextField();
textField.defaultTextFormat = textFormat;
textField.text = "창을 감추기(1초후에 나타남)";
textField.width = 100;
textField.multiline = true;
textField.wordWrap = true;
textField.y = buttonSkin.height/2 - textField.textHeight/2;
buttonSkin.addChild( textField );
var button:SimpleButton = new SimpleButton(buttonSkin,buttonSkin,buttonSkin,buttonSkin);
button.addEventListener(MouseEvent.CLICK, __onHide );
__window.stage.addChild( button );
//Animation 동작 시키기 버튼
buttonSkin = new Sprite;
buttonSkin.graphics.beginFill( 0x0000ff, 1.0 );
buttonSkin.graphics.drawRect(0,0,100,50);
buttonSkin.graphics.endFill();
buttonSkin.filters = [new BevelFilter()];
textFormat = new TextFormat();
textFormat.color = 0xffffff;
textFormat.align = "center";
textField = new TextField();
textField.defaultTextFormat = textFormat;
textField.text = "동작시키기(1 second)";
textField.width = 100;
textField.multiline = true;
textField.wordWrap = true;
textField.y = buttonSkin.height/2 - textField.textHeight/2;
buttonSkin.addChild( textField );
button= new SimpleButton(buttonSkin,buttonSkin,buttonSkin,buttonSkin);
button.y = 52;
button.addEventListener(MouseEvent.CLICK, __onAnimate );
__window.stage.addChild( button );
__window.activate();
__window.addEventListener(Event.CLOSING,__onClosing);
}
private function __init():void {
NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, __onActive );
NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, __onDeactive );
}
private function setFrameRate( frameRate:Number ):void {
stage.frameRate = frameRate;
trace( frameRate );
}
private function animate($duration:int = 1000):void {
trace( "동작시작");
setFrameRate( 50 );
__buffer = getTimer() + $duration;
if(!__isAnimating) {
stage.addEventListener(Event.ENTER_FRAME,__onEnterFrame);
}
}
private function active():void {
if(!__isAnimating) {
setFrameRate( ACTIVE );
}
trace( "active " );
}
private function deactive():void {
if (!__isAnimating) {
setFrameRate( (__window.visible) ? INACTIVE_VISIBLE : INACTIVE_INVISIBLE );
}
trace( "deactive " );
}
private function show():void {
__window.visible = true;
active();
}
private function hide():void {
__window.visible = false;
deactive();
}
private function __onActive($event:Event):void {
__isActive = true;
active();
}
private function __onDeactive($event:Event):void {
__isActive = false;
deactive();
}
private function __onEnterFrame($event:Event):void {
if( __buffer < getTimer() ) {
trace( "동작끝");
stage.removeEventListener(Event.ENTER_FRAME,__onEnterFrame);
__isAnimating = false;
if( __isActive ) {
active();
} else {
deactive();
}
}
}
private function __onHide($event:MouseEvent):void {
hide();
setTimeout(show,1000);
}
private function __onAnimate($event:MouseEvent):void {
animate( 1000 );
}
private function __onClosing($event:Event):void {
NativeApplication.nativeApplication.exit();
}
}
}
찬익님의 블로그(http://blog.chanik.com/25)로 부터 매우 재미있는 내용을 봤다. 바로 커스텀 메타데이터 태그(custom metadata tag)에 대한 내용인데 커스텀 컴포넌트, 커스텀 이벤트등의 용어는 들어봤어도 커스텀 메타데이터 태그는 생소하다. 말그대로 Flex에서 사용하는 메타데이터 태그인 [Event], [Bindable] 이런 것 들은 사실 예전부터 mxmlc로 컴파일될 때에 ActionScript 3.0으로 변환된다는 것은 알고 있었지만 메타데이터 태그가 이렇게 사용되는지에 대한 내막은 전혀 알지 못했던 것이 사실이다. 아무튼 너무 좋은 정보라 공유하고자 한다.
사실 Flex 2시절부터 커스텀 메타데이타에 대한 이야기가 있었다고 한다. 하지만 Flex 3서부터 컴파일 옵션에 "-keep-as3-metadata MyTag"와 같은 형태로 사용할 수 있게 되었다. 이는 다음과 같이 ActionScript 3.0 코드에서 사용할 수 있게 된다.
[Listen(obj="this.closeButton", event="click")]
public function closeClickHandler(event:MouseEvent) {...}
메타데이타 태그는 위처럼 메소드 뿐 아니라 변수 및 클래스에도 사용할 수 있다.
커스텀 메타데이타를 사용하는 방법 커스텀 메타데이타를 사용하는 방법은 3단계로 이뤄진다.
1. 컴파일러 구성 Flex 프로젝트 컴파일 옵션으로 "-keep-as3-metadata+=Meta1, Meta2" 를 삽입한다. 만약 라이브러리 프로젝트에서 한다면 거기에 이 옵션을 사용하면 이 라이브러리 프로젝트를 참조하는 다른 프로젝트에 따로 줄필요는 없다.
2. metadata를 작성
package
{
[Meta2(param1 = "param 1 value")]
public class TestClass
{
[Meta1(param1 = "param 1 value", param2 = "param 2 value")]
public var test1:String;
[Meta2(paramA = "param 1 value", paramB = "param 2 value")]
public function get test2():String
{
return null;
}
public function set test2(val:String):void
{
}
[Meta1(param1 = "param 1 value")]
public function someMethod():void
{
};
}
}
3. 런타임(runtime)시에 작성한 메타데이타를 사용
describeType(TestClass)를 이용한다. 위처럼 클래스와 메소드에 메타데이타를 작성했다면 다음과 같이 E4X형태의 XML로 접근할 수 있다.
이 글에서 말하고 있는 요지는 커스텀 메타데이타를 이용해서 Value Object로 작성한 클래스에 이로 만들어진 객체가 데이타베이스의 어떤 테이블과 어떤 필드에 들어가는지 결정해줄 수 있다는 것이다.
package
{
[Bindable]
[Table(name="contact")]
public class Contact
{
[Id]
[Column(name="contact_id")]
public var contactId:int;
[Column(name="first_name")]
public var firstName:String;
[Column(name="last_name")]
public var lastName:String;
public var address:String;
public var city:String;
public var state:String;
public var zip:String;
public var phone:String;
public var email:String;
}
}
위처럼 작성된 클래스는 contactId 값은 contact 테이블의 contact_id 필드와 매치가 되도록 만든다는 것이다. [Id]메타데이타는 Primay Key와 같은 존재이다. 결국 이것을 해석해서 DB와 연동하는 AIR기반의 EntityManager를 만들어 위 클래스의 객체를 다음과 같이 사용하면 DB연동까지 된다.
var contact:Contact = new Contact();
contact.firstName = "Christophe";
contact.lastName = "Coenraets";
contact.email = "ccoenrae@adob.com";
entityManager.save(contact);
SDK는 압축을 풀고 그안에 있는 내용을 Flash builder가 설치된 sdks/4.0.0과 sdks/3.4.1 폴더에 각각 덮어씌웁니다. 제 경우는 C:\Program Files\Adobe\Adobe Flash Builder Plug-in Beta 2\sdks\4.0.0
Adobe AIR 2 Sample Applications에 들어가 Sample을 받아보고 실제 Flash Builder에서 작업해봅시다. (해당작업화면을 이미지 캡쳐하고 이런거 너무 힘들어서요. 그냥 말로 주절주절 써봅니다.)
저는 일단 수많은 예제들중에 Microphone 예제의 소스를 다운로드 받았습니다.
Flash Builder에서 Flex Project를 생성합니다. 물론 Application Type은 Desktop으로 설정해야겠죠? 예제를 다운받아 사용하므로 프로젝트 이름은 예제 소스 압축을 풀어보면 메인소스의 이름을 선택해주면 됩니다. 저의 경우 MicrophoneExamples군요. 프로젝트를 생성했으면 그 다음으로 Flash Builder에서 방금 생성한 프로젝트를 선택한 상태에서 마우스 오른쪽 버튼을 눌러 Import로 들어갑니다. 창이 뜨면 General > Archive File을 선택하고 다음 버튼을 누릅니다. Browse...버튼을 눌러 다운받은 소스압축파일을 선택합니다. 그리고 Finish하세요. Overwrite할거냐 물으면 Yes To All 을 선택하시면 됩니다. 초반에 sdk 에러가 뜰겁니다. 원본 소스의 sdk 설정이 달라서 그러는데요. 이것을 해결하기 위해 프로젝트명을 선택한후 마우스오른쪽 버튼을 눌러 Properties로 들어가 Flex Compiler를 선택한 다음 Use a specific SDK를 Flex 3.4로 선택해주시면 됩니다. 4.0이 아닌 이유는 예제 소스가 mx:WindowedApplication으로 만든 것으로보아 Flex 3.4 기반으로 만들어졌기 때문입니다. 다른 예제가 s:WindowedApplication으로 만들어져 있다면 Flex 4.0을 선택하세요. 다 끝났습니다. 이제 실행해보세요.
앗... 제 데톱에 마이크가 없군요... ㅡㅡ; 아무튼 이렇게 하면 됩니다. Sample에는 Flex뿐 아니라 Ajax, Flash용도 있으니 잘 활용하시면 학습하는데 도움이 될겁니다.
Flash Player 10.1 Prelease
Flash Player 10.1의 가장 큰 특징은 바로 모바일 지원입니다. 제 블로그에서 앞서 설명했지만 Flash Player 10.1은 오픈소스프로젝트를 통해 탄생된 결과물입니다. 데스크탑 뿐아니라 다양한 기기에서도 Adobe Flash Platform 기술이 적용될 수 있도록 Flash Player 10.1을 만든겁니다. 이는 모바일과 같이 저급(?) 하드웨어 기반에서 항상 이슈가 되어 왔던 메모리, 전력소비, 속도, 하드웨어가속등의 문제를 해결한 Flash Player를 만들었다는 것을 의미합니다. 이외에도 차세대 모바일에 걸맞는 몇가지 기능(멀티터치등)을 구현할 수 있는 API도 추가되었죠. 또한 H.264 비디오도 지원해줍니다.
Flash Player 10.1 기반 개발을 위해 해당 API로 개발할 수 있도록 지원해주는 SWC를 다운로드를 같은 페이지에서 받을 수 있습니다. 다운받아 압축을 풀면 playerglobal.swc가 있습니다. 이것을 자신의 프로젝트에 포함하여 개발하면 됩니다. 함께 포함된 readme.txt파일을 보면 사용하는 방법이 잘 나와 있는데 여기서도 간단히 설명해 드리죠. (단, Flash Builder 4 beta 2 기준입니다.)
playerglobal.swc를 playerglobal10.1.swf로 이름을 바꾸고 만들어진 프로젝트의 libs폴더에 복사합니다. libs폴더에 복사하면 자동으로 Referenced Libraries로 설정됩니다. (여기서 이름을 바꾼 이유는 다음 내용을 설정할 때 playerglobal.swc의 Link Type을 수정못하도록 Flash Builder가 만들어져 있기 때문입니다.)
프로젝트명을 선택후 마우스 오른쪽 버튼을 눌러 properties를 선택한 뒤 Flex Builder Path를 선택합니다. 그런 다음 Library path 탭을 선택한뒤 libs 폴더를 열어 Link Type을 External로 바꿉니다. 그런 다음 Flex 4.0 를 열어 기존 playerglobal.swc는 삭제합니다. Link type이 External이라는 것은 컴파일시 사용한 클래스를 빼놓는다는 뜻입니다. 어짜피 playerglobal.swc에 정의된 클래스는 이미 Flash player 10.1에서 지원해주기 때문에 굳이 swf안에 포함할 필요가 없기 때문이지요.
Flash Player 10.1을 요구하는 HTML이 되도록 만들어주기 위해 Properties 창에서 Flex Compiler를 선택합니다. Adobe Flash Player options에서 Use a specific version을 10.1.0으로 바꾸거나 Additional compiler arguments에 -target-player=10.1.0 을 추가합니다.
이로써 Flash Player 10.1 에서 돌아가는 Flash 애플리케이션을 만들때 환경 구축을 모두 완료했습니다.
아래처럼 Flash Player 10.1 API인 TouchEvent, TransformGestureEvent 등을 사용할 수 있게 되었습니다.
아래 링크를 통해 Flash Player 10.1에 대한 다양한 정보를 얻을 수 있습니다.
Flash, Flex, AIR 개발자들이 한권정도는 꼭 가지고 있을 만한 책이다. 이 책은 콜린 무크의 유명한 책인 Essential ActionScript 3.0을 지금도 업계에서 활발히 일하고 계신 유윤선, 송호철님이 번역한 책이다. ActionScript 3.0에 관한한 거의 바이블 수준이다. 시간될 때마다 쭉 훑어보며 느낀 거지만 ActionScript 3.0에 대한 전반적인 개념을 습득하는데 이만한 책이 없다고 생각된다.
Flash, Flex, AIR를 개발할 때 가장 기초가 되는 개념은 ActionScript 3.0이다. ActionScript 3.0에 대한 전반적인 개념 및 지식없이 Flex에 접근하다 보면 결국 한계를 느끼게 될 것이다. 왜냐하면 Flex 프레임워크가 모든 기능을 수행해 줄 수 있도록 만들어진 것은 아니기 때문이다. Flex는 프레임워크로서 가치가 있는 것이지 모든 기능을 Flex에서 찾으면 안된다. 또한 Flash로 개발할 때도 마찬가지 인데 타임라인만 의지하다가 뭔가 고급기술을 다뤄야할 필요가 있을때 ActionScript 3.0을 알아야 가능해진다. Flash든 Flex든 AIR든... Flash Platform 개발자가 접근할 수 있는 가장 기초가 되는 것은 결국 ActionScript 3.0이다. (예외적으로 AIR의 경우 Javascript로 만들 수 있는데 이는 컴파일러를 지원하는 차원이지 근간은 ActionScript 이다.)
이 책의 한가지 단점이라면 Flash Player 10 API에 해당하는 내용까지 다루지는 않고 있다. 이와 관련된 내용은 여전히 온라인의 ActionScript 3.0 라이브 독을 참고해야한다.
[Embed(source='C:/WINDOWS/Fonts/ARIAL.TTF', fontName = "MyFont", mimeType = "application/x-font-truetype")]
private var font:Class;
그런데 Flash Builder 4에서 작업할 때부터 위처럼 Embed한 폰트가 적용이 되지 않았다. 사용한 True Type 폰트는 언제나 테스트할때 문제없이 동작한 것이기 때문에 왜 안되는지 의문이 들었다. Flash Builder 4의 컴파일러인 mxmlc가 버그가 있거나 다른 설정이 추가되었나 싶었지만 그렇지 않았다. 그래서 열심히 구글링해봤더니 폰트를 Embed 처리할때 embedAsCFF 속성이 추가되었다는 것을 발견하고 아래처럼 테스트 코드를 작성해봤다.
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.text.TextFieldAutoSize;
import flash.text.AntiAliasType;
[SWF(width = "500", height = "240", backgroundColor = "#FFFFFF", framerate = "24")]
public class FontTest extends Sprite {
[Embed(source='C:/WINDOWS/Fonts/ARIAL.TTF', embedAsCFF="false", fontName = "MyFont", mimeType = "application/x-font-truetype")]
private var font:Class;
public function FontTest() {
var format:TextFormat = new TextFormat();
format.font = "MyFont";
format.size = 30;
format.color = 0x000000;
var label:TextField = new TextField();
label.embedFonts = true;
label.autoSize = TextFieldAutoSize.LEFT;
label.antiAliasType = AntiAliasType.ADVANCED;
label.defaultTextFormat = format;
label.text = "blog.jidolstar.com";
addChild(label);
label.rotation = 5;
}
}
}
여기서 embedAsCFF 속성은 도데체 뭔가? 이 전에 CFF(Compact Font Format)가 뭔지 알아야만 했다.
폰트형태는 여러가지 종류가 있다. OTF(Open Type Font)와 TTF(True Type Font)등이 있다. OpenType은 MS와 Adobe가 TrueType의 후속작으로 Cross Platform을 지원하도록 만들 파일 포멧이라고 한다. 이 OpenType에는 Glyph Outline형식에 대한 정의는 없고 TrueType, CFF, Adobe Type 1(PostScript)를 사용한다고 한다. 이 말은 OTF중에는 TrueType으로 글자모양을 정의한 폰트도 있고 CFF 또는 PostScript Font로 정의한 폰트도 있음을 의미한다.
Flash Player 10과 Adobe AIR 1.5이상부터 TTF뿐 아니라 CFF도 지원하게 되었다. 이는 PDF와 직접적인 관계가 있는 것 같다. 그래서 폰트를 포함할때 TTF인지 CFF인지 명시할 필요에 의해 생긴 것이 embededAsCFF인듯하다. 만약 TTF를 사용한다면 위 예제처럼 embededAsCFF를 false로 지정해야한다.
필자도 Font Type에 대한 지식은 거의 없어서 난감했다. CFF를 포함하면 글꼴 렌더링시에 텍스트를 보다 쉽게 읽을 수 있으며 작은 크기에서 글꼴의 표시 품질이 향상된다고 Adobe ActionScript 3.0 가이드 문서에는 나와 있을뿐 정확히 TTF와 CFF에 대한 명확한 해석을 찾지는 못했다.
Flex 또는 ActionScript 3.0 라이브러리를 만들면서 하나의 네임스페이스를 지정키 위해 manifest설정을 하게 된다. (manifest를 모른다면 일단 Flex Builder에서 나만의 manifest만들기를 먼저 읽어보길 바란다.)
Flash Builder 4 beta 2를 이용하면서 같은 방법으로 manifest를 설정하는데 아래와 같은 에러가 계속 나는 것이다.
경험상 소스상에는 문제가 없는 것이기 때문에 다른 부분을 찾다가 beta 2에 있는 새로운 기능을 포착했다. 아래 이미지는 해당 프로젝트에서 Properties > Flex Library Builder Path 에서 Classes 탭을 선택했을때 화면이다. 이전 버전의 Builder에서는 보이고 있는 라디오 버튼이 없었던 것으로 알고 있는데 이번에 새롭게 들어갔나보다.
저 기능은 라이브러리 컴파일시 컴파일할 대상의 Class를 선택하는 기능인데 이번에 기능이 바뀌면서 자동으로 모든 클래스가 포함되는 것을 선택하도록 하는 기능이 추가된 것이다. 이게 기본값이다. manifest관련 에러가 났던 것인 이 부분이 원인이였다. 다음 처럼 Select classes to Include In the library를 선택해보고 다시 컴파일하면 에러가 사라진다.
아놔~~ 이 때문에 1시간 허비했다. 아직 beta버전이니깐 넘어가자. 정식버전 나오면 나아지겠지.
Flash Builder 4는 이전 Flex Builder 3에 비해 너무도 많은 부분이 개선이 되었다. 이제 개발툴로서 제대로 자리매김하는 것으로 보인다. Flash Builder 4 및 다른 제품군을 다운 받기 위해 아래 링크를 참고하길 바란다.
지난 2009년 10월 5일부터 7일까지 3일간 어도비(Adobe)에서 주최하는 컨퍼런스인 Adobe MAX 2009행사에 참여하기 위해 일주일간의 일정으로 미국 LA에 다녀왔다. ACC(Adobe Community Champion)의 구성원 중에 올해는 필자를 포함한 3명이 발탁되어 이번 행사에 행사참여비를 비롯한 모든 여행경비를 거의 전액 무료로 참여하게 되었다. Adobe MAX는 Adobe의 새로운 기술과 트렌드를 공개하는 큰 행사이다. Adobe Flash Platform에 관련된 기술에 항상 관심을 가지고 지켜본터라 이번 행사의 참여는 개인적으로 매우 즐겁고 흥미로운 경험이였다.
행사 일정은 3일이였으나 전체 미국에서의 일정은 1주일이였기 때문에 행사 일정을 제외한 나머지 시간은 LA를 둘러보는 시간도 가질 수 있었다. 개인적으로 LA에 동서댁이 살고 있어서 행사끝나고 가족상봉도 이룰 수 있어서 정말 좋은 시간이였다.
3일간 열리는 이번 Adobe MAX 2009행사는 노키아 극장에서 열리는 2번의 키노트 행사와 LA 컨벤션 센터에서 주제별 세션이 있었다. 키노트는 한 장소에서 모든 행사 참여자가 경청할 수 있으며 전체 흐름과 주제를 파악하는데 필요한 거의 모든 내용을 다룬다. 키노트 행사에는 수천명의 사람들이 참여한다. 반면 주제별 세션은 많게는 100명 적게는 30~40명 정도 들을 수 있는 방에서 자신이 원하는 세부적인 내용을 들을 수 있는 자리이다. 세션은 제품군, 주제, 난이도 등으로 나눠서 입맛에 맞게 골라 경청하거나 실험해 보는 자리로 꾸며진다.
Adobe MAX 행사 참여로 누구보다 가장 빠르게 Adobe 신기술을 접할 수 있으며 또한 미국 또는 세계에서 온 각계각층의 다양한 사람들이 이 행사에 참여하기 때문에 안목을 높힐 수 있는 계기를 만들어주었다고 생각한다.
이 글은 이번 행사를 통해 필자가 알게된 Adobe의 신기술 및 트렌드를 소개하는 것을 목적으로 한다.
내용중에 필자의 주관적 진술이 많이 포함되어 있다. 즉 Adobe의 정책이나 방향을 말하고 있지만 그에 대한 전망에 대한 개인적인 의견이지 Adobe의 실질적인 정책은 아님을 미리 말해둔다.
오픈 스크린 프로젝트 - 디지털 기기간에 장벽제거
이번 Adobe MAX에서 Flash Platform에 관심이 있는 개발자라면 바로 Flash Player 10.1과 AIR 2.0에 대한 언급이 아니였을까 생각한다. 이들 기술은 더욱 다양하고 강력한 API를 제공할 수 있게 되었다. 그러나 이 기술 자체만 관심가지는 것보다 그 기술에 어째서 만들어졌는가? 더 나아가 Adobe는 왜 이런 기술을 만들어냈는가 관심을 가져야할 것이다.
Flash Player 10.1과 AIR 2.0은 오픈 스크린 프로젝트(Open Screen Project)의 첫번째 결실이다. 오픈 스크린 프로젝트는 지금까지 데스크탑 컴퓨터 환경을 뛰어 넘어 텔레비전, PC, 모바일 장비, 각종 소비자 가전제품등의 디지털 기기간에 호환성을 보장해주고 다양한 사용자 경험을 선사하기 위한 프로젝트이다. 이 말을 쉽게 이야기 하자면 다양한 기기에 Flash 및 AIR 애플리케이션이 운용될 수 있도록 각종 디지털 기기 업체와 협력하는 프로젝트인 것이다. 애초부터 Adobe Flash Platform 기술은 웹에서 시작해 데스크탑으로 또 각종 운영체제(Windows, Mac, Linux 등)를 지원해왔다. 하나의 애플리케이션이 다양한 환경에서도 동작하게 하기 위한 전략을 세웠던 Adobe가 이를 더 확장하기 위한 정책으로 만든 프로젝트가 바로 오픈 스크린 프로젝트인 것이다.
오픈 스크린 프로젝트에 참여한 기업은 한국의 삼성, LG를 비롯해 Nvidia, 노키아, 모토로라, 인텔등 다양한 기기 업체들을 포함한다. 또한 각종 컨텐츠 업체들도 참여했는데 대표적으로 구글이 있겠고 BBC, MTV Networks, NBCUniversal 등도 이 프로젝트에 참여했다.
Adobe는 자사의 기술을 널리 활용될 수 있도록 다음과 같은 적극적인 오픈 정책을 실현해왔다.
SWF, FLV/F4V 스팩 사용 제한을 없앰.
어도비 플래시 플레이어용 모바일 단말기 포팅 레이어(APIs)를 퍼블리싱.
어도비 플래시 케스트 프로토콜 및 대용량 데이터 서비스용 AMF 프로토콜을 퍼블리싱.
디바이스용 어도비 플래시 플레이어와 AIR 제품의 차기 버전의 라이센스를 무상 제공.
오픈 스크린 프로젝트의 첫번째 결실이 Flash Player 10.1과 AIR 2.0 이라고 이미 언급했다. 그럼 어째서 이 기술이 이 프로젝트의 결실물이 되는 것인가? 가장 중요하게 보아야 할 것을 뽑는다면 기능, 메모리, 속도, 전력소비량이 아닌가 생각한다.
기능적 측면으로 Flash Player 10.1는 멀터터치가 지원되고 AIR 2.0의 경우 다양한 USB 디바이스 지원, 소켓서버, UDP통신 다양한 설치 포멧(dmg, exe등)등을 지원하게 된다. 이러한 기능이 지원된데에는 기존의 부족한 기술을 업그레이드 시키는 것외에도 오픈 스크린 프로젝트와 연관되어 사용자에게 다양한 경험을 주기 위한 것이다. 가령 요즘 모바일에 멀티터치는 기본기능으로 들어간다. 이러한 기능을 Flash 애플리케이션으로 사용할 수 있도록 한것이다. 기능은 단순히 기술을 돋보이게 하는 것이 아니라 철저한 정책 바탕위에 만들어진다.
다양한 기기에서 Flash 컨텐츠가 문제없이 돌아가야 하므로 메모리, 속도, 전력소비량을 생각하지 않을 수 없을 것이다. 특히나 모바일과 같은 기기에서는 메모리, 속도, 전력소비량을 어떻게 최적화 시키느냐가 관건이 된다. 이는 오픈 스크린 프로젝트를 실현하기 위한 중대한 기술적 이슈로 Adobe의 노력의 결실이 이번 Adobe MAX를 통해 공개된 것이다.
메모리의 경우 매우 괄목할 만한 성장을 보였다고 할 수 있다. 아래 그림은 키노트 당시 화면으로 각종 애플리케이션에서 기존의 Flash Player 10과 새 Flash Player 10.1 간에 메모리 사용량을 비교하고 있다. 2~3배의 메모리 사용량을 줄였음을 볼 수 있다.
다음으로 전력소비량이다. 전력소비량도 다음 키노트 영상에서 볼 수 있듯이 모바일 기기에서 운영되는 Flash 컨텐츠가 얼마나 전력을 소비하는가 절대적 수치로 보여주고 있다. 일반적인 동영상의 경우 3.4시간, 애니메이션이 들어간 컨텐츠의 경우 6.5시간, 마지막으로 저전력 모드에서 14.5시간까지 유지할 수 있다고 한다.
마지막으로 빼놓을 수 없는 것이 속도이다. 다양한 기기들 중에 모바일에서 움직여야하는 컨텐츠의 경우에는 적은 CPU연산으로 속도를 빠르게 하거나 GPU 가속이 필요할 것이다. 오픈 스크린 프로젝트에 참여한 Nvidia가 그것을 실현하는데 결정적인 역할을 하게 되었다. 노트북, 넷북, 스마트폰, 스마트북 등 Nvidia 지포스와 아이온, 테그라 플랫폼 등에 쓰이는 Nvidia GPU의 지원으로 낮은 전력과 CPU점유율을 Flash Player 10.1부터 가능하게 해주었다. 이로써 모바일 기기에서도 HD급 영상을 부드럽게 재생할 수 있게 되었다. 다음 동영상은 이번 키노트를 통해 공개된 속도의 최적화를 단적으로 보여준 동영상이다.
이처럼 Adobe는 오픈 스크린 프로젝트를 통해 Flash Player 10.1과 AIR 2.0을 탄생되었으며 이들 기술은 기능, 메모리, 전력소비량, 속도등의 개선에 큰 성과를 거두었다.
세계 전 PC에 99%이상 Flash Player가 설치되었으며 이미 두터운 사용자 층을 다지고 있는 Flash Platform 기술이 이제 Flash 애플리케이션이 모바일, 텔레비전등에도 동작하게 하는 것은 Adobe가 오래전부터 바래왔던 RIA(Rich Internet Application)의 참모습을 보여주기 위한 것이 아닌가 생각된다.
오픈 스크린 프로젝트의 가장 큰 성과는 바로 엄청난 수의 디자이너와 개발자들이 그들이 가진 자산과 자원을 그대로 사용할 수 있다는 것에 있다. 이로써 Flash Platform 기술을 이용하는 업체들에게 시간과 자본을 매우 줄이는 결정적인 역할을 하게 된 것이다. 이전에 모바일의 Flash 컨텐츠는 Flash Lite로 ActionScript 2.0 기반하에서만 개발할 수 밖에 없는 한계가 있었다. 그러나 이 한계를 기존 Flex, Flash, ActionScript 3.0 기술을 그대로 이용해 데스크탑 뿐 아니라 각종 다양한 기기에도 운영할 수 있는 애플리케이션을 만들 수 있도록 기술적, 정책적 문제를 오픈 스크린 프로젝트를 통해 해결한 것이다. Adobe는 이제 Cross OS, Cross Browser를 넘어 Cross Device를 실현하기 위한 디딤돌을 제대로 만든 셈이다.
불행히도(?) Apple은 오픈 스크린 프로젝트에 참여하지 않았다. 하지만 Adobe는 Adobe Flash Professinal CS5 베타버전을 선보이며 ActionScript 3.0 기반으로 iPhone용 애플리케이션을 만들어 시연하는 모습을 보여줌으로써 Flash Player가 iPhone에 탑제되어야 한다는 문제를 말끔히 씻었다. Adobe Labs에서는 CS5에 대한 설명 및 이를 이용해 만든 iPhone 애플리케이션을 소개하고 있다.
Adobe가 오픈 스크린 프로젝트 프로젝트를 통해 다양한 기기, OS등에 지원하도록 하는 것은 단순히 Flash컨텐츠를 공급하여 자사의 컨텐츠 제작도구를 팔기 위한 것만은 아니라고 생각한다. 물론 지금까지 Adobe는 PhotoShop, CS4, Flex Builder, LCDS등의 다양한 제품을 팔아 이윤을 남겨 회사를 운영했다고 본다. 그런데 몇년전부터 Adobe는 자사의 핵심 기술을 무료로 공개하기 시작했다. 물론 그것이 컨텐츠 제작도구는 아니지만 제품 외에 다양한 기술을 아무 댓가가 없는 것 마냥 공개하기 시작한 것이다. 이미 실시간 메세지 전송 프로토콜인 RTMP과 데이터 통신의 핵심의 일부를 BlazeDS등를 제작해 오픈 소스로 공개하고 있다. 누구든지 오픈소스 홈페이지를 통해 Adobe에서 제작한 소스를 볼 수 있다.
요즘은 공개가 주요 덕목이라고는 하지만 Adobe가 자사의 기술을 이렇게 공개하는 이유는 무엇일까? 또한 오픈 스크린 프로젝트를 통해 Flash 컨텐츠가 다양한 자원, 기기들을 지원할 수 있도록 한 배경은 무엇일까? 이 이유에 대한 답은 이외로 간단하다. 회사는 영리를 목적으로 한다. Adobe도 건실한 하나의 회사이므로 당연히 영리를 목적으로 한다. 영리를 취하기 위한 방편으로 Adobe가 생각한 것은 바로 유통이다.
iPhone, iPod을 사용하는 사용자라면 Apple Store에 대해서는 너무도 잘 알것이다. iPhone이라는 매우 훌륭한 기기를 만든 것도 사실이지만 Apple은 더 앞서 이들 기기에 사용할 애플리케이션이 널리 보급되고 공개될 수 있는 유통 채널을 Apple Store를 통해 확보했다. 애플리케이션 개발업체 및 개인 개발자는 Apple Store를 통해 자신의 애플리케이션을 팔 수 있고 그 이윤의 일부를 Apple이 가진다. 얼마 안되는 액수이긴 하지만 이것이 쌓이면 엄청나다. 이런 유통 채널로 무수한 애플리케이션이 만들어졌고 미려한 iPhone의 디자인에 흠뻑 반한데다가 다양한 컨텐츠까지 접할 수 있는 고객입장에서는 iPhone을 선택하지 않을 수 없게 되었다. 어디 그뿐인가? 이것으로 Apple의 매출을 최고조를 이루고 있고 자사의 회사 이미지도 상승하여 다른 제품군들의 매출도 상승하게 되었다. 이 점에서 필자가 생각하는 Apple의 가장 큰 성공요인은 유통이라고 생각한다.
Adobe는 Apple보다 늦었지만 분명 유통의 강점을 잘 알고 있었을 것이라 생각한다. 유통을 적절하게 해서 성공한 Apple의 사례는 Adobe에게 좋은 간접 경험이 되었으리라 판단한다. 그럼 구체적으로 Adobe는 어떻게 유통을 하겠다는 것인가?
플래시 플랫폼 서비스(Flash Platform Services)는 Apple Store처럼 유통채널을 만들기 위한 첫단추라고 생각한다. 이번 Adobe MAX 2009 키노트에서는 이에 대해 많은 부분 소개하진 않았다. 하지만 이번에 Flash Platform Service을 공개함으로서 Adobe도 Flash 컨텐츠 유통 시스템을 만들고 있다는 것을 예상할 수 있게 되었다.
플래시 플랫폼 서비스는 배포(Distribution), 협업(Collaboration), 소셜(Social)이라는 3가지 키워드로 요약된다.
배포 서비스는 말그대로 Flash Platform 애플리케이션이 배포될 수 있는 공간을 만들어 준다는 것이다.
이 서비스는 만들어진 Flash애플리케이션을 마이스페이스나 페이스북과 같은 소셜 서비스와 모바일 기기, 데스크톱등에 배포하기 위한 일련의 복잡한 절차를 해소 시켜주고 각종 프로모션 및 광고를 쉽게 해주고 각종 통계까지 내준다. 배포 서비스에 대해 더욱 자세히 알기 위해 다음 링크와 동영상을 참고한다.
협업 서비스는 Adobe가 Adobe자체 기술을 지원해준다는 말이다. 가령, 채팅, 오디오, 비디오 서비스등은 일반 개발자뿐 아니라 회사에게 자체 서버가 있어야하는 기술적, 자금적 부담감이 존재한다. 이런 어려운 부분을 Adobe에서 지원해준다는 이야기이다. 다음 링크로 부터 이 협업 시스템의 형태와 Showcase를 볼 수 있겠다.
소셜 서비스은 페이스 북과 마이 스페이스와 같은 소셜 네트워크와 통합해서 이를 가지고 개발할 수 있도록 하는 서비스이다. 하지만 현재 공개되어 있지 않다. 이미 Open API를 통해 매쉬업 애플리케이션들이 만들어져 있고 그 중요성 또한 높아지고 있다. 이것을 더욱 쉽고 강력하게 할 수 있도록 소셜 서비스를 통해 지원해준 다는 것을 의미한다.
위에서 언급한 3가지 키워드를 바탕으로 플래시 플랫폼 서비스로 하여금 유통채널을 만들어 가겠다는 의미로 필자는 받아 들였다. 아직 많은 부분 완성되지 않았지만 앞으로 Flash Player 10.1 및 AIR 2.0 배포되고 이를 지원하는 다양한 디지털 기기들이 판매되며 또한 플래시 플랫폼 서비스의 3가지 키워드가 완성이 된다면 새로운 Flash 컨텐츠 유통채널이 만들어져서 기존 Flash Platform 개발자의 유입이 증대될 것이고 더불어 관련 애플리케이션도 많아져 결국 사용자의 경험을 극대화 시키는 효과와 함께 이것을 수용한 기술 및 제품이 잘 팔리게 되는 효과를 기대할 수 있을 것이라 생각한다. 결국 자사 만족, 개발자만족, 고객만족을 위한 Adobe의 정책이라 할 수 있다.
이미 두텁케 형성된 Flash 컨텐츠 개발자들은 플래시 플랫폼 서비스를 통해 기존 기술을 맘껏 이용해 개발과 배포를 쉽게 할 수 있다. 그리고 각종 기기 및 기술적 어려운 부분은 오픈 스크린 프로젝트를 통해 그 문제를 해결한다. 이들 모두가 결국 Flash 컨텐츠의 유통을 실현하기 위한 정책의 일환임을 알 수 있다.
정리하며
Adobe MAX 2009 행사는 개인적으로 어떤 기술적인 답변을 얻었다것 외에 Adobe가 지향하는 정책에 대한 로드맵을 더욱 이해하는데 도움이 된 자리였다고 생각한다. 어짜피 기술은 계속 발전한다. 기술이 기술자체로 끝나는 것이 아니라 그 방향성이 더 중요하고 결국 사용자에게 감동을 주어야 그 기술이 빛을 발할 것이라 생각한다.
Adobe가 Flash Platform의 확산을 위해 오픈 스크린 프로젝트(Open Screen Project)와 플래시 플랫폼 서비스(Flash Platform Services)라는 여러가지 대안을 마련하여 이에 기술이 뒷받침 되도록 방향성을 맞추어가고 있다는 것을 염두한다면 Flash Platform 관련 기술 적용에 더욱 도움이 될 것이라 생각한다.
독립형 FB4(Flash Builder 4)를 사용하지 않고 굳이 Eclipse에 FB4 plugin을 설치하는 이유는 독립형 FB4는 기능의 제약점이 있기 때문이다. 물론 FB4로도 충분히 개발이 가능하지만 Eclipse와 연동하는 것은 이 편이 실무에 더욱 적합하다. 그 이유는 hika님의 글 Flex Builder는 반드시 Plug in 으로 설치 글을 읽어보면 알 수 있다.
하지만 이러한 설치법은 처음 해보는 사람에게는 단순하지 않다. 한방에 설치하는 독립형 FB4에 비해 이것저것 고려할 것이 많은 것 같은 생각이 들기 때문이다. 이 글을 쓰는 목적은 FB4 plugin을 설치를 하는데 있어서 다소 어려움을 쉽게 극복하기 위한 방법을 소개하기 위함이다.
원래 eclipse.ini에서 수정된 부분은 -vmargs의 위치가 -Xms40m 바로 위로 이동된 것이며 추가된 부분은 -vm 부분이 들어간 것이다. 이때 javaw.exe 경로는 각자 jdk또는 jre 설치 경로를 따라 설정하면 되겠다. 이렇게 해도 같은 에러가 난다면 검색을 통해 다른 방법을 찾길 바란다.
3. Flash Builder 4 plug in을 설치시 반드시 Eclipse 설치경로를 지정해줄것!
FB4 plug in을 설치하면 중간에 Eclipse설치 경로를 지정하는 순서가 있다. 이 부분을 잊지 말고 Eclipse 경로를 지정하기 바란다.
4. FB4를 실행할때는 Eclise를 실행하거나 FB4에 설치된 Run FB Plug-in with alternate Eclipse를 실행한다.
FB4 plug-in에서 Run FB plug-in 을 실행하면 eclipse-host-distro의 Eclipse가 실행되므로 이것을 사용하지 말자.
5. 바로가기를 FB4 아이콘으로 바꾸기 일반적으로 Eclipse를 실행하기 위해 바탕화면에 바로가기를 만들거나 빠른실행아이콘으로 등록해서 사용할 것이다. 하지만 이 바로가기는 기본 아이콘이 이클립스이다. 그러므로 기존에 사용하는 이클립스 아이콘이 있다면 무엇이 Flash Builder이고 무엇이 Eclipse인지 잘 분간이 안갈터...
바로가기의 아이콘을 Flash Builder 아이콘으로 바꿔보자.
1. Flash Builder Plug-in이 설치된 폴더로 가서 eclipse-host-distro 폴더에 가면 Eclipse.ico 파일이 있다. 이것을 복사해서 Eclipse 설치 폴더에 복사한다.
2. 다음으로 바탕화면 또는 빠른실행아이콘을 선택해 마우스 오른쪽 버튼을 눌러 속성을 선택한다.
3. 아이콘 변경 버튼을 눌러 Eclipse 설치 폴더에 복사한 Eclipse.ico로 바꿔준다.
7. 이전 워크스페이스의 SDK경로는 따로 빼자!
Flash Builder의 SDK가 아닌 기존에 원래 사용하던 SDK를 참조할 필요가 있는 경우가 있다. 이런 문제를 해결하기 위한 방법은 여러가지가 있겠지만 본인은 C나 D 드라이브로 SDK폴더를 따로 만들어 FB가 이 SDK를 참조하도록 하고 있다.
다음과 같이 진행한다.
1. C나 D 드라이브등에 사용할 SDK를 복사한다.(새 FB의 설치경로에 sdks에 있는 파일을 복사할 수 있다.)
2. FB를 실행한다.
2. 메뉴에서 Window > Preference를 선택한다.
3. 창이 뜨면 좌측에 Flash Builder를 열어 Installed Flex SDKs를 선택한다.
4. 우측에 Flex 3.4, Flex 4.0이 이전 FB버전의 경로를 참고하고 있을 것이다. 이를 C나 D드라이브에 복사한 SDK를 참조하도록 한다.
8. 기본 플러그인 설치는 기본!
독립형 FB4에는 설치되지 않는 플러그인이 Eclipse에는 언제든지 설치가 가능하다. 주로 협업이 이뤄지므로 SVN등을 설치해야하고 다양한 배포 경로를 확보하기 위해 ANT관련 설정이 필요할 것이다. C/C++개발을 위한 CDT, PHP개발을 위한 PDT등 플러그인을 제한없이 설치할 수 있으니 Eclipse의 FB4 plugin을 설치하는 편이 훨씬 득이라는 것을 느낄 수 있을 것이다.
참석한 Adobe MAX는 Adobe의 가장 큰 행사중에 하나로 1년에 한번씩 미국의 주요 도시를 돌면서 열립니다. 이번 행사 참여로 Adobe 로드맵에 대해서 어느 정도 알 수 있게 되었습니다.
이 로드맵의 첫번째 단추는 Adobe의 기술의 핵심인 Flash Player을 모든 플랫폼에 적용하는 겁니다. 이 플랫폼이라는 것은 모바일이 될 수 있고 각종 다른 기기들이 될 수 있을겁니다. 이것이 가능하게 하기 위해 Adobe는 Open Screen Project(http://www.openscreenproject.org/) 라는 것에 참여하고 있습니다. 이 프로젝트로 각종 기업에서 만들어지는 모바일등의 디바이스에 Flash Player가 설치되고 이미 엄청나게 보급화 되어 있는 Flash 개발인력을 어렵지 않게 흡수 시킬 수 있게 됩니다.
Open Screen Project를 반영하여 탄생된 것이 바로 Flash Player 10.1 입니다. 이 Flash player 10.1은 데스크탑 뿐 아니라 모바일에도 최적화되어 돌아갈 수 있도록메모리 및 속도 향상에 큰 변화를 가져왔습니다. 그리고 기존에 Flash Lite로만 개발했던 인력을 ActionScript 3.0, Flex 개발자들까지 모바일 프로그램을 할 수 있도록 된거지요. 메모리,속도향상등에 더욱 자세한 내용을 보고 싶다면 제 블로그를 보세요.
대부분의 개발자의 주요 관심사인 Apple의 경우 Open Screen Project에 참여하지 않고 있습니다. 그래서 Adobe는 Flash로 개발하고 아에 iPhone용 애플리케이션이 나오도록 해버렸습니다. 이미 어도비 Labs에 Flash로 만든 iPhone용 애플리케이션이 애플스토어에 올라왔다는 것을 확인할 수 있습니다. 현재 직접 아이튠즈에서 다운로드 받아볼 수 있습니다.
Open Screen Project를 통해 대부분의 디바이스 및 각종 플랫폼에 Flash Player가 설치될 수 있도록 하여 Adobe가 얻을 수 있는 것은Flash 애플리케이션의 유통일겁니다. Adobe가 내놓은 모든 것들이 이제는 모두 이 유통에 집중될 모양입니다. 이에 대한 구체적인 시스템이 바로 Flash Platform Service(http://www.adobe.com/devnet/flashplatform/services/index.html) 입니다. 아래링크는 제 블로그에 올린 Flash Platform Service에 대한 전문입니다.
여러분은 지금 Flash로 만든 iPhone, iPod 용 애플리케이션을 애플 스토어에서 다운로드 받을 수 있습니다. Adobe Lab(http://labs.adobe.com)에서 올해 말에 나올 Flash Professional CS5를 홍보하기 위해 떡밥 제대로 내놯습니다. ^^
미국 LA에서 열리는 Adobe MAX 2009 행사 키노트에서 요즘 한국에서도 급부상하고 있는 아이폰(iPhone) 애플리케이션을 Flash로 제작할 수 있게 되었다고 최초로 공개했다. Flash CS5부터 Flash IDE에서 제작한 결과물을 iPhone용으로 컴파일하는 기능이 추가될 예정이다.
아래 그림 하나로 모든게 설명되는.... ^^
아래는 키노트 시에 공개된 동영상이다.
Adobe 사장, 부사장 둘이서 아이폰을 어떻게 구워삼을까 고민하다가 결국 개발자에게 넘긴다. 한방에 해결된다는... 뭐... 그런거?
Adobe MAX 행사는 키노트 외에도 각종 세션이 있습니다. 행사 참여자는 자신이 듣고 싶은 세션을 선택해서 언제든지 들을 수 있지만 다른 세션과 중복되는 경우에 각 세션에서 진행한 내용을 Adobe TV를 통해 못봤던 세션을 볼 수 있습니다.
Building Applications for iPhone with Flash Professional CS5
Flex for mobile devices
아래는 위 동영상에서 Flex로 만든 애플리케이션을 iPhone에서 구동 시연을 캡쳐한 사진입니다.
결론 : Flash Platform 개발자들이여! 이것저것 다하려 하지 말고 Flash하나만 잘해서 향후 10년 밥줄이어갑시다. ㅋ
이번 Adobe MAX 2009에서 Flash Player 10.1을 공개했습니다. 이번 키노트를 통해 더욱 최적화되고 강력해진 Flash player에 대해 설명을 들을 수 있었는데요, 주목할 점은 다양한 모바일등의 다양한 플렛폼 지원과 최적화 부분이겠네요.
MAX현장에서 직접 찍은 사진입니다. ^^
위 화면에서 Flash Player 10.1의 추가 및 향상된 기능을 보실 수 있습니다. 스마트 폰을 지원하며 멀티터치 기능이 가능해집니다. 또한 메모리, 전력, 하드웨어 가속에 대해서 최적화 했으며 Http 비디오 스트리밍등을 지원하게 됩니다.
각종 스마트폰에 지원이 되는 만큼 애플리케이션의 저전력 구동은 핵심이 될겁니다. 일반 비디오는 3.4시간, 활동적인 에니메이션이 들어간 애플리케이션인 경우 6.5시간, 저전력 모드에서는 14.5시간 볼 수 있다고 언급하고 있습니다.
Flash Player 10.1과 기존 Flash Player 10의 메모리 사용양을 나타냅니다. 같은 자원을 쓰고서도 거의 1/2~2/3가량 용량이 줄어들었습니다. Flash Player 10.1이 모바일에 지원되기 위한 최적화의 노력의 성과겠네요.
Adobe는 이번 키노트를 통해 Flash Player가 더이상 데스크탑이 아닌 모바일에서도 같은 동작을 한다는 것을 강조하고 있습니다. 지금까지 Flash Lite로만 모바일 기기 애플리케이션을 만들었지만 Flash Player 10.1부터는 일반 Flash로도 충분히 모바일에서 돌아가는 플래시 컨텐츠를 생산할 수 있게 되었습니다. 이렇게 Flash Player가 다양한 모바일에 지원된데에는 오픈 스크린 프로젝트(Open Screen Project)의 추진과 관련 있습니다. 흥미로운 점은 이 프로젝트에 구글이 동참했다는 점입니다. 오픈 스크린 프로젝트는 더이상 PC, 모바일만을 뜻하지 않으며 다양한 플렛폼에서 다양한 경험을 제공하는 것을 목표로 합니다. 이 오픈 스크린 프로젝트는 구글, 삼성, LG를 비롯해 노키아, NVIDIA등 수많은 회사가 참여하고 있으며, 앞으로 이들이 내높는 다양한 플랫폼에 Flash Player를 지원하게 되어 어디서든 Flash 컨텐츠를 접할 수 있게 됩니다. 하지만 아쉽게도 아이폰의 제작 회사인 Apple은 이 프로젝트에 포함되지 않았군요.
하지만 가만히 있을 Adobe가 아니죠.
위 그림 하나로 다들 쓰러졌다는....
그러니깐 Flash IDE에서 Flash컨텐츠를 개발해서 그대로 iPhone용으로 익스포트 시켜주는 기능이 CS5부터 추가된다고 합니다. 멀티터치 기능도 추가되겠다. 결국 이 기능도 iPhone을 겨냥한듯합니다. ㅎㅎ
구를 표현하는데 있어서 많은 3D 예제들이 그냥 경도, 위도로 나눠서 텍스쳐 입히는 것이 대부분입니다. 사실 그게 가장 쉬운 방법이고 완성된 구를 표현할 것 같으면 그편이 좋습니다.
Geodesic Sphere에 대한 프로그램 코드는 그리 많지 않은 것 같더군요. 대신 건축물은 왜 이렇게 많은지.. ㅎㅎ 이 형태의 구로 만든 건축물이 매우 이쁘고 독특해보이죠. 디즈니랜드의 Epcot Dom이 매우 유명한 Geodesic Sphere의 한종류이죠.
응용하면 아래처럼 의자도 만들 수 있네요. 왠지 세련되어 보입니다.
Geodesic이라는 말은 두점간에 최단선(측지선)을 의미합니다. 이 원리를 이용해 만든 구가 바로 Geodesic 구라는 것이지요.
구글 어스(Google Earth)와 같은 3D 프로그램에서 구의 형태를 어떻게 표현했다고 생각하시나요? 정확히는 모르겠지만 Geodesic Sphere 기법을 이용했을 거라 추측합니다. 구글어스에 보이는 지도는 타일 이미지들의 모임입니다. 만약 경도,위도로 그 타일 이미지를 나눠버리면 결국 극쪽(북극, 남극)쪽에 불러와야할 타일 이미지는 엄청 많아지겠죠. 확대할수록 더할 겁니다. 이런 점에 비춰볼때 3D에서 Geodesic Sphere의 선택이 필요할 것 같아집니다.
Geodesic Sphere를 표현하는 방법은 다양합니다. TETRAHEDRON, OCTAHEDRON, ICOSAHEDRON 기반등을 이용해 그려나갈 수 있지요. 아래처럼요.
아직 3D 지도에 어떤 방식이 좋을지 명확히 판단하지 못했지만 OCTAHEDRON 또는 ICOSAHEDRON 기반이 아닐까 생각합니다.
회전 : 마우스 드래그
폴리곤수 조절 : 방향키 Up/Down
Flash 3D API의 drawTriangle 메소드 기반으로 그려본겁니다. 일반 경도, 위도만을 가지고 그릴때보다 복잡한 편이라 애를 먹었습니다. 극부분이 이미지가 찌그러져보이는 것은 UV설정이 잘못되었기 때문입니다. 이부분에 대한 보완이 필요합니다. 어쨌든 3D 지도 기반을 만들기 위한 첫단추를 꽨 셈이군요. ^^
Flash에서 이미지 처리는 지금까지 BitmapData 조작이였다. 싱글스레드 기반의 Flash Player는 이미지 조작을 하기에 좋은 퍼포먼스를 가지기 어려웠다. 하지만 Flash Player 10부터 멀티스레드를 기반으로하는 Adobe Pixel Bender를 지원함에 따라 이제 이미지 프로세싱에 Flash의 막강화력을 보여줄 수 있게 되었다. Adobe Pixel Bender에 대한 국내 문서는 그다지 많지 않은 편이지만 앞으로 Flash/Flex/ActionScript 개발자들에게 각광받는 기술이 될 것임에 틀림없겠다.
한글 에러 : ArgumentError: Error #2180: AVM1 내용(AS1 또는 AS2)이 AVM2(AS3) 내용으로 로드된 경우 AVM1 내용을 displayLis의 다른 부분으로 이동할 수 없습니다."
영문 에러 : ArgumentError: Error #2180: It is illegal to move AVM1 content (AS1 or AS2) to a different part of the displayList when it has been loaded into AVM2 (AS3) content.
위와 같은 에러를 본 적이 있는가?
이것은 Flash Player 9 버전으로 만들어진 애플리케이션에서는 발생하지 않는다. Flash Player 10 버전으로 만들어진 애플리케이션에서 위와 같은 문제가 발생한다.
위 에러가 발생하는 조건은 다음과 같다.
AVM2(ActionScript Virtual Machine 2)기반으로 만들어진 Flash 애플리케이션 AVM2 기반이라는 것은 ActionScript 3.0 기반으로 만들어진 애플리케이션을 의미한다.
Flash Player 10 기반으로 컴파일한다. 컴파일 옵션에서 Flash Player 버전을 9.0.124 등이 아닌 10.0.0을 기반으로 한다.
위 두 조건하에서 AVM1기반으로 만들어진 SWF파일을 flash.display.Loader를 이용해 로드한다. AVM1 기반이라는 것은 ActionScript 1.0 또는 ActionScript 2.0 기반으로 만든 SWF파일을 의미한다.
Loader.contentLoaderInfo.content를 addChild() 한다. Loader는 외부의 이미지, 플래시 파일등을 로드해서 디스플레이 객체로 등록하는 일종의 wrapper역할을 담당한다. 이들을 로드완료하면 Loader.contentLoaderInfo.content에 해당 객체의 참조를 얻을 수 있다. 일반적으로 화면에 출력하기 위해 addChild( Loader ) 식으로 하면 되는데 이렇게 안하고 addChild( Loader.contentLoaderInfo.content ) 를 하는 경우다. 이것이 가능한 이유는 Loader.contentLoaderInfo.content 도 DisplayObject이기 때문이다.
위 조건에 맞춰서 ActionScript 3.0 기반으로 코딩을 아래와 같이 해보겠다.
package
{
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.Sprite;
import flash.events.Event;
import flash.net.URLRequest;
public class AVM1LoadTest extends Sprite
{
private var loader:Loader;
public function AVM1LoadTest()
{
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoadComplete);
loader.load( new URLRequest("avm1asset.swf") );
}
private function onLoadComplete( event:Event ):void
{
var loaderInfo:LoaderInfo = event.target as LoaderInfo;
trace( loader.numChildren );
trace( loaderInfo.content.parent );
var avm1asset:DisplayObject = loaderInfo.content;
addChild( avm1asset );
trace( loader.numChildren );
trace( loaderInfo.content.parent );
}
}
}
위 프로그램을 Flash Player 9 버전으로 컴파일하고 실행해보자. (실행되는 Flash Player 버전은 10이어야 한다. 당연히 실험 애플리케이션이 Flash Player 9버전 뿐 아니라 10버전도 만들 것이기 때문이다.)
아래 화면과 같이 AVM1 기반 SWF를 예쁘게 출력해준다.
onLoadComplete() 안을 살펴보면 addChild() 앞뒤로 똑같은 trace()문이 있다. 이것은 addChild() 전후로 loader.numChildren과 loaderInfo.content.parent(이것은 loader.content.parent와 같다)의 변화를 살펴보기 위함이다. loader.numChildren은 Loader 객체에 로드된 AVM1객체가 자식으로 등록되어 있는 경우에는 1이 출력되고 그 반대는 0이 된다. loaderInfo.content.parent는 로드된 AVM1객체의 부모가 무엇인지 가리킨다.
결과는 다음과 같다.
1 [object Loader] 0 [object AVM1LoadTest]
무엇을 의미하는가? addChild()를 하기 전에는 AVM1객체는 Loader의 자식이지만 addChild() 후로는 AVM1LoadTest객체의 자식이 된다. AVM1LoadTest는 위 프로그램의 메인 클래스이다. 이것은 당연한 결과로 자식은 두개 이상의 부모를 가질 수 없는 것을 의미한다. Flash Player 9버전으로 만든 경우에는 이러한 코딩이 가능했다.
조건을 바꿔보자. 이제 위 프로그램을 Flash Player 10 버전으로 컴파일하고 실행해보자. 언급했던 에러가 발생한다.
"ArgumentError: Error #2180: AVM1 내용(AS1 또는 AS2)이 AVM2(AS3) 내용으로 로드된 경우 AVM1 내용을 displayLis의 다른 부분으로 이동할 수 없습니다."
무엇을 의미하는가? Flash Player 10 기반으로 만들어진 애플리케이션은 AVM1 객체를 AVM2 기반의 디스플레이 객체로의 이동을 불허한다. 즉 Loader에서 떠나지 못함을 의미한다.
Flash Player 10기반에서 AVM2 SWF를 로드한 경우는 addChild( loader.contentLoaderInfo.content ) 가 가능할까? 이것은 된다!
Flash Player 10에서 AVM1기반의 SWF는 부모로 Loader이어야만 하는 이유는 무엇일까? 사실 여기에 대한 답변을 나는 아직 찾지 못했다. 혹시 아시는 분은 댓글 및 트랙백을 부탁한다.
일본에서는 이미 이 문제로 고민한 사람이 꽤 있었다. 재미있게도 AVM1을 AVM2로 강제로 바이트 단위로 버전을 수정해 버려 로드해버리는 커스텀 Loader까지 만들어 배포하는 사람이 있었다. 좋은 방법인지는 모르겠지만 아무튼 이런 연구가 활발히 진행되는 일본이 부럽당.. ㅡㅡ
Flash가 Cross OS, Cross Browser를 지향하지만 한글문제를 비롯해 각종 몇가지 기능을 제대로 수행하지 못하는 경우가 있다. 마우스 휠(Mouse Wheel)도 그와 같은 맥락이다.
Mac 운영체제에서는 마우스 휠 기능이 전혀 먹지 않는다. MS Window에서 wmode가 transparent일때 Internet Explorer를 제외하고 다른 브라우저에서는 마우스 휠 기능을 사용할 수 없다.
이 문제를 해결할 수 있는 유일한 방법은 Javascript를 이용하는 방법이다. ActionScript3의 ExternalInterface를 이용해 Javascript와 통신해서 마우스 휠 이벤트를 사용하는 것이다. 자바스크립트를 이용하는 방법은 내 블로그에도 몇번 글을 올렸다.
단, 위 방법이 잘될 수 있도록 하기 위해 allowScripAccess는 같은 도메인의 swf인 경우 sameDomain, 다른 도메인의 swf인 경우 always로 지정해야한다. allowNetworking은 항상 all로 설정해야한다. 이에 대한 자세한 내용은 다음글을 참고한다.
SWFWheel 클래스는 browserScroll 속성이 있다. 이것을 이용해면 Flash 위에서 MouseWheel을 이용할 때 Flash를 담은 브라우저의 스크롤링을 허용할 것인가 설정할 수 있다. 기본값은 false이다.
네이버 오픈캐스트의 메인 프로그램이 Flash로 만들어져 있는데 마우스 휠 기능이 어떤 운영체제든 브라우져든 잘 동작한다. 아마도 이 SWFWheel을 사용하지 않았나 생각된다.
이렇게 꽁수 안부리고 마우스 휠이든 한글문제든 Flash Player가 문제 없이 잘 동작하면 얼마나 좋을까?
[생각더하기]일본의 Spark 프로젝트의 이름에 눈길이 간다. Flex 4의 새로운 컴포넌트는 Spark로 명명했다. 그럼 Flex 4가 만들어질때 일본의 Spark 프로젝트의 역할이 컷던 것 아닐까? 실제로 Spark 프로젝트는 일본내에서 매우 활발하고 유명한 Flash 관련 프로젝트이다. 그 유명한 증강현실(FLARToolKit)도 이 프로젝트에서 만들어진 것이다. 우리 나라에는 왜 이런 멋진 프로젝트 팀이 없는 것일까? 안타깝다.
3D 환경맵핑(Environment Mapping)의 한 기법으로 Cube Maps가 있다. 말그대로 직육면체의 각면에 대한 텍스쳐 이미지로 3D 환경을 조성하는 방법인데 아래 이미지를 보면 바로 이해할 수 있다.
출처 : developer.com
Cube Maps는 환경 맵핑 방법중 가장 빠르고 매우 사실적으로 묘사할 수 있는 방법으로 내가 알기로는 게임등에 자주 사용하는 것으로 알고 있다. 단점은 모서리 부분에서 약간 티가 난다는 점이다.
Flash Player 10부터 3D API를 제공한다. 이 API들을 적절히 활용하면 Papervision3D나 Away3D와 같은 라이브러리를 이용하지 않고도 어려움 없이 Cube Maps을 구현할 수 있다.
아래 프로그램은 Flash Player 10에서 제공하는 3D API만 이용해서 Cube Map을 구현한 것이다. 마우스 드래그로 회전이 가능하다.
마우스로 Drag하면 회전이 됩니다. (Mac에서 화면이 작게 나오는데 아직 이유를 모르겠네요 ^^;)
위와 같은 프로그램을 만들기 위해 6면을 가지는 텍스쳐 이미지가 필요하다. 인터넷에 많이 있는데 아래처럼 Layout이 여러종류가 있다.
Cube Map Layout 출처 : cgtextures.com
나는 가장 일반적이고 자주 쓰이는 Horizontal Cross방식 대신에 Horizontal Strip(NVidia DDS Exporter Layout)을 이용했다. 이 방식은 아래같이 구성된다.
Cube Map Layout 출처 : cgtextures.com
이러한 이미지가 어떻게 Cube Map을 만들 수 있는지 아래 화면을 보면 쉽게 알 수 있다.
마우스로 Drag하면 회전이 됩니다.
아래는 위 프로그램에 대한 소스이다.
package
{
import flash.display.*;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.*;
import flash.utils.getTimer;
[SWF(frameRate=60, backgroundColor=0x000000)]
/**
* Cube Map 예제
* @author Yongho, Ji (http://blog.jidolstar.com/574)
* @since 2009.08.05
*/
public class CubeSky extends Sprite
{
[Embed(source="sky.jpg")]
private const SKY:Class;
//투영된 Vectex 정보
private var projected:Vector.<Number>;
//World 변환 행렬
private var world:Matrix3D;
//투영을 위한 변환행렬
private var projection:Matrix3D;
//Mesh 데이터
private var mesh:GraphicsTrianglePath
//Texture
private var texture:BitmapData = (new SKY as Bitmap).bitmapData;
//Viewport (3D 렌더링 대상)
private var viewport:Shape;
//Viewport의 Z축 위치
private var viewPortZAxis:Number = 0;
public function CubeSky()
{
//Viewport
viewport = new Shape;
addChild( viewport );
//투영 변환 행렬
var p:PerspectiveProjection = new PerspectiveProjection()
p.fieldOfView = 30;
projection = p.toMatrix3D();
//World 변환 행렬
world = new Matrix3D();
var check3D:Vector3D = Utils3D.projectVector(
projection,
new Vector3D(1.0,0,1.0)
);
//Mesh 데이타
mesh = createCubeMesh( check3D.x );
projected = new Vector.<Number>(0,false);
viewPortZAxis = check3D.x;// * 4;
//이벤트 핸들러 등록
stage.addEventListener( Event.RESIZE, resize );
stage.addEventListener( Event.ENTER_FRAME, render );
//stage.addEventListener( MouseEvent.MOUSE_WHEEL, onMouseWheel );
stage.addEventListener( MouseEvent.MOUSE_DOWN, onMouseEvent );
resize();
}
private function resize( event:Event = null ):void
{
viewport.x = stage.stageWidth/2;
viewport.y = stage.stageHeight/2;
}
private function render( event:Event = null ):void
{
world.identity(); //단위행렬로 전환
world.appendRotation( zRotation, Vector3D.Z_AXIS );
world.appendRotation( 90+xRotation, Vector3D.X_AXIS );
world.appendTranslation(0, 0, viewPortZAxis); //이동
world.append(projection); //투영 변환 적용
// mesh 데이터를 투영하여 projected 생성
// uvtData도 갱신된다. 갱신되는 데이터는 T값이다.
Utils3D.projectVectors( world, mesh.vertices, projected, mesh.uvtData );
// texture를 이용해 렌더링
viewport.graphics.clear();
//viewport.graphics.lineStyle( 1, 0xff0000 );
viewport.graphics.beginBitmapFill( texture, null, false, true );
viewport.graphics.drawTriangles( projected, mesh.indices, mesh.uvtData, mesh.culling );
//Cube는 z축을 굳이 정렬할 필요 없다.
//viewport.graphics.drawTriangles( projected, getSortedIndices(mesh), mesh.uvtData, mesh.culling );
}
/**
* 마우스 휠 처리
*/
private function onMouseWheel( event:MouseEvent ):void
{
viewPortZAxis += event.delta * 10;
}
private var xRotation:Number = 0;
private var zRotation:Number = 0;
private var prevX:Number;
private var prevY:Number;
/**
* 마우스 이벤트 - x,y축 회전
*/
private function onMouseEvent( event:MouseEvent ):void
{
switch( event.type )
{
case MouseEvent.MOUSE_DOWN:
stage.addEventListener( MouseEvent.MOUSE_MOVE, onMouseEvent );
stage.addEventListener( MouseEvent.MOUSE_UP, onMouseEvent );
prevX = mouseX;
prevY = mouseY;
break;
case MouseEvent.MOUSE_MOVE:
if( event.buttonDown == false )
{
stage.removeEventListener( MouseEvent.MOUSE_MOVE, onMouseEvent );
stage.removeEventListener( MouseEvent.MOUSE_UP, onMouseEvent );
break;
}
var dx:Number = mouseX - prevX;
var dy:Number = mouseY - prevY;
zRotation += dx;
xRotation += dy;
if( xRotation > 90 ) xRotation = 90;
if( xRotation < -90 ) xRotation = -90;
prevX = mouseX;
prevY = mouseY;
break;
case MouseEvent.MOUSE_UP:
stage.removeEventListener( MouseEvent.MOUSE_MOVE, onMouseEvent );
stage.removeEventListener( MouseEvent.MOUSE_UP, onMouseEvent );
break;
}
}
}
}
import flash.display.GraphicsTrianglePath;
import flash.display.TriangleCulling;
/**
* Cube Mesh 데이타 작성
* @param size 한변의 사이즈
* @return mesh 데이터
*/
function createCubeMesh( size:Number = 512 ):GraphicsTrianglePath
{
var vertices:Vector.<Number> = new Vector.<Number>( 0, false );
var indices:Vector.<int> = new Vector.<int>( 0, false );
var uvtData:Vector.<Number> = new Vector.<Number>( 0, false );
var mesh:GraphicsTrianglePath = new GraphicsTrianglePath( vertices, indices, uvtData, TriangleCulling.POSITIVE );
var s:Number = size/2;
var w:Number = size * 6;
var u00:Number = 0;
var u01:Number = (size-1)/w;
var u10:Number = size/w;
var u11:Number = (size*2-1)/w;
var u20:Number = (size*2)/w;
var u21:Number = (size*3-1)/w;
var u30:Number = (size*3)/w;
var u31:Number = (size*4-1)/w;
var u40:Number = (size*4)/w;
var u41:Number = (size*5-1)/w;
var u50:Number = (size*5)/w;
var u51:Number = (size*6-1)/w;
mesh.vertices.push(
//Right
s,-s,-s, //0
s,-s,s, //1
s,s,s, //2
s,s,-s, //3
//Left
-s,s,-s, //4
-s,s,s, //5
-s,-s,s, //6
-s,-s,-s, //7
//Top
-s,-s,s, //8
-s,s,s, //9
s,s,s, //10
s,-s,s, //11
//Bottom
-s,s,-s, //12
-s,-s,-s, //13
s,-s,-s, //14
s,s,-s, //15
//Front
-s,-s,-s, //16
-s,-s,s, //17
s,-s,s, //18
s,-s,-s, //19
//Back
s,s,-s, //20
s,s,s, //21
-s,s,s, //22
-s,s,-s //23
);
mesh.indices.push(
0,1,2, 0,2,3, //Right
4,5,6, 4,6,7, //Left
8,9,10, 8,10,11, //Top
12,13,14, 12,14,15, //Bottom
16,17,18, 16,18,19, //Front
20,21,22, 20,22,23 //Back
);
mesh.uvtData.push(
//Right
u00, 1, 1,
u00, 0, 1,
u01, 0, 1,
u01, 1, 1,
//Left
u10, 1, 1,
u10, 0, 1,
u11, 0, 1,
u11, 1, 1,
//Top
u20, 1, 1,
u20, 0, 1,
u21, 0, 1,
u21, 1, 1,
//Bottom
u30, 1, 1,
u30, 0, 1,
u31, 0, 1,
u31, 1, 1,
//Front
u40, 1, 1,
u40, 0, 1,
u41, 0, 1,
u41, 1, 1,
//Back
u50, 1, 1,
u50, 0, 1,
u51, 0, 1,
u51, 1, 1
);
return mesh;
}
/**
* GraphicsTrianglePath를 기반으로, Z축으로 sort된 인덱스를 돌려준다.
* 이 작업을 해주어야 z축 깊이에 따라 Triangle이 제대로 그려진다.
* @param mesh 정보
* @return sort된 index 데이터
*/
function getSortedIndices( mesh:GraphicsTrianglePath ):Vector.<int>
{
var triangles:Array = [];
var length:uint = mesh.indices.length;
//z축 sort를 위한 기반 제작
for ( var i:uint=0; i < length; i += 3 )
{
var i1:uint = mesh.indices[ i+0 ];
var i2:uint = mesh.indices[ i+1 ];
var i3:uint = mesh.indices[ i+2 ];
var z:Number = Math.min( mesh.uvtData[i1 * 3 + 2], mesh.uvtData[i2 * 3 + 2], mesh.uvtData[i3 * 3 + 2] );
if (z > 0)
{
triangles.push({i1:i1, i2:i2, i3:i3, z:z});
}
}
//z축으로 sort
triangles = triangles.sortOn("z", Array.NUMERIC);
//sort된 값을 이용해 Vector값 만듬
var sortedIndices:Vector.<int> = new Vector.<int>(0, false);
for each (var triangle:Object in triangles)
{
sortedIndices.push(triangle.i1, triangle.i2, triangle.i3);
}
return sortedIndices;
}
아래 이미지는 위 프로그램에서 사용한 이미지이다.
위 프로그램에서는 Graphics.drawTriangle() 메소드를 이용했다. 하지만 이 함수를 사용하지 않고도 만들수 있다. 왜냐하면 Flash Player 10부터는 DisplayObject에 대해 x,y,z축 회전 및 이동 API가 추가되었기 때문이다. 그러면 위 프로그램 소스처럼 힘들게 vertex, index, uvt 데이타를 만들지 않아도 될 것이다.
내 생각에 Flash에서 3D 개발을 위해 Graphics.drawTriangle()와 DisplayObject의 3D API, Matrix3D 등을 서로 섞어가면서 만드는 것이 좋을 것 같다.
TLF는 Flash Player 10, AIR 1.5 기반의 새로운 Text 엔진이다. Adobe Flash CS4 및 Flex 4 에서 사용할 수 있다. Flash API에서 제공하는 TextField의 부족한 부분을 개선하고 일반 워드 처럼 Text 편집 작업을 할 수 있도록 하는 것이 이 프레임워크의 목적이 아닌가 싶다.
Adobe Labs에 다운로드 페이지에서 직접 받을 수 있다. 소스는 최신 Flex 4 SDK에 포함되어 있다고 한다. Night Build 버전으로 다운로드 받을 수 있고 [여기]를 참조한다.
TLF의 Beta 1 버전은 다운로드 받으면 CS4, Flex 3, Flex 4 환경에서 개발할 수 있고 꼭 Flash Player 10 버전으로 컴파일 옵션으로 지정해야한다. 그리고 3개의 SWC파일인 textLayout_conversion.swc, textLayout_core.swc, textLayout_edit.swc 를 라이브러리로 포함하면 되겠다.