jueves, julio 20, 2006

MMmm... Que lío de conceptos y versiones!

Últimamente con la vorágine de novedades que Microsoft nos está obsequiando al respecto de DirectX, hay cantidad de conceptos que están un poco liados (o al menos eso me parece a mi). Después de navegar por esos mundos de dios, he llegado a las siguientes conclusiones:

  1. DirectX: El inicio de todo. Un conjunto de APIs para la programación de videojuegos y aplicaciones multimedia de alto rendimiento en Windows. Su versión actual es la 9.0c.

  2. .NET: Es complicado definir que és .NET. Para nuestros propósitos la podemos entender como la plataforma de desarrollo y ejecución de aplicaciones de Microsoft. Actualmente se encuentra en su versión 2.0. .NET se instala sobre Windows como un componente de sistema más, y es imprescindible para la ejecución de aplicaciones .NET (conocidas como aplicaciones managed).

  3. MDX 1.1: Es la versión de DirectX 9 para la plataforma .NET. Permite crear aplicaciones .NET que usen DirectX 9. MDX 1.1 requiere .NET 1.1. o bien .NET 2.0.

  4. MDX 2.0: Es la segunda revisión de las APIs para .NET de DirectX 9. Eso es importante: MDX 2.0 es DirectX 9, no DirectX 10. Actualmente MDX 2.0 está en fase beta. MDX 2.0 funciona sobre .NET 1.1 y sobre .NET 2.0.

  5. D3DX: Librería que forma parte de DirectX, con un conjunto de rutinas de alto nivel para facilitar la creación de aplicaciones con Direct3D.

  6. DirectX 10: NO existe en la actualidad DirectX 10. Existe una versión de Direct3D 10, que actualmente está en beta. Direct3D 10 aparecerá sólamente en Windows Vista.

  7. WGF (Windows Graphics Framework): El nombre que en teoría recibiría Direct3D en Vista. WFG1.0 sería un Direct3D 9 ligeramente modificado para Vista (finalmente Direct3D 9Ex) y WFG2.0 sería Direct3D 10. Al final nada de nada: En Vista seguiremos hablando de Direct3D y DirectX.

  8. WPF - Windows Presentation Foundation: Anteriormente conocida como Avalon, WPF es la nueva capa de presentación de Windows Vista, que utiliza Direct3D 9Ex para sus propósitos.

  9. XNA Framework: La madre de todo el cotarro. Un nuevo conjunto de APIs que permitirán la creación de aplicaciones managed compatibles entre Windows y XBox 360. MDX 2.0 se integrará dentro de XNA Framework como parte del API gráfica (aunqué serán necesarios cambios, así que el API gráfica de XNA y MDX 2.0 no serán iguales) y algunas de las APIs actuales de DirectX serán sustituídas por otras (entre ellas, DirectSound por XACT y DirectInput por XInput).

En resumen, así es como creo que está el patio en la actualidad...

miércoles, julio 19, 2006

Algunos enlaces sobre el XNA Framework.

Concéis el XNA Framework? Se trata del nuevo Framework orientado a la creación de juegos compatibles entre XBox 360 y Windows. Está basado en .NET (sí, sí han portado el CLR a XBox 360) y su objetivo primordial es facilitar la creación de juegos que sean compatibles con Windows y XBox 360 sin que sea necesario código propio para cada plataforma.

Desde que MS anunció el XNA Framework, varias dudas se han ido planteando: p.ej. qué ocurrirá con Managed DirectX (actualmente MDX 2.0 está en fase beta), o como se gestionarán las diferencias de dispositivos entre plataformas (p.ej. como se gestionarán ratones o teclados que son más propios de PC que de XBox).

Os dejo algunos posts muy interesantes sobre XNA para que les vayais hechando un vistazo si os apetece.

  • Para empezar un post donde Albert Ho habla de XNA Framework. Resumiendolo muy por encima, comenta que MDX pasará a convertirse en el API gráfico de XNA y que DirectSound será reemplazado por XACT y DirectInput por XInput. Lo que no queda muy claro es como podremos gestionar dispositivos no compatibles con XInput desde XNA, p.ej.

  • Una entrevista con Matt Lee. Mucho, mucho no habla de XNA, si acaso cuatro cosillas sobre XNA Build (variación de MSBuild) y XNA Studio (un Visual Studio orientado a la creación de juegos). Pese a no hablar mucho de XNA es una entrevista bastante interesante.

  • Un post de David Weller donde se mencionan algunos de los puntos claves del XNA Framework. Interesante el último punto donde menciona que XNA Framework no admitirá referencias a System.Drawing o System.Windows.Forms. Veremos como impacta esto en el desarrollo de aplicaciones no full-screen en XNA.


En resumen, todavía hay muy poca información sobre XNA y es cierto que quedan muchas dudas en el tintero, pero la verdad es que las noticias que van apareciendo son muy interesantes ;-)

Un par de buenos tutoriales de MDX

Si estais empezando a batallar com Managed DirectX, os recomiendo los siguientes tutoriales:

  1. Tutorial de Managed DirectX de C-Unit. Tienen también un tutorial de DirectX no managed.

  2. Riemer's DirectX Tutorials for C# and C++. La parte de C# es Managed DirectX, la parte de C++ es DirectX tradicional.


Por otro lado en breve empezaré a publicar una serie de posts-tutoriales sobre Managed DirectX. No voy a contar nada que no esté ya publicado por esos mundos de dios, pero intentaré que sea un tutorial fácil de entender, orientado básicamente a programación 2D usando Direct3D y en castellano.

miércoles, julio 12, 2006

[OT] Sintaxis coloreada de VS.NET en blogger

Jejejee... habéis visto el post justo anterior a éste?
Que os parece la sintaxis coloreada del código? ;)

Algunos sistemas de blog (como p.ej. la comunidad clearscreen tienen un sistema de coloreado automático de sintaxis (cosa lógica, pues son sistemas de blogs orientados al desarrollo de S/W), pero blogger no. Y hombre, colorear la sintaxis "a mano" es posible para trozos de código pequeños, pero puede ser un infierno para trozos de código más largos.

Por eso he estado buscando algún sistema para pasar código coloreado de VS.NET a formato HTML, manteniendo los colores... y lo he encontrado aquí. Es un add-in para VS.NET 2005 que añade una opción en el menú contextual llamada Copy as HTML. Además permite establecer bastantes parámetros para personalizar el HTML generado.

O sea que, ahora ya podré colorear los trozos de código que vaya poniendo por ahí! ;)

PD: Si usais blogger y este add-in, ojo si usáis el modo wysiwyg de blogger, ya que tiene la manía de sustituir los   por un espacio en blanco... con lo que se pierden las indentaciones!

El bucle de juego definitivo

El bucle de juego (game loop) es una de las características más importantes de los juegos. Al revés de las aplicaciones de gestión, que estan guiadas por eventos, un juego generalmente tiene cosas que hacer (p.ej. animaciones) aunque el usuario no haga nada.
Un bucle de juego eficiente hará que el juego ocupe menos CPU y por lo tanto indirectamente, pueda generar más fps.

En este post, Tom Miller propone un bucle de juego muy interesante, tanto por su sencillez como por su eficiencia. Se basa en el uso del API Win32 PeekMessage().

Basándome en este bucle de juego he creado una clase que simplemente lo encapsula. El código de la clase (a la que presuntuosamente he llamado GameEngine) es el siguiente:

namespace foo

{

    class GameEngine

    {

        Form1 frm = new Form1();

        public void MainLoop()

        {

            System.Windows.Forms.Application.Idle += new EventHandler(OnApplicationIdle);

            frm.InitializeGraphics();

            System.Windows.Forms.Application.Run(frm);

        }

 

        private void OnApplicationIdle(object sender, EventArgs e)

        {

            while (AppIddle)

            {

                // Update Graphics

                // Render Graphics

            }

        }

 

        private bool AppIddle

        {

            get

            {

                NativeMethods.Message msg;

                return !NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, 0);

            }

        }

    }

}

static class NativeMethods

{

        [StructLayout(LayoutKind.Sequential)]

        public struct Message

        {

            public IntPtr hWnd;

            public IntPtr msg;

            public IntPtr wParam;

            public IntPtr lParam;

            public uint time;

            public System.Drawing.Point p;

        }

 

        [System.Security.SuppressUnmanagedCodeSecurity]

        [DllImport("User32.dll", CharSet = CharSet.Auto)]

        public static extern bool PeekMessage(out Message msg, IntPtr hWnd, uint messageFilterMin, uint messageFilterMax, uint flags);

}



Nota: Form1 es el nombre de la clase formulario principal.

Usando esa clase la función Main() quedaría de la siguiente manera:

        [STAThread]

        static void Main()

        {

            // Inicializaciones previas

            GameEngine ge = new GameEngine();

            ge.MainLoop();       

            // Destrucciones finales

        }

    }



Simple, sencillo... y eficaz!

martes, julio 11, 2006

Reiner's Tilesets - recursos gráficos freeware

Si como muchos desarrolladores el tema gráfico no es lo vuestro ;) y buscais recursos gráficos para desarrollar vuestros juegos (2D) echad un vistazo a Reiner's Tilesets. Contiene varios gráficos freeware que podeis usar en vuestros desarrollos... Están orientados a juegos de estrategia o tipo Diablo, aunque hay un poco de todo... :-)

lunes, julio 10, 2006

ColorKey en texturas PCX

En el post anterior puse una posible manera de obtener texturas a partir de archivos PCX. Dado que se usa Texture.FromBitmap, no se puede establecer el ColorKey de la textura, lo que invalida el método para crear Sprites (o lo complica demasiado, vamos).

Los métodos que permiten establecer el ColorKey de una textura están en la clase TextureLoader en los métodos FromStream y FromFile respectivamente.
Así que reescribí el código para cargar la texura usando TextureLoader. Teoricamente no debía ser muy complicado, pues en el MemoryStream tenía la información de la Textura en formato BMP que es uno de los soportados.
El código que probé era:

public Texture TextureFromDIB(uint dib, Device device)
{
uint hmem;
byte[] content;
// open and allocate a memory stream
hmem = FreeImage.OpenMemory(IntPtr.Zero, 0);
bool b = FreeImage.SaveToMemory(FreeImageAPI.FIF.FIF_BMP, dib, hmem, 0);
FreeImage.Unload(dib);
IntPtr ptr = IntPtr.Zero;
int size_in_bytes = 0;
FreeImage.AcquireMemory(hmem, ref ptr, ref size_in_bytes);
content = new byte[size_in_bytes];
Marshal.Copy(ptr, content, 0, size_in_bytes);
System.IO.MemoryStream ms = new System.IO.MemoryStream(content);
Bitmap bmp = new Bitmap(ms, false);
FreeImage.CloseMemory(hmem);
ms.Seek(0, System.IO.SeekOrigin.Begin);
Texture t = TextureLoader.FromStream(device, ms, 0, 0, 0, Usage.SoftwareProcessing, Format.P8, Pool.Managed, Filter.Point, Filter.Point, Color.Magenta.ToArgb());
ms.Close();
return t;
}


Al probarlo mi gozo en un pozo :(
El código me lanzaba una excepción Microsoft.DirectX.Direct3D.InvalidDataException (D3DXERR_INVALIDDATA).
Primero pensé que quizá FreeImage guardaba los datos en alguna variación de BMP que quizá no era soportada por TextureLoader, así que guardé el contenido del MemoryStream en un fichero y intenté cargar la textura usando el mismo método FromStream, pasándole un FileStream apuntando al fichero recién creado: funcionó.

Al final pude dar con el problema: faltaba posicionar el puntero de lectura del MemoryStream al inicio de los datos:

FreeImage.CloseMemory(hmem);
ms.Seek( 0, System.IO.SeekOrigin.Begin );
Texture t = TextureLoader.FromStream(device, ms, ...);

Llamando a Seek justo antes de la llamada a FromStream funcionó todo perfectamente! ;)

sábado, julio 08, 2006

Texturas a partir de archivos PCX

Para el proyecto que estoy desarrollando me intersaba dar soporte a archivos PCX: es decir crear texturas a partir de archivos PCX.

La clase TextureLoader permite cargar una textura a partir de un archivo gráfico, da soporte a varios formatos (entre ellos .bmp, .jpg y .png como más destacados) pero no da soporte a arhivos PCX.
Así pues intenté ver como podía cargar un archivo PCX y crear una textura Direct3D a partir de él.
Para ello el primer paso fue encontrar alguna librería para leer archivos PCX. Estuve buscando por google a ver si encontraba alguna librería .NET (gratuita) para leer este tipo de archivos. No encontré ninguna pero vi que FreeImage tenia un wrapper de C#, así que me decidí utilizarla. Ya había usado FreeImage en proyectos anteriores (con DirectDraw y C++) y me había gustado así que me pareció una buena idea.

La clase Texture tiene un método llamado fromBitmap, que a partir de un objeto System.Drawing.Bitmap crea el objeto Textura correspondiente. Así que en resumen se trataba de obtener un Bitmap a partir de FreeImage.

FreeImage és una librería que trabaja con varios formatos gráficos, pero internamente los convierte todos al formato DIB (Device Independent Bitmap).

El primer paso era cargar la imagen con FreeImage:

uint handle = FreeImage.Load(FIF.FIF_PCX, System.Windows.Forms.Application.StartupPath + @"\..\..\texture.pcx", 0);

Para pasar la imagen del formato DIB interno de FreeImage al formato Bitmap de .NET se me ocurrió utilizar las funciones de memoria de la propia FreeImage. En concreto lo que quería hacer era:
  1. Guardar la imagen en un bloque de memoria en formato Bitmap
  2. Copiar la información en un array de bytes
  3. Crear un objeto Bitmap inicializado con los datos del array de bytes.
El primer problema que me encontré era que el wrapper de C# para FreeImage estaba incompleto: Las funciones de manejo de memoria de FreeImage no aparecían en el wrapper. Por suerte el wrapper no es nada más que un pequeño archivo .cs con las definiciones de P/Invoke de las funciones de FreeImage, así que pude añadir las definiciones que me faltaban:

[DllImport(dllName, EntryPoint = "FreeImage_OpenMemory")]

public static extern FIMEMORY OpenMemory(IntPtr bits, Int32 size_in_bytes);

[DllImport(dllName, EntryPoint = "FreeImage_CloseMemory")]

public static extern void CloseMemory(FIMEMORY stream);

[DllImport(dllName, EntryPoint = "FreeImage_SaveToMemory")]

public static extern bool SaveToMemory(FIF fif, FIBITMAP dib, FIMEMORY stream, int flags);

[DllImport(dllName, EntryPoint = "FreeImage_AcquireMemory")]

public static extern long AcquireMemory(FIMEMORY stream, ref IntPtr data, ref int size_in_bytes);


Una vez añadido esto en el wrapper (y recompilarlo) usé el siguiente código para obtener un objeto System.Drawing.Bitmap:

uint hmem;
int w, h, stride;
byte[] content;
// Obtenemos un buffer de memoria de FreeImage
hmem = FreeImage.OpenMemory(IntPtr.Zero, 0);
// Grabamos la imagen en el buffer de memoria en formato BMP
bool b = FreeImage.SaveToMemory(FreeImageAPI.FIF.FIF_BMP, dib, hmem, 0);
FreeImage.Unload(dib);
// Obtenemos un puntero (unmanaged) al buffer de memoria de FreeImage
IntPtr ptr = IntPtr.Zero;
int size_in_bytes = 0;
FreeImage.AcquireMemory(hmem, ref ptr, ref size_in_bytes);
content = new byte[size_in_bytes];
// Copiamos el contenido del buffer de memoria unmanaged a un byte[]
Marshal.Copy(ptr, content, 0, size_in_bytes);
// Creamos un MemoryStream que apunte al contenido copiado y creamos el Bitmap
System.IO.MemoryStream ms = new System.IO.MemoryStream(content);
Bitmap bmp = new Bitmap(ms, false);
// Cerramos el buffer de memoria de FreeImage (para evitar memory-leaks)
FreeImage.CloseMemory(hmem);
ms.Close();
// Listos.
return bmp;


En este punto el Bitmap está creado, así que ya sólo queda usar el método fromBitmap de la clase Texture y ya tenemos una textura Direct3D lista para usar.

En mi caso para hacer una prueba rápida cogí el Tutorial #5 de Direct3d (muestra un cilindro texturizado) y lo ejecuté dos veces: una con una textura PCX y otra con un archivo BMP convertido (usé Irfanview) a partir del PCX , y comprobé que en ambos casos el resultado era el mismo.

Nota: Aparte del wrapper "oficial" de FreeImage, que se encuentra en su página oficial, encontré otro wrapper que incluía las definiciones de P/Invoke de todas las funciones de FreeImage que le faltan al wrapper "oficial" además de ofrecer algunas funciones helper adicionales. Este wrapper está en http://hauntedhousesoftware.com/blog/Files/FreeImage.cs

miércoles, julio 05, 2006

El comienzo de todo...

Hola a todos!
Al final me he decidido a crear este blog, donde voy a comentar mis experiencias, frustraciones, alegrías y demás sobre Managed DirectX.

Antes que nada... ¿quien soy yo? Pues me llamo Eduard Tomàs, edu para los amigos, y en la actualidad trabajo como director de proyectos para raona. Pero este blog no tiene nada que ver con temas profesionales, si no con uno de mis hobbies: el desarrollo de videojuegos, y más concretamente usando Managed DirectX.

Pues nada... espero que nos sigamos leyendo por ahí ;-)