posted by REDFORCE 2017. 3. 14. 10:21

엔진 코어를 제작하기 위해 여러 자료들을 찾아다니고 


병렬 프로그래밍부터 시작해서 객체지향적인 구조를 설계해야하는가? 등등 공부해온 결과



현재 많은 게임사들이 쓰고있고 시도하고있는 


Component Based GameObject 구조 방식을 도입해보려고 합니다.



현재 까지 만들어두었던 June_Engine의 방식은 객체지향 구조에


1 Processor - 1 Thread.


Initialize -> Update -> Render 순으로 동작하는 로직이었습니다만


이 구조를 조금 다듬어 보았습니다.

[아직 시도중일 뿐 완전하진 않습니다!]


render / update 루프를 돌게 되는 모든 객체들을 GameObject라 명하고 Component를 기반으로 작성됩니다.


그러면 대표적인 Component를 살펴보겠습니다.


RenderComponent / Physics Component / AI Component / Network Component / Position Component / Animation Component 등...


이름만 봐도 알 수 있듯이 어떤 행위 자체를 수행하게 되는 함수들을 일련의 컴포넌트라 칭합니다.

(그러나 함수 자체에 어떤 객체와 같은 의의를 두는 것!)


그리고 컴포넌트들이 탑재 되어 있는 어떤 행동 주체가 되는 "객체"(?) 를 Game Object라 부를 수 있습니다.



게임을 위한 엔진이니 게임을 예로 들어보면 


1. 플레이어 캐릭터를 만든다. 이 플레이어 캐릭터는 GameObject를 상속받은 하나의 객체입니다.

2. 몬스터 캐릭터를 만든다. 이 몬스터 캐릭터는 GameObject를 상속받은 하나의 객체입니다.


여기서 플레이어/ 몬스터 캐릭터는 동일한 캐릭터라는 성질을 갖고 있기 때문에


캐릭터 라는 Class를 생성하고 GameObject를 상속받는 구조로 만들면 되겠군요.



그래서 이 GameObject와 Component를 대체 어떤식으로 만드는가?

우리는 먼저 Component를 먼저 정의할 필요가 있습니다.



아래의 코드를 살펴보면서 주요 부분을 열거해서 적도록 하겠습니다.


1. ComponentBase Class는 현재(this) Component의 주인이 될 Owner GameObject* 를 갖고 있습니다.

2. ComponentBase Class는 추상 클래스 입니다.

3. 순수 가상함수로 componentID / familyID 가 있습니다.

4. Component 들이 사용 할 virtual 가상함수들이 내포되어 있습니다.



다음 GameObject Class 입니다.

[Entity를 상속받은 점은 신경안쓰셔도 됩니다]


1. 자기 자신의 고유 id 값이 있습니다 ( m_Id )

2. GameObject Class 안에는 Component TABLE 이 있습니다. ( m_Components )

3. 생성자에서 무조건 id 값을 받도록 되어있습니다.

4. familyId를 이용하여 자신이 갖고있는 components에서 해당 컴포넌트를 찾을 수 있습니다.



cpp 파일이야 뭐...헤더에 선언 해뒀던 내용 그대로 구현 되었을 뿐입니다.


다만 저도 아직 햇갈리는 점은 GameObject::setGOC ( ComponentBase * newGOC ) 함수에서


m_Components에서 componentID 값으로 비교를 하는게 맞나?

라는 의문이듭니다.


familyId도 있지 않았나...?응?응???

하는 뒤숭숭한게 있습니다만 정확히 저도 gpg 6 를 다시 정독해보고 확인하면 수정하도록 하겠습니다.







[GitHub(Gist) - Component.h / .cpp]


[GitHub(Gist) - GameObject.h / .cpp]


posted by REDFORCE 2017. 3. 13. 23:22

본 글에서는 EngineCore에 대해 다뤄보도록 하겠습니다.


EngineCore는 엔진의 핵심 구동 부분을 명시합니다.



현재 개발중인 Engine의 로직은 다음과 같습니다.



WinMain에서 EngineSystem의 SystemStart( ) 함수를 호출 하면 

EngineSystem의 필요한 항목들을 초기화시키고 EngineCore를 Start 합니다.


EngineCore( ) 가 시작되면 가상함수로 넣어 뒀던 Update ( )와 Render ( ) 구역을 멀티 쓰레드로 수행하게 됩니다.


문제는 매 프레임 Update ( )와 Render ( ) 함수가 수행 되어야 하는데, 두 펑션이 멀티쓰레드로 구현 될 경우 루프를 돌면서 두 펑션이 각기 다른 타이밍에 돌 수 있다는 가정이 바로 나올 수 밖에 없습니다.


Update Thread는 45 Frame 째를 update ( ) 중이지만


Render Thread 는 아직 40 Frame 째를 Render ( ) 할 수도 있다는 것이지요.


따라서 두 쓰레드는 매 프레임 같은 간격으로 호출 될 수 있도록 동기화가 되어야 합니다.



Update Thread와 Render Thread 는 EngineCore에서 구현이 되어 있으며


이 글에서는 이 두 쓰레드에 대한 동기화에 대해서 먼저 보도록 하겠습니다.


공부하면서 만들다 보니 쓰레드를 백날 여러개만들어서 돌려봤자 동기화와 제대로 된 실행 시점이 정의 되지 않으면 똥망 한다는 것을 직접 체험해버렸습니다.


그래서 코어의 구조 자체를 한번 엎고 돌아오겠습니다.

posted by REDFORCE 2017. 3. 13. 21:24

본 글에서는 Graphics.cpp 에 대한 내용을 다루도록 하겠습니다.


Header에 대한 내용을 아직 읽고 오지 않으신 분은 먼저 .h 에 대한 내용을 참고하시기를 추천합니다.

[코드 전체는 최하단에 있습니다]


1. Graphics 생성자

 - Graphics.h 에서 정의한 Graphics 클래스의 생성자 입니다.

 - direct3d / device3d 등 미리 사용 될 변수들에 대해 초기화를 이루어집니다.



2. Graphics::initialize

 - 핵심 부분인 initialize 입니다.

 - 파라미터 값으로 device를 올린 window핸들값 HWND와 width , height, fullscreen

 - direct3d = Direct3DCreate9(D3D_SDK_VERSION) 에서 볼 수 있듯이 본 엔진은 Direct9을 사용합니다.

 - Direct3DCreate9 은 directX 함수로 현재 PC의 directX sdk 버전을 체크해서 directx를 생성합니다.

 - 만약 널 값이면 알아서 에러뿜뿜..으로 처리했습니다.

 - 그리고 InitD3Dpp() 함수를 수행합니다. (d3dpp 포맷이나 모드를 결정합니다)

 - 그 외에 더럽게 많은 device나 sprite 등의 셋팅을 진행합니다.



모든 변수들과 내용을 일일이 설명하기엔 너무 글이 길어지므로

그냥 아 DirectX 함수로 디바이스 생성하고 초기화 하고 이런저런 셋팅을 하네~ 하고 보시면 됩니다.



 - 그림이 하도 커져서 두개로 나누었습니다.

  !! if(FAILED(result))

         throw(GameError(gameErrorNS::FATAL_ERROR, "Error Creating Direct3D Device));


 가 겹쳐 있습니다.


3. LoadTexture

 - 앞으로 사용할 모든 텍스쳐 파일을 로드해올 때 사용하는 함수입니다.

 - 파라미터 값으로 

/ 파일의 경로 / transcolor 값 /텍스쳐 크기 / 담아둘 텍스쳐 포인터 / 를 받습니다.

 - LoadTexture 함수는 일반적인 모든 Texture Image들을 받아옵니다.  ( bmp, jpg, png 등 )



4. LoadTextureSystemMem

 - LoadTexture 함수와 동일한 기능을 수행합니다.

 - 큰 차이는 System Memory를 사용한다는 점 입니다.

 - D3DXCreateTextureFromFileEx ( ) 를 보시면 D3DPOOL_SYSTEMMEM 값이 다른 것을 알 수 있습니다.

 - bitmap 파일만 읽을 수 있습니다.



5. CreateVertexBuffer

- 버텍스 버퍼를 이용한 렌더시 사용하는 함수입니다.

- 주로 버텍스 버퍼를 이용하여 선이나 상자를 그릴 때 사용합니다.

- 버텍스버퍼에 대한 설명은 생략하겠습니다.


6. DrawQuad & DrawLine

- 버텍스 버퍼를 이용하여 선이나 네모 상자를 그릴 때 사용합니다.



7. showBackBuffer

 - device를 이용해서 모든 그리기 작업이 끝나면 불려지는 함수 입니다.

 - device3d->present(NULL, NULL, NULL, NULL) 을 수행합니다.

 - 결과 값으로 HRESULT 값을 받은 것을 그대로 리턴~



8. DrawSprite

 - 앞으로 더럽게 많이 쓰게 될 DrawSprite 함수 입니다.

 - 2D Game에서 모든 그리기 작업은 이 함수를 통해 그리게 됩니다.

 - 다소 설명이 들어가야 할 것 같으니 파라미터부터 설명해드리도록 하겠습니다.


 (1) SpriteData 구조체 참조 값과 transcolor 값을 받습니다.

 (2) 받아온 spriteData의 값을 토대로 VECTOR2 로 center / translate / scaling 작업을 하고 상하좌우 반전 여부를 체크하고 반전 시 그림을 반대로 반전시킵니다.

 (3) D3DMatrix 로 출력할 내용을 2D 행렬로 변환 합니다.

 (4) 변환 시킨 행렬의 내용을 device의 sprite->setTransform( ) 를 통해 transform을 setup 시킵니다.

 (5) 마지막으로 Draw!! 


Draw작업 시에는 SpriteData의 텍스쳐 / 텍스쳐에서 출력할 RECT 위치 / 투명 처리 시킬 color 값이 들어갑니다.



내용이 길어서 2장의 그림으로 나누었습니다.

매트릭스 부분부터 겹쳐 있으니 코드 보시는데 참고!



9. ChangeDisplayMode

 - 혹여나 게임을 진행중에 DisplayMode가 변할 시 불려지는 함수 입니다.

 - 파라미터 값으로 헤더에 선언해두었던 DISPLAY_MODE 열거형 값을 받습니다.

 - 워낙 직관적인 내용들뿐이라 따로 설명은 안하겠습니다.

 - 심플하게 전체화면이면 전체화면으로 돌리는 작업을 하면서 Device가 잡혀있는 Window(HWND)를 전체화면으로 변경합니다.

 - 창모드는 반대로~



마찬가지로 2장의 사진이 겹쳐있습니다.



10. PixcelCollision

 - 저도 다시 정리해보면서 확인을 해서 조금 충격먹었습니다. (픽셀 충돌 처리부분이 있었군요 ㅡ ㅡa)

 - 실제 픽셀충돌에 대해서 처리를 하려면 device에서 renderstate로 설정해야 될 것들이 조금 많습니다만 일일이 설명드리기엔 역시나 너무 길어지므로 그냥 저런식으로 셋팅한다는 점만 보고 넘어가셔도 될 것 같습니다.

 - 주요 부분은 픽셀 충돌 처리를 해야하는 SpriteData 구조체 A, B에서 

 - IDirect3DQuery9* 를 이용하여 DirectX 함수를 사용한다는 점 입니다.

 - 이 함수가 알아서 두 sprite에서 픽셀충돌이 이뤄졌는지를 반환해줍니다.

 - 최종적으로 pOcclusionQuery->GetData( ) 함수를 통해 얼마나 픽셀충돌이 이뤄졌는지를 알 수 있습니다.

 - 반환 형은 DWORD 값! ( 충돌한 픽셀 사이즈 입니다 )



11. 그 외 디바이스 처리( 릴리즈 / 리셋 )

 - 아래 3개의 함수는 우리가 위에서 만든 Device가 로스트 되거나 release를 할 시

사용 되는 함수들 입니다.


 - 첫 번째 getDeviceState() 함수는 호출 시 Device가 갑자기 뒤져버렸을 때 다시 device를 reset 시킬 수 있는지 여부를 알아 낼 수 있습니다.

 - 주로 전체화면 중에 갑자기 AltTab을 하다가 버벅버벅 거리던 중 화면이 까맣게만 되고 아무것도 안나오는 게임화면을 보신 적이 있을 겁니다. 그와 같은 경우에 이 함수를 이용하여 Device를 다시 얻어 낼 수 있는지 여부를 확인 할 때 사용합니다.



 - 두 번째 releaseAll() 함수는 호출 시 Device에 담아두었던 모든 내용들을 해지 시키는 내용뿐입니다.

 - safeRelease( )는 템플릿 형태의 매크로로 만들어둔 내용입니다.



 - 세 번째 reset()

 - reset 함수는 위의 getDeviceState() 를 통해 device가 다시 reset 될 수 있는지 여부를 알아 낸 후 호출되는 함수 입니다.

 - 다시 initD3Dpp() 함수를 통해 디바이스 모드를 재설정하고

 - sprite->OnLostDevice() 함수를 통해 sprite를 release 한 뒤,

 - device3d -> reset( ) 함수를 작동시킵니다. ( 요기서 이제 우리의 DirectX Device가 리셋~)

 - 다시 재기동 된 device의 renderState 값들을 재설정 해주고 혹여나 충돌 처리에서 썼던 값 또는 sprite를 박아두었던게 있다면 reset시켜 줍니다.




간추리고 요약해보려고 해도 이건 뭐 정리할 게 너무많아서 쉽지가 않은 것 같습니다.


Graphics.cpp 에 대한 내용은 워낙 방대한지라 기본적으로 알고 와야지 이해할 수 있을 법한 내용들이 많습니다.


따라서 독자 분들이 먼저 DirectX에 대해서 선행 한 뒤에 구독하시는 게 Graphics 클래스의 구조를 이해하시는데 도움이 될 거라 생각됩니다.



귀찮으면 그냥 graphics.h graphics.cpp 파일 복붙 해서 그냥 써버리세요.

솔직히 저도 다시 정리하면서 봐도 뭐가 뭔지 모르겠습니다. ㅡ,   . ㅡ;;귀찮아서 그냥 복붙하고

 쓰고말지...


중요한 것은 우리가 이 Graphics 클래스를 통해 directX Device에 대한 설정을 하나의 객체로 빼고 쓴다는 점입니다. 이게 어떻게 돌아가는지 하나하나 다 파고들려면 암걸려요. 암.



Graphics.cpp 파일의 전체 내용은 아래와 같습니다.


[GitHub - June_Engine Project : Graphics.cpp]


posted by REDFORCE 2017. 3. 13. 09:30

[Engine Graphics.h]


본 글에서는 DirectX를 통한 Graphics.header 를 다뤄보겠습니다.

[코드 전체는 최하단에 있습니다]


.cpp에 대한 내용은 다음 글을 참고하세요~


먼저 Header 에서 선언한 내용들을 살펴보도록 하겠습니다.


1. 이름 더럽게 긴것들 #define으로 선언

- 주로 사용하는 변수들의 이름이 너무 길기 때문에 

TEXTURE / DEVICE / VERTEXBUFFER / SPRITE / FONT / LINE


에 해당하는 것들만 #define 으로 편하게 바꿨습니다.


2. 자주 사용하는 컬러 값 묶기

- 자주 사용하는 컬러 값들에 대해 미리 namespace로 묶어서 열거되있습니다.

- 열거형으로 DISPLAY_MODE 가 있습니다(전체화면/창모드 구분 시 사용)



3. VertexC 구조체 선언

 - 앞으로 사용할 Vertex구조체 입니다.

 - x,y,z 좌표 값과 rhw 값(기본 1.0f)

 - color 값이 들어있습니다.



4. SpriteData 구조체

 - 앞으로 꾸준히 미친듯이 사용하는 SpriteData 구조체 입니다.

 - Engine에서 Graphic Device를 통해 그림을 출력 할 때 사용하는 SpriteData 정보.


 - x, y, width, height

 - scale (크기 값)

 - angle (그림 회전 각)

 - rect ( 텍스쳐에서의 출력할 RECT )

 - LP_TEXTURE ( 텍스쳐 파일 )

 - flipHorizontal ( 좌우 반전 여부 )

 - flipVertical (상하 반전 여부 )


에 대한 값들이 들어있습니다.




5. Graphics Class

 - 마지막으로 핵심부분인 Graphics 클래스 입니다.

 - 미리 선언해두었던 device부터 sprite와 texture에 대한 포인터 변수들

 - device 생성시 사용할 각 모드 값들이 들어있습니다.

 - 각 값들이 어떤 것인지까지는 설명하진 않겠습니다( 이거 다 설명하려면 너무 글이 길어져요

   ㅠㅠ DirectX CreateDevice 에 대해서 찾아보세요!)

 - 그 외에 초기화 결과 값을 반환 할 때 사용할 HRESULT 값과 그래픽스가 사용 될 핸들 값(HWND)가 있습니다.

 - 기타 변수들에 대한건 변수명 자체가 직관적이라 생략합니다.



6. 기타

- 그 외 public: 안에 담겨있는 각종 함수들이 엄청 많습니다만 일일이 다 설명하기엔 너무 길어지므로

필요할 때마다 설명을 추가하도록 하겠습니다.



그래서 ?? 결론은??


우리가 여기서 확인할 중요한 요지는 DirectX를 생성하고 초기화 하는데 필요한 얘들을 지금 Graphics 클래스로 따로 빼놓았다는 점입니다.


실제 DirectX에서 device를 생성하고 초기화하는데 코드를 작성해보면 약 100~200 줄 정도의 코드가 나옵니다. 

이거를 메인에서 같이 막 수행했다간....[ O _ o];;;;


따라서 DirectX초기화와 관련 된 얘들을 따로 클래스로 빼서 관리한다는 점이 중요합니다.


너무 내용이 많은지라 이글에서 한번에 모든것을 다루기는 어렵습니다만


간단히 엔진을 제작하기 위해 혹시나 참조하시는 분들 또는 DirectX를 공부하시는 분들께서는

아 Graphics를 따로 빼서 이렇게 만들 수도 있구나 하는 감을 잡는데에 도움이 되지 않을까 생각됩니다.


주 함수들의 내용이나 Graphics가 하는 일에 대해서는 cpp 글에서 다루도록 하겠습니다.



실제 헤더파일에 대한 전체 코드는 아래와 같습니다.


[GitHub - June_Engine Project : Graphics.h]


posted by REDFORCE 2017. 3. 12. 22:22

[Engine WindowSystem]


이 글에서 다룰 문제는


FrameWork에서 만들어 둔 함수 내용들을 GUI 형태로 제어할 수 있도록

EngineGUI를 어떤 구조로 만드냐가 문제입니다.



유니티 3D를 참고로 정리해 본 UI 형태는


1. 메인 HWND (저는 Engine Main-Window 로 부르고 있습니다) 가 최상위로 존재하고

(메인 HWND는 Menubar를 갖고 있음)


2. 첫 번째 자식 윈도우 (First Child-Window 라 부르고 있습니다)

 - 화면(카메라 컨트롤)

 - 선택한 오브젝트 이동/회전/스케일 조정

 - 엔진 재생/일시정지 등 UI Layer 조정


을 할 수 있는 버튼이 있음


3. 각각의 Window( Scene / Game / Project / Hierarchy / Inspector 등 Second Child-Window)

 - 각 Window는 Menubar / Caption / Titlebar 가 없음

 - 기본적으로 하나이상의 TAB ITEM을 갖고 있음

 - 해당 탭에 들어갈 자식 Window가 있음

   ( TAB Item의 Window는 여러 방식이 있음

    예: 게임렌더링 화면 / 폴더 리스트 뷰어 / 어떤 정보항목 등)


가 있는 구조 였습니다.



해서 정리해본 결과...


First Child Window 까지는 직접 EngineSystem에서 구현해도 무난하겠다 싶어서 포함을 시켰습니다.

각각의 Window는 



EngineWindow 라는 클래스를 생성하고 얘를 항상 부모로 담도록 하자.


라고 생각하고 EngineWindow 에서 생성 되면 First Child-Window 를 부모로 하여

Default 위치값을 줘서 Window를 생성하도록하게 했습니다.



대충 틀을 잡아 본 형태가 위 사진과 같군요.

(아직 #01에서 다루는 두 개의 렌더링 화면 출력이 해결 되지 않은 사진 입니다)


이제 문제가...각 윈도우들은 1개이상의 TAB Item을 갖고 있는 TAB 컨트롤러 라는 것인데

해당 Second Child-Window는 TAB Control을 갖고있는 Window이고


해당 TAB 의 Item 항목은 각각의 Window들을 갖는 구조로 넣을 수 있도록 받게 해야합니다.




그러면... TAB에 Item 항목으로 들어갈 내용들 또한 어떤 Window(HWND) 라는 것인데...


이 내용들은 전부다 하나의 Engine-Window Class를 부모로 하는 Tab Item 항목들이라는 게 될 거라보입니다.


따라서 TAB Item 항목으로 들어갈 수 있는 구조로 만들어서 본 글을 업데이트 하도록 하겠습니다.

posted by REDFORCE 2017. 3. 12. 18:01

본 프로젝트의 개발 일지 및 프로젝트 상세 내용을 작성 함에 있어

구어체의 사용이 있음을 미리 알려드립니다.


[System Architecture]


2D Game Engine을 만들기 위해

In Game 용도의 FrameWork 자체는 필요한 부분에 한해서는 다 완성이 되어 있는 상태입니다.


예) Graphics, Game, Entity, Collision, Manager Class 등


그러나 엔진으로써의 구동을 위한 핵심 코어 시스템은 섣불리 만들기가 어려운 상황입니다.

[글쓴이 저자가 너무 됻밥이라...(시무룩)]



현재 구상해본 구조는 핵심부분만 보자면


WinMain -> Engine System Initialize -> Engine Core Start 

-> Engine Window System Initialize -> Engine Graphics -> Run Loop


입니다만


Engine Window System을 설계하는 것과 


목표인 2개의 화면.

Engine Scene / Engine Game


에 Graphics를 올리고 Run을 시키는 구조를 잡는게 너무 어려운 것 같습니다.


Graphics를 2개를 잡아서 올리자니 비효율적인 것 같고


1개의 Graphics만 갖고 2개의 화면에 띄우는 작업을 하려니



Scene에서의 화면은 엔진 사용자가 이리저리 움직이며 다양한 컴포넌트들을 올리면서 에디트가 가능해야하고


Game에서의 화면은 엔진에서 빌드를 수행했을 시 인게임컨트롤을 통한 화면움직임이 이루어질텐데

([예] Unity3D Scene / Game화면)


말이지요.


이게 현재 겪고 있는 첫 번째 난관입니다만



일단 각각의 HWND 화면을 하나의 Graphics에서 정보를 가져와서 렌더링 할 수 있는 구조와 방법을 생각해 봐야겠습니다.



이 문제가 해결 된다면


수정해서 해결한 방안을 적어보도록 하겠습니다.

posted by REDFORCE 2017. 3. 12. 16:06

[June_Engine Project Introduce]



본 프로젝트는 글쓴이 저자 'REDFORCE'의 개인 프로젝트로 


DirectX 기반 2D Game Engine을 개발함으로

다양한 고통(?)과 인내심을 고양(?)시킬 목적으로 진행 중에 있음을 미리 알려드립니다.

[비상업적 용도입니다]


본 프로젝트는 2017년 1월 1일 부터 시작되었습니다.


프로젝트 계획 큰 흐름도는 아래와 같은 순서로 진행하고 있었습니다.


1. DirectX 기반 2D Game FrameWork 개발 (90%완료)

2. June_Engine FileSystem 및 Renderer 개발 (90%완료)

2. WinAPI 기반 DirectX를 활용한 June_Engine GUI 개발 (현재 개발중)


3. June_Engine 멀티쓰레드를 적용한 병렬 처리 기반 시스템 개발 (미구현)

4. C++ Script 제작 지원(미구현)

5. AudioKinetic SDK를 이용한 Sound System 개발(미구현)



[2017년 3월 12일 현재]

3단계(Engine GUI)를 개발중이며 MFC를 이용하지 않는 상황이기 때문에

WinAPI를 이용한 GUI 개발에 있어 상당히 곤혹을 겪고 있습니다. (한강 뛰어내리고 싶을 정도...)



프로젝트 소스 코드 자체는 오픈 소스로 공개되어 있으며


[GitHub] 

https://github.com/redforce01/DirectX_Engine


[주의] 현재 진행 중인 프로젝트 버전은 Branch : Kim-Jaejun 에서 확인 할 수 있습니다.


깃허브 위 링크에서 프로젝트를 받으실 수 있습니다.


모바일 플랫폼 등 멀티 플랫폼에 대한 것은 고려하지 않고 있기 때문에

OpenGL을 사용하지는 않습니다.



본 프로젝트에 참여 하시고 싶으신 분은


본 블로그의 방명록,

이메일( redforce01@naver.com )

카카오 ID : redforce01


로 연락주시면 답변 드리도록 하겠습니다.


엔진에 대한 개발 된 자세한 시스템 내역은 추후에 계속 포스팅을 적으면서 올리도록 하겠습니다.