Curso completo de DirectX 9 com C\C++
Gameprog - Escola de programação de jogos digitais
Contato: gameprog.br@gmail.com
Fase 06-3

index << >>


06.3 Sprite 2d com DirectInput

1.1 Visão geral
Neste tópico vamos aprender a utilizar o teclado utilizando o DirectInput que permite uma leitura mais rápida do teclado. O DirectInput permite também o acesso ao mouse e joystick com um código razoavelmente semelhante na montagem do cenário de utilização destes diferentes dispositivos. Na utilização do Direct3D entra em cena trêz processos: a criação do dispositivo Direct3D que depois participa ativamente da criação do dispositivo renderizador e depois tem o processo da renderização. O caminho de uso do DirectInput tem um roteiro similar: é criado o o dispositivo DirectInput que depois participa ativamente na criação do dispositivo ativo (mouse, teclado, joystick) e depois é necessário uma terceira função para ler e tratar os dados de status do dispositivo montado. 1.2 Estrutura principal da aplicação
Arquivo: motor.cpp
initGfx() Inicializa objeto Direct3d Inicializa dispositivo renderizador Inicializa objeto DirectInput via inicializar_DirectInput() Inicializa objeto teclado via inicializar_Teclado() Inicializa objeto para mostrar texto via inicializarTexto() Inicializa objetos para mostrar sprite via inicializarSprite() inicializar_DirectInput() inicializa objeto DirectInput ( g_DirectInput ) inicializar_Teclado() Inicializa dispositivo de entrada ( g_teclado ) inicializarSprite() Carrega textura Inicializa objeto de mostrar sprite Configuração da posição 3d e rotação inicial da sprite tratarTeclado() Coleta status do teclado Verifica pressionamento das setas Atualiza coordenada (x,y) da sprite no pressionamento das setas. renderizarSprite() Configura coordenada (x,y) atual da sprite Define parte da textura que vai ser exibida como sprite Desenha a sprite na tela Renderizar() Verifica teclado via tratarTeclado() Limpa a tela Desenha a cena mostra texto Desenha a sprite com renderizarSprite() Apresenta a cena processaJanela() tratamento das mensagens Verifica teclado - finaliza aplicação na tecla Escape chama Limpar() na finalização da aplicação chama Renderizar() para desenhar os gráficos Limpar() Libera o objeto de textura Libera o objeto de mostrar sprite Libera objeto de mostrar texto Libera dispositivo renderizador Libera objeto Direct3d Libera objetos do DirectInput via limpar_DirectInput() limpar_DirectInput() Libera objeto DirectInput ( g_DirectInput ) Liberado objeto teclado ( g_teclado )
2.1.1 Aspectos globais - Arquivo: motor.h
// Projeto: prj_Teclado01 - Arquivo: motor.h // Esta aplicação ilustra como utilizar o teclado via DirectInput #ifndef motor_h #define motor_h // Esta função inicializa o motor gráfico HRESULT initGfx (HWND hJanela); // Essa função libera os objetos utilizados void Limpar(); // Essa função desenha a cena void Renderizar(); // Esta função inicializa o objeto para mostrar texto void inicializarTexto(); // Esta função mostra um texto na coordenada (x, y) da janela void mostrarTexto( int x, int y, char* texto); // Inicializa a sprite void inicializarSprite(); // Desenha a sprite void renderizarSprite(); // Essa função inicializa o objeto DirectInput bool inicializar_DirectInput(); // Essa função inicializa o dispositivo de acesso ao teclado bool inicializar_Teclado(); // Essa função trata o pressionamento do teclado void tratarTeclado(); // Essa função libera os objetos do DirectInput void limpar_DirectInput(); // Declaração da função que atende as mensagens da janela LRESULT CALLBACK processaJanela (HWND hJanela, UINT mensagem, WPARAM wParam, LPARAM lParam); #endif
// Essa função inicializa o objeto DirectInput bool inicializar_DirectInput(); Essa função cria o objeto DirectInput representado pela interface IDirectInput8 que depois é responsável por criar os dispositivos de acesso a teclado, mouse e joystick. O ponteiro para este objeto é a variável g_DirectInput. // Essa função inicializa o dispositivo de acesso ao teclado bool inicializar_Teclado(); Essa função inicializa o dispositivo de acesso ao teclado (g_teclado) representado pela interface IDirectInputDevice8 que pode assumir a forma de mouse, teclado ou joystick. // Essa função trata o pressionamento do teclado void tratarTeclado(); Essa função trata o pressionamento das setas dentro dos moldes do DirectInput. // Essa função libera os objetos do DirectInput void limpar_DirectInput(); Essa função libera os objetos do DirectInput que foram inicializados. 2.1.2 Aspectos globais - Arquivo: motor.cpp
// ----------------------------------------------------------------------------- // Projeto: prj_Teclado01 - arquivo: motor.cpp // Esta aplicação ilustra como utilizar o teclado via DirectInput // Produzido por www.gameprog.com.br // ----------------------------------------------------------------------------- #include <windows.h> #include <d3d9.h> #include <d3dx9.h> #include <stdio.h> #include "motor.h" #include <dinput.h> // Inclui as bibliotecas do Direct3D #pragma comment(lib, "d3d9.lib") #pragma comment(lib, "d3dx9.lib") // Bibliotecas do DirectInput #pragma comment(lib, "dinput8.lib") #pragma comment(lib, "dxguid.lib") // Variáveis globais // Representa o dispositivo Direct3D LPDIRECT3D9 g_Direct3d = NULL; // Representa o dispositivo Renderizador IDirect3DDevice9* g_device = NULL; // Ponteiro para uma fonte do directx ID3DXFont* gdxFonte = NULL; // Essa variável recebe informação de erro do Directx HRESULT g_hr = 0; extern int g_xtela; extern int g_ytela; // Interfaces necessárias para a criação da sprite // A textura vai compor a imagem da sprite IDirect3DTexture9* g_textura = NULL; ID3DXSprite* g_sprite = NULL; // Argumentos necessários na criação da sprite // Posicionamento e recorte da sprite RECT g_recorte; // Posicionamento 3d da sprite D3DXVECTOR3* g_posicao = NULL; // Centro de apoio para rotações da sprite D3DXVECTOR3* g_centro = NULL; // Controle de movimentação da sprite int movimento_direcao = 1; int xpos = -240; int ypos = -160; // Constante para a cor branca const DWORD branco = 0xFFFFFFFF; // Ponteiro para o objeto DirectInput IDirectInput8* g_DirectInput = NULL; // Ponteiro para o dispositivo de teclado IDirectInputDevice8* g_teclado = NULL; // O DirectInput necessita de acesso à janela extern HWND hJanela;
// Bibliotecas do DirectInput #pragma comment(lib, "dinput8.lib") #pragma comment(lib, "dxguid.lib") Estas são as bibliotecas que permitem usar as funcionalidades do DirectInput. // Ponteiro para o objeto DirectInput IDirectInput8* g_DirectInput = NULL; Este é o ponteiro para o objeto DirectInput que é utilizado na criação dos dispositivos de acesso ao mouse, teclado ou joystick. // Ponteiro para o dispositivo de teclado IDirectInputDevice8* g_teclado = NULL; Este é o ponteiro que será usado para o acesso ao teclado. Essa interface pode assumir a forma de mouse ou joystick conforme configuração particular. // O DirectInput necessita de acesso à janela extern HWND hJanela; Uma das pequenas mudanças em relação ao projeto base ( prj_Sprite ) é que o handle da janela teve o acesso globalizado pois ele é necessário na configuração de um aspecto do dispositivo. 2.2 Inicializando os motores do directx
// initGfx() - Inicializa o Direct3D HRESULT initGfx( HWND hJanela ) { // Cria o objeto Direct3D que é necessário para criar o dispositivo gráfico g_Direct3d = Direct3DCreate9( D3D_SDK_VERSION); // Verifica se objeto Direct3D foi criado if(g_Direct3d == NULL) { MessageBox (NULL, "Falha na inialização do Direct3D", "InitGfx()", MB_OK); return E_FAIL; } // endif // Declara a variável para os parâmetros de apresentação D3DPRESENT_PARAMETERS pps; // Limpa a estrutura ZeroMemory( &pps, sizeof(pps) ); // Configura os parâmetros de apresentação // A aplicação vai ter janela pps.Windowed = TRUE; // Esse método vira rapidamente o backbuffer para a tela imediata pps.SwapEffect = D3DSWAPEFFECT_DISCARD; // Esse formato vai procurar se encaixar no modo de video corrente pps.BackBufferFormat = D3DFMT_UNKNOWN; // Configuração do renderizador a ser criado // Adaptador default (0) int nAdaptador = D3DADAPTER_DEFAULT; // Tipo de dispositivo Hardware ou emulador de referência (software) D3DDEVTYPE dispositivo_tipo = D3DDEVTYPE_HAL; // Flags de configuração do dispositivo DWORD create_flags = D3DCREATE_SOFTWARE_VERTEXPROCESSING; // Criamos aqui o dispositivo renderizador g_hr = g_Direct3d->CreateDevice( nAdaptador, dispositivo_tipo, hJanela, create_flags, &pps, &g_device ); // Verifica se houve falha no processo if( FAILED( g_hr ) ) { MessageBox (NULL, "Falha na criação: g_device", "initGfx()", MB_OK); return E_FAIL; } // endif inicializar_DirectInput(); inicializar_Teclado(); // Inicializa texto inicializarTexto(); // Inicializa sprite inicializarSprite(); return S_OK; } // initGfx().fim
inicializar_DirectInput(); inicializar_Teclado(); A função initGfx() assume a tarefa de chamar as funções que inicializam o DirectInput e o teclado. Aliás, até o final do curso initGfx() fará esse trabalho de convocar as funções que inicializam os outros objetos. 2.3 Inicializando o DirectInput
// inicializar_DirectInput() - Cria o objeto DirectInput bool inicializar_DirectInput() { // Criação do objeto DirectInput g_hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&g_DirectInput, NULL); if FAILED(g_hr) { MessageBox (NULL, "DirectInput: falha na criação", "inicializar_DirectInput()", MB_OK); return false; } // endif return true; } // inicializar_DirectInput().fim
// inicializar_DirectInput() - Cria o objeto DirectInput // Criação do objeto DirectInput g_hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&g_DirectInput, NULL); Então este é o código que inicializa o objeto DirectInput. Depois de linhas como essa é sempre importante conferir g_hr para ver se o o objeto foi realmente criado. 2.4 Inicializando o dispositivo de acesso ao teclado
// inicializar_Teclado() - Essa função inicializa o teclado bool inicializar_Teclado() { // Criação do ponteiro para uma interface IDirectInputDevice8 g_hr = g_DirectInput->CreateDevice(GUID_SysKeyboard, &g_teclado, NULL); if FAILED(g_hr) { MessageBox (NULL, "g_DirectInput->CreateDevice() falhou.", "inicializar_Teclado()", MB_OK); limpar_DirectInput(); return false; } // endif // Configuração do formato de dados do dispositivo com uma constante // pré-definida de teclado do DirectInput ( c_dfDIKeyboard ) g_hr = g_teclado->SetDataFormat(&c_dfDIKeyboard); if FAILED(g_hr) { MessageBox (NULL, "g_teclado->SetDataFormat() falhou.", "inicializar_Teclado()", MB_OK); limpar_DirectInput(); return false; } // endif // Configuração do nível de cooperação DWORD cooperacao_flags = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE; g_hr = g_teclado->SetCooperativeLevel( hJanela, cooperacao_flags); if FAILED(g_hr) { MessageBox (NULL, "g_teclado->SetCooperativeLevel() falhou.", "inicializar_Teclado()", MB_OK); limpar_DirectInput(); return false; } // endif // Pega acesso ao dispositivo de entrada. g_hr = g_teclado->Acquire(); if FAILED(g_hr) { limpar_DirectInput(); return false; } // endif return TRUE; } // inicializar_Teclado().fim
// Criação do ponteiro para uma interface IDirectInputDevice8 g_hr = g_DirectInput->CreateDevice(GUID_SysKeyboard, &g_teclado, NULL); Aqui é criado o dispositivo que dará acesso ao teclado. O guid é um mecanismo de identificação única e exclusiva de um recurso ou dispositivo dentro de um computador local. Geralmente cada peça de hardware tem um guid mas ele também é usado para identificar 'peças' de software. if FAILED(g_hr) { MessageBox (NULL, "g_DirectInput->CreateDevice() falhou.", "inicializar_Teclado()", MB_OK); limpar_DirectInput(); return false; } // endif Esse código é rotineiro dentro de um programa robusto. Verificamos se não houve sucesso no processo. // Configuração do formato de dados do dispositivo com uma constante // pré-definida de teclado do DirectInput ( c_dfDIKeyboard ) g_hr = g_teclado->SetDataFormat(&c_dfDIKeyboard); Aqui é formatado o buffer de dados que recebe o status do dispositivo que neste caso é modelado para o teclado. // Configuração do nível de cooperação DWORD cooperacao_flags = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE; g_hr = g_teclado->SetCooperativeLevel( hJanela, cooperacao_flags); Aqui é configurado o nível de cooperação que estabelece como a sua aplicação vai compartilhar o dispositivo com o sistema e outras aplicações. Neste caso o domínio do dispositivo não é exclusivo ( DISCL_NONEXCLUSIVE ) e ainda que sua janela esteja minimizada ou desfocada ( DISCL_BACKGROUND ) a aplicação ainda recebe eventos do dispositivo. Esta é a configuração mais fácil de usar pois as outras possibilidades não funcionam ou são complicadas de gerenciar o vai e vem do domínio do dispositivo. Nesta configuração o único cuidado a ser tomado é sair da função se sua janela estiver minimizada ou desfocada com um código que pode ter essa forma no início da função de tratar o teclado:
// Estrutura para coletar informações da janela WINDOWINFO info_janela; // GetWindowInfo() precisa disso aqui configurado info_janela.cbSize = sizeof(WINDOWINFO); // Obtém informações da janela GetWindowInfo(hJanela, &info_janela); // Saia da função caso a janela esteja sem foco! if ( info_janela.dwWindowStatus == 0) return;
// Pega acesso ao dispositivo de entrada. g_hr = g_teclado->Acquire(); Depois é necessário utilizar Acquire() para se conectar aos eventos do dispositivo. 2.5 Tratando o teclado do DirectInput
// tratarTeclado() - Essa função trata o pressionamento do teclado void tratarTeclado() { // Memória para coletar informação de estados do teclado char buffer[256]; // Obtém o status das teclas do teclado g_hr = g_teclado->GetDeviceState( sizeof(buffer), (LPVOID) &buffer); if FAILED(g_hr) { // Se falhou é porque o dispositivo foi provavelmente perdido. // Verifique se g_hr == DIERR_INPUTLOST // Se for, tente readquirí-lo aqui com g_teclado->Acquire(); return; } // endif // Macro para facilitar leitura do teclado #define KEYDOWN(name, key) (name[key] & 0x80) // Atualiza (xpos, ypos) conforme tecla pressionada if (KEYDOWN(buffer, DIK_RIGHT) ) xpos = xpos - 5; if (KEYDOWN(buffer, DIK_LEFT)) xpos = xpos + 5; if (KEYDOWN(buffer, DIK_UP) ) ypos = ypos + 5; if (KEYDOWN(buffer, DIK_DOWN) ) ypos = ypos - 5; } // tratarTeclado().fim
char buffer[256]; Este bloco de memória vai ser usado para coletar informação de estados do teclado. // Obtém o status das teclas do teclado g_hr = g_teclado->GetDeviceState( sizeof(buffer), (LPVOID) &buffer); Com esta função o buffer de memória é preenchido com status de pressionamento das teclas. Se esta função falhar a função retorna com o código abaixo. if FAILED(g_hr) { // Se falhou é porque o dispositivo foi provavelmente perdido. // Verifique se g_hr == DIERR_INPUTLOST // Se for, tente readquirí-lo aqui com g_teclado->Acquire(); return; } // endif // Macro para facilitar leitura do teclado #define KEYDOWN(name, key) (name[key] & 0x80) Esta macro retorna verdadeiro se a tecla especificada estiver pressionada. Segue abaixo como usá-la. // Atualiza (xpos, ypos) conforme tecla pressionada if (KEYDOWN(buffer, DIK_RIGHT) ) xpos = xpos - 5; if (KEYDOWN(buffer, DIK_LEFT)) xpos = xpos + 5; if (KEYDOWN(buffer, DIK_UP) ) ypos = ypos + 5; if (KEYDOWN(buffer, DIK_DOWN) ) ypos = ypos - 5; Esta é a forma de tratar o pressionamento das setas do teclado nos moldes do DirectInput. 2.6 Renderização da cena Antes da renderização da cena a função tratarTeclado() é chamada para atualizar o posicionamento da sprite (xpos, ypos). É geralmente neste ponto, antes da renderização, que costuma ser atualizada a lógica do jogo.
// ----------------------------------------------------------------------------- // Renderizar() - Desenha a cena // ----------------------------------------------------------------------------- VOID Renderizar() { // Retorne se o dispositivo estiver nulo if( g_device == NULL) return; // String para mostrar posição da sprite char info[40]; tratarTeclado(); // Limpa o backbuffer com uma cor branca g_device->Clear( 0, NULL, D3DCLEAR_TARGET, branco, 1.0f, 0); // Começa a cena if( SUCCEEDED( g_device->BeginScene() ) ) { // Todo código de desenhar ocorre aqui dentro mostrarTexto (220, 160, "www.gameprog.com.br"); mostrarTexto (170,400, "Movimente a sprite com as setas."); // Mostra posicionamento da sprite sprintf (info, "( %i, %i )", xpos, ypos); mostrarTexto (10, 10, info); // Desenha sprite renderizarSprite(); // Finalizando a cena g_device->EndScene(); } // endif // Apresenta o conteúdo do backbuffer na tela g_device->Present( NULL, NULL, NULL, NULL); } // Renderizar().fim
2.7 Liberando os objetos do DirectInput Repare na função limpar_DirectInput() os cuidados tomados na liberação dos objetos do DirectInput. Este estilo de reconfigurar o ponteiro com NULL é um bom exemplo a ser tomado.
// limpar_DirectInput() - Libera os objetos do DirectInput void limpar_DirectInput() { if (g_DirectInput) { if (g_teclado) { // Liberação do teclado // Chame primeiro unacquire() antes de chamar Release(). g_teclado->Unacquire(); g_teclado->Release(); g_teclado = NULL; } // endif (g_teclado) // Liberação do objeto DirectInput g_DirectInput->Release(); g_DirectInput = NULL; } // endif (g_DirectInput) } // limpar_DirectInput().fim
2.8 Limpeza geral A função Limpar() faz uma limpeza geral chamando limpar_DirectInput() para limpar os objetos do DirectInput.
// Limpar() - Libera todos os objetos previamente inicializados // ----------------------------------------------------------------------------- VOID Limpar() { // Libera o objeto textura if( g_textura != NULL) g_textura->Release(); // Libera o objeto sprite if( g_sprite != NULL) g_sprite->Release(); // Libera objeto de mostrar texto if( gdxFonte != NULL) gdxFonte->Release(); // Libera o dispositivo gráfico if( g_device != NULL) g_device->Release(); // Libera o motor do Direct3D if( g_Direct3d != NULL) g_Direct3d->Release(); limpar_DirectInput(); } // Limpar().fim
2.9 Aspectos globais - Arquivo: entrada.cpp O destaque aqui é o handle da janela ( hJanela ) que saiu do escopo local da função WinMain() e foi para o escopo global pois é necessária na definição do nível de cooperação dos dispositivos criados.
//----------------------------------------------------------------------------- // Projeto: prj_Teclado01 - arquivo: entrada.cpp // Esta aplicação ilustra como utilizar o teclado via DirectInput // Produzido por www.gameprog.com.br //----------------------------------------------------------------------------- #include <windows.h> #include <d3d9.h> #include <d3dx9.h> #include "motor.h" // Variável global da classe da janela char sclasseJanela[ ] = "cls_directx"; // Dimensões da janela int g_xtela = 640; int g_ytela = 480; // alça da janela HWND hJanela; int WINAPI WinMain (HINSTANCE app_instancia, HINSTANCE app_anterior, LPSTR sComando,int nExibir) { // Estrutura de recepção das mensagens MSG mensagem; // Estrutura de descrição da janela WNDCLASSEX wcls; // Estrutura que descreve a janela wcls.hInstance = app_instancia; wcls.lpszClassName = sclasseJanela; wcls.lpfnWndProc = processaJanela; wcls.style = CS_HREDRAW | CS_VREDRAW; wcls.cbSize = sizeof (WNDCLASSEX); // O cursor e os ícones da aplicação são default wcls.hIcon = LoadIcon (NULL, IDI_APPLICATION); wcls.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wcls.hCursor = LoadCursor (NULL, IDC_ARROW); // Aplicação sem menu wcls.lpszMenuName = NULL; // Nada de espaço extra atrelado a classe da janela (wcls) wcls.cbClsExtra = 0; // Nada de espaço extra atrelado a janela wcls.cbWndExtra = 0; // Cor default da janela wcls.hbrBackground = ( HBRUSH) COLOR_BACKGROUND; // Registra a janela e retorna se esta operação falhar int status = RegisterClassEx (&wcls); if(status == 0) { MessageBox(NULL, "Registro falhou!", "WinMain()", MB_OK); return 0; } // endif // Com a classe criada pode-se criar a janela DWORD estiloExtra = 0; const char janelaTitulo[] = "prj_Teclado01"; DWORD controleEstilo = WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX; int xpos = 160; int ypos = 120; HWND hjanelaPai = HWND_DESKTOP; HMENU sem_menu = NULL; LPVOID dadoExtra = NULL; // Cria a janela hJanela = CreateWindowEx(estiloExtra, sclasseJanela, janelaTitulo, controleEstilo, xpos, xpos, g_xtela, g_ytela, hjanelaPai, sem_menu, app_instancia, dadoExtra ); // Verifica se janela foi criada if(hJanela == NULL) { MessageBox(NULL, "Falha na criação da janela!", "WinMain()", MB_OK); return 0; } // endif // Essa variável recebe informação de erro do Directx HRESULT hr; // Inicia o Direct3D hr = initGfx ( hJanela ); // Encerre a aplicação se houve falha if(FAILED (hr) ) { MessageBox (hJanela, "Direct3D: falha na inicialização", "WinMain()", MB_OK); UnregisterClass( sclasseJanela, wcls.hInstance); return E_FAIL; } // endif // Mostra a janela ShowWindow(hJanela, nExibir); UpdateWindow(hJanela ); // Rode a bombeamento de mensagens até GetMessage() retornar 0 while (GetMessage(&mensagem, NULL, 0, 0)) { // Traduz mensagem de tecla virtual em mensagem de caracteres TranslateMessage( &mensagem ); // Despacha a mensagem para a função processaJanela */ DispatchMessage( &mensagem ); } // endwhile // O valor de retorno é zero(0) passado por PostQuitMessage() UnregisterClass( sclasseJanela, wcls.hInstance); return mensagem.wParam; } // WinMain().fim
3. Código fonte do projeto de exemplo: prj_Teclado01
// Projeto: prj_Teclado01 - Arquivo: motor.h // Esta aplicação ilustra como utilizar o teclado via DirectInput #ifndef motor_h #define motor_h // Esta função inicializa o motor gráfico HRESULT initGfx (HWND hJanela); // Essa função libera os objetos utilizados void Limpar(); // Essa função desenha a cena void Renderizar(); // Esta função inicializa o objeto para mostrar texto void inicializarTexto(); // Esta função mostra um texto na coordenada (x, y) da janela void mostrarTexto( int x, int y, char* texto); // Inicializa a sprite void inicializarSprite(); // Desenha a sprite void renderizarSprite(); // Essa função inicializa o objeto DirectInput bool inicializar_DirectInput(); // Essa função inicializa o dispositivo de acesso ao teclado bool inicializar_Teclado(); // Essa função trata o pressionamento do teclado void tratarTeclado(); // Essa função libera os objetos do DirectInput void limpar_DirectInput(); // Declaração da função que atende as mensagens da janela LRESULT CALLBACK processaJanela (HWND hJanela, UINT mensagem, WPARAM wParam, LPARAM lParam); #endif
// ----------------------------------------------------------------------------- // Projeto: prj_Teclado01 - arquivo: motor.cpp // Esta aplicação ilustra como utilizar o teclado via DirectInput // Produzido por www.gameprog.com.br // ----------------------------------------------------------------------------- #include <windows.h> #include <d3d9.h> #include <d3dx9.h> #include <stdio.h> #include "motor.h" #include <dinput.h> // Inclui as bibliotecas do Direct3D #pragma comment(lib, "d3d9.lib") #pragma comment(lib, "d3dx9.lib") // Bibliotecas do DirectInput #pragma comment(lib, "dinput8.lib") #pragma comment(lib, "dxguid.lib") // Variáveis globais // Representa o dispositivo Direct3D LPDIRECT3D9 g_Direct3d = NULL; // Representa o dispositivo Renderizador IDirect3DDevice9* g_device = NULL; // Ponteiro para uma fonte do directx ID3DXFont* gdxFonte = NULL; // Essa variável recebe informação de erro do Directx HRESULT g_hr = 0; extern int g_xtela; extern int g_ytela; // Interfaces necessárias para a criação da sprite // A textura vai compor a imagem da sprite IDirect3DTexture9* g_textura = NULL; ID3DXSprite* g_sprite = NULL; // Argumentos necessários na criação da sprite // Posicionamento e recorte da sprite RECT g_recorte; // Posicionamento 3d da sprite D3DXVECTOR3* g_posicao = NULL; // Centro de apoio para rotações da sprite D3DXVECTOR3* g_centro = NULL; // Controle de movimentação da sprite int movimento_direcao = 1; int xpos = -240; int ypos = -160; // Constante para a cor branca const DWORD branco = 0xFFFFFFFF; // Ponteiro para o objeto DirectInput IDirectInput8* g_DirectInput = NULL; // Ponteiro para o dispositivo de teclado IDirectInputDevice8* g_teclado = NULL; // O DirectInput necessita de acesso à janela extern HWND hJanela; // initGfx() - Inicializa o Direct3D HRESULT initGfx( HWND hJanela ) { // Cria o objeto Direct3D que é necessário para criar o dispositivo gráfico g_Direct3d = Direct3DCreate9( D3D_SDK_VERSION); // Verifica se objeto Direct3D foi criado if(g_Direct3d == NULL) { MessageBox (NULL, "Falha na inialização do Direct3D", "InitGfx()", MB_OK); return E_FAIL; } // endif // Declara a variável para os parâmetros de apresentação D3DPRESENT_PARAMETERS pps; // Limpa a estrutura ZeroMemory( &pps, sizeof(pps) ); // Configura os parâmetros de apresentação // A aplicação vai ter janela pps.Windowed = TRUE; // Esse método vira rapidamente o backbuffer para a tela imediata pps.SwapEffect = D3DSWAPEFFECT_DISCARD; // Esse formato vai procurar se encaixar no modo de video corrente pps.BackBufferFormat = D3DFMT_UNKNOWN; // Configuração do renderizador a ser criado // Adaptador default (0) int nAdaptador = D3DADAPTER_DEFAULT; // Tipo de dispositivo Hardware ou emulador de referência (software) D3DDEVTYPE dispositivo_tipo = D3DDEVTYPE_HAL; // Flags de configuração do dispositivo DWORD create_flags = D3DCREATE_SOFTWARE_VERTEXPROCESSING; // Criamos aqui o dispositivo renderizador g_hr = g_Direct3d->CreateDevice( nAdaptador, dispositivo_tipo, hJanela, create_flags, &pps, &g_device ); // Verifica se houve falha no processo if( FAILED( g_hr ) ) { MessageBox (NULL, "Falha na criação: g_device", "initGfx()", MB_OK); return E_FAIL; } // endif inicializar_DirectInput(); inicializar_Teclado(); // Inicializa texto inicializarTexto(); // Inicializa sprite inicializarSprite(); return S_OK; } // initGfx().fim // inicializar_DirectInput() - Cria o objeto DirectInput bool inicializar_DirectInput() { // Criação do objeto DirectInput g_hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&g_DirectInput, NULL); if FAILED(g_hr) { MessageBox (NULL, "DirectInput: falha na criação", "inicializar_DirectInput()", MB_OK); return false; } // endif return true; } // inicializar_DirectInput().fim // inicializar_Teclado() - Essa função inicializa o teclado bool inicializar_Teclado() { // Criação do ponteiro para uma interface IDirectInputDevice8 g_hr = g_DirectInput->CreateDevice(GUID_SysKeyboard, &g_teclado, NULL); if FAILED(g_hr) { MessageBox (NULL, "g_DirectInput->CreateDevice() falhou.", "inicializar_Teclado()", MB_OK); limpar_DirectInput(); return false; } // endif // Configuração do formato de dados do dispositivo com uma constante // pré-definida de teclado do DirectInput ( c_dfDIKeyboard ) g_hr = g_teclado->SetDataFormat(&c_dfDIKeyboard); if FAILED(g_hr) { MessageBox (NULL, "g_teclado->SetDataFormat() falhou.", "inicializar_Teclado()", MB_OK); limpar_DirectInput(); return false; } // endif // Configuração do nível de cooperação DWORD cooperacao_flags = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE; g_hr = g_teclado->SetCooperativeLevel( hJanela, cooperacao_flags); if FAILED(g_hr) { MessageBox (NULL, "g_teclado->SetCooperativeLevel() falhou.", "inicializar_Teclado()", MB_OK); limpar_DirectInput(); return false; } // endif // Pega acesso ao dispositivo de entrada. g_hr = g_teclado->Acquire(); if FAILED(g_hr) { limpar_DirectInput(); return false; } // endif return TRUE; } // inicializar_Teclado().fim // tratarTeclado() - Essa função trata o pressionamento do teclado void tratarTeclado() { // Memória para coletar informação de estados do teclado char buffer[256]; // Obtém o status das teclas do teclado g_hr = g_teclado->GetDeviceState( sizeof(buffer), (LPVOID) &buffer); if FAILED(g_hr) { // Se falhou é porque o dispositivo foi provavelmente perdido. // Verifique se g_hr == DIERR_INPUTLOST // Se for, tente readquirí-lo aqui com g_teclado->Acquire(); return; } // endif // Macro para facilitar leitura do teclado #define KEYDOWN(name, key) (name[key] & 0x80) // Atualiza (xpos, ypos) conforme tecla pressionada if (KEYDOWN(buffer, DIK_RIGHT) ) xpos = xpos - 5; if (KEYDOWN(buffer, DIK_LEFT)) xpos = xpos + 5; if (KEYDOWN(buffer, DIK_UP) ) ypos = ypos + 5; if (KEYDOWN(buffer, DIK_DOWN) ) ypos = ypos - 5; } // tratarTeclado().fim // ----------------------------------------------------------------------------- // Renderizar() - Desenha a cena // ----------------------------------------------------------------------------- VOID Renderizar() { // Retorne se o dispositivo estiver nulo if( g_device == NULL) return; // String para mostrar posição da sprite char info[40]; tratarTeclado(); // Limpa o backbuffer com uma cor branca g_device->Clear( 0, NULL, D3DCLEAR_TARGET, branco, 1.0f, 0); // Começa a cena if( SUCCEEDED( g_device->BeginScene() ) ) { // Todo código de desenhar ocorre aqui dentro mostrarTexto (220, 160, "www.gameprog.com.br"); mostrarTexto (170,400, "Movimente a sprite com as setas."); // Mostra posicionamento da sprite sprintf (info, "( %i, %i )", xpos, ypos); mostrarTexto (10, 10, info); // Desenha sprite renderizarSprite(); // Finalizando a cena g_device->EndScene(); } // endif // Apresenta o conteúdo do backbuffer na tela g_device->Present( NULL, NULL, NULL, NULL); } // Renderizar().fim // limpar_DirectInput() - Libera os objetos do DirectInput void limpar_DirectInput() { if (g_DirectInput) { if (g_teclado) { // Liberação do teclado // Chame primeiro unacquire() antes de chamar Release(). g_teclado->Unacquire(); g_teclado->Release(); g_teclado = NULL; } // endif (g_teclado) // Liberação do objeto DirectInput g_DirectInput->Release(); g_DirectInput = NULL; } // endif (g_DirectInput) } // limpar_DirectInput().fim void inicializarSprite() { // Carrega e prepara textura 256 x 256 const char* stextura = "C:\\gameprog\\gdkmedia\\bitmap\\teste-transp.png"; g_hr = D3DXCreateTextureFromFile(g_device, stextura, &g_textura); if (FAILED(g_hr )) { MessageBox (NULL, "Textura: falha no carregamento", "inicializarSprite()", MB_OK); return; } // endif g_hr = D3DXCreateSprite (g_device, &g_sprite); if (FAILED(g_hr )) { MessageBox (NULL, "Sprite: falha na criação", "inicializarSprite()", MB_OK); } // endif // Posicionamento 3d não utilizado extensamente g_posicao = &D3DXVECTOR3(0.0f, 0.0f, 0.0f); g_centro = &D3DXVECTOR3(0.0f, 0.0f, 0.0f); } // inicializarSprite().fim void renderizarSprite() { // Cor difusa da sprite DWORD cor_difusa = branco; // Indica o ponto de corte da sprite int direita = 128; int fundo = 120; // Configuração posição de colocação da sprite na tela // o ponto de corte da textura SetRect(&g_recorte, xpos, ypos, direita, fundo); // Inicia a renderização considerando efeito de transparência g_sprite->Begin (D3DXSPRITE_ALPHABLEND); // Renderiza sprite conforme configuração previamente definida g_sprite->Draw(g_textura, &g_recorte, g_centro, g_posicao, cor_difusa); // Finaliza processo de renderização de sprites g_sprite->End(); } // renderizarSprite().fim // Esta função é chamada por DispatchMessage() LRESULT CALLBACK processaJanela (HWND hJanela, UINT mensagem, WPARAM wParam, LPARAM lParam) { switch (mensagem) { case WM_DESTROY: // Coloca uma mensagem WM_QUIT na fila de mensagem Limpar(); PostQuitMessage (0); break; case WM_KEYDOWN: if (wParam == VK_ESCAPE) { Limpar(); PostQuitMessage( 0); } // endif // tratarTeclado ( wParam ); break; // Essa mensagem vai ocorrer a todo momento case WM_PAINT: // Renderiza a cena Renderizar(); // Invalida a tela para chamar WM_PAINT novamente InvalidateRect( hJanela, NULL, false); break; // Processamento default de mensagens não tratada pela aplicação default: return DefWindowProc (hJanela, mensagem, wParam, lParam); } // endswitch return 0; } // processaJanela().fim void inicializarTexto() { // Altura int nAltura = 24; // Largura UINT nLargura = 0; // Peso ( weight ) UINT nPeso = FW_BOLD; // Nível de mipmap - 0: mipmap automático UINT nMipmap = 0; // Efeito itálico bool bItalico = false; // Conjunto de caracteres (charset) DWORD nCharset = DEFAULT_CHARSET; // Precisão (OutputPrecision) DWORD nPrecisao = OUT_DEFAULT_PRECIS; // Qualidade DWORD nQualidade = DEFAULT_QUALITY; // Pitch e família DWORD nFamilia = DEFAULT_PITCH | FF_DONTCARE; // Nome da fonte char* sFonte = "Arial"; g_hr = D3DXCreateFont( g_device, nAltura, nLargura, nPeso, nMipmap, bItalico, nCharset, nPrecisao, nQualidade, nFamilia, sFonte, &gdxFonte ); if(FAILED (g_hr) ) MessageBox(NULL, "Texto: falha na inicialização", "inicializarTexto()", MB_OK); } // inicializarTexto().fim void mostrarTexto(int x, int y, char* texto) { // Retorne se não houver fonte inicializada if(gdxFonte == NULL) return; // Cor de fundo da janela D3DCOLOR azul = D3DCOLOR_XRGB(0, 0, 255); RECT area_limite; SetRect( &area_limite, x, y, g_xtela, g_ytela ); gdxFonte->DrawText( NULL, texto, -1, &area_limite, 0, azul ); } // mostrarTexto().fim // Limpar() - Libera todos os objetos previamente inicializados // ----------------------------------------------------------------------------- VOID Limpar() { // Libera o objeto textura if( g_textura != NULL) g_textura->Release(); // Libera o objeto sprite if( g_sprite != NULL) g_sprite->Release(); // Libera objeto de mostrar texto if( gdxFonte != NULL) gdxFonte->Release(); // Libera o dispositivo gráfico if( g_device != NULL) g_device->Release(); // Libera o motor do Direct3D if( g_Direct3d != NULL) g_Direct3d->Release(); limpar_DirectInput(); } // Limpar().fim
//----------------------------------------------------------------------------- // Projeto: prj_Teclado01 - arquivo: entrada.cpp // Esta aplicação ilustra como utilizar o teclado via DirectInput // Produzido por www.gameprog.com.br //----------------------------------------------------------------------------- #include <windows.h> #include <d3d9.h> #include <d3dx9.h> #include "motor.h" // Variável global da classe da janela char sclasseJanela[ ] = "cls_directx"; // Dimensões da janela int g_xtela = 640; int g_ytela = 480; // alça da janela HWND hJanela; int WINAPI WinMain (HINSTANCE app_instancia, HINSTANCE app_anterior, LPSTR sComando,int nExibir) { // Estrutura de recepção das mensagens MSG mensagem; // Estrutura de descrição da janela WNDCLASSEX wcls; // Estrutura que descreve a janela wcls.hInstance = app_instancia; wcls.lpszClassName = sclasseJanela; wcls.lpfnWndProc = processaJanela; wcls.style = CS_HREDRAW | CS_VREDRAW; wcls.cbSize = sizeof (WNDCLASSEX); // O cursor e os ícones da aplicação são default wcls.hIcon = LoadIcon (NULL, IDI_APPLICATION); wcls.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wcls.hCursor = LoadCursor (NULL, IDC_ARROW); // Aplicação sem menu wcls.lpszMenuName = NULL; // Nada de espaço extra atrelado a classe da janela (wcls) wcls.cbClsExtra = 0; // Nada de espaço extra atrelado a janela wcls.cbWndExtra = 0; // Cor default da janela wcls.hbrBackground = ( HBRUSH) COLOR_BACKGROUND; // Registra a janela e retorna se esta operação falhar int status = RegisterClassEx (&wcls); if(status == 0) { MessageBox(NULL, "Registro falhou!", "WinMain()", MB_OK); return 0; } // endif // Com a classe criada pode-se criar a janela DWORD estiloExtra = 0; const char janelaTitulo[] = "prj_Teclado01"; DWORD controleEstilo = WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX; int xpos = 160; int ypos = 120; HWND hjanelaPai = HWND_DESKTOP; HMENU sem_menu = NULL; LPVOID dadoExtra = NULL; // Cria a janela hJanela = CreateWindowEx(estiloExtra, sclasseJanela, janelaTitulo, controleEstilo, xpos, xpos, g_xtela, g_ytela, hjanelaPai, sem_menu, app_instancia, dadoExtra ); // Verifica se janela foi criada if(hJanela == NULL) { MessageBox(NULL, "Falha na criação da janela!", "WinMain()", MB_OK); return 0; } // endif // Essa variável recebe informação de erro do Directx HRESULT hr; // Inicia o Direct3D hr = initGfx ( hJanela ); // Encerre a aplicação se houve falha if(FAILED (hr) ) { MessageBox (hJanela, "Direct3D: falha na inicialização", "WinMain()", MB_OK); UnregisterClass( sclasseJanela, wcls.hInstance); return E_FAIL; } // endif // Mostra a janela ShowWindow(hJanela, nExibir); UpdateWindow(hJanela ); // Rode a bombeamento de mensagens até GetMessage() retornar 0 while (GetMessage(&mensagem, NULL, 0, 0)) { // Traduz mensagem de tecla virtual em mensagem de caracteres TranslateMessage( &mensagem ); // Despacha a mensagem para a função processaJanela */ DispatchMessage( &mensagem ); } // endwhile // O valor de retorno é zero(0) passado por PostQuitMessage() UnregisterClass( sclasseJanela, wcls.hInstance); return mensagem.wParam; } // WinMain().fim

index << >>

Produzido por Gameprog: Jair Pereira - Agosto/2014 © gameprog.br@gmail.com http://www.gameprog.com.br