| Artículos | 01 SEP 2000

Fondos y profundidad

Tags: Histórico
Introducción a DirectDraw (y IV)
Francisco Charte.
Dedicamos esta última entrega a la gestión de fondos de grandes dimensiones y la creación de efectos de profundidad.

Los ejemplos propuestos en este curso han ido ganando en complejidad poco a poco hasta llegar a la demostración final de la entrega anterior a ésta, en la que teníamos un fondo estático con una figura, concretamente una pelota, rebotando por la pantalla. Para llegar a eso, previamente aprendimos a detectar los dispositivos disponibles para DirectDraw, los modos gráficos permitidos, a crear superficies, copiarlas e intercambiarlas, etc.
En esta entrega final, usando los mismos objetos y métodos que ya conocemos, nos centraremos en el trabajo con fondos y en la importancia del orden en el eje Z para dar sensación de profundidad. Nuestro único fondo, hasta el momento, era un mapa de bits que tenía las mismas dimensiones que el modo gráfico seleccionado y, por tanto, aparecía estático. En dicho ejemplo siempre copiábamos primero el fondo y, después, la figura de la pelota. Esto permitía que la pelota apareciese sobre el fondo y no al revés, de tal forma que, visualmente, el fondo quedaba detrás de la pelota.

¿Cuánta memoria hay disponible?
Actualmente las tarjetas gráficas suelen contar con 8 megabytes o más de memoria, una cantidad que, en la mayoría de los casos, será suficiente para almacenar una superficie visible, otra oculta y algunas figuras. Cuando se trabaja con grandes superficies, sin embargo, hay que tener en cuenta que la memoria disponible puede no ser suficiente.
La interfaz IDirectDraw7 cuenta con un método, llamado GetCaps(), cuya finalidad es obtener información tanto del hardware gráfico como de la capa de emulación de DirectX. Entre los datos recuperados encontramos el total de memoria disponible en el adaptador para DirectX y la parte que está actualmente libre, no utilizada por superficies. Los datos a facilitar a ese método son dos estructuras DDCAPS. Los datos que nos interesan estarán en los miembros lVidMemTotal y lVidMemFree.
Hay que tener en cuenta que una parte de la memoria del adaptador está siempre ocupada con la imagen mostrada en pantalla. Esa cantidad está ya restada de los datos que devuelve GetCaps(). Lógicamente, la cantidad de memoria utilizada dependerá de la resolución y profundidad de color actuales. Por ello, los valores devueltos por el método anterior serán distintos si previamente activamos modos de vídeo diferentes.
El simple código siguiente, escrito con Delphi, mostraría una ventana con la cantidad de memoria que tiene el adaptador disponible para la creación de superficies, asumiendo que hasta ahora no hemos definido ninguna. En la Figura 1 se puede ver un ejemplo del resultado que se obtendría: la cantidad de memoria en bytes.
var
DD7: DirectDraw7;
hwCaps, helCaps: DDCAPS;
begin
DirectX.DirectDrawCreate(‘’, DD7);
// obtenemos capacidades del adaptador
DD7.GetCaps(hwCaps, helCaps);
// Mostramos los datos obtenidos
ShowMessage(
‘Memoria total: ‘ +
IntToStr(hwCaps.lVidMemTotal) +
#13#10 + ‘Memoria libre: ‘ +
IntToStr(hwCaps.lVidMemFree));
Algunos adaptadores no tratan toda la memoria por igual, sino que reservan ciertas partes para texturas, otras para superficies de intercambio, etc. En este caso, para conocer cuál es la cantidad de memoria disponible para un cierto tipo de recurso utilizaríamos el método GetAvailableVidMem() de la interfaz IDirectDraw7.
Si el adaptador no contase con memoria suficiente para almacenar los mapas de bits que necesitemos, siempre existe la alternativa de utilizar la memoria del sistema. DirectX está preparado para aprovechar la velocidad de transferencia de los actuales buses AGP pero, a pesar de todo, nunca se obtendrá el rendimiento que tendríamos con todas las superficies alojadas en la memoria del adaptador.

Desplazamiento de una superficie grande
Suponga que va a diseñar un programa en el que un cierto personaje va a desplazarse por un fondo, concretamente un muro sobre el cual aparecerá un cielo azul con algunas nubes. Este fondo será móvil, de tal forma que no sólo se moverá el citado personaje sino que también lo hará el propio fondo. En principio, vamos a centrarnos en el desplazamiento del fondo olvidándonos por ahora del personaje.
Lo primero que tenemos que hacer es dibujar el fondo. Éste tendrá unas dimensiones de 1.024 por 480 puntos, siendo nuestro objetivo trabajar con una resolución de 640 por 480 puntos. Esto significa que el fondo será más grande que el propio ancho de la pantalla, de tal forma que nunca será visible totalmente. En la Figura 2 se puede ver el fondo completo abierto en Paint.
Para recuperar esta imagen de fondo utilizaríamos el mismo método CreateSurfaceFromFile() que conocemos y hemos usado en ejemplos de entregas previas. Como sabemos, tenemos que preparar una estructura DDSURFACEDESC2 con los atributos de la superficie a crear, recuperando un puntero a su interfaz IDirectDrawSurface7.
A la hora de dibujar este fondo en pantalla, es necesario tener en cuenta que sus dimensiones son mayores; en este caso es más ancho que la propia pantalla. Deberemos tener, por tanto, un índice horizontal que nos indique a partir de qué punto tenemos que comenzar a copiar, punto de inicio al que sumaríamos el número de puntos de la propia pantalla. Así, en principio se copiaría a la superficie de pantalla el área que va desde el punto 0 hasta el 639, después del 1 al 640, del 2 al 641, etc.
Llegará un momento, a medida que vayamos desplazando la imagen, en que no tengamos fondo suficiente para llenar la pantalla. Cuando el punto de inicio sea 380 el de fin será 1.019, y cuando sea 385 estaríamos en el punto 1.024 de final. En la Figura 3 se puede ver representada gráficamente la situación. Cuando el punto de inicio sea el 400, el de fin irá más allá del final del fondo. En este momento tendríamos que añadir un trozo del principio, sólo lo suficiente para completar el resto del espacio en pantalla.

Una demostración práctica
La teoría anterior es lo que nos hace falta para poder poner en práctica la composición de una escena en la que un fondo grande se desplaza horizontalmente. Aunque en principio pueda parecer algo complejo, se trata tan sólo de unos cálculos simples en los que intervienen unas sumas y restas; así de fácil.
Partiendo de la imagen mostrada en la Figura 2, lo primero que haríamos sería iniciar DirectDraw y crear dos superficies del tamaño de la pantalla, una visible y otra oculta, además de una tercera que tendría las dimensiones del fondo. Éste se recuperaría con el citado método CreateSurfaceFromFile() y, en principio, sería la única fuente que usaríamos con el método BltFast() para copiar algo en la superficie oculta.
Observe, en el Listado 1 correspondiente a un fragmento de este programa, cómo se comprueba si la variable dX, que es la que establece el punto de inicio de copia sobre el fondo, es superior a 384. La resolución horizontal de la pantalla es de 640 puntos, a los que si sumamos 384 nos da como resultado 1.024, que es el ancho de nuestra imagen. Este valor clave, 384, es el que nos indica si queda parte de la pantalla sin un fondo dibujado, caso en el que hay que añadir un trozo del inicio, creando así un efecto rotatorio.
Fíjese también en cómo inc

Contenidos recomendados...

Comentar
Para comentar, es necesario iniciar sesión
Se muestran 0 comentarios
X

Uso de cookies

Esta web utiliza cookies técnicas, de personalización y análisis, propias y de terceros, para facilitarle la navegación de forma anónima y analizar estadísticas del uso de la web. Consideramos que si continúa navegando, acepta su uso. Obtener más información