Отобразить массив цветов в C

Моя программа пишет как считывает массивы цветов, подобных этой:

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

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

Как я могу отобразить такой массив на экране в C?

0
09 февр. '14 в 15:14
источник поделиться
1 ответ

Графический рендеринг:

Я использую среду win32 и Borland С++, поэтому я придерживаюсь этого, но различия в других средах в основном относятся только к именам классов. Сначала некоторые подходы:

  • консольные/текстовые режимы

    вы можете использовать текстовую графику (ASCII art, я думаю, на английском языке). Где точка представлена ​​символом . Интенсивность производится более или менее заполненными символами. Обычно есть таблица символов, отсортированная по интенсивности, например " ..:+*#", и используйте это вместо цветов. Для печати что-то может использовать iostream как cout << "text" << endl; или printf из stdio Я думаю (не используя старую консольную консоль более десяти лет).

    Текстовые режимы videoram (VRAM) начинаются с 0B000:0000, если у вас есть привилегии для этого, вы можете сделать прямой доступ следующим образом:

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

    но в Windows вы можете забыть о прямом доступе

  • Режим VGA gfx

    в Windows вы также можете забыть об этом... Вот небольшой пример:

        //==============================================================================
        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 swith VGA to 320*200*256 color mode (fits inside single 64KB 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 6bit long therefore the shr al,2 
                out dx,al
                }
            scr=(char far*)0xA0000000;     // VRAM start address
            }
        //==============================================================================
        void cls()   // this clear screen with zero
            {
            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 draw 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 аналогичен, но вам приходится иметь дело с пересечением сегментов и поисковым вызовом. Вот небольшой пример Turbo С++:

    VESA.h

     
    //==============================================================================
    //=== Globals: =================================================================
    //==============================================================================
    char far* scr=(char far*)0xA0000000;    // VGA/VESA memory pointer
    int VESA_page,VESA_pages;       // actaul 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 vide 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     {
            // waut 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. =====================================================================
    //==============================================================================
    

    main.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. =====================================================================
    //==============================================================================
    
  • GDI

    Canvas является графическим подкомпонентом визуальных компонентов в Windows. В borland находится класс TCanvas с именем Canvas. Все окна имеют также PaintBoxes,Bitmaps,.... Это интерфейс GDI между Windows и вашим приложением. Он имеет подкомпоненты, такие как Pen,Brush,Font для строк, заливок или текстовой бумаги, текстовых чернил.

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

    где Form1 - мое окно VCL, этот код рисует желтую строку.

    GDI имеет множество функций, таких как Arc,Ellipse,Pixels[][],..., для получения дополнительной информации см. сборку с помощью вашей IDE.

  • Растровое изображение GDI

    это особый объект, это растровое изображение с графическим дескриптором ОС (DC). Это позволяет растровому изображению быть чем-то вроде окна и иметь доступ к GDI

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

    это создает растровое изображение VCL и устанавливает его в 100x100x32bit с прямым доступом. Теперь вы можете получить доступ к свойству ScanLine. Также присутствует bmp->Canvas, чтобы вы могли делать все GDI.

    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
    

    Будьте осторожны, чтобы остаться с x,y внутри растрового изображения или исключение. Цветовое кодирование зависит от pixelformat обычно 0x00RRGGBB или 0x00BBGGRR. Я думаю, что этот подход является лучшим вариантом для вас, и вы можете привлечь любой объект GDI к любому другому объекту GDI

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

    это рисует ваше растровое изображение в окно, чтобы вы могли видеть его на самом деле.

  • Графическая библиотека

    Существует много, но наиболее часто используемых OpenGL DirectX. Я предпочитаю OpenGL, потому что его проще реализовать (по крайней мере для стартеров), а также OpenGL является кросс-платформенным DirectX - это только окна. Также при запуске кодирования не было DirecX. Когда я начал использовать OpenGL, все поставщики имеют его в составе драйверов. Теперь единственными поставщиками, которые по-прежнему актуальны, являются nVidia и ATI (AMD). Существует почти всегда проблема с драйверами между ними, но в целом nVidia лучше для OpenGL (имеет ошибки в реализации DirectX) и ATI (только версии AMD) лучше для DirectX (имеет ошибки в OpenGL). Но для основных операций вы в порядке (проблемы попадают на более сложные функции)

    Продавцы вроде Intel, SiS,... остановили свои реализации на более новых версиях OpenGL, по крайней мере, я не знаю ни одного драйвера лучше, чем OpenGL 3.3 для них

    Чтобы начать работу с OpenGL, см. OpenGL получить контекст устройства

Я настоятельно рекомендую сначала начать с GDI + Bitmap. вы можете много сделать с ними, я все еще использую его для не комплексного рендеринга.

Как уже упоминалось ранее, я являюсь borland ( VCL style), поэтому, если вы используете другой компилятор /IDE, измените имена объектов GDI, чтобы соответствовать вашей среде. Я думаю, что Canvas тот же, и растровое изображение HBitmap, но лучше проверьте вашу помощь/документы, по крайней мере, вы знаете, что искать.

Надеюсь, это поможет немного.

[Edit1] другие платформы

+3
11 февр. '14 в 10:21
источник

Посмотрите другие вопросы по меткам или Задайте вопрос