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! ;)

No hay comentarios: