Data
XML, JSON
현재 예제에서는 파일 포멧이 따로 없고 메모리상에 정보만을 가지고 있다
이를 특정 파일 포멧에 저장하고 그 포멧안에 있는 정보를 메모리에 저장하여 표현을 할 수 있게 할것이다
우리가 특정 파일 포멧을 설정해도 되지만 그것보단 많이 사용하는 XML이나 JSON 형태의 파일을 많이 사용한다
이 파일을 사용하기 위해서는 특정 라이브러리를 사용해야 하는대 C++은 제공되는 라이브러리가 없기 때문에 외부 라이브러리중 tinyxml2라는 라이브러리를 사용할 것이다
tinyxml 추가
이 라이브러리를 다운받아 99.Headers/Utils 폴더에 넣어 추가해준 뒤 빌드를 해준다
이때 미리컴파일된 헤더가 문제가 생길 것인데 이는 .cpp 파일에 미리 컴파일된 헤더를 추가하거나 비리 컴파일된 헤더를 사용하지 않게 해주면 해결된다
마찬가지로 미리 컴파일된 헤더에 헤더를 추가하여 어디서든 사용할 수 있게 만들어준다
pch.h ... #include "tinyxml2.h" using namespace tinyxml2; ...
XML Save, Load
이번 실습에서는 간단하게 xml을 save하고 load하는 것을 할것인데, 이러한 정보들을 채운 클래스가 Animation뿐이므로 이를 이용해 실습을 할것이다
XML 파일은 노드를 만들어 트리를 만들어준다 생각하면 되는데, 이런식으로 계층 구조를 만들어주게 되는 것이다
XML Save
Animation.cpp ... void Animation::Save(const wstring& path) { ResourceBase::Save(path); tinyxml2::XMLDocument doc; XMLElement* root = doc.NewElement("Animation"); doc.LinkEndChild(root); string nameStr(GetName().begin(), GetName().end()); root->SetAttribute("Name", nameStr.c_str()); root->SetAttribute("Loop", bLoop); root->SetAttribute("TexturePath", "TODO"); for (const Keyframe& keyframe : m_vKeyframes) { XMLElement* node = doc.NewElement("Keyframe"); root->LinkEndChild(node); node->SetAttribute("OffsetX", keyframe.offset.x); node->SetAttribute("OffsetY", keyframe.offset.y); node->SetAttribute("SizesetX", keyframe.size.x); node->SetAttribute("SizesetY", keyframe.size.y); node->SetAttribute("Time", keyframe.time); } string pahtStr(path.begin(), path.end()); XMLError result = doc.SaveFile(pahtStr.c_str()); assert(result == XMLError::XML_SUCCESS); } ...
XMLDocument 객체를 만들어 XML 문서를 생성할 준비를 해준다
doc.NewElement("Animation")으로 새로운 XML 요소를 만들어 주는데 요소의 태그 이름은 Animation으로 이 값을 XMLElement* 에 저장해준다
저장된 변수를 doc.LinkEndChild에 넣어 XML의 최상위 자식으로 추가되는 것이다
XML에서는 char* 를 사용해 문자열을 나타내기 때문에 wstring을 사용하는 Animation의 이름은 string으로 바꿔 .c_str을 사용해 저장해줘야한다
이때 element에 속성 값을 저장하기 위해 root->SetAttribute 함수를 사용해 속성의 이름, 속성 값을 넘겨주면 된다
Animation 요소의 속성 값들인 Name, Loop 여부, Texture의 위치를 셋팅해준다
또한 Animation마다 keyframe이 존재할 것이므로 for each문을 통해 매개변수 Keyframe 요소로 만들어 root의 자식으로 추가해 속성값들을 가져와 저장해준다
실제 저장
Animation을 XML로 저장할 함수를 만들었으니 직접 실행해 XML 파일이 생성이 됐는지 확인해 볼것이다
ResourceMGR.cpp ... void ResourceMGR::CreateDefaultAnimation() { ... //XML animation->Save(L"TestAnimation.xml"); }
ResourceMGR에서 Animation을 만들어주는 함수에서 Animation을 만들고 Add를 통해 추가해준 뒤 Save 함수를 콜해 저장해 줄것인데 이때 저장될 이름과 확장자를 path로 넘겨준다
실행을 하게되면 xml 파일이 잘 생성된 것을 볼 수 있다
XML Load
Load는 Save와 대칭적이니 Save에서 했던 반대방향으로 해주면 된다
Animation.cpp void Animation::Load(const wstring& path) { ResourceBase::Load(path); tinyxml2::XMLDocument doc; string pathStr(path.begin(), path.end()); XMLError error = doc.LoadFile(pathStr.c_str()); assert(error == XMLError::XML_SUCCESS); XMLElement* root = doc.FirstChildElement(); string nameStr = root->Attribute("Name"); m_sName = wstring(nameStr.begin(), nameStr.end()); bLoop = root->BoolAttribute("Loop"); m_sPath = path; //Load Texture XMLElement* node = root->FirstChildElement(); for (; node != nullptr; node = node->NextSiblingElement()) { Keyframe keyframe; keyframe.offset.x = node->FloatAttribute("OffsetX"); keyframe.offset.y = node->FloatAttribute("OffsetY"); keyframe.size.x = node->FloatAttribute("SizeX"); keyframe.size.y = node->FloatAttribute("SizeY"); keyframe.time = node->FloatAttribute("Time"); AddKeyframe(keyframe); } }
SMLDocument를 만들어 path를 char* 형으로 바꾼 값으로 파일을 읽어오기 위해 LoadFile을 사용해준다
이번에는 doc에 저장된 요소중 첫번째 요소를 FirstChildElement로 가져와 그 안에 있는 요소를 가져와 반대로 wstring 형태로 만들어 m_sName에 저장해 줄것이다
bLoop에도 역시 BoolAttribute를 이용해 요소를 가져와 값을 저장해주고, m_sPath에는 함수에서 전달받은 path를 저장해준다
doc에 저장된 첫번째 요소의 속성을 다 저장했으면 texture에대한 정보인 keyframe을 가져와 저장해 주기 위해 root에 FirstChildElement로 root에 연결된 자식 중 첫번째 요소를 가져와 저장해준다
반복문을 통해 맨 마지막 요소까지 돌면서 요소안에 속성을 keyframe에 저장한 뒤 AddKeyframe을 통해 keyframe을 추가해주는데 이때 다음 요소로 넘어가기 위해 NextSiblingElement함수를 사용해주면 된다
Load 사용해보기
void ResourceMGR::CreateDefaultAnimation() { ... //XML animation->Save(L"TestAnimation.xml"); shared_ptr<Animation> anim2 = make_shared<Animation>(); animation->Load(L"TestAnimation.xml"); }
Load 함수를 사용해보기 위해 XML을 Save 했던 ResourceMGR에서 Animation을 하나 새로 만들어 그 객체로 Load 함수를 불러줄 것이다
이때 path는 Save로 만들어진 XML 파일의 이름을 넘겨주어 저장한 애니메이션 그대로 Load되게 해주는 것이다
2D 종료
이렇게 DirectX에서 2D로 간단한 실습 예제가 끝이났다
물론 완벽한 엔진이 된건 아니지만 이를 통해 파이프라인이라던지 Scene을 그리거나 Object를 추가하고 애니메이션을 그리는 등의 실습을 통해 3D로 가기 전 기초를 다지는 느낌으로 강의가 진행됐었다
이해가 100로 다 된것은 아니지만 앞으로의 3D 강의를 정독하고 다시한번 더 강의를 보면서 더욱더 이해를 할 수 있게 노력할 것이다
'DirectX' 카테고리의 다른 글
34 사각형 띄우기 (0) | 2025.01.16 |
---|---|
33 새 프로젝트 시작 (0) | 2025.01.16 |
30 Material, Mesh (1) | 2025.01.12 |
29 Render Manager (0) | 2025.01.12 |
28 ResourceManager (0) | 2025.01.12 |