我的程序都写了一个读取颜色数组,如下所示:
struct Image {
size_t width;
size_t height;
struct Color *data;
}
struct Color {
char r;
char g;
char b;
}
如何在C屏幕上显示这样的数组?
答案 0 :(得分:4)
图形渲染:
我已经习惯了win32和Borland C ++环境,所以我坚持使用它,但其他环境的差异主要只在类名中。首先是一些方法:
控制台/文字模式
你可以使用文字图形(ASCII art我想用英文)。 点由字符表示的位置。 强度由或多或少的填充字符组成。通常有一个按强度排序的字符表,如" ..:+*#"
,并使用它而不是颜色。要打印出来的内容可以使用iostream
cout << "text" << endl;
或printf
来自stdio
我认为(不使用旧式控制台输出超过十年)。
文字模式视频( 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
这样的子组件,用于行,填充或文本文本,文本墨水。
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 实施中有错误)。但对于基本操作,你很好(问题在于更高级的功能)
英特尔,SiS 等供应商已停止在较新的 OpenGL 版本上实施,至少我不知道任何驱动程序比 OpenGL 3.3更好对他们来说
要开始使用OpenGL,请参阅OpenGL get Device Context
我强烈建议先从GDI + Bitmap开始。你可以用它们做很多事情我还在用它来进行非复杂的渲染。
如前所述,我对borland( VCL 样式)友好,所以如果您使用不同的编译器/ IDE,则更改 GDI 对象名称以符合您的环境。我认为Canvas是相同的,位图是HBitmap
,但最好检查一下你的帮助/文档,至少你知道要搜索什么。
希望它有所帮助。
[Edit1]其他平台