图形渲染:
我习惯于Win32和Borland C++环境,所以我坚持它,但其他环境的差异主要只在类名中。首先是一些方法:
控制台/文本模式
你可以使用文本图形(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 c++例子:
维萨
//==============================================================================
//=== 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. =====================================================================
//==============================================================================
主.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
的类。所有窗口都有它。它是Windows和你的应用程序之间的GDI接口。它有子组件,如
Canvas
用于行、填充或文本纸张、文本墨水。
Form1->Canvas->Pen->Color=clYellow;
Form1->Canvas->MoveTo(10,10);
Form1->Canvas->LineTo(100,150);
其中
PaintBoxes,Bitmaps,...
是我的VCL窗口此代码绘制一条黄线。
GDI有许多函数,如
Pen,Brush,Font
有关更多信息,请参阅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位图,并通过直接访问将其设置为
Form1
。现在您可以访问
Arc,Ellipse,Pixels[][],...
属性。还有
100x100x32bit
的存在,所以你也可以做所有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
请注意在位图内使用
ScanLine
,否则将引发异常。颜色编码取决于
bmp->Canvas
通常是
x,y
或
pixelformat
。我认为这种方法是您的最佳选择,您还可以将任何GDI对象绘制到任何其他GDI对象
Form1->Canvas->Draw(0,0,bmp);
这会将位图绘制到窗口,以便您可以实际看到它。
图形库
有很多,但最常用的是OpenGL和DirectX。我更喜欢OpenGL,因为它更易于实现(至少对于初学者来说是这样),而且OpenGL是跨平台的,DirectX只是windows。当我开始编码时,没有DirecX。当我开始使用OpenGL时,所有的供应商都将它包含在驱动程序中。现在唯一仍然是最新的供应商是nVidia和ATI(AMD)。它们之间几乎总是有一些驱动程序问题,但一般来说,nVidia更适合OpenGL(DirectX实现中有bug),而ATI(仅限AMD版本)更适合DirectX(OpenGL实现中有bug)。但是对于基本的操作来说,你是可以的(问题出现在更高级的函数上)
像英特尔,SiS,。。。已经停止了他们在新的OpenGL版本上的实现,至少我不知道有比OpenGL 3.3更好的驱动程序
要开始使用OpenGL,请参见
OpenGL get Device Context
我强烈建议首先从GDI+位图开始。你可以用它们做很多事情,我仍然在使用它进行非复杂的渲染。
如前所述,我对borland(VCL风格)很友好,因此如果您使用不同的编译器/IDE,那么请更改GDI对象名以对应您的环境。我认为Canvas是相同的,bitmap是
0x00RRGGBB
但是最好查看帮助/文档,至少你知道要搜索什么。
希望能有点帮助。
[Edit1]其他平台和东西
linux中的简单gfx这里:
X11/Xlib.h example
VGA modes in assembly 8086
我是一名优秀的程序员,十分优秀!