광원을 추가하려고 하는데, 하기 전에 IMGUI를 먼저 프로젝트에 추가하고 나서 하는게 좋을듯 해서 IMGUI를 추가하기로 하였다.

 

if (!ImguiInit())
{
    return FALSE;
}

 

EngineBase의 Init에 IMGUI를 초기화하는 함수도 추가해주었다.

 

BOOL EngineBase::ImguiInit()
{
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGui::StyleColorsDark();

    if(!ImGui_ImplWin32_Init(hWnd))
    {
        std::cout << "IMGUI Win32 Init Failed" << std::endl;
        return FALSE;
    }

    if (!ImGui_ImplDX11_Init(Device.Get(), Context.Get()))
    {
        std::cout << "IMGUI Dx11 Init Failed" << std::endl;
        return FALSE;
    }

    return TRUE;
}

 

코드는 위와 같다. IMGUI에서 제공해주는 예제 코드에서 필요해보이는 함수만 가져와서 작성하였다.

 

 ImguiUpdate();
 ImGui::Render();

 Update();
 Render();

 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());

 SwapChain->Present(1, 0);

 

위 코드는 EngineLoop의 코드이다. 원래는 update,Render, Present만 있었지만, Imgui에 대한 코드도 추가해주었다.

void EngineBase::ImguiUpdate()
{
    ImGui_ImplDX11_NewFrame();
    ImGui_ImplWin32_NewFrame();
    ImGui::NewFrame();

    ImGui::Begin("Hello, world!");                         
    ImGui::Text("This is some useful text.");            
    ImGui::End();
}

 

일단 테스트를 위해, GUI엔 간단한 텍스트만 출력하도록 해주었다.

 

 

상단에 GUI가 잘 만들어진 것을 볼 수 있다.

 

근데 뭔가 메모리 해제가 안됐나보다.

WPARAM EngineBase::End()
{
    ImGui_ImplDX11_Shutdown();
    ImGui_ImplWin32_Shutdown();
    ImGui::DestroyContext();

    return msg.wParam;
}

 

EngineBase의 End에 Imgui의 메모리를 해제하는 함수들도 추가해주니 메모리 누수는 더이상 발견되지 않았다.

 

이제 GUI업데이트 부분을 다시 수정하고자 한다.

아무래도, 렌더러에서 GUI에 변수를 연결하는 경우가 많을 것 같아서 렌더러쪽에서 GUI 업데이트 함수를 직접 작성할 수 있도록 callback방식으로 구성하고자 한다.

 

std::list<std::function<void()>> GUIFunctions;

 

Enginebase에는 위와 같이 함수포인터를 원소로 하는 list를 선언해주었다.

 

void AddGUIFunction(const std::function<void()> _Func)
{
    GUIFunctions.push_back(_Func);
}

 

외부에선 위 함수를 이용해 함수포인터를 list에 추가해줄 수 있다.

 

void EngineBase::ImguiUpdate()
{
    ImGui_ImplDX11_NewFrame();
    ImGui_ImplWin32_NewFrame();
    ImGui::NewFrame();

    ImGui::Begin("Hello, world!"); 
    
    for (const std::function<void()> _Func : GUIFunctions)
    {
        _Func();
    }

    ImGui::End();
}

 

GUI 업데이트 코드는 위와 같이 수정해주었다.

 

테스트를 해보자.

void BoxRenderer::Init()
{
    CreateVertexAndIndex();
    
    RenderBase::CreateVertexBuffer();
    RenderBase::CreateIndexBuffer();
    RenderBase::CreateConstantBuffer<Transform>(TransFormData);
    RenderBase::CreateConstantBuffer(UV);

    SetTexture("BoxTexture.png");
    SetSampler("LINEARWRAP");

    EngineBase::GetInstance().AddGUIFunction([] {ImGui::Text("AAA"); });
    EngineBase::GetInstance().AddGUIFunction([] {ImGui::Text("BBB"); });
    EngineBase::GetInstance().AddGUIFunction([] {ImGui::Text("CCC"); });
}

 

위와 같이 박스 렌더러의 init에서 AAA,BBB,CCC 텍스트를 출력하는 함수를 EngineBase에 추가해주었다.

 

결과는.. 잘 나오는 것 같긴 한데 왜 Imgui 윈도우 창 크기 조절이 안되는거지?

 

extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

LRESULT CALLBACK EngineBase::WndProc(HWND _hWnd, UINT _message, WPARAM _wParam, LPARAM _lParam)
{
    if (ImGui_ImplWin32_WndProcHandler(_hWnd, _message, _wParam, _lParam))
        return true;

    switch (_message) {
    case WM_SIZE:
        break;
    case WM_SYSCOMMAND:
        if ((_wParam & 0xfff0) == SC_KEYMENU)
            return 0;
        break;
    case WM_MOUSEMOVE:
        break;
    case WM_LBUTTONUP:
        break;
    case WM_RBUTTONUP:
        break;
    case WM_KEYDOWN:
        break;
    case WM_DESTROY:
        ::PostQuitMessage(0);
        return 0;
    }

    return ::DefWindowProc(_hWnd, _message, _wParam, _lParam);
}

 

찾아보니, 윈도우 메세지 처리 함수의 상단에 위와 같이 Imgui함수 코드를 추가해줘야 한다고 한다.

이 함수를 정삭적으로 실행하려면 코드 최상단에 있는 것처럼 전방선언을 해주어야 한다.

 

다시 실행해보면?

 

윈도우 크기 조절도 잘 되고, 텍스트도 잘 추가된 것을 볼 수 있다!

 

이번엔 프로젝트에 델타타임도 추가해보자.

IMGUI엔 계산된 Deltatime을 매 프레임마다 제공해주는 기능이 있다.

 

float CurDelta = ImGui::GetIO().DeltaTime;

위와 같은 함수를 사용하면, 현재 프레임의 델타타임을 얻을 수 있다.

 

Update(CurDelta);
Render(CurDelta);

 

이후, Update와 Render함수에 float형 인자를 추가하여, 델타타임을 인수로 전달해주었다.

void EngineBase::Update(float _DeltaTime)
{
    for (std::shared_ptr<RenderBase> Renderer : Renderers)
    {
        Renderer->Update(_DeltaTime);
    }
}

 

Renderer의 Update와 Render에도 델타타임을 추가해주었다.

 

잘 되는지, 테스트해보자.

Rotation += 18.0f * _DeltaTime;
float RotRad = Rotation / 180.0f * DirectX::XM_PI;

 

박스 렌더러의 Update에서 위의 코드처럼 1초에 18도씩 회전하도록 Rotation을 업데이트해주었다.

 

 

잘 작동하는 것을 볼 수 있다.

이제, 조명을 추가할 준비가 얼추 된 것 같다.

+ Recent posts