Categorias
Usando DirectDraw com Delphi
Isso mostra como começar a utilizar a biblioteca DirectX em programas Delphi e, em seguida, demonstra uma simples aplicação utilizando a biblioteca freeware DelphiX.
Se você já tentou fazer um output de tela rápido no Windows, você sabe que isso não é uma tarefa fácil. Com todos os truques possíveis lamentavelmente ela ainda fica muito aquém das velocidades de jogo comercial. Mas eu vou mostrar-lhe como utilizar o DirectX no seu aplicativos para fazer um bom e rápido output que pode ser cronometrado em microssegundos, não em minutos!
Há alguns anos, os desenvolvedores da Microsoft perceberam que o Windows não era uma plataforma de jogos e eles juraram mudar esta situação. Em 1995, o fugaz Wing apareceu. Isto permitiu rápido output em modos 256 cores nos Win 3.1 e Win 95. Era rápido, mas limitado, e em breve substituído por DirectX. Esta é uma família de APIs para rápidos inputs e outputs. Seus aplicativos podem usar placas de vídeo, placas de som e até mesmo joysticks através do DirectX. Vou olhar para o visual do API DirectDraw e voltar para os outros no futuro. Outros APIs DirectX incluem DirectSound para placas de som, DirectInput para joysticks etc, Direct3D para gráficos 3D e DirectPlay para multi-jogadores. Embora o DirectX esteja agora na versão 6.1, DirectDraw tem sido praticamente inalterada desde a versão 3. A propósito, a versão 3 é a versão construída no Win NT 4.0.
A força do Windows é que ele trabalha com vários monitores, placas de vídeo e em várias profundidades de resoluções e cores diferentes. Isso requer uma grande quantidade de código entre o Aplicativo e hardware da placa de vídeo e este "Thick Api 'é o motivo pelo qual as rotinas de output do Windows são lentas. Isto também acontecia com Dos quando ele apareceu pela primeira vez, e os desenvolvedores de jogos foram direto para o metal em vez de utilizar as rotinas BIOS ou DOS API. Até dois anos atrás, a maioria dos jogos ainda eram escritos para Dos, mesmo aqueles executados no Windows 95. Agora, provavelmente 99% utilizam DirectX e em breve parece que os micros Windows CE terão máquinas de jogos (árcades) comerciais utilizando o DirectX.
DirectX / DirectDraw suporta uma fina aproximação API com poucas camadas entre o hardware e o seu Aplicativo. O DirectX é construído sobre COM, o Component Object Model, para que novas versões possam ser liberadas sem quebrar seu código existente. Se o seu Aplicativo funciona com o DirectX versão 5, é garantido que funcionará com o DirectX 6, 7 ... 308!
DirectDraw fornece informações para o seu Aplicativo sobre o que caracteriza o hardware de vídeo ou da placa de som tem, e qual é emulado por software. Esta abordagem DirectX garante que o software funcionará em placas ainda não concebidas e será capaz de utilizar os seus recursos avançados. Em contrapartida, isso significa que você tem que escrever duas ou três maneiras diferentes de fazer as coisas e escolher o melhor (= mais rápido) método em tempo de execução.
DirectX e Delphi
Embora C e C + + sejam as principais linguagens para DirectX, o Delphi é muito adequado para IR. Blake Stone fez a primeira tradução do cabeçalho DirectX para C e o Borland do Charlie Calvert tem falado sobre o tema em seus livos Delphi 2 / 4 'Unleashed'. Sr. Hiroyuki Hori no Japão desenvolveu o DelphiX - um excelente conjunto de componentes Delphi gratuitamente para o DirectX. Estes estão disponíveis em muitos sites na internet ou na sua página em http://www.ingjapan.ne.jp/hori/. Você também terá que instalar o DirectX versão 5 ou superior. Provavelmente você já pegou no seu sistema se você já tiver comprado um jogo no último ano. O Windows 98 e o futuro NT5 vêm com DirectX incluído. O NT 4, Service Pack 3 também suporta DirectX 3.0.
Agora eu vou lhe mostrar o essencial da programação do DirectDraw e como aproveitar ao máximo os componentes do DelphiX com um Aplicativo exemplo. Se você usa DelphiX, você verá que os arquivos de ajuda do Sr. Hori talvez não sejam totalmente claros, mas você obtém o código fonte completo e um grande número de boas amostras de programas para superar isto. DelphiX é uma excelente peça de software e você pode escrever jogos de qualidade perto de arcade em Delphi utilizando-o.
Mesmo se você não for muito de jogos de programação, o excesso de velocidade que o DirectDraw oferece permite que você crie aplicativos com o output gratuito flicker de alta velocidade, como displays de radar, osciloscópios, percorrer mapas, etc. Eu usei-o para mover um mapa e ele desenha uma tela cheia hexágonos de 256 cores em resolução 1024 x 768 (cada hex se encaixa em um retângulo de 32 pixels de largura por 34 de profundidade) em 26 ms em um P2 300 equipado com uma placa AGP Matrox Millennium. Isso é quase 40 frames por segundo, nada mal para Delphi...
Em DirectDraw, a Microsoft também não chucked out o GDI. Uma das grandes dores de cabeça dos desenvolvedores de jogos em Dos foi saída de texto, particularmente tendo que criar suas próprias fontes ou mensagens bitmaps. Felizmente, o GDI trabalha com o DirectDraw para que as fontes TrueType possam ser usadas. Na verdade a maior parte dos GDI funcionam, desde que seja tomado um pouco de cuidado. Claro que o output GDI não é muito rápido, por isso você deve realmente usá-lo apenas para a criação de texto, menus, etc.
Primeiros passos
Você vai precisar dos arquivos header do DirectX - não há lugar melhor do que a biblioteca DelphiX. O Directx.pas oferecido tem um tamanho gritante de 300Kb. Inclui todos os registros APIs, DirectSound, etc. Se você esteve pensando no Gobi durante os últimos cinco anos, talvez você não esteja familiarizado com GUIDs, mas eles são simplesmente uma coleção de números como este [ '(5C690320-0BD2 -11D3-89DF-00409545E8E7) '] que identificam objetos e classes no Windows. A Microsoft cuidadosamente coloca GUIDs contendo as suas placas de rede Endereço Mac em todos os arquivos do Word e Excel criados no seu PC. Se você der um Ctrl Shift-G no Delphi Ide, os últimos 12 dígitos do GUID gerados são o Mac Endereço das suas placas de rede (se você tiver uma placa de rede).
DirectDraw não é tão difícil de se trabalhar, só um pouco demorado em alguns locais. Aqui está o meu guia de cinco pontos para novatos para você começar. Primeiro crie um objeto DirectDraw. Isto representa uma placa de vídeo / monitor set-up, e no Windows 98 irá suportar vários dispositivos. Esta é a definição de DirectDrawCreate.
function DirectDrawCreate
(lpGUID: PGUID;
out lplpDD: IDirectDraw;
pUnkOuter: IUnknown): HRESULT;
Em qualquer lugar que existir um parâmetro pUnkOuter, apenas passe nulo. Este apelo deve retornar um valor DD_OK (= 0). Qualquer outra coisa é um erro e deve ser tratado pelos seu código...
Etapa dois é especificar o nível de cooperação. Será que quer toda a tela exclusiva ou compartilhá-la? A maioria dos jogos são executados em modo de tela cheia para que o seu aplicativo possa escolher o modo de tela e resolução usada. Se você usá-lo em uma janela ,seu aplicativo não deve alterar o modo.
O parâmetro dwFlags permite que você especifique se você quer usar tela cheia ou não, ou se o seu aplicativo controla a tela de forma que nenhum outro aplicativo possa alterá-lo e até mesmo se o usuário pode dar um Ctrl + Alt + Del para reiniciar.
function SetCooperativeLevel(hWnd: HWND; dwFlags: DWORD): HRESULT;
É possível pedir ao objeto DirectDraw por todos os modos de vídeo suportados. A maioria das placas de vídeo suporta vários modos, mas os modos de maior freqüência / cor podem necessitar maior largura de banda do que o seu monitor pode suportar. Mudar para estes modos não vai funcionar e poderá deixar o monitor em um estado não sincronizado, por isso não se esqueça de incluir uma declaração de exoneração de responsabilidade quando você distribuir seus aplicativos! Melhor ainda, faça com que o usuário escolha a modalidade a partir de uma lista. Quake e muitos jogos utilizam essa abordagem.
Passo 3 é definir o modo da tela. Isso se aplica somente se você quiser acessar a tela cheia.
function SetDisplayMode(dwWidth, dwHeight, dwBpp: DWORD): HRESULT;
dwBpp é bits por pixel, ou seja, 8 para 256 cores. 640x 480 por 8 é provavelmente uma aposta segura em qualquer PC!
Etapa 4 é onde as superfícies são criadas. Todas as imagens são realizadas em superfícies. Estes são apenas blocos de ram com uma paleta opcional e o seu aplicativo pode criar superfícies no principal sistema de RAM do PC, ou na placa de vídeo ram. Nenhum prêmio para adivinhar que imagens em vídeo ram são mais rápidas para copiar para vídeo ram, embora placas AGP podem mover os dados do seu PC ram muito rapidamente.
CreateSurface creates a surface according to the surface description parameter.
function CreateSurface(const lpDDSurfaceDesc: DDSURFACEDESC;
out lplpDDSurface: IDirectDrawSurface; pUnkOuter: IUnknown): HRESULT;
A superficie principal representa a tela e é conhecida como Primary Surface. Atualizar isto diretamente pode levar à exibição da captura de imagens enquanto elas são desenhadas. Isto dá um efeito de corte e você pode evitá-lo usando outro bloco de vídeo ram como um back buffer. O Primary Surface sempre é exibido, mas o seu aplicativo sempre escreve para o back- buffer e, em seguida, chama o método flip. Isso faz com que os conteúdos de Primary Surface e Back Buffer troquem de posições e agora o seu monitor mostra a nova imagem Esse é o segredo da boa animação de computador e pode acontecer até 70 vezes por segundo.
A Primary Surface de 1024 x 768 em 256 cores mais um back buffer pega 1.5Mb de memória RAM de vídeo. Então, uma placa de vídeo com 4Mb de vídeo-ram terá apenas 2.5Mb de sobra para armazenar suas imagens. Você poderá preferir atribuir um grande bloco de memória ram no PC principal, fazer todas as manipulações neste e, em seguida, copiar a superfície da placa de vídeo para ser exibida. Existem muitas técnicas para otimizar a velocidade de updates e parte da diversão é experimentá-las. Seguir a pista de qual bit da tela mudou e copiar apenas esse bit é uma maneira de minimizar o tráfego. Nem todo mundo tem AGP então você deve testar seu aplicativo no maior número de sistemas possível.
Isso é realmente tudo que existe. Passo 5 é sentar e pensar – uau - agora eu posso usar o DirectDraw. Existem apenas algumas complexidades menores como pegar as imagens a partir de arquivos bitmap ou recursos em uma superfície DirectDraw. O bitmap tem que ser carregado na memória e depois copiado de volta para o buffer... Bitmaps do Windows contêm uma paleta e são normalmente armazenados de cabeça para baixo. Você pode se divertir codificando-os você mesmo ou usar os componentes da biblioteca do DelphiX para gerenciar os bitmaps e a paleta.
O acesso direto ao vídeo Ram
Se o seu Aplicativo tem que modificar pixels diretamente na memória de vídeo, então você deve especificar uma área retangular, chamar o bloqueio para obter acesso exclusivo à ram, alterar ou ler os pixels e finalmente chamar o desbloqueio para liberá-lo. Os códigos de bloqueio e desbloqueio deverão ser mantidos curtos quando o Windows está parado.
Veja a tonalidade!
Cada superfície tem uma tonalidade. É a largura ajustada em bytes. Se você manipular imagens ao nível byte, você deve estar ciente disto. O tom de uma superfície é muitas vezes diferente da largura. Cada linha de pixel começa com "tons" de bytes a partir do anterior. Isso pode acontecer porque a largura é um número ímpar de bytes e o tom arredonda para a palavra dupla mais próxima ou é apenas a maneira como a sua placa de vídeo faz. A largura pode ser 105, mas talvez o tom poderia ser 108. A primeira linha é de 0 bytes desde o início, a próxima 108, depois 216 e assim por diante.
GDI
Usar o GDI não é um grande problema. O GDI está um pouco preso em suas formas e sempre usa o mesmo bloco de vídeo ram. Isto significa que um sistema de mensagem (como uma exceção não tratada) pode não aparecer se você estiver usando um virador de página e exibindo o outro bloco de ram. No entanto, você pode chamar fliptoGDI para fazer a Primary Surface ser GDI GetGDISurface ou para obter um ponteiro para o objeto da superfície.
Perder os seus dados
Perder imagens em vídeo é um problema menor se o usuário faz um Alt-Tab. Tudo está perdido. No entanto, o DirectX mantém um registro dos status "perdido" de superfícies e dará um 'erro "Surface Lost se tentar utilizá-lo. Seu aplicativo deve ter um manipulador para recriar as superfícies e recarregar as imagens de volta.
Os inconvenientes ....
A principal deles é que os aplicativos de depuração da tela cheia do DirectX são complicados. Acessar memória de vídeo é feito parando o Windows temporariamente. A não ser que você esteja muito confortável em trabalhar num nível mais baixo, isto pode ser um passeio em território SoftIce, não há nenhuma maneira que você possa passar através do seu código entre um par bloqueio... desbloqueio. Uma forma de arredondar isso é utilizar um processo de despejo de parâmetros strings para anexar um arquivo de log, ou depurar uma janela como na Gexperts.
Se você sabe C ou C + + é claro que a Microsoft fornece um DirectDraw SDK gratuito, com muitos exemplos e provavelmente o mais informativo arquivo de ajuda que eu já vi. Eu recomendo o livro da Microsoft “Inside DirectX” para todas as informações de background sobre o DirectX. Microsoft Press; ISBN: 1572316969. Um livro alternativo é o Windows Game Programming for Dummies, por Andre Lamothe, editora IDG Books Worldwide Inc; ISBN: 0764503375, mas, de novo. está baseado em C / C + +.
Delphix
Tendo aprendido como fazer coisas simples de DirectDraw em Delphi, agora você tem uma escolha, desenvolver os seus próprios componentes ou usar aqueles definidos para você – como o DelphiX. Não tenho nenhuma ligação com o autor, exceto admiração por um excelente trabalho e sua generosidade em distribuí-lo. Se você é novo no DelphiX, ele pode ser um pouco demais, e eu sugiro que você imprima as amostras e as demonstrações e estude-as em detalhe. Aqui está a minha visão sobre como utilizá-los.
Um TdxForm é um formulário modificado que deve ser usado como o formulário antecessor, não o TForm – ele faz algum movimento de mensagens, incluindo as exceções de movimentações e mudam a superfície primária GDI para que você veja mensagens. Uma componente DxDraw é deixado sobre ele e as propriedades definas para resolução e profundidade de cor. Este evento tem movimentadores que lidam com o objeto de inicialização e que encerramento. Estes manipuladores são onde seu aplicativo deve fazer o seu carregamento de imagens e de preparação para o loop do jogo.
O principal loop do jogo é na verdade um evento manipulador impulsionado por um temporizador. O temporizador mantém registro de qualquer desfasamento, para que possamos ver se seu código está levando muito tempo para ser executado.
Existen componentes imagelist e imagem que lhe permitem criar imagens bitmap em um tempo designado e você pode especificar em qual tipo de ram (sistema PC ou vídeo), as imagens são colocadas.
Um manipulador RestoreSurface é fornecido para que o seu aplicativo possa recarregar as imagens após o usuário dê um Alt-Tab e perca o conteúdo ram do vídeo.
A classe TDirectDrawSurface implementa cerca de todas as funcionalidades de superfície DirectX. As superfícies podem ser criadas em qualquer lugar, com qualquer tamanho e as imagens são rapidamente blitted com escala e rotação opcional entre superfícies. A maioria das placas de vídeo têm um hardware blitter e o DirectDraw vai usar isso. As imagens raramente são retangulares, mas são sempre definidas em um bloco retangular. Uma rotina de um mapa desenhado chama 150 hexágonos em menos de 4 ms ou seja, cada um leva cerca de 26 microssegundos.
A criação de um back-buffer é feita automaticamente se a opção Dxdraw.Doflip for verdadeira. Note que a saída vai para o back- buffer nesse caso, e você não verá nada até que dxdraw.flip é chamado. Se a opção Doflip for falsa, como em executar em uma janela, o output vai direto e você não precisa chamar dxdraw.flip (embora isso não faz nenhum dano).
O Código de Radar.Exe.
Em 370 linhas de código, escrevi uma pequena simulação de aeronaves voando em direções aleatórias, isto é uma funcionalidade esqueleto, então não espere uma detecção de colisão ou explosões! As teclas são ESC para sair, 'A' para adicionar um avião e Alt-1, 2 ou 3 para mudar para maiores resoluções de tela de 640 por 480, 800 x 600 e 1024 x 768.
Os aviões voam em três cores diferentes aleatoriamente em toda a tela a níveis de velocidades ligeiramente diferentes e alguns vão piscar. Há 25 para começar, mas mantenha pressionada a tecla A e os números vão aumentar rapidamente. Os aviões são mostrados como retângulos em torno da tela co-ordenada e este texto é produzido pela rotina Gdi TextOut; isto atrasa um pouco as coisas. Para ver o efeito disso, experimente com 100 aeronaves em seguida, comente as referidas linhas abaixo no método tPlane.MovenDraw e execute novamente. Tudo o que será mostrado é a moldura envolvente. Esta é uma montagem feita por código, eu estava apenas sendo exibicionista!
if fflashcount >=0 then
with fdxdraw.Surface.Canvas do
begin
brush.color := fcolor;
str := inttostr(fx)+inttostr(fy);
textout(fx,fy,str);
release;
end;
Note, a utilização da liberação neste trecho de código. Este é um método do TDirectDrawSurface e libera a movimentação do subjacente Display Context. Qualquer hora que você usar um Gdi você deve pedir uma liberação.
Agora você pode ter muito mais aeronaves (bem, frames retangulares) voando sem problemas em torno da tela. Vale a pena tentar ativar e desativar para ver se isso faz alguma diferença.
Como Funciona.
Grande parte do trabalho burro é feito através da definição de propriedades no componente DXDraw .- por exemplo, Resolução da tela, tela cheia ou minimizada, doFlip, etc, etc.
Eu uso um tstringlist para deter todos os objetos aeronaves. Estes são criados com coordenadas e direções de movimentos aleatórios. No manipulador de temporizador, todos os aviões são movidos por cada frame aleatoriamente especificando deslocamentos x e y, fora do campo, saindo das bordas da tela. A tela é limpada e todos os aviões redesenhados a cada vez.
O texto, no canto superior esquerdo mostra quantos aviões estão na tela e atrasados. Um valor normal para os atrasados é 1. Tudo é produzido em um frame. Se isso vai para 2 ou mais (aperte a tecla A), o movimento da aeronave torna-se irregular, uma vez que está levando mais tempo do que um período de frame para sair. Tente evitar isto!
O método DrawFrame não utilizado desenha o frame de retângulos em branco e é muito rápido. Tanto isto como o método Drawrect não utilizado são bons exemplos de vídeo ram acessando diretamente através de bloqueio e desbloqueio... e ambas as rotinas usam o membro tonalidade da Surface Descriptor (DDS) para mover para baixo a partir de uma linha de pixel para a próxima.
Notas para Usuários Delphi 4,0 e NT 4.0
Existem duas versões disponíveis do DelphiX e ambas irão trabalhar com Delphi 3.0, o primeiro tem um menor arquivo Zip (606Kb). O segundo (841Kb) tem algum código Delphi 4.0 específico (sobrecarregando e padronizando parâmetros) e suporta DirectX 6, mas programas incluídos não serão executados no Win NT 4,0- em vez disso, você irá obter o erro "Interface não suportada". Use a versão anterior, nesse caso.
---------------------
O arquivo zip incluí arquivos fonte, mas não o código DirectX. Isto pode ser baixado em http://www.yks.ne.jp/~hori/DelphiX-e.html ou em vários outros lugares.
O arquivo para este artigo pode ser baixado aqui - ddraw.ZIP