La estructura bitmap es así:
   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.
   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:
   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:
   #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;
   }