在C中显示一个颜色数组
我的程序都写了一个像这样的颜色读取阵列:
struct Image { size_t width; size_t height; struct Color *data; } struct Color { char r; char g; char b; }
我怎样才能在C屏幕上显示这样的数组?
图形渲染:
我习惯win32和Borland C ++环境,所以我坚持下去,但其他环境的差异大多只在类名中。 首先一些方法:
-
控制台/文本模式
你可以使用文字图形(我认为是英文的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上,您可以忘记直接访问
-
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. ===================================================================== //==============================================================================
-
GDI
Canvas
是Windows上可视组件的图形子组件。 在borland是TCanvas
类Canvas
。 所有的窗户也有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的帮助以获取更多信息。 -
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
通常是0x00RRGGBB
或0x00BBGGRR
。 我认为这种方法对你来说是最好的选择,你也可以将任何GDI对象绘制到任何其他的GDI对象Form1->Canvas->Draw(0,0,bmp);
这将您的位图绘制到窗口,以便您可以实际看到它。
-
图形库
有很多,但最常用的是OpenGL的DirectX 。 我更喜欢OpenGL,因为它更容易实现(至少对于初学者来说), OpenGL也是跨平台的,而DirectX只是Windows。 另外当我开始编码时,没有DirecX 。 当我开始使用OpenGL的时候,所有的供应商都包含了驱动程序。 现在唯一还在最新的厂商是nVidia和ATI(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例子