Para estruturar um aplicativo básico em DirectX, vamos desenvolver uma organização simples e modular que cubra as funções essenciais para a inicialização e renderização. Essa estrutura permitirá que você gerencie a janela, configure o DirectX, e renderize uma tela básica. Vou dividir isso em módulos principais para deixar mais claro.
Estrutura Básica de um Aplicativo DirectX
- Módulo Principal (
main.cpp
): onde fica a entrada do aplicativo (WinMain) e o loop principal de execução. - Classe
DirectXApp
: uma classe que encapsula toda a lógica de inicialização e renderização do DirectX. - Função de Processamento de Mensagens (
WindowProc
): responsável por gerenciar as mensagens do Windows.
Aqui está um esboço de como organizar cada uma dessas partes:
1. Módulo Principal (main.cpp)
Este módulo contém a função de entrada WinMain, que cria uma instância da nossa classe de aplicativo DirectX (DirectXApp), executa o loop de mensagens e chama a função de renderização.
#include <windows.h>
#include "DirectXApp.h" // Inclui a classe que vamos criar
// Função de entrada do Windows
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow) {
// Inicializa a aplicação DirectX
DirectXApp dxApp;
if (!dxApp.Initialize(hInstance, nCmdShow)) {
MessageBox(nullptr, "Falha ao inicializar o DirectX.", "Erro", MB_OK | MB_ICONERROR);
return -1;
}
// Loop principal de mensagens
MSG msg = {};
while (msg.message != WM_QUIT) {
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
dxApp.Render(); // Renderiza a cada loop
}
}
return static_cast(msg.wParam);
}
Explicação
- WinMain: Inicializa uma instância de DirectXApp. Se a inicialização falha, exibe uma mensagem de erro.
- Loop Principal de Mensagens: Mantém o aplicativo em execução enquanto espera mensagens do sistema operacional (eventos de usuário, notificações do sistema etc.). No caso de não haver mensagens (PeekMessage retorna falso), a função Render é chamada para atualizar a tela.
2. Classe DirectXApp
A classe DirectXApp encapsula a lógica de inicialização e renderização do DirectX. Esta estrutura modulariza o código e facilita o gerenciamento dos recursos gráficos.
DirectXApp.h
DirectXApp.cpp
Explicação
#pragma once
#include <d3d11.h>
#include <windows.h>
class DirectXApp {
public:
DirectXApp() : g_device(nullptr), g_context(nullptr), g_renderTargetView(nullptr), hwnd(nullptr) {}
~DirectXApp();
bool Initialize(HINSTANCE hInstance, int nCmdShow);
void Render();
private:
HWND hwnd; // Handle da janela
ID3D11Device* g_device; // Dispositivo Direct3D
ID3D11DeviceContext* g_context; // Contexto do dispositivo
IDXGISwapChain* g_swapChain; // Troca de buffers
ID3D11RenderTargetView* g_renderTargetView; // Visão de destino de renderização
bool InitializeWindow(HINSTANCE hInstance, int nCmdShow);
bool InitializeDirectX();
};
DirectXApp.cpp
#include "DirectXApp.h"
#include <stdexcept>
// Inicializa o DirectX e a janela
bool DirectXApp::Initialize(HINSTANCE hInstance, int nCmdShow) {
if (!InitializeWindow(hInstance, nCmdShow))
return false;
if (!InitializeDirectX())
return false;
return true;
}
bool DirectXApp::InitializeWindow(HINSTANCE hInstance, int nCmdShow) {
const char CLASS_NAME[] = "DirectX Window Class";
WNDCLASS wc = {};
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
RegisterClass(&wc);
hwnd = CreateWindowEx(
0, CLASS_NAME, "Meu Aplicativo DirectX",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
nullptr, nullptr, hInstance, nullptr);
if (!hwnd) return false;
ShowWindow(hwnd, nCmdShow);
return true;
}
bool DirectXApp::InitializeDirectX() {
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferCount = 1;
swapChainDesc.BufferDesc.Width = 800;
swapChainDesc.BufferDesc.Height = 600;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.OutputWindow = hwnd;
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.Windowed = TRUE;
HRESULT hr = D3D11CreateDeviceAndSwapChain(
nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, 0,
D3D11_SDK_VERSION, &swapChainDesc, &g_swapChain, &g_device,
nullptr, &g_context);
if (FAILED(hr)) return false;
ID3D11Texture2D* backBuffer = nullptr;
hr = g_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer));
if (FAILED(hr)) return false;
hr = g_device->CreateRenderTargetView(backBuffer, nullptr, &g_renderTargetView);
backBuffer->Release();
if (FAILED(hr)) return false;
g_context->OMSetRenderTargets(1, &g_renderTargetView, nullptr);
D3D11_VIEWPORT viewport = {};
viewport.Width = 800;
viewport.Height = 600;
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
g_context->RSSetViewports(1, &viewport);
return true;
}
void DirectXApp::Render() {
float clearColor[4] = { 0.0f, 0.2f, 0.4f, 1.0f };
g_context->ClearRenderTargetView(g_renderTargetView, clearColor);
g_swapChain->Present(1, 0);
}
DirectXApp::~DirectXApp() {
if (g_renderTargetView) g_renderTargetView->Release();
if (g_swapChain) g_swapChain->Release();
if (g_context) g_context->Release();
if (g_device) g_device->Release();
}
Explicação
- Initialize: Chama as funções InitializeWindow e InitializeDirectX para configurar a janela e o DirectX.
- InitializeWindow: Configura e cria a janela.
- InitializeDirectX: Cria o dispositivo, contexto, e a troca de buffers. Configura a visão de destino e a viewport para renderização.
- Render: Limpa a tela com uma cor de fundo azul e apresenta o conteúdo da renderização na tela.
- Destrutor: Libera todos os recursos alocados pelo DirectX.
3. Função de Processamento de Mensagens (WindowProc)
A função WindowProc processa as mensagens enviadas pelo sistema operacional para a janela.
Explicação
#include <windows.h>
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
Explicação
- WM_DESTROY: Quando a janela é fechada, esta mensagem é enviada e o PostQuitMessage(0) encerra o loop de mensagens.
- DefWindowProc: Processa todas as mensagens que não foram capturadas especificamente.
Resumo e Funcionamento
- Inicialização: WinMain cria uma instância de DirectXApp e inicializa a janela e o DirectX.
- Loop de Mensagens e Renderização: O loop verifica se há mensagens e, caso não haja, chama a função Render.
- Limpeza de Recursos: Quando o aplicativo é encerrado, o destrutor da DirectXApp libera todos os recursos DirectX.
Essa estrutura básica é extensível. Com ela, você pode adicionar lógica de renderização, manipulação de entradas e mais componentes DirectX para avançar seu desenvolvimento.
1 Comentários
Muito bom, parabéns!
ResponderExcluir