在 C 中显示颜色数组 [英] Display an array of color in C

查看:19
本文介绍了在 C 中显示颜色数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的程序既写入又读取这样的颜色数组:

My program both writes and reads arrays of colors like this one:

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

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

如何在 C 语言中在屏幕上显示这样的数组?

How can I display such an array on the screen in C?

推荐答案

图形渲染:

我习惯了win32和Borland C++环境,所以就坚持了,但是在其他环境上的区别大多只在类名上.首先是一些方法:

I am used to win32 and Borland C++ environments, so I stick to it, but the differences on other environments are mostly only in class names. First some approaches:

  1. 控制台/文本模式

您可以使用文本图形(ASCII 艺术,我认为是英文).其中字符表示.强度由或多或少填充的字符组成.通常有一个按强度排序的字符表,如 "..:+*#" 并使用它代替颜色.要打印某些内容,您可以使用 iostream,例如 cout <<文本"<<endl;printf 来自 stdio 我想(我已经十多年没有使用旧式控制台输出了).

You can use text graphics (ASCII art I think in English). Where point is represented by character. Intensity is made by more or less filled chars. Usually have a table of characters sorted by intensity like " ..:+*#" and use that instead of colors. For printing out something, you can use iostream, like cout << "text" << endl; or printf from stdio I think (I am not been using old-style console output for more than a decade).

文本模式视频 RAM (VRAM) 从 0B000:0000 开始,如果您有权限,您可以像这样直接访问:

Text modes video RAM (VRAM) starts at 0B000:0000 if you have the privileges for it you can do direct access like this:

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

但是在 Windows 上,您可以忘记直接访问.

  1. VGA 图形模式

(仅限 DOS,不是 Windows;这是对 VGA 硬件的直接访问).这是一个小例子:

(DOS only, not Windows; this is doing direct direct access to the VGA hardware). Here is a small example:

 // 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 访问类似,但您必须处理段交叉和分页.这是一个小的 Turbo C++ 示例:

VESA access is similar, but you have to deal with segment crossing and paging. Here is a small Turbo C++ example:

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. =====================================================================
    //==============================================================================

ma​​in.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 - 可在 Windows 上使用
  1. GDI - usable on Windows

Canvas 是 Windows 上可视化组件的图形子组件.Borland 中的 TCanvas 类名为 Canvas.所有窗口也有它,PaintBoxes, Bitmaps, ....它是 Windows 和您的应用程序之间的 GDI 接口.它具有用于线条、填充或文本纸、文本墨水的钢笔、画笔和字体等子组件.

Canvas is graphic subcomponent of visual components on Windows. In Borland is the class TCanvas named Canvas. All windows has it also, PaintBoxes, Bitmaps, .... It is the GDI interface between Windows and your application. It has subcomponents like Pen, Brush, and Font for lines, fills or text paper, texts ink.

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

其中 Form1 是我的 VCL 窗口.这段代码画了一条黄线.

where Form1 is my VCL window. This code draws a yellow line.

GDI 有很多函数,如Arc、Ellipse、Pixels[][]、....有关详细信息,请参阅 IDE 的内置帮助.

GDI has many functions like Arc, Ellipse, Pixels[][],.... See the built-in help of your IDE for more information.

  1. GDI 位图

这是一个特殊的对象.它是一个带有 OS 图形句柄(DC 设备上下文)的位图.这允许位图类似于窗口并且可以访问 GDI:

This is a special object. It is a bitmap with an OS graphic handle (DC device context). This allows a bitmap to be something like a window and have access to 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

这将创建一个 VCL 位图,并将其设置为 100x100x32 位 以直接访问.现在您可以访问 ScanLine 属性.还存在 bmp->Canvas,因此您也可以执行所有 GDI 操作.

This creates a VCL bitmap and sets it to 100x100x32 bit with direct access. Now you can access the ScanLine property. Also bmp->Canvas is present, so you can do all GDI stuff too.

    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,通常是0x00RRGGBB0x00BBGGRR.我认为这种方法是您的最佳选择.此外,您可以将任何 GDI 对象绘制到任何其他 GDI 对象:

Be careful to stay with x,y inside a bitmap or an exception will be thrown. The color coding depends on pixelformat, and usually it is 0x00RRGGBB or 0x00BBGGRR. I think this approach is the best option for you. Also, you can draw any GDI object to any other GDI object:

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

这会将您的位图绘制到窗口中,因此您可以实际看到它.

This draws your bitmap to the window, so you can see it actually.

  1. 图形库

有很多,但最常用的是 OpenGLDirectX.我更喜欢 OpenGL,因为它实现起来更简单(至少对于初学者来说),而且 OpenGL 是跨平台的,而 DirectX 仅适用于 Windows.此外,当我开始编码时,没有任何 DirecX.当我开始使用 OpenGL 时,所有供应商都将其包含在驱动程序中.现在唯一保持最新状态的供应商是 NvidiaATI (AMD).它们之间几乎总是存在一些驱动程序问题,但总的来说,Nvidia 更适合 OpenGL(在 DirectX 实现中存在错误),ATI(仅限 AMD 版本)更适合 DirectX(它在 DirectX 实现中存在错误)OpenGL 实现).但是对于基本操作,你没问题(更高级的功能会出现问题).

There are many, but the most used are OpenGL and DirectX. I prefer OpenGL, because it is simpler to implement (at least for starters) and also OpenGL is cross-platform and DirectX is Windows only. Also when I started coding there wasn't any DirecX. When I started using OpenGL all vendors had it included in the drivers. Now the only vendors which are still up to date are Nvidia and ATI (AMD). There is almost always some driver issue between them, but in general Nvidia is better for OpenGL (has bugs in the DirectX implementation) and ATI (AMD versions only) is better for DirectX (it has bugs in the OpenGL implementation). But for basic operations you are fine (problems gets on more advanced functions).

英特尔、SiS 等供应商已停止在较新的 OpenGL 版本上实施.至少,我不知道有比 OpenGL 3.3 更好的驱动程序.

Vendors like Intel, SiS, etc. have stopped their implementations on newer OpenGL versions. At least, I do not know of any driver better than OpenGL 3.3 for them.

要开始使用 OpenGL,请参阅OpenGL 获取设备上下文.

To get started with OpenGL, see OpenGL get Device Context.

我强烈建议先从 GDI + Bitmap 开始.你可以用它们做很多事情.我仍在使用它进行非复杂渲染.

如前所述,我对 Borland(VCL 风格)友好,因此如果您使用不同的编译器/IDE,则更改 GDI 对象名称以对应您的环境.我认为 Canvas 是相同的,位图是 HBitmap,但最好检查您的帮助/文档.至少你知道要搜索什么.

As mentioned before, I am Borland (VCL style) friendly, so if you use different compiler/IDE then change the GDI object names to correspond your environment. I think Canvas is the same and bitmap is HBitmap, but better check your help/documentation. At least you know what to search for.

其他平台和东西

这篇关于在 C 中显示颜色数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆