WIN32 FILE I/O, UI

Date:     Updated:

카테고리:

태그:

20일차.

- Default
    - Client.h
    - framework.h
    - Resouce.h
    - targetver.h
- Engine
    1. Header
        1. define.h
        **2. struct.h**
        3. func.h
        4. func.cpp
        5. global.h
    2. Core
        1. CCore.cpp
 ****       2. CCore.h
    3. Manager
        1. KeyMgr
            1. CkeyMgr.cpp
            2. CkeyMgr.h
        2. TimeMgr
            1. CTimeMgr.cpp
            2. CTimeMgr.h
        3. SceneMgr
            1. CSceneMgr.cpp
            2. CSceneMgr.h
    		4. PathMgr
						1. CPathMgr.cpp
						2. CPathMgr.h
				5. ResMgr
						1. CResMgr.cpp
						2. CResMgr.h
	****			6. CollisionMgr
						1. CCollisionMgr.cpp
						2. CCollisionMgr.h
				7. EventMgr
						1. CEventMgr.cpp
****						2. CEventMgr.h
				8. Camera
						1. CCamera.cpp
****						2. CCamera.h
				9. CUIMgr.
						1. CUIMgr.cpp
						2. CUIMgr.h
    4. Object
		    1. Monser
			    1. CMonster.cpp
			    2. CMonster.h
			  2. Missle
				  1. Missile.cpp
				  2. Missile.h
****				3. Player
					1. CPlayer.cpp
					2. Cplayer.h
				4. Tile
					1. CTile.cpp
					2. CTile.h
				**5. UI
					1. BtnUI
						1. CBtnUI.cpp
						2. CBtnUI.h**
					2. PanelUI
						1. CPanelUI.cpp
						2. CPanelUI.h
****					1. CUI.cpp
					2. CUI.h
****        1. CObject.cpp
        2. CObject.h
    5. Scene
        1. Scene_Start
            1. CScene_Start.cpp
            2. CScene_Start.h
        **2. Scene_Tool
		        1. CScene_Tool.cpp
		        2. CScene_Tool.h**
        **3. CScene.cpp
        4. CScene.h**
    6. Resource
		    1. Sound
		    2. Texture
			    1. CTexture.cpp
				  2. CTexture.h
		    3. CRes.cpp
		    4. CRes.h
		7. Component
				1. Collider
					1. CCollider.cpp
					2. CCollider.h
				2. Animator
					1. Animation
						1. CAnimation.cpp
						2. CAnimation.h
					1. CAnimator.cpp
					2. CAnimation.h
		8. Module
				1. SelectGDI.cpp
				2. SelectGDI.h
- 리소스 파일
- main.cpp
- pch.h.
  • 오늘 주로한 것인 파일 입출력(세이브&로드), 버튼(함수 포인터)쪽이다.
  1. CPathMgr.h, cpp
#pragma once

class CPathMgr
{
	SINGLE(CPathMgr);

private:
	wchar_t		m_szContentPath[256];
	wchar_t		m_szRelativePath[256];

public:
	void init();
	const wchar_t* GetContentPath() { return m_szContentPath; }

	wstring GetRelativePath(const wchar_t* _filepath);
};

#include "pch.h"
#include "CPathMgr.h"

#include "CCore.h"

CPathMgr::CPathMgr() 
	: m_szContentPath{}
{

}

CPathMgr::~CPathMgr() {

}

void CPathMgr::init()
{

	//Ctrl + F5쓰면, 혹은 일반적으로 해도 프로젝트 폴더가 됨.
	//즉 비주얼 스튜디오에서 실행하는거랑, 프로그램 자체 실행이랑
	//경로값이 달라짐. 
	GetCurrentDirectory(255, m_szContentPath);
	//상위폴더로 나가고(\\을 만날때까지 찾고 거기에 null문자 넣기.) 
	int dirLen = static_cast<int>(wcslen(m_szContentPath));
	for (int dirIDX = dirLen - 1; dirIDX >= 0; dirIDX--) {
		if ('\\' == m_szContentPath[dirIDX]) {
			m_szContentPath[dirIDX] = '\0';
			break;
		}
	}
	//  + bin\\content\\ 경로 붙여주기
	wcscat_s(m_szContentPath, 255, L"\\bin\\content\\");
	//상대 경로 설정 완료.
	//SetWindowText(CCore::GetInstance()->GetMainHwnd(), m_szContentPath);
}

wstring CPathMgr::GetRelativePath(const wchar_t* _filepath)
{
	wstring strFilePath = _filepath;
	size_t iAbsLen = wcslen(m_szContentPath);
	size_t iFullLen = strFilePath.length();
	wstring strRelativePath = strFilePath.substr(iAbsLen, iFullLen - iAbsLen);
	
	return strRelativePath;
}

  • 절대경로를 받아 상대경로를 반환해주는 함수를 만들었다.
  1. CTile.h, cpp
#pragma once
#include "CObject.h"

class CTexture;
class CTile :
    public CObject
{

private:
    CTexture*       m_pTileTex;
    int             m_iImgIdx;

public:
    void SetTexture(CTexture* _pTex) {
        m_pTileTex = _pTex;
    }

    void AddImgIdx() {
        ++m_iImgIdx;
    }

private:
    virtual void update();
    virtual void render(HDC _dc);

public:
    virtual void Save(FILE* _pFile);
    virtual void Load(FILE* _pFile);
    CLONE(CTile);
public:
    CTile();
    ~CTile();
};

#include "pch.h"
#include "CTile.h"

#include "CTexture.h"

CTile::CTile()
	: m_pTileTex(nullptr)
	, m_iImgIdx(0)
{
	SetScale(Vec2(TILE_SIZE, TILE_SIZE));
}

CTile::~CTile()
{
	
}
//Tool Scene을 통해서 타일의 배치를 자신이 코드가 아닌 방식으로 배치할 수 있어야 하는데.
//타일을 개별적으로 건드려서, 각 타일의 모양새를 바꿀 수 있어야함. 

//그리고 저장 & 로드가 가능해야함. 
void CTile::update()
{

}

void CTile::render(HDC _dc)
{

	if (m_pTileTex == nullptr || -1 == m_iImgIdx) {
		return;
	}

	UINT iWidth = m_pTileTex->Width();
	UINT iHeight = m_pTileTex->Height();

	UINT IMaxCol = iWidth / TILE_SIZE;
	UINT IMaxRow = iHeight / TILE_SIZE;

	UINT iCurRow = (UINT)(m_iImgIdx / IMaxCol);
	UINT iCurCol = (UINT)(m_iImgIdx % IMaxCol);

	Vec2 vRenderPos = CCamera::GetInstance()->GetRenderPos(GetPos());
	Vec2 vScale = GetScale();

	if (IMaxRow <= iCurRow) {
		assert(nullptr);
	}
	
	BitBlt(_dc,
		(int)(vRenderPos.x),
		(int)(vRenderPos.y),
		(int)(vScale.x),
		(int)(vScale.y),
		m_pTileTex->GetDC(),
		iCurRow * TILE_SIZE,
		iCurCol * TILE_SIZE,
		SRCCOPY);
}

void CTile::Save(FILE* _pFile)
{
	fwrite(&m_iImgIdx, sizeof(int), 1, _pFile);
}

void CTile::Load(FILE* _pFile)
{
	fread(&m_iImgIdx, sizeof(int), 1, _pFile);
}

  • 파일 포인터를 통한 fwrite, fread로 파일에 적고 읽어온다.
  1. CBtnUI.h
#pragma once
#include "CUI.h"

//여기서 원형을 알려주지 않으면 함수 포인터(정확한 클래스의 구조)를 
//모르기에 이상한 지점에 접근할 수 있어 에러가 생김. 

//멤버함수 포인터 접근할 때에는 정확한 클래스 정보를 알아야 함. 
#include "CScene.h"
#include "CObject.h"
typedef void(*BTN_FUNC) (DWORD_PTR, DWORD_PTR);

//툴 씬이 보유하고 있는 특정 멤버 함수를 받아와야만 함. 

//버튼 UI는 범용적으로 바라는데, 이런 식으로 멤버를 쓰는 게 맞나?
//어떤 오브젝트의 기능을 쓰고 싶으면? 범용적으로 쓸 방법 없을까?

//이렇게 하면 SCENE이나, 오브젝트에서 파생된 것을 쓸 수 있음. 
typedef void(CScene:: *SCENE_MEMFUNC)(void);
typedef void(CObject::*OBJECT_MEMFUNC)(void);

class CBtnUI :
    public CUI
{

private:
    //함수 포인터를 불러와서 버튼이 눌렸을 때 그걸 씀.
    BTN_FUNC    m_pFunc;
    DWORD_PTR   m_param1;
    DWORD_PTR   m_param2;

    //씬 멥버 함수를 얻기 위한 객체와, 호출 할 함수. 
    SCENE_MEMFUNC   m_pSceneFunc;
    CScene*         m_pSceneInst;

public:
    virtual void MouseOn();
    virtual void MouseLbtnDown();
    virtual void MouseLbtnUp();
    virtual void MouseLbtnClicked();

    void SetClickedCallBack(BTN_FUNC _pFunc, DWORD_PTR _param1, DWORD_PTR _param2) {
        m_pFunc = _pFunc;
        m_param1 = _param1;
        m_param2 = _param2;
    }

    void SetClickedCallBack(CScene* _pScene, SCENE_MEMFUNC _pSceneFunc);

    CLONE(CBtnUI)

public:
    CBtnUI();
    ~CBtnUI();
};

  • 이 부분이 어려운데 주석에 적혀있듯이 멤버 함수의 함수 포인터를 가져오려면 객체가 필요하다.
  • 또한 그 클래스에 대한 정확한 정보가 필요하기에 인클루드를 해야한다.
  1. CScene.h
	void LoadTile(const wstring& _strRelativePath);

함수 추가

  1. CScene.cpp
void CScene::CreateTile(UINT _IXCount, UINT _IYCount)
{
	DeleteGroup(GROUP_TYPE::TILE);

	m_iTileX = _IXCount;
	m_iTileY = _IYCount;

	//타일 생성
	CTexture* pTileTex = CResMgr::GetInstance()->LoadTexture(L"Tile", L"texture\\tera2.bmp");
	
	for (UINT tileIDX = 0; tileIDX < _IYCount; tileIDX++) {
		for (UINT tileJDX = 0; tileJDX < _IXCount; tileJDX++) {
			CTile* pTile = new CTile();

			pTile->SetPos(Vec2((float)(tileJDX * TILE_SIZE), (float)(tileIDX * TILE_SIZE)));
			pTile->SetTexture(pTileTex);

			AddObject(pTile, GROUP_TYPE::TILE);
		}
	}
}

void CScene::LoadTile(const wstring& _strRelativePath)
{
	wstring strFilePath = CPathMgr::GetInstance()->GetContentPath();
	strFilePath += _strRelativePath;
	//커널 오브젝트
	FILE* pFile = nullptr;
	_wfopen_s(&pFile, strFilePath.c_str(), L"rb");

	assert(pFile);

	//데이터 로드.

	UINT xCount = 0;
	UINT yCount = 0;

	fread(&xCount, sizeof(UINT), 1, pFile);
	fread(&yCount, sizeof(UINT), 1, pFile);

	CreateTile(xCount, yCount);

	//모든 타일들을 개별적으로 저장할 데이터를 로드하게 함. 
	const vector<CObject*>& vecTile = GetGroupObject(GROUP_TYPE::TILE);

	for (size_t tileIdx = 0; tileIdx < vecTile.size(); tileIdx++) {
		((CTile*)vecTile[tileIdx])->Load(pFile);
	}

	fclose(pFile);
}
  • CreateTile에서 타일을 만들때, 이전에 있던 타일들 삭제.
  • 또한 LoadTile로 타일을 받아온다.
  1. CScene_Tool.h
#pragma once
#include "CScene.h"

class CUI;
class CScene_Tool :
    public CScene
{
private:
    CUI* m_pUI;

public:
    virtual void update();
    virtual void Enter();
    virtual void Exit();

public:
    //마우스를 클릭해서 타일의 Index를 변경한다(이미지)
    void SetTileIdx();

    void SaveTileData();
    void SaveTile(const wstring& _strFilePath);

    void LoadTileData();

    
    

public:
    CScene_Tool();
    ~CScene_Tool();
};

  1. CScene_Tool.cpp
#include "pch.h"
#include "CScene_Tool.h"
#include "CkeyMgr.h"
#include "CSceneMgr.h"
#include "CTile.h"
#include "CCore.h"
#include "CResMgr.h"

#include "resource.h"
#include "CSceneMgr.h"
#include "CUI.h"
#include "CPanelUI.h"
#include "CBtnUI.h"
#include "CUIMgr.h"
#include "CPathMgr.h"

void ChangeScene(DWORD_PTR, DWORD_PTR);

CScene_Tool::CScene_Tool()
{

}

CScene_Tool::~CScene_Tool()
{

}

void CScene_Tool::Enter()
{
	CreateTile(5, 5);
	Vec2 vResolution = CCore::GetInstance()->GetResolution();

	//UI가 무언가 역할을 수행하려면 클릭할 수 있어야만 함. 
	//전반적인 UI의 이벤트 설계를 해준다면 <- 특정 상황때 호출하는 함수가 명확

	CUI* pPanelUI = new CPanelUI;
	pPanelUI->SetName(L"ParentUI");
	pPanelUI->SetScale(Vec2(500.f, 300.f));
	pPanelUI->SetPos(Vec2(vResolution.x - pPanelUI->GetScale().x, 0.f));

	CBtnUI* pBtnUI = new CBtnUI;
	pBtnUI->SetName(L"ChildUI");
	pBtnUI->SetScale(Vec2(100.f, 40.f));
	pBtnUI->SetPos(Vec2(0.f, 0.f));

	//버튼 UI에 등록해둔 함수를 출력할 수 있게 해놨다. 
	//함수의 형태는 반드시 반환이 void이고, 인자가 2개인 함수만 받을 수 있음.
	//그런데 내가 넣고 싶은 함수는 전역함수가 아닌 멤버함수임...

	//멤버 함수를 쓰려면 반드시 객체가 필요함. 
	//호출 시킬 객체가 반드시 필요함. 
	((CBtnUI*)pBtnUI)->SetClickedCallBack(this, (SCENE_MEMFUNC)&CScene_Tool::SaveTileData);

	//pBtnUI->SetClickedCallBack(ChangeScene, 0, 0);
	pPanelUI->AddChild(pBtnUI);
	AddObject(pPanelUI, GROUP_TYPE::UI);

	
	/*
	CUI* pClonePanel = pPanelUI->Clone();
	pClonePanel->SetPos(pClonePanel->GetPos() + Vec2(-500.f, 0.f));

	//이렇게 해주면 기능이야 같겠지만, 다른 포인터.
	((CBtnUI*)pClonePanel->GetChildsUI()[0])->SetClickedCallBack(ChangeScene, 0, 0);
	AddObject(pClonePanel, GROUP_TYPE::UI);

	m_pUI = pClonePanel;*/
	//Camera Look 지점.
	CCamera::GetInstance()->SetLookAt(vResolution / 2.f);
}

//씬 안에 존재하는 모든 것은 오브젝트. 
//1. 무언가를 입력 받을 수 있는 오브젝트를 만들면 되는 거 아닐까.
//값을 세팅하거나, 그런 게 있는데 윈도우에서 어느정도 기능을 제공하는 것이 있음. 
void CScene_Tool::Exit()
{
	//이전 씬에서 포커싱되었던 것을 UIMgr이 기억하고 있는데...
	//그래서 씬 바꿀때는 그런 거 다 해제 해야함. 

	//여기서 타일 정보 저장할 수 있어야함. 
	DeleteAll();
}

void CScene_Tool::update()
{
	//부모쪽 기능 호출. 
	CScene::update();

	SetTileIdx();

	if (KEY_TAP(KEY::CTRL)) {
		LoadTileData();
		//LoadTile(L"tile\\Test.tile");
	}
}

void CScene_Tool::SetTileIdx()
{
	if (KEY_TAP(KEY::LBTN)) {
		Vec2 vMousePos = MOUSE_POS;

		vMousePos = CCamera::GetInstance()->GetRealPos(vMousePos);

		int iTileX = (int)GetTileX();
		int iTileY = (int)GetTileY();

		int iCol = (int)vMousePos.x / TILE_SIZE;
		int iRow = (int)vMousePos.y / TILE_SIZE;

		if (vMousePos.x < 0.f || iTileX <= iCol
			|| vMousePos.y < 0.f || iTileY <= iRow) return;

		UINT iIdx = iRow * iTileX + iCol;

		const vector<CObject*>& vecTile = GetGroupObject(GROUP_TYPE::TILE);

		((CTile*)vecTile[iIdx])->AddImgIdx();
	}
}

void CScene_Tool::SaveTileData()
{
	OPENFILENAME ofn = {};

	wchar_t szName[256] = {};

	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hwndOwner = CCore::GetInstance()->GetMainHwnd();
	ofn.lpstrFile = szName;
	ofn.nMaxFile = sizeof(szName);
	ofn.lpstrFilter = L"ALL\0*.*\0Tile\0*.tile\0";
	ofn.nFilterIndex = 0;
	ofn.lpstrFileTitle = nullptr;
	ofn.nMaxFileTitle = 0;
	
	wstring strTileFolder = CPathMgr::GetInstance()->GetContentPath();
	strTileFolder += L"tile";
	ofn.lpstrInitialDir = strTileFolder.c_str();
	ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
	
	//Modal 방식. 
	if (GetSaveFileName(&ofn)) {
		//저장으로 누르면 true, 취소는 false.
		CPathMgr::GetInstance()->GetRelativePath(szName);
		SaveTile(szName);
	}
}

void CScene_Tool::SaveTile(const wstring& _strFilePath)
{

	//커널 오브젝트
	FILE* pFile = nullptr;
	_wfopen_s(&pFile, _strFilePath.c_str(), L"wb");

	assert(pFile);

	//데이터 저장. 

	UINT xCount = GetTileX();
	UINT yCount = GetTileY();

	fwrite(&xCount, sizeof(UINT), 1, pFile);
	fwrite(&yCount, sizeof(UINT), 1, pFile);

	const vector<CObject*>& vecTile = GetGroupObject(GROUP_TYPE::TILE);

	//모든 타일들을 개별적으로 저장할 데이터를 저장하게 함. 
	for (size_t tileIdx = 0; tileIdx < vecTile.size(); tileIdx++) {
		((CTile*)vecTile[tileIdx])->Save(pFile);
	}

	fclose(pFile);
}

void CScene_Tool::LoadTileData()
{
	OPENFILENAME ofn = {};

	wchar_t szName[256] = {};

	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hwndOwner = CCore::GetInstance()->GetMainHwnd();
	ofn.lpstrFile = szName;
	ofn.nMaxFile = sizeof(szName);
	ofn.lpstrFilter = L"ALL\0*.*\0Tile\0*.tile\0";
	ofn.nFilterIndex = 0;
	ofn.lpstrFileTitle = nullptr;
	ofn.nMaxFileTitle = 0;

	wstring strTileFolder = CPathMgr::GetInstance()->GetContentPath();
	strTileFolder += L"tile";
	ofn.lpstrInitialDir = strTileFolder.c_str();
	ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

	//Modal 방식. 
	if (GetOpenFileName(&ofn)) {
		//저장으로 누르면 true, 취소는 false.
		wstring strRelativePath = CPathMgr::GetInstance()->GetRelativePath(szName);
		LoadTile(strRelativePath);
	}
}

void ChangeScene(DWORD_PTR, DWORD_PTR) {
	ChangeScene(SCENE_TYPE::START);
}

//=============================
// Tile Count Window Proc
//=============================

// 정보 대화 상자의 메시지 처리기입니다.

//__stdcall은 함수 호출 규약. 
INT_PTR __stdcall TileCountProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	switch (message)
	{
	case WM_INITDIALOG:
		return (INT_PTR)TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK)// ok나 X창 누르면
		{
			UINT iXCount = GetDlgItemInt(hDlg, IDC_EDIT1, nullptr, false);
			UINT iYCount = GetDlgItemInt(hDlg, IDC_EDIT2, nullptr, false);

			CScene* pCurScene = CSceneMgr::GetInstance()->GetCurScene();

			//이게 성공하면 정상적으로 캐스팅이 완료 
			CScene_Tool* pToolScene = dynamic_cast<CScene_Tool*>(pCurScene);
			assert(pToolScene);

			pToolScene->DeleteGroup(GROUP_TYPE::TILE);
			pToolScene->CreateTile(iXCount, iYCount);

			EndDialog(hDlg, LOWORD(wParam));    //Dialog 끝내기. 
			return (INT_PTR)TRUE;
		}
		else if (LOWORD(wParam) == IDCANCEL) {
			EndDialog(hDlg, LOWORD(wParam));    
			return (INT_PTR)TRUE;
		}
		break;
	}
	return (INT_PTR)FALSE;
}

//저장해놔야 작업하던 거 다시 로딩 가능. 

WINAPI 카테고리 내 다른 글 보러가기

댓글 남기기