在C中显示一个颜色数组

我的程序都写了一个像这样的颜色读取阵列:

struct Image { size_t width; size_t height; struct Color *data; } struct Color { char r; char g; char b; } 

我怎样才能在C屏幕上显示这样的数组?

图形渲染:

我习惯win32和Borland C ++环境,所以我坚持下去,但其他环境的差异大多只在类名中。 首先一些方法:

  1. 控制台/文本模式

    你可以使用文字图形(我认为是英文的ASCII艺术 )。 哪里是由字符表示。 强度是由或多或少的填充字符。 通常有一个按照强度排序的字符表,如" ..:+*#"并用它来代替颜色。 打印出来的东西可以用cout << "text" << endl; 或从stdio printf我认为(不使用旧式的控制台输出超过十年)。

    文本模式videoram( VRAM )从0B000:0000开始,如果您有权限,可以直接访问,如下所示:

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

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

  2. 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 C ++的例子:

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

    Canvas是Windows上可视组件的图形子组件。 在borland是TCanvasCanvas 。 所有的窗户也有PaintBoxes,Bitmaps,... 这是Windows和你的应用程序之间的GDI接口。 它具有Pen,Brush,Font线条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的帮助以获取更多信息。

  4. GDI位图

    这是特殊的对象,它是一个OS图形句柄( 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通常是0x00RRGGBB0x00BBGGRR 。 我认为这种方法对你来说是最好的选择,你也可以将任何GDI对象绘制到任何其他的GDI对象

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

    这将您的位图绘制到窗口,以便您可以实际看到它。

  5. 图形库

    有很多,但最常用的是OpenGLDirectX 。 我更喜欢OpenGL,因为它更容易实现(至少对于初学者来说), OpenGL也是跨平台的,而DirectX只是Windows。 另外当我开始编码时,没有DirecX 。 当我开始使用OpenGL的时候,所有的供应商都包含了驱动程序。 现在唯一还在最新的厂商是nVidiaATI(AMD) 。 他们之间几乎总是有一些驱动程序问题,但总的来说nVidia更适合OpenGL (在DirectX实现中存在缺陷), ATI(仅限AMD版本)DirectX更好(在OpenGL实现中有缺陷)。 但对于基本的操作你没事(问题得到更多的高级功能)

    英特尔,矽统等供应商已停止在较新的OpenGL版本的实施,至少我不知道任何更好的驱动程序,然后OpenGL 3.3为他们

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

我强烈建议先从GDI +位图开始。 你可以做很多与他们我仍然使用它非复杂的渲染。

如前所述,我是borland( VCL样式)友好的,所以如果你使用不同的编译器/ IDE,那么改变GDI对象名称以符合你的环境。 我认为画布是相同的,位图是HBitmap但更好的检查你的帮助/文档,至少你知道要搜索什么。

希望它有一点帮助。

[编辑1]其他平台

  • 在linux下简单的gfx: X11 / Xlib.h例子