팬더형님 블로그에 들렀다가 아아아아아아아주 뒤늦게 보게된 물건, hikari.
(http://dragonjoon.egloos.com/9721359
 아마 당시 plusjune-眞본좌-님의 전화가 이 자료를 찾으신 시발점이었던 듯하다.)

한줄 요약 : 이거 끝내주잖아!!!!


이 정도면 꽤나 안정적!

이 정도면 꽤나 안정적!


Ogre3D용이긴 하지만 kimsama형님께서 Nebular device에서 하신 것과 비슷하다능~!

사실 이 자체보단 Flash.ocx를 재배포해도 괜찮은 것 같다...라는 사실과
팬더형님 말씀대로 memcpy()로 구현했다는 사실에 더 끌린다.

...이로써 Winbee 아저씨가 오래 전, 비싼 술을 걸고 요청했던 무언가를 만들수 있는 초안이 되는 것 같다.
지금 마시는 발렌타인 30년산이 다 되어 가는데, 소주 마시듯 30년산을 요구해야지.

아!!
이름부터 얼마나 끌리나, Hikari... . 도키메키 메모리얼2의 히로인...
필시 이 프로젝트의 멤버들도 우리처럼 덕후들일꺼야, 암, 그렇구말구~~!

기념으로 예전 홈페이지에서 찾아낸 그림... .
언젠진 모르겠지만, 오래전에 퍼즐 다마2의 히카리를 베껴 그려봤던 그림이다.
참고로 Rhea君도 왼쪽 눈 아래 점이 있다.

도키메키 메모리얼2는 영원하다!

도키메키 메모리얼2는 영원하다!



결론 : 잉여들~ 
       D3D따윈 잊어버리고 느긋~하게 어도비의 geo 네임스페이스나 공부하자구~!




크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Rhea君
TAG Hikari, ogre, swf


한때 만화를 그렸기 때문에(+오덕질) 기존 Hatch 셰이더에서 스크린톤을 만들어 적용시켜 보았다.
그래픽 노블이 아닌 스크린톤이 듬뿍 붙여진 만화가 더 끌리는데 평평한 면에서는 그럭저럭 괜찮아 보였지만,
굴곡이 들어가는 순간, 스크린톤이 아니라 철망같은 느낌이 든다.

다른 시도가 필요한데 만화가 만화답게 보일려면 톤질을 할때 굴곡에 대해선 어느 정도 무시가 필요하단 생각이 든다.

이런 경우는 역시 그라데이션이 있어야겠다...

이런 경우는 역시 그라데이션이 있어야겠다...

굴곡을 만나는 순간 좆망함;;;;

굴곡을 만나는 순간 좆망함;;;;

더더욱 좆망함;;;;;;;;

더더욱 좆망함;;;;;;;;

흠... 좌절스럽다. 톤질이 듬뿍 들어간 만화책을 만들어보고 싶었는데 역시 연구가 더 필요하다.
스크린톤의 그라데이션을 위해 컬러값까지 바꾸고 싶진 않지만 적절한 트릭을 위해선 컬러 장난질이 필요할지도 모르겠다.
일단 굴곡을 무시하게 해보는게 좋을듯 하다... .

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Rhea君
모션 포트레이트 이야기 1/2 : http://rhea.pe.kr/247

지금으로부터 까마득한 과거, 티라노가 풀뜯어먹던 시절에 그래픽하는 선배랑 룸메를 하고 있었다.
당시 다양한 그래픽툴들을 구경할 수 있었고 배울수 있었는데,
그중 개발자로써 관심이 많이 갔던 것이 브라이스(Bryce)라는 툴이었다.

지금은 회사가 돌고 돌아 홈페이지는 이곳 : http://www.daz3d.com/i.x/software/bryce
그 당시, 이런건 마법이었다.

그 당시, 이런건 마법이었다.


브라이스는 독특하게도 지형 모델링 + 렌더링에 특화된 전문툴로써 MAX처럼 폴리곤이 아닌 2D 이미지를 그려대면 그것을 기초로 멋진 3D 지형을 만들어 주었다. 기본적인 텍스쳐까지 말이다!
브라이스는 스스로를 Fractal 어쩌구 하면서 자랑을 하는 툴이었고,
한눈에 봐도 엄청나보이는 알고리즘과 무지막지할 수학 공식이 엿보였으므로,

"난 평생 이런거 짤일 없을꺼야~"

라는 부끄러운 자위를 하며 분석과 흉내란 도전에서 도망쳤었다.

그러나 시간은 흘러 게임에서 지형은 삼각형 양탄자에서 쿼드트리를 거쳐 높이맵, 라이트맵이 나오고 지형엔진이란 말까지 오래 전에 나와버렸다. Rhea君의 경우, MMORPG보다는 MO를 더 좋아하기에 솔직히 지형에 대한 공부는 별로 하지 않았다. Seamless 월드보단 메탈기어솔리드2같이 한정된 공간 사이사이에서 뛰어노는 게임이 더 좋았고 콘솔게임에 익숙하다보니 월드를 이동할때 생기는 로딩과 연출, 거기에서 나오는 게임의 성격을 자연스레 받아들인 탓이었다.

아뭏든 그래도 직업이 직업이다보니 공부는 계속 하게될수 밖에 없고 실전(=상용) 프로젝트에서 사용하든 접히든(- -;;;;) 계속 삽질을 해야하는게 개발자의 사명이거니 했다. 물론 그 과정 속에서 브라이스가 보여준 독특한 지형 제작 방식이 높이맵(Heghtmap)이란 것도 저절로 알게되었다.

모르는 사람들을 위한 높이맵 이야기
산, 바다, 언덕, 계곡...등과 같이 높낮이가 있는 지형을 만드는 것이 높이맵이다. 상식적으로 모든 3D는 삼각형들로 이루어져 있으며 지형 역시 삼각형 덩어리이다. 이 삼각형들이 같은 높이로 깔려있으면 그야말로 평지일 것이고 높이 방향에 대해 튀어 나오고 들어가면 산이 되고 바다가 된다.

이래뵈도 VS 2.0으로 뽑아낸 폴리곤들이랍니다. 단순한 LineTo()가 아니라고요!

이래뵈도 VS 2.0으로 뽑아낸 폴리곤들이랍니다. 단순한 LineTo()가 아니라고요!


그럼 튀어나오게 하고 들어가게 하는 정의가 필요한데 주로 사용되는 것이 256 단계를 지닌 Gray Scale 비트맵 이미지가 되겠다. 알다시피 컴퓨터에서 채도가 없는 회색은 0~255의 단계를 지니고 있기에 256 그레이 스케일 이미지는 높낮이 편집에 아주 유용한 데이터 정의가 된다. 바로 브라이스가 이걸 보여줬었던 것이다. 0이면 솟아오르고 255면 꺼지면 된다.

지구를 만드는 신의 기분으로~

지구를 만드는 신의 기분으로~


이 이미지를 바탕으로 정점들을 올리고 내리자. 그냥 작업하면 너무 밋밋하니까 잔디 무늬가 있는 텍스쳐도 하나 같이 올리자.
헐퀴~~ 뭔가 튀어나왔다~!

헐퀴~~ 뭔가 튀어나왔다~!


위에 있는 회색 이미지와 비교해보라.

위에 있는 회색 이미지와 비교해보라.


텍스쳐를 더 올리면 부드러운 지형을 얻을 수 있다.

텍스쳐를 더 올리면 부드러운 지형을 얻을 수 있다.


포스트 공간도 부족하고, 높이맵 따라하기~ 스터디용이 아니니까,
이 싯점에서 굳히 소스까지 뿌려가며 설명할 필요는 없으리라 생각한다.

아뭏든 여기서 중요한 것은, 이제 LOD를 구현하고 원금감을 위해 포그(fog)를 넣어야 한다
3D 모델링이 원래 높낮이가 있다는 것이 아니라 읽어들인 한장의 이미지에 의해 높낮이가 만들어졌다는 사실이다.

더 정확히 말하자면 높낮이를 위해서 1장, 텍스쳐 세장, 그리고 텍스쳐의 경계선을 만들기 위해 1장, 총 5장의 이미지가 사용되었다. 그러나 가장 중요한 3D를 만들기 위해서는 정말 1장이 쓰여졌다.

결론 :
높이맵은 모션포트레이트가 핵심으로 내걸고 있는 "한장의 이미지로 방향을 갖고 움직이게 한다"라는 사실과 일치한다.


모션포트레이트
액션스크립트 3.0에서 flash.geom 네임스페이스가 추가되었다.
(http://help.adobe.com/ko_KR/AS3LCR/Flash_10.0/flash/geom/package-detail.html)
아, 정말 플래시 너무하는구나. 이것으로 본격 3D 개발툴이 되었다. GPU까지 직접 쓸수 있게 되면... 우~~ 놀라워라~~!
현재로는 소프트웨어 렌더러라고 생각되지만 아뭏든 플래시의 행보는 무섭다.
비단 플래시 뿐만 아니라 포토샵 CS4 역시 Dimension이 번들되면서 GPU 지원까지 하고 있는데 플래시도 조만간 GPU를 적극 활용할 것 같다.

WPF도 Direct3D를 불러쓰고있지만 WPF가 보여주는 아웃풋은 플래시의 그것과는 자뭇 달라서 실망감이 컸던게 사실이었다. 물론 가장 필요한 킬러 타이틀이 없어서 그렇기도 하지만, 현재로 보기에 WPF는 처량해보이는게 사실이다. 차라리 Silverlight에게 희망을 걸어보고 싶지만... 수많은 디자이너들이 액션스크립트에서 C#으로 넘어가는 것도 결코 쉽지 않을 것이라 HD 스트리밍을 제외하면 플래시가 앞으로도 우위를 지킬 것 같다.

...또 말이 꽤나 빗나갔군. 모션 포트레이트, 다시 한번 더 봅니다.

우리 단장님.


역시 이게 만들자~ 식의 강좌는 아니고 포스트 길이의 압박으로 과정과 소스 분석은 생략하고... 지난 회에서 역컴파일 했을 때, 회색으로 나온 높이맵 이미지를 일단 올려보았다.
 
원본 높이맵 소스

원본 높이맵 소스

 
일단 3D 높낮이가 만들어졌다.

일단 3D 높낮이가 만들어졌다.

 
흠좀무... 텍스쳐를 그대로 사용했더니 마치 화성의 안면암이 떠오른다. - -;;;;;;;;;;;;;
(보통 책에서는 텍스쳐를 없애버리고 음영만 준다.)
 
......ㅎㄷㄷ;;;;

......ㅎㄷㄷ;;;;

한장의 높이맵 이미지로 3D를 만들었으니, 일단 이것으로 모션포트레이트의 비밀은 증명이 되었다.


텍스쳐 스케일링을 변경해 기본 텍스쳐를 먼저 올려보았다.

텍스쳐 스케일링을 변경해 기본 텍스쳐를 먼저 올려보았다.


무섭다. ㅠㅠ
솔직히 나는 정교한 MAX 모델링(예컨데 얼굴 + 눈알이 있는)을 보고도 ㅎㄷㄷ;;; 거린다.
텍스쳐 이미지를 보면 인간의 살가죽을 벚겨놓은 듯해 코딩하면서도 조낸 무서워한다. ㅠㅠ;;;;
카메라에 대한 멀미도 하는데... 어찌보면 게임 프로그래머로써 최악의 조건을 지닌 셈이다.

우선 매핑을 더 올려보았다.

이리 돌리고~

이리 돌리고~

저리 돌리고~

저리 돌리고~

보기 드믄 하루히 옆모습...

보기 드믄 하루히 옆모습...

코가 아주 못생겨졌는데 이는 아직 전체에 대한 원근감이 남아있기 때문에 색이 두드러져 보이기 때문이다.
이제 노말 적용, 직교행렬을 이용한 카메라 설정, 커서 위치 판단...등등이 남았다.

시간 관계상, 오늘은 일단 여기까지 적용해본다.
워낙 텍스쳐가 뛰어나니 높낮이를 없애고 직교행렬만 적용시키면 정말 상기의 모션포트레이트처럼 나오리라 확신한다.

이것으로 한동안 화제였던 모션포트레이트의 기본적인 비밀을 밝혔다.
(원래 생각은 한꺼번에 다 구현해볼 생각이었는데 먹고 사는 문제 때문에... ㅠㅠ)

모션포트레이트를 이렇게 적어보았고, Rhea君이 조금 충격을 먹었던 것은, 기술에 대한 선입견을 없앤다는 것이었다.
"높이맵 = 외부 지형, 라이트맵 = 내부 지형"이란 선입견의 제약으로
조금만 더 아이디어를 올리면 무언가를 해볼수 있는 기회를 우리는 그냥 놓아버리게 되는 것이 아닐까 한다.

모션포트레이트도 보다 모에하도록 구현을 해볼 것이고 위에 느낀 감정을 기억하며 하나의 기법으로 새로운 효과를 만들어내는 습관을 지녀야 할 것같다.

보다 모에해지고, 쓸만한 효과가 나올떄 모션포트레이트를 다시 포스팅하겠다.




크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Rhea君


소니(Sony-Kihara Research Center)에서 개발한 모션 포트레이트(motion portrait)는 이제 꽤나 알려진 기술이 되었다.



또다른 데모들은 모션 포트레이트 사의 홈페이지에서도 볼수 있다.
http://www.motionportrait.com/about/demo_others_01.html

하지만 실제 게임에서 적용된 것은 반다이-남코의 "스즈미야 하루히의 약속"과 "토라도라 P"일 것이다.
(홈페이지를 보면 실제 모션 포트레이트는 모션 포트레이트 사에서 가져온 기술이라고 적혀있다.)

SWF로 약간의 데모가 공개되어 있어서, 염치불구하고 이곳으로 모셔보았다.



닥치고 우리 단장님 찬양하시죠.

숏다리임에도 모에가 느껴지는 타이가

 
이런 모션 포트레이트 기술이 루리웹등을 통해 알려진 것은 "1장의 이미지로 만드는 2D 기술"이란 설명 때문이었다.
결론부터 먼저 이야기하면 이것은 2D 기술이 아니었다. 완벽한 3D 기술이었다.
 
처음에 Rhea君 역시 그 말을 보고 다음과 같은 상상을 했었다.
 
1) 움직이는 부분들은 각각의 2D 이미지이다.
2) 이미지는 각각 개체와 되어 움직이다. 와타나베 연구소의 Glove On Fight처럼.
Glove On Fight

Glove On Fight

3) 얼굴을 돌리는 것은 영역별로 픽셀을 줄이거나 늘리거나 해서 돌아가는 것처럼 보인다.
 
그러나 3)의 경우, 아무리 생각해도 결코 쉽지않은, 노가다^노가다^노가다^노가다 스러운 부분이라 호기심이 발동하지 않을 수가 없었다.
그리하여, 플래시 디컴파일러를 동원하여 살펴보기로 하였다.
 
디컴파일 중~

디컴파일 중~

 
아 그런데 SWF 속에는 원하는 이미지 따위는 존재하지 않았다.
(눈썹이나 입 모양을 위해 PNG 파일을 로딩하는 부분은 발견했다. 따지고 보면 하드코딩한 부분이라 할수 있다.)
 
혹시나 하는 마음에 Fiddler를 통해 살펴보니, 역시나 예상대로 비트맵 이미지를 모아둔 SWF를 따로 로딩하는 것을 확인할수 있었고 해당 SWF도 까...보았다.
  
리소스 전용 SWF를 다운받는 것, 발각!

리소스 전용 SWF를 다운받는 것, 발각!

 
 
단장님의 얼굴이시다...그런데?

단장님의 얼굴이시다...그런데?

 
윗 짤방은 리소스들을 보여주는데 일단 조각난 얼굴이 공포스럽게 해주신다.
그리고 image10 과 image 13 처럼 알파값처럼 나타나는 부분은 아주 중요한 부분이 될 것 같다는 느낌이 든다.
 
이 때 마침, Rhea君 옆을 우연히 지나던 우연君과 태완성, 이 모습을 보고 한마디씩 하신다.
 
태완성 : 니들은 또 미소녀만 갖고 노냐?
Rhea君 : 허어~ 형님~ 이건 미소녀이 아니라 그래픽 공부라고요~*
태완성 : ...근데 니들 그래픽 예제는 왜 다들 미소녀만 나와?
Rhea君 : 아니 미소녀가 없는데 왜 관심을 가져야 하나요?
             .......우연君, 이 알파값으로 픽셀 영역을 줄이거나 늘릴 영역을 지정하는것 아닐까?
우연君 : 흠... 내가 보기엔 이거 알파값이 아니라 깊이(Depth)값 같은데? 
 
이때 삥!하고 계시가 내려왔다!
그렇다, 이건 2D 장난이 아니라 깊이맵으로 구현한 것이란 직감이 들었다.

지못미, 하루히

지못미, 하루히



깊이맵과 모션포트레이트 분석은 다음 포스트에서 계속!!!
                                                         http://rhea.pe.kr/261
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Rhea君

 D3DXMATRIX mat_Ortho;
 D3DXMatrixIdentity(&mat_Ortho);
 gd3dDevice->SetTransform(D3DTS_WORLD, &mat_Ortho);
 gd3dDevice->SetTransform(D3DTS_VIEW, &mat_Ortho);

 D3DXMatrixOrthoOffCenterLH( &mat_Ortho, 0, 800, 600, 0, 0, 1 );
 3dDevice->SetTransform(D3DTS_PROJECTION, &mat_Ortho)


늙어감에 따라 현명해진다는데 나날히 바보가 되어가는 느낌...;;; ㅠㅠ
예전 소스나 뒤지고 있는 나는 정녕 바보!

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Rhea君

요즘 개발자라면 대부분 Dual 모니터 환경에서 작업을 할 것이다.
간혹 어떤 사연으로 Primary 모니터가 아닌 Secondary 모니터로 Full Screen으로 된 DX 화면을 띄우고 싶을 때가 있을 것이다(예컨데, 창모드 지원이 되지 않는 프레임워크에서 디버깅을 위해서나 그냥 그렇게 보는 게 더 편하다거나.).

그렇다면 IDirect3D9::CreateDevice() 에서 흔히 사용하는 D3DADAPTER_DEFAULT 대신 다른 방법을 써야 한다.
D3DADAPTER_DEFAULT는 Primary 모니터를 가르키기 때문이다. 안타깝게도 이를 위한 매크로는 따로 없다.

모니터 식별은 IDirect3D9::GetAdapterIdentifier()로 얻어낼 수 있는데 이름에서 알수 있듯, DX에게 중요한 것은 모니터가 아니라 비디오 카드의 출력단자인 것이다.

먼저 모니터 식별에 대한 리턴값을 저장하기 위해 구조체를 만든다.

class CVGAAdapter
{
public:
 UINT m_iAdapterOrdinal;
 D3DADAPTER_IDENTIFIER9 m_Identifier;
 D3DDISPLAYMODE m_mode;
 D3DDEVTYPE  m_DevType;
};


그 다음은 IDirect3D9::GetAdapterCount()로 비디오카드의 출력단자가 몇개인지를 잰다.

UINT iAapterCount = m_pD3DObject->GetAdapterCount();

이제 for()문을 돌며 각 그래픽 카드에 하드웨어 정보를 얻어내자.

for(UINT iAdapterOrdinal = 0; iAdapterOrdinal < iAapterCount; iAdapterOrdinal++)
 {
  CVGAAdapter VGAAdapter;

  VGAAdapter.m_iAdapterOrdinal = iAdapterOrdinal;
  VGAAdapter.m_DevType = m_D3DTypeDef;

  m_pD3DObject->GetAdapterIdentifier(iAdapterOrdinal, 0, &VGAAdapter.m_Identifier );
  m_pD3DObject->GetAdapterDisplayMode(iAdapterOrdinal, &VGAAdapter.m_mode);

  // 윈도우 모드일때 정보 얻음
  HR(m_pD3DObject->CheckDeviceType(iAdapterOrdinal, m_D3DTypeDef, VGAAdapter.m_mode.Format, VGAAdapter.m_mode.Format, TRUE));
 
  // 풀스크린일때 정보 얻음
  HR(m_pD3DObject->CheckDeviceType(iAdapterOrdinal, m_D3DTypeDef, D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8, FALSE));

 // 벡터에 저장
 m_vecVGAAdapter.push_back(VGAAdapter);
 }

마지막 push_back에서 알 수 있듯이 CVGAAdapter는 vector로 관리했는데,
엽기적으로 그래픽카드를 여러개 꽂아 3개 이상의 모니터를 사용하는 변태도 있기 때문이다.

이제 m_vecVGAAdapter[0]은 Primary 모니터를 의미하고 m_vecVGAAdapter[1]은 Secondary 모니터를 의미하게 된다.

이제 IDirect3D9::CreateDevice()의 1, 2번 인자에는 각각 m_vecVGAAdapter[0].m_iAdapterOrdinal과 m_vecVGAAdapter[0].m_DevType 를 적어주면 된다.

만약 풀스크린과 윈도우 모드를 동시 지원하는 프레임워크라면 분명 각 모드에 대한 D3DPRESENT_PARAMETERS 구조체를 채우는 함수가 있을 것이다. 여기에 CVGAAdapter.m_mode의 값을 넣어주자. 이때 해상도를 변경하고 싶으면 사용가능한 해상도 정보를 얻기 위해 IDirect3D9::EnumAdapterModes()를 이용하여 위의 for() 내에서 한 아답터 정보를 얻어마자 다시 사용 가능한 해상도를 얻어낸다.

이는 어차피 DX 기본 프레임워크에 구현되어 있으니 참조하도록 하며 상기의 내용 정도라면 개발시 Secondary 모니터로 풀스크린을 만드는데에는 큰 불편함이 없을 것이다.


크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Rhea君

헤더파일을 만들고 사용하면 된다.

#include "dxut.h"

#ifndef __TRACE_H__
#define __TRACE_H__

#include <crtdbg.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

#ifdef _DEBUG
#define TRACEMAXSTRING 1024

char szBuffer[TRACEMAXSTRING];
inline void Trace(const char* format,...)
{
 va_list args;
 va_start(args,format);
 int nBuf;
 nBuf = _vsnprintf(szBuffer,
  TRACEMAXSTRING,
  format,
  args);
 va_end(args);

 _RPT0(_CRT_WARN,szBuffer);
}
#define TraceEx _snprintf(szBuffer,TRACEMAXSTRING,"%s(%d): ", \
 &strrchr(__FILE__,'\\')[1],__LINE__); \
 _RPT0(_CRT_WARN,szBuffer); \
 Trace

#else
inline void Trace(0);
inline void TraceEx(0);
#endif


#endif // __TRACE_H__

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Rhea君
TAG Trace
비스타에서 추가된 DwmExtendFrameIntoClientArea(), 이거 아주 유용하다.
창을 없애고 이래저래 작업을 해보니, 드디어 폴리곤만 바탕화면에 띄울 수 있었다.
이것으로 비스타 전용의 무언가를 해볼수 있지 않을까...싶다.
폴리곤 그릴때 최적화를 잘하면 가젯을 활용한 것보다 더 유용하지 않을까 싶다... .
아직 더 연구해봐야겠지만.

내 하드 안에는 쓸만한 모델링 파일이 없다는 것을 깨달았다...

내 하드 안에는 쓸만한 모델링 파일이 없다는 것을 깨달았다...

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Rhea君




제어판에 있던 다이렉트X 속성이 언젠가부터 사라졌다.
디버깅을 위해서는 이 속성정보가 상당히 유용했었는데... .

구글에서 뒤져보니 cpl 파일로 떠돌고 있는 것을 발견하였다.
이 패널을 System32 폴더에 넣고 제어판을 실행시키면 다시 다이렉트X 속성을 볼 수 있다.

유용하게 쓰시길~*

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Rhea君
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1045802&SiteID=1

http://xna.tiddlyspot.com/#Hello [[Building for Xbox 360 and Windows with one project]]


왜 이런 짓이 나와야했는지, XGSE의 철학이 궁금하다.
Cross-Platform을 표방했으면서 두개의 각기 다른 템플릿이 나오는 XGSE... . - -;;
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by Rhea君
TAG Migration, XNA