La estructura bitmap es as�:
Tambi�n hay otras cosas en la estructura, pero podr�an cambiar, y no deber�a usar nada excepto lo de arriba. El rect�ngulo de recorte es inclusivo arriba a la izquierda (0 permite dibujar en la posici�n 0) pero exclusivo abajo a la derecha (10 permite dibujar en la posici�n 9, pero no en la 10). F�jese que �ste no es el mismo formato que el que se usa con set_clip(), el cual toma coordenadas inclusivas para las cuatro esquinas.typedef struct BITMAP { int w, h; - tama�o del bitmap en pixels int clip; - no-cero si recortar est� activado int cl, cr, ct, cb; - l�mites de recorte izquierdo, derecho, superior e inferior int seg; - segmento para uso con los punteros a l�nea unsigned char *line[]; - punteros al comienzo de cada l�nea } BITMAP;
Hay varios modos de conseguir acceso directo a la memoria de imagen de un bitmap, variando en complejidad dependiendo del tipo de bitmap que use.
El modo m�s simple s�lo servir� si trabaja con bitmaps de memoria (obtenidos con create_bitmap(), ficheros de datos, y ficheros de im�genes) y sub-bitmaps de bitmaps de memoria. Esto usa una tabla de punteros char, llamados 'line', la cual es parte de la estructura bitmap y contiene punteros al comienzo de cada l�nea de la imagen. Por ejemplo, una funci�n putpixel simple para un bitmap de memoria es:
void memory_putpixel(BITMAP *bmp, int x, int y, int color) { bmp->line[y][x] = color; }
Para modos truecolor, es necesario especificar el tipo del puntero de l�nea, por ejemplo:
void memory_putpixel_15_or_16_bpp(BITMAP *bmp, int x, int y, int color) { ((short *)bmp->line[y])[x] = color; } void memory_putpixel_32(BITMAP *bmp, int x, int y, int color) { ((long *)bmp->line[y])[x] = color; }
Si quiere escribir en la pantalla y tambi�n en bitmaps de memoria, necesita usar algunas macros auxiliares, porque la memoria de v�deo puede no ser parte de su espacio de direcciones normal. Esta simple rutina funcionar� para cualquier pantalla lineal, p.ej unos framebuffers lineales de VESA.
Para los modos truecolor deber�a reemplazar bmp_write8() por bmp_write16(), bmp_write24(), o bmp_write32(), y multiplicar el desplazamiento x por el n�mero de bytes por p�xel. Por supuesto hay funciones similares para leer el valor de un pixel de un bitmap, y son bmp_read8(), bmp_read16(), bmp_read24() y bmp_read32().void linear_screen_putpixel(BITMAP *bmp, int x, int y, int color) { bmp_select(bmp); bmp_write8((unsigned long)bmp->line[y]+x, color); }
Esto, sin embargo, seguir� sin funcionar en los modos de SVGA por bancos, o en plataformas como Windows, que hacen un procesado especial dentro de las funciones de cambio de banco. Para un acceso m�s flexible a los bitmaps de memoria, necesita llamar a las rutinas:
unsigned long bmp_write_line(BITMAP *bmp, int line);
Selecciona la l�nea de un bitmap en la que va a dibujar.
unsigned long bmp_read_line(BITMAP *bmp, int line);
Selecciona la l�nea de un bitmap de la que va a leer.
unsigned long bmp_unwrite_line(BITMAP *bmp);
Libera el bitmap de memoria despued de que haya acabado de trabajar con
�l. S�lo necesita llamar a esta funci�n una vez al final de una operaci�n
de dibujado, incluso si ha llamado a bmp_write_line() o bmp_read_line()
diversas beces antes.
Estas est�n implementadas como rutinas de ensamblador en l�nea, por lo que no son tan ineficientes como podr�an parecer. Si el bitmap no necesita cambio de banco (ejemplo: es un bitmap de memoria, pantalla en modo 13h, etc), estas funciones simplemente retornan bmp->line[line].
A pesar de que los bitmaps de SVGA usan bancos, Allegro permite acceso lineal a la memoria dentro de cada scanline, por lo que s�lo necesita pasar una coordenada y a estas funciones. Varias posiciones x pueden ser obtenidas simplemente sumando la coordenada x a la direcci�n devuelta. El valor devuelto es un entero largo sin signo en vez de un puntero a caracter porque la memoria bitmap puede no estar en su segmento de datos, y necesita acceder a �l con punteros far. Por ejemplo, una funci�n putpixel usando funciones de cambio de banco es:
Se dar� cuenta de que Allegro tiene funciones separadas para seleccionar los bancos de lectura y escritura. Es importante que distinga entre estos, porque en algunas tarjetas de v�deo los bancos pueden ser seleccionados individualmente, y en otros la memoria de v�deo es le�da y escrita en direcciones diferentes. No obstante, la vida nunca es tan simple como desear�amos que fuese (esto es verdad incluso cuando _no_ estamos hablando de programaci�n de gr�ficos :-) y por supuesto algunas tarjetas de v�deo s�lo pueden proveer un banco. En �stas, las funciones de lectura/escritura se comportar�n id�nticamente, por lo que no deber�a asumir que puede leer de una parte de la memoria de v�deo y escribir en otra al mismo tiempo. Puede llamar bmp_read_line(), y leer lo que quiera de la l�nea, entonces llamar bmp_write_line() con el mismo o diferente valor de l�nea, y escribir lo que quiera en ella, pero no deber�a llamar bmp_read_line() y bmp_write_line() a la vez y esperar poder leer una l�nea y escribir en otra simult�neamente. Ser�a bueno si esto fuese posible, pero si lo hace, su c�digo no funcionar� en tarjetas SVGA de un banco.void banked_putpixel(BITMAP *bmp, int x, int y, int color) { unsigned long address = bmp_write_line(bmp, y); bmp_select(bmp); bmp_write8(address+x, color); bmp_unwrite_line(bmp); }
Y tambi�n est� el modo-X. Si nunca antes hab�a programado gr�ficos en este modo, probablemente no entienda esto, pero para aquellos que quieren saber c�mo Allegro trabaja con los bitmaps de pantalla del modo-X, aqu� va...
Los punteros a l�nea todav�a est�n presentes, y contienen direcciones lineales, esto es, la direcci�n con la cual accedes al primer pixel de la l�nea. Est� garantizada la alineaci�n cada cuatro pixels de las direcciones, por lo que puede fijar el plano de escritura, dividir su coordenada entre cuatro, y a�adirla al puntero de l�nea. Por ejemplo, un putpixel en modo-X es:
void modex_putpixel(BITMAP *b, int x, int y, int color) { outportw(0x3C4, (0x100<<(x&3))|2); bmp_select(bmp); bmp_write8((unsigned long)bmp->line[y]+(x>>2), color); }
Ah s�: el truco de djgpp del nearptr. Personalmente, no me gusta demasiado porque desactiva la protecci�n de la memoria y no es portable a otras plataformas, pero hay mucha gente que suspira por �l porque puede dar acceso directo a la memoria de pantalla via un puntero normal de C. �Aviso: Este m�todo s�lo funcionar� con la librer�a djgpp, cuando est� usando el modo VGA 13h o un framebuffer lineal!
En su c�digo de inicializaci�n:
Luego:#include <sys/nearptr.h> unsigned char *screenmemory; unsigned long screen_base_addr; __djgpp_nearptr_enable(); __dpmi_get_segment_base_address(screen->seg, &screen_base_addr); screenmemory = (unsigned char *)(screen_base_addr + screen->line[0] - __djgpp_base_address);
void nearptr_putpixel(int x, int y, int color) { screenmemory[x + y*SCREEN_W] = color; }