Mostrar una matriz de color en C [closed]

11 minutos de lectura

avatar de usuario
neh

Mi programa escribe y lee matrices de colores como esta:

struct Image {
    size_t width;
    size_t height;
    struct Color *data;
}

struct Color {
    char r;
    char g;
    char b;
}

¿Cómo puedo mostrar una matriz de este tipo en la pantalla en C?

  • ¿Mostrar como en “dibujar una imagen” o mostrar como en “imprimir contenido de matriz de manera descriptiva”?

    usuario529758

    9 de febrero de 2014 a las 15:16

  • La programación en C no tiene una biblioteca estándar para manipular gráficos. Hay una gran cantidad de bibliotecas que proporcionan características gráficas. Tendrás que encontrar el que se adapte a tus necesidades.

    – Rullof

    9 de febrero de 2014 a las 15:17

  • Además, ¿qué has probado…?

    usuario529758

    9 de febrero de 2014 a las 15:17

  • mostrar como “dibujar una imagen” Probé SDL2.0 pero necesito hacer doble almacenamiento en búfer y SDL2.0 no parece ser adecuado para esa tarea…

    – neeh

    9 de febrero de 2014 a las 15:23


  • ¿Con qué sistema operativo estás trabajando?

    – usuario1118321

    9 de febrero de 2014 a las 16:03

avatar de usuario
espectro

Representación de gráficos:

Estoy acostumbrado a los entornos win32 y Borland C++, por lo que me atengo a ellos, pero las diferencias con otros entornos se encuentran principalmente en los nombres de las clases. Primero algunos enfoques:

  1. modos de consola/texto

Puede usar gráficos de texto (arte ASCII, creo que en inglés). Donde punto está representado por personaje. Intensidad está formado por caracteres más o menos rellenos. Suele tener una tabla de caracteres ordenados por intensidad como " ..:+*#" y usa eso en lugar de colores. Para imprimir algo, puede usar iostreamme gusta cout << "text" << endl; o printf desde stdio Creo (no he estado usando la salida de consola de estilo antiguo durante más de una década).

Modos de texto RAM de video (VRAM) empieza a 0B000:0000 si tiene los privilegios para ello, puede hacer un acceso directo como este:

    char far *scr = (char far*)0x0B0000000;
    scr[0] = 'A'; // Print A to left upper corner

Pero en Windows puedes olvidarte de acceso directo.

  1. Modo de gráficos VGA

(Solo DOS, no Windows; esto es acceso directo directo al hardware VGA). Aquí hay un pequeño ejemplo:

 // Turbo C++ for 16-bit real mode DOS
        //==============================================================================
        char far* scr;              // VGA screen
        const _sx= 320;             // Physical screen size
        const _sy= 200;
        //==============================================================================
        void gfxinit();
        void cls();
        void pnt(int x,int y,char c);
        //==============================================================================
        void gfxinit()
            {
            asm {   mov ax,19               // This switches  VGA to 320*200*256 color mode (fits inside a single 64 KB segment so no funny stuff is needed)
                int 16
                }
            for (int i=0;i<256;i++) asm { // This overwrites 256 color palette with some BW gradients
                mov dx,0x3C8
                mov ax,i
                out dx,al              // Overwrite color al = i 
                inc dx
                shr al,2               // al=al>>2
                out dx,al              // r,g,b or b,g,r not sure now 
                out dx,al              // All values are 6-bit long, therefore the shr al,2 
                out dx,al
                }
            scr=(char far*)0xA0000000;     // VRAM start address
            }
        //==============================================================================
        void cls()   // This clears the screen with zeros
            {
            asm {   push    es
                mov ax,0xA000
                mov es,ax
                mov di,0x0000
                sub ax,ax
                mov cx,32000
                rep stosw
                pop es
                }
            }
        //==============================================================================
        void pnt(int x,int y,char c) // This draws a single point of color c
            {
            unsigned int adr;
            if (x<_sx)
             if (x>=0)
              if (y<_sy)
               if (y>=0)
                {
                y=y*_sx;
                adr=x+y;
                scr[adr]=c;
                }
            }
        //==============================================================================

VESA el acceso es similar, pero hay que lidiar con el cruce de segmentos y la paginación. Aquí hay un pequeño ejemplo de Turbo C++:

VESA.h

// Turbo C++, still 16-bit DOS, 
// but using VESA calls to set modes instead of VGA registers
    //==============================================================================
    //=== Globals: =================================================================
    //==============================================================================
    char far* scr=(char far*)0xA0000000;    // VGA/VESA memory pointer
    int VESA_page,VESA_pages;       // Actual page and total pages
    int VESA_xs,VESA_ys,VESA_bpp;       // Video mode properties
    int VESA_page_xy[64]={-1,-1};       // Starting x,y for each page
    const int VESAmodes[]=          // Usable video modes table
        {
         320, 200, 8,0x150,
         640, 480, 8,0x101,
         800, 600, 8,0x103,
        1024, 768, 8,0x105,
        1280,1024, 8,0x107,
    
         320, 200,16,0x10E,
         640, 480,16,0x111,
         800, 600,16,0x114,
        1024, 768,16,0x117,
    
         320, 200,32,0x10F,
         640, 480,32,0x112,
         800, 600,32,0x115,
    
        0,0,0,0
        };
    //==============================================================================
    //=== Headers: =================================================================
    //==============================================================================
    int  VESAmode(int xs,int ys,int bpp);   // Set video mode
    void VESApage(int page);        // Set page
    void VESAexit();            // Return to VGA text mode
    void VESAcls();             // Clear with 0
    void VESApnt(int x,int y,unsigned int c); // Render 8/16 bpp point
    void VESApnt32(int x,int y,int r,int g ,int b); // render 32bpp point
    //==============================================================================
    //=== Graphic: =================================================================
    //==============================================================================
    int VESAmode(int xs,int ys,int bpp)
        {
        int i,mode,x,y;
        unsigned int adr0,adr,dx,dy;
        // find video mode
        for (i=0;VESAmodes[i];i+=4)
         if (VESAmodes[i+0]==xs)
          if (VESAmodes[i+1]==ys)
           if (VESAmodes[i+2]==bpp)
            break;
        if (!VESAmodes[i]) return 0;
        mode=VESAmodes[i+3];
        VESA_xs=xs;
        VESA_ys=ys;
        VESA_bpp=bpp;

        // Compute start x,y for each page>0
        dx=bpp>>3;
        dy=xs*dx;
        VESA_pages=1;
        for (adr=i=x=y=0;y<VESA_ys;y++)
            {
            adr0=adr;
            adr+=dy;
            if (adr0>adr)
                {
                while (adr>0) { adr-=dx; x--; }
                while (x<0) { x+=VESA_xs; y--; }
                VESA_page_xy[i]=x; i++;
                VESA_page_xy[i]=y+1; i++;
                VESA_pages++;
                }
            }
        VESA_page_xy[i]=-1; i++;
        VESA_page_xy[i]=-1; i++;
    
    // Set video mode
        asm {
            mov bx,mode
            mov ax,0x4F02
            int 16
            }
        VESApage(0);
    /*
        // Set palette to grayscale
        if (VESAbpp==8)
         for (int i=0;i<256;i++) asm {
            mov dx,0x3C8
            mov ax,i
            out dx,al
            inc dx
            shr al,2
            out dx,al
            out dx,al
            out dx,al
            }
    */
        return 1;
        }
    //==============================================================================
    void VESApage(int page)
        {
        int p=page;
        asm {
            mov dx,p
            mov bx,0
            mov ax,0x4f05
            int 16
            }
        VESA_page=page;
        }
    //==============================================================================
    void VESAexit()
        {
        asm     {
            // Wait for key press
            mov ax,0
            int 0x16
            // VGA 80x25 text mode
            mov ax,3
            int 16
            }
        }
    //==============================================================================
    void VESAcls()
        {
        int i;
        for (i=0;i<VESA_pages;i++)
            {
            VESApage(i);
            asm     {
                push es
                mov ax,0xA000
                mov es,ax
                mov di,0x0000
                mov ax,0
                mov cx,32000
                rep stosw
                pop es
                }
            }
        }
    //==============================================================================
    void VESApnt(int x,int y,unsigned int c)
        {
        unsigned int adr;
        int p;
        // inside screen?
        if ((x>=0)&&(x<VESA_xs))
         if ((y>=0)&&(y<VESA_ys))
            {
            // Low 16 bit of address
            adr=y;
            adr*=VESA_xs;
            adr+=x;
            adr*=(VESA_bpp>>3);
            // Page
            for (p=0;VESA_page_xy[p+p+0]>=0;p++)
                {
                if (VESA_page_xy[p+p+1]>y) break;
                if (VESA_page_xy[p+p+1]<y) continue;
                if (VESA_page_xy[p+p+0]>x) break;
                }
            if (p!=VESA_page) VESApage(p);
            // Render
            scr[adr]=c;
            if (VESA_bpp==16)
                {
                adr++; if (adr==0) VESApage(p+1);
                scr[adr]=(c>>8);
                }
            }
        }
    //==============================================================================
    void VESApnt32(int x,int y,int r,int g ,int b)
        {
        unsigned int adr;
        int p;
        // inside screen?
        if ((x>=0)&&(x<VESA_xs))
         if ((y>=0)&&(y<VESA_ys))
            {
            // Low 16 bit of address
            adr=y;
            adr*=VESA_xs;
            adr+=x;
            adr*=(VESA_bpp>>3);
            // Page
            for (p=0;VESA_page_xy[p+p+0]>=0;p++)
                {
                if (VESA_page_xy[p+p+1]>y) break;
                if (VESA_page_xy[p+p+1]<y) continue;
                if (VESA_page_xy[p+p+0]>x) break;
                }
            if (p!=VESA_page) VESApage(p);
            // Render
            scr[adr]=b; adr++; if (adr==0) VESApage(p+1);
            scr[adr]=g; adr++; if (adr==0) VESApage(p+1);
            scr[adr]=r;
            }
        }
    //==============================================================================
    //=== End. =====================================================================
    //==============================================================================

principal.cpp

    //==============================================================================
    //=== Includes: ================================================================
    //==============================================================================
    #include "vesa.h"
    //==============================================================================
    //=== Main: ====================================================================
    //==============================================================================
    void main()
        {
        if (!VESAmode(800,600,32)) return;
        VESAcls();
        int x,y;
        unsigned int c;
        for (y=0;y<VESA_ys;y++)
         for (x=0;x<VESA_xs;x++)
            {
            if (VESA_bpp== 8)
                {
                c=x+y;
                VESApnt(x,y,c);
                }
            if (VESA_bpp==16)
                {
                c=(x&31)+((y&63)<<5);
                VESApnt(x,y,c);
                }
            if (VESA_bpp==32) VESApnt32(x,y,x,x+y,y);
            }
    
        VESAexit();
        }
    //==============================================================================
    //=== End. =====================================================================
    //==============================================================================
  1. GDI – utilizable en Windows

Canvas es un subcomponente gráfico de componentes visuales en Windows. En Borland es la clase TCanvas llamado Canvas. Todas las ventanas lo tienen también, PaintBoxes, Bitmaps, .... Es el GDI interfaz entre Windows y su aplicación. Tiene subcomponentes como Pen, Brush, and Font para líneas, rellenos o papel de texto, tinta de textos.

    Form1->Canvas->Pen->Color=clYellow;
    Form1->Canvas->MoveTo(10,10);
    Form1->Canvas->LineTo(100,150);

donde Form1 es mi VCL ventana. Este código dibuja una línea amarilla.

GDI tiene muchas funciones como Arc, Ellipse, Pixels[][],.... Consulte la ayuda integrada de su IDE para obtener más información.

  1. Mapa de bits GDI

Este es un objeto especial. Es un mapa de bits con un sistema operativo mango gráfico (corriente continua contexto del dispositivo). Esto permite que un mapa de bits sea algo así como una ventana y tenga acceso a GDI:

    Graphics::TBitmap *bmp=new Graphics::TBitmap;
    bmp->Width=100;
    bmp->Height=100;
    bmp->HandleType=bmDIB;    // Allows use of ScanLine
    bmp->PixelFormat=pf32bit; // 32-bit - the same as int so we can use int* for pixels pointer

Esto crea un VCL mapa de bits y lo establece en 100x100x32 bit con acceso directo. Ahora puedes acceder a la ScanLine propiedad. También bmp->Canvas está presente, por lo que puede hacer todo GDI cosas también

    int *p=bmp->ScanLine[10]; // p = pointer to y=10 line of bitmap
    p[20]=0;                    // Draw dot on x=20,y=10   color=0x00000000 which is black
    int c = p[15];              // Read pixel x=15,y=10 from bitmap to c

Tenga cuidado de quedarse con x,y dentro de un mapa de bits o se lanzará una excepción. El código de colores depende de pixelformaty por lo general es 0x00RRGGBB o 0x00BBGGRR. Creo que este enfoque es la mejor opción para usted. Además, puedes dibujar cualquier GDI oponerse a cualquier otro GDI objeto:

    Form1->Canvas->Draw(0, 0, bmp);

Esto dibuja su mapa de bits en la ventana, para que pueda verlo en realidad.

  1. biblioteca de gráficos

Hay muchos, pero los más usados ​​son OpenGL y DirectX. Prefiero OpenGL, porque es más simple de implementar (al menos para principiantes) y también OpenGL es multiplataforma y DirectX es solo para Windows. Además, cuando comencé a codificar no había ningún DirecX. Cuando comencé a usar OpenGL, todos los proveedores lo tenían incluido en los controladores. Ahora los únicos proveedores que todavía están actualizados son nvidia y ATI (AMD). Casi siempre hay algún problema de controlador entre ellos, pero en general Nvidia es mejor para OpenGL (tiene errores en la implementación de DirectX) y ATI (solo versiones de AMD) es mejor para DirectX (tiene errores en la implementación de OpenGL). Pero para las operaciones básicas está bien (los problemas se ponen en funciones más avanzadas).

Proveedores como Intel, SiS, etc. han detenido sus implementaciones en versiones más nuevas de OpenGL. Al menos, no conozco ningún controlador mejor que OpenGL 3.3 para ellos.

Para comenzar con OpenGL, consulte OpenGL obtener contexto de dispositivo.

Recomiendo encarecidamente comenzar con GDI + Bitmap primero. Puedes hacer mucho con ellos. Todavía lo estoy usando para renderizado no complejo.

Como se mencionó antes, soy Borland (VCL estilo) amigable, por lo que si usa un compilador / IDE diferente, cambie el GDI nombres de objetos que correspondan a su entorno. Creo que Canvas es lo mismo y bitmap es HBitmap, pero mejor revisa tu ayuda/documentación. Al menos sabes qué buscar.

Otras plataformas y cosas

  • Los gráficos simples en Linux están aquí: ejemplo X11/Xlib.h
  • Modos VGA en ensamblaje 8086

  • Hola Spektre, ¡gracias por esta respuesta completa! Estoy acostumbrado a OpenGLES 2.0. Pero tengo que implementar un procesador de software. ¿Crees que los mapas de bits son los más adecuados para la rasterización?

    – neeh

    13 de febrero de 2014 a las 14:35

  • sí, los mapas de bits son la forma más fácil,… y con el uso adecuado de la propiedad de la línea de exploración, también es eficiente (obtener 70 fps en mi software 3D que admite reflejos de texturas phong…)

    – Espectro

    13 de febrero de 2014 a las 17:14

  • sería increíble si alguien agrega algo como mi respuesta para MSVC ++ gcc y así sucesivamente … para tener todos los enfoques básicos de representación en un sitio simple y claro …

    – Espectro

    13 de febrero de 2014 a las 17:16

  • En Windows también puedes olvidarte de esto… He aquí un pequeño ejemplo: – Pensé que iba a ser un ejemplo de “olvidarlo” y hacer algo diferente en Windows. pero esta usando out instrucciones, por lo que está haciendo acceso HW directo. Se beneficiaría de un comentario en la parte superior del bloque de código como // Turbo C++, for 16-bit DOS with VGA. (Si eso es exacto.)

    – Peter Cordes

    13 de junio de 2021 a las 8:48


  • Re: VGA emulado: tal vez menos totalmente virtual de lo que piensas. Aparentemente, el hardware de video de PC moderno todavía tiene soporte de hardware real para el modo de texto, no captura lenta a SMM como pensé que podría ser el caso: ¿El hardware de video de PC moderno admite el modo de texto VGA en HW, o el BIOS lo emula (con el modo de administración del sistema )?

    – Peter Cordes

    13 de junio de 2021 a las 9:12

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad