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