第二章 DOS 電玩程式
2.2 螢幕輸出
2.2.3 DOS 遊戲的架構
2.2.3.2 遊戲運算和資料處理
2.2.3.3.1 背景的繪製
2.2.3.3 螢幕輸出
這個部分負責畫出背景、主角和主角發射的氣功
2.2.3.3.1 背景的繪製
否
是
否
是 開始
i=0 to 199
j=0 to 319
如果螢幕上第 i 列 第 j 行的像點不在 主角圖片範圍以內
如果螢幕上第 i 列 第 j 行的像點不在 氣功圖片範圍以內
算出這個像點的顏色
1 2
3 4
1
畫出這個像點
j
2 3
i 4
結束
2.2.3.3.2 主角的動畫製作
開始
i= 0 to 19
j= 0 to 19
把記憶體位置 p+j+i×20 的內容 複製到
s+j+x×20+320×i+y×20×320 就是說把主角圖片第 I 列第 j 行 的像點值拷貝到顯示記憶體要 輾是他的位置
p 是儲存主角圖片的記憶體位置 的起始指標,s 是顯示記憶體的 起始指標,(x,y)是主角在螢幕上 的位置。
j
j
結束
41
2.2.3.3.3 氣功的動畫製作
開始
i= 0 to 19
j= 0 to 19
把記憶體位置 p+j+i×20 的內容 複製到
s+j+x×20+320×i+y×20×320 就是說把氣功圖片第 I 列第 j 行 的像點值拷貝到顯示記憶體要 輾是他的位置
p 是儲存氣功圖片的記憶體位置 的起始指標,s 是顯示記憶體的 起始指標,(x,y)是主角在螢幕上 的位置。
j
j
結束
2.2.4 DOS GAME 程式碼
因為我的 DOS 模式底下的遊戲並不是成品。只是一個寫遊戲的試驗但是還是 從中間學到了粉多以下是完整的程式碼。
---
#include "alloc.h"
#include "bios.h"
#include "mem.h"
#include <dos.h>
#include <stdio.h>
#define BYTE unsigned char
//這是一個用來儲存中斷服務程式起始位置的指標 static void (interrupt far *old_kb_int)(void);
static int kb_init=0;
/********************************************************************/
/*這個函是把鍵盤中斷的起始位置設定成另外一個函式的起始位置 */
/* */
/*input 值是一個指向函式起始位置的指標 */
/*沒有回傳值 */
/********************************************************************/
void setkbint(void (interrupt far * new_kb_int)(void));
int key=0;
/********************************************************************/
/*我們自己改寫的新的鍵盤中斷服務程式 */
/* */
/*沒有輸入值 */
/*沒有輸出值 */
/********************************************************************/
void interrupt far kb_int(void);
/********************************************************************/
/*把鍵盤中斷改回原來的鍵盤中斷 */
/********************************************************************/
void resetkbint(void);
/********************************************************************/
/*清除鍵盤中斷狀態 */
/********************************************************************/
void clearkbintstate(void);
/********************************************************************/
/*這個函式是用來解碼 PCX 圖檔的 */
/* */
/*input char far aÎ圖檔名稱 */
/*input FILE *bÎ圖檔的檔案指標 */
/*input int cÎ圖片寬度 */
/*input int dÎ圖片長度 */
/*沒有輸出 */
/*******************************************************************/
void Decodepcxfile(char far *a,FILE *b,int c,int d);
/*******************************************************************/
/*解碼圖檔中的每一行 */
/* */
/*input FILE *bÎ圖檔的指標 */
/*input char far *aÎ圖檔的名稱 */
/*int cÎ圖檔的寬度 */
/*沒有輸出 */
/********************************************************************/
void Decodeline(char far *a,FILE *b,int c);
/********************************************************************/
/*設定調色盤為 256 色 */
/* */
/*沒有輸入 */
/*沒有輸出 */
/********************************************************************/
void Set256pal();
/********************************************************************/
/*設定顯示卡為繪圖模式 */
/* */
/*沒有輸入 */
/*沒有輸出 */
/********************************************************************/
void Initgraph();
/********************************************************************/
/*關閉顯示卡的繪圖模式改回文字模式 */
/* */
/*沒有輸入 */
/*沒有輸出 */
/********************************************************************/
void Closegraph();
/********************************************************************/
/*這個函式由 showmap()呼叫它負責顯示地圖 */
/********************************************************************/
void Show();
/********************************************************************/
/*這個函式把主角畫在(b*20,c*20)的位置 */
/* */
/*input char far *aÎ主角圖片所儲存的記憶體位置指標 */
/*input int bÎ主角的 x 座標除以 20 */
/*input int cÎ主角的 y 座標除以 20 */
/*沒有輸出值 */
/********************************************************************/
void Showman(char far *a,int b,int c);
/********************************************************************/
/*這個函式是負責畫出主角發射得武器 */
/* */
/*input char far *aÎ武器的圖片所存在的記憶體位置的指標 */
/*input int bÎ這個武器的 x 位置 */
/*input int cÎ這個武器的 y 位置 */
/*沒有輸出 */
/********************************************************************/
void Showpoken(char far *a,int b,int c);
/********************************************************************/
/*這個函式是個失敗品並沒有達到儲存螢幕的功能所以我在 MAIN 中從未乎叫*/
/*這個函式 */
/********************************************************************/
void savescreenmap(char far *,int,int);
/********************************************************************/
/*這個函式畫出背景地圖 */
/********************************************************************/
void Showmap();
/********************************************************************/
/*一個定義敵人的結構 */
/********************************************************************/
struct ghost {
int ox,oy,nx,ny;
int direct;
int exist;
};
/********************************************************************/
/*一個定義主角所發射出的武器的結構 */
/********************************************************************/
struct POKEN {
int poken_x,poken_y;
int poken_x_in_screen,poken_y_in_screen;
int poken_direction;//0 for up,1 for down,2 for left,3 for right;
int poken_state;// 0 for not exist,1 for exist;
char far *poken_pcx;
};
struct ghost kk[10];
struct POKEN poken[10];
char palet[768];
char palet0[768];
char far *pta,*ptb,*pp,*pg,*wholescreen;
int mp;
unsigned actor_x,actor_y;
char map[80][80];
void main(void) {
FILE *file_ptr;
int c,i=0;
int up=0,down=0,left=0,right=0;
unsigned bufseg,bufoff;
//file_ptr=fopen("thing.pcx","rb");
//pt=(char far *)malloc(20*20*5); /* allocate memory buffer for .pcx */
//fseek(file_ptr,-768,SEEK_END);/* find the palette */
//fread(palet,1,768,file_ptr) ;/* read the palette to palet[] */
//for(c=0;c<768;++c)/* transfer palet[] to match .pcx file */
//{
// palet[c]>>=2;
//}
//fseek(file_ptr,128,SEEK_SET); /*move pointer to data part*/
//Decodepcxfile(pt,file_ptr,5*20,20); /* decode a .pcx file to memory buffer */
//
file_ptr=fopen("ch4a.pcx","rb");
pta=(char far *)malloc(20*20*32);
fseek(file_ptr,-768,SEEK_END);
fread(palet,1,768,file_ptr);
for(c=0;c<768;++c) {
palet[c]>>=2;
}
fseek(file_ptr,128,SEEK_SET);
Decodepcxfile(pta,file_ptr,2*20,320);
//
file_ptr=fopen("ch4b.pcx","rb");
ptb=(char far *)malloc(20*20*16);
fseek(file_ptr,-768,SEEK_END);
fread(palet,1,768,file_ptr);
for(c=0;c<768;++c) {
palet[c]>>=2;
}
fseek(file_ptr,128,SEEK_SET);
Decodepcxfile(ptb,file_ptr,1*20,320);
//
file_ptr=fopen("people.pcx","rb");
pp=(char far *)malloc(20*20*8);
fseek(file_ptr,-768,SEEK_END);
fread(palet,1,768,file_ptr);
for(c=0;c<768;++c) {
palet[c]>>=2;
}
fseek(file_ptr,128,SEEK_SET);
Decodepcxfile(pp,file_ptr,8*20,20);
fclose(file_ptr);
file_ptr=fopen("badman","rb");
pg=(char far *)malloc(20*20); /* allocate memory buffer for .pcx */
fread(pg,1,400,file_ptr) ; /* read the palette to palet[] */
fclose(file_ptr);
wholescreen=(char far *)malloc(64000);
if(wholescreen=='\0') {
printf("ppppppppp\n");
//getchar();
}
file_ptr=fopen("map.gam","rb");
for(i=0;i<=79;i++) {
for(c=0;c<=79;c++) {
map[c][i]=fgetc(file_ptr);
} }
Initgraph(); /*get into graph mode(320x200) */
Set256pal();/* set the paletet */
printf("PRESS ENTER TO GO ON ...");
for(i=0;i<=19;i=i+1) {
kk[i].exist=0;
}
kk[0].exist=1;
kk[0].ox=3;
kk[0].oy=6;
//
actor_x=380;
actor_y=120;
setkbint(kb_int);
while(key!=0x01) {
if(key!=0x01) {
switch(key) {
case 0x4d:
{
actor_x++;
if((map[(actor_x+19)/20][(actor_y)/20]&0x80==0x80)||(map[(actor_x+19)/20][(actor_y +19)/20]&0x80==0x80))
{
actor_x=actor_x-1;
}
if((right++)%2==0)
{
mp=4;
} else {
mp=5;
} break;
}
case 0x4b:
{
actor_x--;
if((map[(actor_x)/20][(actor_y)/20]&0x80==0x80)||(map[(actor_x/20)][(actor_y+19)/20 ]&0x80==0x80))
{
actor_x=actor_x+1;
}
if((left++)%2==0)
{
mp=6;
} else {
mp=7;
} break;
}
case 0x48:
{
actor_y--;
if((map[(actor_x)/20][(actor_y)/20]&0x80==0x80)||(map[(actor_x+19)/20][(actor_y)/20 ]&0x80==0x80))
{
actor_y=actor_y+1;
}
if((up++)%2==0)
{
mp=2;
} else {
mp=3;
} break;
}
case 0x50:
{
actor_y++;
if((map[(actor_x)/20][(actor_y+19)/20]&0x80==0x80)||(map[(actor_x+19)/20][(actor_y +19)/20]&0x80==0x80))
{
actor_y=actor_y-1;
}
if((down++)%2==0)
{
mp=0;
} else {
mp=1;
} break;
}
case 0x18://0x18 is p's scane code;
{ i=0;
if(mp==0||mp==1)
{
poken[i].poken_pcx=pg;
poken[i].poken_state=1;
poken[i].poken_x=actor_x;
poken[i].poken_y=actor_y+20;
poken[i].poken_x_in_screen=140;
poken[i].poken_y_in_screen=100+20;
poken[i].poken_direction=1;
}
if(mp==2||mp==3)
{
poken[i].poken_pcx=pg;
poken[i].poken_state=1;
poken[i].poken_x=actor_x;
poken[i].poken_y=actor_y-20;
poken[i].poken_x_in_screen=140;
poken[i].poken_y_in_screen=100-20;
poken[i].poken_direction=0;
}
if(mp==4||mp==5)
{
poken[i].poken_pcx=pg;
poken[i].poken_state=1;
poken[i].poken_x=actor_x+20;
poken[i].poken_y=actor_y;
poken[i].poken_x_in_screen=140+20;
poken[i].poken_y_in_screen=100;
poken[i].poken_direction=3;
}
if(mp==6||mp==7) {
poken[i].poken_pcx=pg;
poken[i].poken_state=1;
poken[i].poken_x=actor_x-20;
poken[i].poken_y=actor_y;
poken[i].poken_x_in_screen=140-20;
poken[i].poken_y_in_screen=100;
poken[i].poken_direction=2;
}
//printf("i love you");
break;
}
default:
{
break;
} } }
Showmap();
Showman(pp+mp*400,7,5);
for(i=0;i<=0;i++)//decide the position of poken;
{
if(poken[i].poken_state==1) {
switch(poken[i].poken_direction) {
case 0:
{
poken[i].poken_x=poken[i].poken_x;
poken[i].poken_y=poken[i].poken_y-1;
poken[i].poken_x_in_screen=poken[i].poken_x_in_screen;
poken[i].poken_y_in_screen=poken[i].poken_y_in_screen-1;
break;
}
case 1:
{
poken[i].poken_x=poken[i].poken_x;
poken[i].poken_y=poken[i].poken_y+1;
poken[i].poken_x_in_screen=poken[i].poken_x_in_screen;
poken[i].poken_y_in_screen=poken[i].poken_y_in_screen+1;
break;
}
case 2:
{
poken[i].poken_x=poken[i].poken_x-1;
poken[i].poken_y=poken[i].poken_y;
poken[i].poken_x_in_screen=poken[i].poken_x_in_screen-1;
poken[i].poken_y_in_screen=poken[i].poken_y_in_screen;
break;
}
case 3:
{
poken[i].poken_x=poken[i].poken_x+1;
poken[i].poken_y=poken[i].poken_y;
poken[i].poken_x_in_screen=poken[i].poken_x_in_screen+1;
poken[i].poken_y_in_screen=poken[i].poken_y_in_screen;
break;
}
default:
{
break;
} } }
//printf("actor position (%d,%d)",actor_x,actor_y);
}
for(i=0;i<=0;i=i+1) {
if(poken[i].poken_state==1) {
Showpoken(pp+mp*400,poken[0].poken_x_in_screen,poken[0].poken_y_in_scree n);
} } }
resetkbint();
Closegraph();
farfree(pta);
farfree(ptb);
farfree(pp);
farfree(pg);
farfree(wholescreen);
}
/********************************************************************/
/*這個函是把鍵盤中斷的起始位置設定成另外一個函式的起始位置 */
/* */
/*input 值是一個指向函式起始位置的指標 */
/*沒有回傳值 */
/********************************************************************/
void setkbint(void (interrupt far *new_kb_int)(void)) {
disable();
if (kb_init==0) {
old_kb_int=getvect(0x09);
kb_init=1;
}
setvect(0x09,new_kb_int);
enable();
}
/********************************************************************/
void interrupt far kb_int(void);
/********************************************************************/
void interrupt far kb_int(void) {
key=inportb(0x60)&0x7f;
clearkbintstate();
}
/********************************************************************/
/*把鍵盤中斷改回原來的鍵盤中斷 */
/********************************************************************/
void resetkbint(void) {
if (kb_init==1) {
disable();
setvect(0x09,old_kb_int);
kb_init=0;
enable();
} }
/********************************************************************/
/*清除鍵盤中斷狀態 */
/********************************************************************/
void clearkbintstate(void) {
BYTE code;
code=inportb(0x61);
code|=0x80;
outportb(0x61,code);
code&=0x7f;
outportb(0x61,code);
outportb(0x20,0x20);
enable();
}/********************************************************************/
/*這個函式由 showmap()呼叫它負責顯示地圖 */
/********************************************************************/
void Show(void) {
int i=0,j=0,k=0,column=0,row=0;
int flage=0;
char m;
char far *temp_ptr;
unsigned x,y,a,b;
unsigned bufseg,bufoff;
a=actor_x-140;
b=actor_y-100;
x=actor_x%20;
y=actor_y%20;
for(i=0;i<=199;i++) {
for(j=0;j<=319;j++) {
if(i>=100&&i<120&&j>=140&&j<160) {
a=a+1;
x=x+1;
if(x>=20) {
x=0;
} } else {
flage=0;
for(k=0;k<=0;k++) {
if(poken[k].poken_state==1) {
if((i>=poken[k].poken_y_in_screen&&i<=poken[k].poken_y_in_screen+19)&&(j>=po ken[k].poken_x_in_screen&&j<poken[k].poken_x_in_screen+19))
{
a=a+1;
x=x+1;
if(x>=20) {
x=0;
}
flage=1;
}
//printf("i love you");
}
}
if(flage==0) {
m=map[a/20][b/20];
if((m&0x80)==0x80) {
temp_ptr=pta;
} else {
temp_ptr=ptb;
}
column=(int)(( m & 0x70)>>4);
row=(int)( m & 0x0f);
bufseg=FP_SEG(temp_ptr+320*20*column+320*y+20*row+x);
bufoff=FP_OFF(temp_ptr+320*20*column+320*y+20*row+x);
movedata(bufseg,bufoff,0x0a000,j+i*320,1);
a=a+1;
x=x+1;
if(x>=20)
{
x=0;
} } } }
a=actor_x-140;
b=b+1;
x=actor_x%20;
y=y+1;
if(y>=20) {
y=0;
} }
b=actor_y-100;
}
/********************************************************************/
void Showman(char far *a,int b,int c);
/********************************************************************/
void Showman(char far *p,int x,int y) {
int i,j;
unsigned bufseg,bufoff;
for(i=0;i<20;i++) {
for(j=0;j<20;j++) {
bufseg=FP_SEG(p+j+i*20);
bufoff=FP_OFF(p+j+i*20);
movedata(bufseg,bufoff,0x0a000,j+x*20+320*i+y*20*320,1);
} } }
/********************************************************************/
void Showpoken(char far *a,int b,int c);
/********************************************************************/
void Showpoken(char far *p,int x,int y) {
int i,j;
unsigned bufseg,bufoff;
for(i=0;i<20;i++) {
for(j=0;j<20;j++) {
bufseg=FP_SEG(p+j+i*20);
bufoff=FP_OFF(p+j+i*20);
movedata(bufseg,bufoff,0x0a000,j+x+320*i+y*320,1);
} } }
/********************************************************************/
/*這個函式是個失敗品並沒有達到儲存螢幕的功能所以我在 MAIN 中從未乎叫*/
/*這個函式 */
/********************************************************************/
void savescreenmap(char far *p,int x,int y)// now is no use;
{
int i;
unsigned bufseg,bufoff;
for(i=0;i<20;i++) {
bufseg=FP_SEG(p+i*20);
bufoff=FP_OFF(p+i*20) ;
movedata(bufseg,bufoff,FP_SEG(wholescreen),FP_OFF(wholescreen)+x*20+320*i+y*
20*320,20);
} }
/********************************************************************/
/*這個函式畫出背景地圖 */
/********************************************************************/
void Showmap(void) {
int x,y,m;
unsigned bufseg,bufoff;
Show();
/*for(loop=0;loop<=19;loop=loop+1) {
//decisionghostpos(loop);
//moveghost(loop);
//checktouch(loop);
if(kk[loop].exist==1) {
if((kk[loop].ox!=(7+xi))||(kk[loop].oy!=(5+yi))) {
if(kk[loop].ox<(7+xi)) {
kk[loop].ox=kk[loop].ox+1;
}
if(kk[loop].ox>(7+xi)) {
kk[loop].ox=kk[loop].ox-1;
} }
if((kk[loop].ox<=(9+xi))&&(kk[loop].ox>=(0+xi))&&(kk[loop].oy<=(15+yi))&&(kk[l oop].oy>=(0+yi)))
{
Show(pg,kk[loop].ox-xi,kk[loop].oy-yi);
} } }*/
}
/********************************************************************/
/*設定顯示卡為繪圖模式 */
/* */
/*沒有輸入 */
/*沒有輸出 */
/********************************************************************/
void Initgraph() /* into 320x200 mode */
{
_AX=0x0013;
geninterrupt(0x10);
}
/********************************************************************/
/*關閉顯示卡的繪圖模式改回文字模式 */
/* */
/*沒有輸入 */
/*沒有輸出 */
/********************************************************************/
void Closegraph() {
_AX=0x0003;
geninterrupt(0x10);
}
/********************************************************************/
/*設定調色盤為 256 色 */
/* */
/*沒有輸入 */
/*沒有輸出 */
/********************************************************************/
void Set256pal() {
extern char palet[768];
_ES=FP_SEG(palet);
_DX=FP_OFF(palet);
_CX=256;
_BX=0x0000;
_AX=0x1012;
geninterrupt(0x10);
}
/*******************************************************************/
/*解碼圖檔中的每一行 */
/* */
/*input FILE *bÎ圖檔的指標 */
/*input char far *aÎ圖檔的名稱 */
/*int cÎ圖檔的寬度 */
/*沒有輸出 */
/********************************************************************/
void Decodeline(char far *ptr,FILE *file_ptr,int length) {
int data,count;
int len=0;
while(len<length) /* loop for a line */
{
data=fgetc(file_ptr);
if(data <= 0xc0)
{ /* if single data */
*(ptr+(len++))=data; /* put single data */
}
else /* else */
{ /* get repeat counts */
count=data&0x3f;
data=fgetc(file_ptr); /* get data */
while(count--) /* put repeat data */
{
*(ptr+(len++))=data;
} } }
}/********************************************************************/
/*這個函式是用來解碼 PCX 圖檔的 */
/* */
/*input char far aÎ圖檔名稱 */
/*input FILE *bÎ圖檔的檔案指標 */
/*input int cÎ圖片寬度 */
/*input int dÎ圖片長度 */
/*沒有輸出 */
/*******************************************************************/
void Decodepcxfile(char far *ptr,FILE *file_ptr,int length,int width) {
int i;
for(i=0;i<length;i++) /* decode whole file to the memory buffer */
{
Decodeline(ptr+i*width,file_ptr,width);
} }
---
第三章 WINDOWS 電玩程式
WINDOWS 電玩程式有一個很重要的函式庫叫做 DIRECTX,DIRECTX 它不 僅僅只是一套函式庫,當你安裝完它的時候你同時也安裝了很多附屬的工具程式。
為什麼需要用到 DIRECTX 呢?當我們寫 WINDOWS GAME 時為何不可以把我 們要秀的圖的資料直接丟到顯示記憶體呢?為何不能直接用 TURBO C 中的
outportb()來輸出資料到 port 呢?這是因為 WINDOWS 不准許我們直接控制電腦硬 體,當我們要做螢幕輸出、輸出音效、設定顯示卡的顯示模式時我們要經由 MICROSOFT 所發展出的函式幫我們達成我們所要做的。
DirectX 是當紅的 2D、3D application 開發 SDK,特別是應用在多媒體,
graphics、games 上。目前許多的 pc game 甚至 arcade game 都是用 DirectX 所開發,
將來還會更普及。DirectX 的前身 WinG,也就是 Windows Game SDK,事實上根 本是為遊戲製作而量身打造的,到了 DirectX 之後,由於對硬體的支援更普遍,更 密切,已經不只是遊戲專用的 SDK。使用 DirectX 最大的好處是你可以很方便取 得硬體性能資訊,將硬體的性能發揮得淋漓盡致,包括 2D、 3D、音效、搖桿、
鍵盤等輸入設備、網路等,這一點是其他的 3D SDK 如 Glide 和 OpenGL 所做不到 的。在以前,光是要支援一個遊戲的音效,就是一件很麻煩的事,你得考慮到 Ad Lib、SoundBlast、音源器、MIDI、VOC,後來的又出現 wave table、Windows wav 等格式和新產品,將來還會有更複雜的東西出現,光是搞這些東西就會耗掉程式 設計師許多時間,相對的,純粹花在遊戲設計的時間就少了很多,效率就不好。
其實不只是音效,顯示卡的性能也越來越好,越來越複雜,不論 2D 或 3D 加速卡,
如果你是一個有經驗的程式設計師或寫過顯示卡的驅動程式,你就會了解到要寫 一個可以適用於所有的系統的 game 是一件非常不容易的事,如今可憐的程式設計 師發現他們又要面對網路,特別是 internet。所以 DirectX 的最大好處不是在於 game 本身,而是對硬體的充分支援,和其便利性。
DirectX 包含幾個部分:
DirectDraw:最主要的功能是處理顯示記憶體和系統記憶體,比如你可以規劃系統 記憶體來儲存影像,再將這些影像以硬體所支援的功能輸出到顯示記憶體,於是 就可以在螢幕上看到影像。由於 DirectDraw 可以偵測並且充分使用顯示卡的性 能,因此可以將顯示速度提昇到最佳的狀況,這一點是 win32 SDK 所做不到的,
因為 Windows 是多工作業系統,基本上並不允許任何應用程式隨意存取系統或顯示 記憶體,所有的 window 影像都必須由作業系統來儲存和安排。
你可以使用 DirectDraw 設定你的程式是普通的 windows window 或者使用整個螢幕 而捨棄 window,成為一個 full-screen application,在這種狀況下你可以任意設定解 析度。
除此之外,DirectDraw 還提供一些基本的 2d 功能,比方設定 color key,使圖
形的背景顏色成為透明.這一點在 game 中應用很廣泛。Clipper 則可以使我們的角 色在 window 中自由運動,不必擔心會跑到 window 外,或是角色超出顯示記憶體 的定址( addressing )範圍.其他還有一些比較冷僻,對 game 沒有什麼用處,但是硬 體還是支援的部分,像是 overlay。
Direct3D Immediate Mode:使用 Direct3D IM 並不是一件愉快的事,首先,你必須提 供 3d model 轉換成 world,world 轉成 view,view 轉成投影平面的三組矩陣,然後 你還得設定 light,render,texture,z-buffer 等等的 state,換句話說,你必須先對線 性代數和 3d 電腦圖學下一番功夫,瞭若指掌,不然你不知道這些到底是什麼東西, 也無從使用 IM。
若是依我之見,除非你要開發一些 Direct3D Retained Mode 所缺乏的功能,或 是你要使用某種 RM 所不支援的 3d 檔,否則沒有必要使用 IM。
但是要偵測 3D 加速卡,讓 3D 應用程式能有最佳表現,還是要用到一小部分的 D3D IM.
Direct3D Retained Mode:架構在 IM 之上的一個介面。可以這樣比喻,IM 好像是程 式語言,RM 是由程式語言所寫的函式庫。RM 有豐富的介面,拿來開發一套標準
Direct3D Retained Mode:架構在 IM 之上的一個介面。可以這樣比喻,IM 好像是程 式語言,RM 是由程式語言所寫的函式庫。RM 有豐富的介面,拿來開發一套標準