Graafika Programmeerimine.

Link: http://www.theparticle.com/pgraph.html

Sissejuhatus…

Programmeerimine, graafika on palju raskem, kui enamik inimesi arvavad. See hõlmab tonni teadmisi. Täpsemalt, mida pead teadma mõistete taga on andmestruktuuride, matemaatika ja olema üsna hea mõningaid programmeerimise keel. Kõige tähtsam on aga see, et sa ei taha õppida! See on kõrval võimatu õppida midagi, kui sa ei taha õppida!

Kui te vaatate teie arvuti ekraani (vaata lähemalt), siis märkad, et see on tehtud väikesed värvilised täpid. Neid punkte nimetatakse pikslit. Iga piksel on kindlat värvi ja asukoha ekraanil. Nüüd, lihtne määratlus graafika programmeerimine on kindel, et paremal pikslit ilmuvad õiges kohas õigel ajal. Kui me saame teha, et see juhtub, saame kaaluda end graafika programmeerijad.

eespool Esitatud definitsioon on lihtsam öelda kui teha. Jälgida iga piksel on kõrval võimatu ilma mingi hästi kavandatud algoritme. Ja see, mida enamik käesolev dokument on kõik umbes, algoritmid!

Koodi näited on enamasti Java, kuna see on ainus süsteem sõltumatu keel, mis on võimelised graafika. Ma siiski illustreerivad mõned asjad, C/C++ samuti.

Põhitõed (kuidas läheb)…

Enne, kui me saame liiga sügavale teema graafika programmeerimine, ma tahaks illustreerivad mõned põhitõed. Kui sa juba tead, kuidas määrata pikslit ekraanil, muuta video mode, jne., seejärel saate lihtsalt selle osa vahele jätta. See osa on siin nii, et sa tead, kuidas katsetada. Ma ei saa lihtsalt tahan anda sulle algoritmi, et tõmmata joon, ükski meetod tegelikult joonistus.

järgmised mõned lõigud võivad olla süsteem, sõltuv, riistvara sõltub, koostaja sõltuv jne. Kuid, et on probleeme kõige graafika, see on kõrval võimatu luua 100% süsteemi sõltumatu graafika (välja arvatud Java).

Ploting Pikslit…

Teie arvuti ekraan on kahemõõtmeline; iga piksel ekraanil on mõned asukoht, mis on näidatud x ja y väärtusi. Kui x on horisontaalne nihe vasakule poole ekraani, ja y on vertikaalne nihe ülevalt (või mõnikord ka alt), ekraani. Nii, asukohta x = 0 ja y = 0, on ülemises vasakus nurgas oma ekraan. Teades umbes x ja y, saate mõelda oma ekraan nagu kahemõõtmeline massiiv. x, horisontaalne asukohad ja y vertikaalne kohtades. Iga väärtus sees array esindab piksel. Krundi piksel ekraanil kell öelda, x = 70 ja y = 100, siis tahaks panna pixel andmeid arvesse, et kahemõõtmeline massiiv, kell asukohta [100][70].

Nüüd, võimaldab muuta see veelgi rohkem abstraktne! Arvan, et teie ekraani nii ühemõõtmeline massiiv, selline nagu, alustades ülemisest vasakust nurgast läheb paremale, kuni rea lõpu, ja algab uuesti liini, ja jätkuvalt meeldib, et kuni see tabab alumises paremas nurgas. Kasuta seda lähenemist, et krunt pikslit, me ka teadma, laius ekraani. Lukily meile, enamik aega me teame, laius ja kõrgus ekraani täpselt. Näiteks võimaldab nimi meie üks dimentional array “ekraan“, nii, et krunt piksli värvi “värv” asukohta x = 70 ja y = 100, me tahaks teha midagi sellist: ekraan[y * laius + x] = color. Nagu sa näed (või jälg), see on täpselt sama asi nagu ekraan[y][x] = color, ainult me täpsustades laius käsitsi.

Enim korda, kui me töötame koos graafika, me töötame koos kursorit. Osuti võib olla, et mälu või otse video seade. Meie funktsioonid, et “kas graafika” ei pea olema mures, kui kursor punkti, tuleb lihtsalt teha pikslit arvesse, et osuti (või tasakaalustamisega) kuigi see oli tõeline ekraani. Ma näitan hiljem, kui joonistus mälu võib olla väga kasulik.

DOS Graafika…

Tänapäeva operatsioonisüsteemidel on tühistatud joonis otse seadmed. Aga see on veel võimalik teha Reaalses Mode DOS programmid (ja natuke petmine, alusel Kaitstud Režiimi samuti). Hetkel eeldame me töötame Reaalses DOS Mode, kasutades Borland C++ v3.1 (või DOS-i versioon Turbo C++). Ei, windows koostajad ei tööta!

Enne me ei saa midagi teha, graafiline siiski, meil on vaja, et määrata graafika mode. Me teeme seda, helistades BIOS-i. Funktsiooni, et muuta režiimi on AH = 00h, AL = mode kasutades 0x10 vahele segada. Kui te ei ole tuttav koostajale või madalal tasemel, programmeerimine, ärge muretsege; enamik asju siin on üsna lihtne mõista. C keele funktsiooni set video mode DOS on:

typedef unsigned char byte_t;

void vid_mode(byte_t mode){
union REGS regs;
regs.h.ah = 0;
regs.h.al = mode;
int86(0x10,&regs,&regs);
}

Nagu näed, ma olen määratletud eriline tüüp byte_t, mis on täpselt sama asi nagu unsigned char. Mõnikord aitab see, et abstraktsed asjad nagu, et… ma kasutan ka union REGS tööd CPU registrid. REGS liit on määratletud sees <dos.h> file. Ma olen seadistus regs.h.ah väärtuseks 0 ja regs.h.al video režiim ma tahaks minna, ja siis helistab int 0x10. Väärib märkimist, et see kood töötab ainult DOS. Ja nüüd, lihtne näide, kasutades koodi üle. (kood DOS-i versioon Borland C++ v3.1 järeldub)

#include <stdlib.h>
#include <conio.h>
#include <dos.h>

typedef unsigned char byte_t;

byte_t palju* video_buffer = (byte_t palju*)0xA0000000;

void vid_mode(byte_t mode){
union REGS regs;
regs.h.ah = 0;
regs.h.al = mode;
int86(0x10,&regs,&regs);
}

void set_pixel(int x,int y,byte_t värv){
video_buffer[y * 320 + x] = värv;
}

int main(){

vid_mode(0x13);

while(!kbhit())
set_pixel(rand()%320,rand()%200,rand()%256);

vid_mode(0x03);

 return 0;
}

pea Meeles, kõik asjad, mida ma olen öelnud töötamise kohta, mille osuti? Noh, see kood näitab, et hästi. All DOS (kasutades VGA), me saame tegeleda ekraani otse, et “eriline aadress” on 0xA0000000 video-režiim 13h, mis minu arvates kõige lihtsam videorežiim koos töötada.

Me defineerime viida video_buffer, punkt otse 0xA0000000 ja set_pixel(int, int, byte_t) function lihtsalt krunti, värvi sobival asukoht ekraanil. Video resolutsioon mode 13h on 320x200. Mis tähendab, et laius on ekraani 320 pikslit lai ja 200 pikslit kõrge. Nii, nagu näete, meie krunt pixel funktsiooni korrutab y koordineerida poolt laius, ja lisab x, ja hiljem, milles asukoht värvi.

See on oluline märkida, et sa ei taha krunt pikslit väljaspool 320x200 valik, sest kui te seda teete, saate hõlpsalt kustutada osade DOS, ja krahhi arvuti. (Muidugi, enamik “tänapäeva” operatsioonisüsteemid, ei ole viga, lihtsalt kick oma programmi süsteemist välja.)

Sees meie main(), me oleme esimene setting mode väärtuseks 13h, siis me kaarde, kuni nuppu vajutatakse, joonistus juhuslik pikslit juhuslikult asukohti ekraanil. Lõpuks, me lihtsalt tagasi, et DOS-video-režiim, mis on hästi määratletud, et oleks 0x03. 0x03 on tekst põhineb režiim (kuvatakse tekst), teksti resolutsioon 80x25. See 0x03 režiimis on 16 color mode, kuigi 0x13 režiimis on 256 color mode.

Kõige graafika inimesed töötavad koos on 256 värvid, kuid tundub, et trend liigub 16 bit värvi (see on 65535 värvid).

Nüüd, natuke “konventsiooni” ja kiirus. Kasutades video_buffer osuti krundi pikslit on aeglasem, kui kasutavad muid viiteid teiste mälu. See on tingitud asjaolust, et kui sa krunt pikslit arvesse video mälu, süsteem toimib mälu kaardistatud I/O, jah, enamik aega, me tahaksime, et vältida. Tavaline viis seda vältida on krundi pikslit arvesse regulaarne mälu, ja hiljem “blitting” (kiiresti kopeerimine), et mälu onto ekraani. See vähendab värelus ja suurendab üldist kiirust protsessi.

Me teeme seda kõigepealt eraldada mälu kogu ekraani ja arveldus, et mälu. Me siis kirjutada, et mälu ja blit (koopia it) video mälu. See lähenemine on tavaliselt teada, kui double buffering.

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>
#include <string.h>
#include <alloc.h>

typedef unsigned char byte_t;

byte_t palju* video_buffer = (byte_t palju*)0xA0000000;

void vid_mode(byte_t mode){
union REGS regs;
regs.h.ah = 0;
regs.h.al = mode;
int86(0x10,&regs,&regs);
}

void blit(byte_t palju* mida){
_fmemcpy(video_buffer,mida,320*200);
}

int main(){

int x,y;
byte_t palju* double_buffer;

double_buffer = (byte_t palju*)farmalloc((unsigned long)320*200);
kui(double_buffer == NULL){
printf("vabandust, ei ole piisavalt mälu.\n");
return 1;
}
_fmemset(double_buffer,0,(unsigned long)320*200);

vid_mode(0x13);

while(!kbhit()){
x = rand()%320;
y = rand()%200;
double_buffer[y * 320 + x] = (byte_t)(rand()%256);
blit(double_buffer);
}

vid_mode(0x03);
farfree(double_buffer);
return 0;
}

koodi üle esimese eraldab mälu puhvri suurust ekraani, siis kontrolli, et näha, kui me tegelikult tegime mälu eraldada. Viga kontrollimine reaalses mode mälu eraldamine on VÄGA oluline, sest seal ei ole palju mälu, et minna ümber. Testimise ajal ülaltoodud programmi, ma pean olema saanud “vabandust, ei ole piisavalt mälu” kirja kümneid kordi, ja mul on 64 megs of ram! Tõeline Režiim kasutab ainult 640k DOS mälu.

Me siis edasi, puhastades mälu oleme eraldatud. See on oluline, kuna see EI vaja arveldus (võite proovida ilma selleta, ja vaata, mida sa saad). Me siis jagunevad !kbhit() kaarde, juhuslike x ja y ja krunt juhuslik piksli double_buffer need random x ja y. Me siis helista blit(double_buffer), mis kopeerib double_buffer väärtuseks video_buffer, mis omakorda on määratud 0xA0000000.

Saate ka teate, et see programm on palju aeglasem kui enne. See ei ole, sest me kasutame topelt puhver, kuid kuna me oleme kopeerimine on seda liiga palju. Iga kord, kuigi hoop, me blitting. Enamik korda, me oleme drawing palju, et double_buffer (mitte ainult üks piksel), ja blitting võimalikult harva.

Üks väike märkus programmi kohta enne, kui me läheme edasi. Teha seda tööd, on teil vaja koostada selle alusel vähemalt keskmise mälu mudel. Kui sul ei ole, seda ei ole võimalik mälu eraldada kasutades farmalloc(). Borland C++ v3.1, te lähete Valikud| Koostaja| Code Generation| ja vali Keskmise Mudel.

Palett…

Töötamine 256 värve võib tunduda piiravad, kuid enamiku ajast, see ei ole. Põhjus on, sest piirang on ainult värvide arvu, mida on võimalik kuvada korraga. VGA on tegelikult võimelised kuvama 262,144 värvid. Trikk on selles, et pikslit me joonestamist arvesse video mälu, ei ole täpselt pikslit, nad on viited arvesse värvi, look-up table. Seda värvi look-up table nimetatakse palett, ja mis on tehtud kuni 3 baiti iga viide. 3 baiti on Punane, Roheline ja Sinine, (B) võrra. Nii, krunt kindla punane pixel aadressil x = 100 ja y = 100, me tahaks seada, näiteks 50 elementi värvi, look-up table 0xFF, 0x00, 0x00, (see on B, kus R <punane> 0xFF, B <sinine> 0x00 ja B <sinine> 0x00). See peaks muutma piksli väärtus on 50, punane. Nii me siis krunt, mille väärtus on 50 mällu asukohta x = 100 ja y = 100 ja meil on punane pixel selles kohas.

See võib tunduda keeruline, kuid see ei ole. Enamik aega, seadsime palett üks kord ja koo fikseeritud kogu palett. Enne, kui me saame määrata, et “üks” palett, meil on vaja see luua (või kasutada “standard” üks). Selle numbri, me enamasti kasutada kenasti määratletud “standard” Windows palett. (Ma olen loonud BMP faili standard windows värvid, salvestada ja seda hiljem kaevandatud palett välja, kasutades oma programmi.)

on toimingud palett. Me saame valida üks indeks värvi, look-up table konkreetse 3 bait kanne, või meil on võimalik hankida need 3 baitide konkreetse indeksi palett. Ei saagi all VGA siiski. VGA on palett koosneb kolmest 6 bitine kanded (pole 8 bit kanded bait soovitan). Nii, 6 * 3 = 18 ja 2^18 on 262,144. Ja see, kui maksimaalne arv värvid on saadaval. Kui see on võimalik talletada bait, meil oleks 8 * 3 = 24 ja 2^24 on 16,777,216; see on palju rohkem värve kui standard VGA. Enamik mitte-VGA lähenemisviiside toetamiseks bait (8 bitti) põhineb palett (hea näide on JPEGpildid 24 bitine värv, nad ei ole täpselt palett põhineb, kuid B põhinev).

Saadud teavet, mis teil on, saab juba arvutada, suurus 256 värvipalett. See 3 baiti per pixel, 256 eri pikslit, nii et 3 * 256 = 768! Ja tegelikult, 768 on suurus kõige 256 värvi paletti, sealhulgas üks PCX failid. Mõnikord, siiski, nad store 4 baiti per pixel kiirust, tõhusust (näiteks BMP – failid). Viimane bait ei kasutata. Enamik kordi palett, et on B, kuid mõnikord on see BGR (jälle, nagu BMP failid) või midagi veel abstraktne… Seal on palju konventsioonide see; sa pead ainult teadma, põhiline vähe, ja kõige, sa pead olema võimeline mõtlema meie päris kergesti, kui sul on põhi arusaam.

Nüüd, laseb kirjutada programm, mis loeb ja määrab palett, ja ei mõned lahedad efektid lihtsalt mängides palett (ilma tegelikult joonistus midagi sees peamine kaare).

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>
#include <string.h>
#include <alloc.h>

typedef unsigned char byte_t;

byte_t palju* video_buffer = (byte_t palju*)0xA0000000;

void vid_mode(byte_t mode){
union REGS regs;
regs.h.ah = 0;
regs.h.al = mode;
int86(0x10,&regs,&regs);
}

void blit(byte_t palju* mida){
_fmemcpy(video_buffer,mida,320*200);
}

void setpalette(byte_t c,byte_t r,byte_t g,byte_t b){
outp(0x3c6,0xff);
outp(0x3c8,c);
outp(0x3c9,r);
outp(0x3c9,g);
outp(0x3c9,b);
}

void getpalette(byte_t c,byte_t* r,byte_t* g,byte_t* b){
outp(0x3c6,0xff);
outp(0x3c7,c);
*r = inp(0x3c9);
*g = inp(0x3c9);
*b = inp(0x3c9);
}

void setpalette_all(byte_t palett[256][3]){
int i;
for(i=0;i<256;i++)
setpalette i,palett[i][0]>>2,palett[i][1]>>2,
palett[i][2]>>2);
}

void vline(int x,int y1,int y2,byte_t värvi,byte_t palju* kui){
for(;y1 <= y2;y1++)
kui[y1*320+x] = värv;
}

void movepalette(){
byte_t r,g,b,r1,g1,b1;
int i;
getpalette(0,&r1,&g1&b1);
for(i=0;i<255;i++){
getpalette(i+1,&r&g,&b);
setpalette i,r,g,b);
}
setpalette(255,r1,g1,b1);
}

int main(){
FAILI* sisend;
int i;
byte_t palett[256][3];
byte_t palju* double_buffer;

double_buffer =
(byte_t palju*)farmalloc((unsigned long)320*200);
kui(double_buffer == NULL){
printf("vabandust, ei ole piisavalt mälu.\n");
return 1;
}
_fmemset(double_buffer,0,(unsigned long)320*200);

sisend = fopen("palett.dat","rb");
if(sisend == NULL){
printf("ei saa lugeda faili...\n");
exit(1);
}

kui(fread(palett,sizeof(palette),1,input) != 1){
printf("ei saa lugeda faili...\n");
exit(1);
}
fclose(sisend);

vid_mode(0x13);

setpalette_all(palette);

for(i=0;i<320;i++)
vline(i,0,199,i%256,double_buffer);
blit(double_buffer);

while(!kbhit())
movepalette();

vid_mode(0x03);
farfree(double_buffer);
return 0;
}

Kui te vaatate tähelepanelikult allika juures, siis näed, et see on lihtsalt laiendus vana allikas. Laiendused on funktsioone, mis võimaldavad meil manipuleerida palett. Meil on setpalette() function, ja getpalette()function. Need komplekti ja saada määratud palett väärtus vastavalt. Sees main(), loeme meie palett.dat – failis, mis on Windows vaikimisi palett. Me siis määra see palett. Pane tähele, et sees meie setpalette()function, me oleme minnes palett väärtus 2. See on, sest tegelik arv bitti standard VGA palett on 6 (nagu varem mainitud). Nii, me shift 2, et kõrvaldada tähtsusetu kaks bitti) ja säilitada olulisemad.

vline() funktsioon juhib vertikaalset joont. See ei ole parim viis, et tõmmata jooni, ja me arutame palju erinevaid line joonistus algoritme, kui me oleme teinud selle osa. Me siis blit(), double_buffer, et ekraanile, ja alustada mängides palett. Pange tähele, et me ei ole kirjutanud midagi, et video mälu, ja veel, terve ekraani liigub (see on ilu paletti).

ma arvan, et kui te lähete üle ülaltoodud programmi, saad teada (ja aru) üsna palju paletti. Nii et, ärge kartke, ja minna üle! (kindlasti koostada, ja vaata, mõju) lõplik jaotus käesolev dokument hõlmab ka palett faili ka, aga kui sa ei ole see, sa ei saa lihtsalt luua oma palett. Midagi read:

for(i=0;i<256;i++){
palett[i][0] = palett[i][1] = palett[i][2] = i;
}

Või saate mängida kaart, nii et vaata, mis välja parimad. See on see põhitõdesid, kuidas graafika all töötavad Päris DOS Mode all Borland C++ v3.1!

Protected Mode Graafika…

Graafika all Päris DOS Mode on tore, aga mõnikord on lihtsalt liiga palju piiranguid plain vanilla ÜLESANDEID. Kõige silmatorkavam need piirangud on ranged piirangud mälu. (mõnikord ma tahan, et mu programme kasutada palju rohkem kui lihtsalt 640k RAM-i!) Rääkimata anoyance tegelevad palju näpunäited! Noh, sa saad pildi, teeme midagi tõsist Reaalses DOS Mode on põrgu!

appi, tuleb ohutu ja lahe 32 bit Kaitstud Režiim. Koostaja me kasutame selles osas on DJGPP v2. See on TASUTA 32 bit Kaitstud Režiimi kompilaator DOS-i jaoks. Ei lase, et “DOS” sa viska maha jäänud, DJGPP töötab suurepäraselt alusel Win95/98, WinNT samuti. Kuigi te ei saa koguda midagi, kasutades Win32 API, või MFC saab siiski kirjutada DOS-i põhised programmid, mis on väga võimas ja lahe otsin, ja kasutada nii palju mälu, kui nad vajavad (kuni 4 gb muutmälu (RAM), kui vaja).

saate alla laadida DJGPP http://www.delorie.com, lihtsalt klõpsake DJGPP link ja järgige allalaadimise juhiseid. Kui teil on mingeid probleeme setup, vaadata läbi KKK, mis on kättesaadav ka sellel veebilehel (või e-posti mind). Seal on ka tööriista nimega RHIDE, mis kenasti simuleerib Borland ‘ IDE (nii, võite tunda nagu kodus, kui teil hakata kasutama DJGPP).

Eeldades, et sa pole alla laaditud (ja paigaldatud) DJGPP, võimaldab nüüd port meie Tõeline DOS Mode programm eelmisest jagu 32-bit Kaitstud Režiimi DOS, kasutades DJGPP. See võib tunduda keerulisem, kui see tegelikult on.

Kuna enamik allikas on C, me ei’ pea muretsema, seda kõige rohkem. Osad me ei pea muretsema, on mälu kirjalikult osad. Sest nüüd me oleme kaitstud režiimis, ei saa me lihtsalt kirjutada, et 0xA0000000, sest et mälu on kaitstud (nagu ka igal teisel mälu kaitstud režiimi). Meil on mitmeid võimalusi, kuid me saame kasutada DJGPP konkreetne süsteem, kõne, et kopeerida double buffer, et video mälu (asendades meie blit() function), või me võib ajutiselt keelata mälu kaitse, siis kirjutage ekraani ja seejärel lubage mälu kaitse.

on plussid ja miinused nii! Kasutades süsteemi kõne koopia mälu on ohutu ja ühildub paljude süsteem, sealhulgas DOS/Win95/98/NT (jah, see töötab alusel NT4!), aga see on liiga aeglane! Keelamine mälu kaitse, kopeerimine, ja hiljem, mis võimaldab mälu kaitse ei ole väga ühilduvad (ega ohutu), kuid see on palju kiirem. See teine lähenemine töötab alusel DOS/Win95/98, kuid MITTE alla WinNT! Noh, laseb kirjutada koodi, mis annab meile võimaluse kasutada nii need lähenemised, ja ma lasen teil valida üks, mida soovite kasutada…

#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <string.h>
#include <conio.h>

typedef unsigned char byte_t;

void vid_mode(byte_t mode){
union REGS regs;
regs.h.ah = 0;
regs.h.al = mode;
int86(0x10,&regs,&regs);
}

void blit0(byte_t* mida){
dosmemput(mida,320*200,0xA0000);
}

#include < sys/nearptr.h>
/* VÄGA ohtlik, kuid kiire! */
void blit1(byte_t* mida){
/* keelata mälu kaitse */
__djgpp_nearptr_enable();
/* kirjutage mälu */
memcpy((void*)(0xA0000+__djgpp_kokkuleppeline_base),
mida,320*200);
/* võimaldada mälu kaitse */
__djgpp_nearptr_keelata();
}

void setpalette(byte_t c,byte_t r,byte_t g,byte_t b){
outp(0x3c6,0xff);
outp(0x3c8,c);
outp(0x3c9,r);
outp(0x3c9,g);
outp(0x3c9,b);
}

void getpalette(byte_t c,byte_t* r,byte_t* g,byte_t* b){
outp(0x3c6,0xff);
outp(0x3c7,c);
*r = inp(0x3c9);
*g = inp(0x3c9);
*b = inp(0x3c9);
}

void setpalette_all(byte_t palett[256][3]){
int i;
for(i=0;i<256;i++)
setpalette i,palett[i][0]>>2,palett[i][1]>>2,
palett[i][2]>>2);
}

void vline(int x,int y1,int y2,byte_t värvi,byte_t* kui){
for(;y1 <= y2;y1++)
kui[y1*320+x] = värv;
}

void movepalette(){
byte_t r,g,b,r1,g1,b1;
int i;
getpalette(0,&r1,&g1&b1);
for(i=0;i<255;i++){
getpalette(i+1,&r&g,&b);
setpalette i,r,g,b);
}
setpalette(255,r1,g1,b1);
}

int main(){
FAILI* sisend;
int i;
byte_t palett[256][3];
byte_t* double_buffer;

double_buffer = (byte_t*)malloc(320*200);
kui(double_buffer == NULL){
printf("vabandust, ei ole piisavalt mälu.\n");
return 1;
}
memset(double_buffer,0,320*200);

sisend = fopen("palett.dat","rb");
if(sisend == NULL){
printf("ei saa lugeda faili...\n");
exit(1);
}

 kui(fread(palett,sizeof(palette),1,input) != 1){
printf("ei saa lugeda faili...\n");
exit(1);
}
fclose(sisend);

vid_mode(0x13);

setpalette_all(palette);

for(i=0;i<320;i++)
vline(i,0,199,i%256,double_buffer);
blit0(double_buffer);

while(!kbhit())
movepalette();

vid_mode(0x03);
tasuta(double_buffer);
return 0;
}

Nagu näete, koodi ei muuda palju. Tegelikult, ainult mälu käitlemise muutunud. farmalloc() sai lihtne vana malloc(), farfree() pöördus vaba(), jne. Peamine tähelepanu peaks olema suunatud blit#() funktsioonid… praegu on neid kaks. (Ma olen kindel, et seal on palju rohkem lähenemisviise, et kirjutada, et video mälu kaitstud režiim, üks, mis on väärt otsivad oma on _farnspokel()on määratletud <sys/farptr.h> – faili.)

blit0() on lihtne ja lihtne. See lihtsalt nõuab süsteemi teha koopia, ja ongi kõik. Mida märkad on see, et me oleme kopeerimine, et 0xA0000, et on, sest see on füüsiline mälu ekraani (teade neli 0s). Kaitstud režiim, me ei pea segmendid või tasakaalustamisega, kuna reaalses režiim (tegelikult on segmendid ja vastuostud kaitstud režiimis, kuid neil on eri tähendus ei), nii, kaitstud režiimi me kasutame täieliku füüsiline aadress kui meil on vaja, et lahendada mälu kaardistatud seade nagu VGA.

blit1() on keerulisem üks. See esimene kõned __djgpp_nearptr_enable(), mis tegelikult tühistab mälu kaitse. Funktsioon ei ole viga kontrollides, et vaadata tagasi väärtuseks __djgpp_nearptr_enable(). Kui mälu kaitse on kadunud, me võime lihtsalt kirjutada ükskõik (sh ekraanil). (või kirjutada Operatsioonisüsteemi kui me soovis <või oli viga, mis tegin seda>!) Me kasutame regulaarselt memcpy() kopeeri puhvrisse ekraaniga, mis on 0xA0000, __djgpp_kokkuleppeline_baasi (kokkuleppeline mälu base) nihe. Me siis edasi, võimaldades mälu kaitse helistades __djgpp_nearptr_keelata().

Nagu ta on, see meetod ei ole palju kiiremini, kui enne. Põhjus on see, et funktsioonid, mida lubada ja keelata mälu kaitse on üsna aeglane. Nii, *tavaliselt* kui olete saanud viimase debug etapi oma projekti, sa lihtsalt keelata mälu alguses oma programmi, ja see võimaldaks lõpus. See on VÄGA ohtlik küll, ja võib põhjustada tõsiseid probleeme (sealhulgas täielik kadu kõike).

Windows Graafika…

Windows on tulevikus (või nii nad ütlevad), nii et ilmselt teeme graafika lihtsas vana DOS ei ole hea mõte (või nii nad ütlevad). Ma ikka arvan, et see on hea idee, sest ainult DOS-is saab eraldada ennast rumalus Operatsioonisüsteemi, ja muretsema ainult OMA programmi, ja mitte seda, kuidas Windows töötab oma programmi. DOS, enamik korda, teie programm muutub operatsioonisüsteemi. Enamik mänge ON operatsioonisüsteemid; nad käepide I/O, klaviatuur, kõike! Igatahes, tundub, Windows on võitnud sõja, ja see on aega, et õppida, Windows programmeerimine.

Üks raskemaid asju DOS-i programmeerijad mõista, kuidas saada Windows on, et sa ei ole tasu enam; Windows on! Kui teie programm tahab MIDAGI teha, see on selleks, et küsida, Windows seda teha. Sa ei saa lihtsalt minna ümber joonestamist pikslit arvesse video mälu, sa pead küsi windows seda sinu jaoks. Kõik Aknad on kontrolli all Windows; ja teie programm peab arvestama, et see “mõistmine” või see on vσlja süsteem.

käesolevas jaos, peate Microsoft Visual C++ v5 Pro (või hiljem). See jagu hõlmab põhilisi Windowsi graafika, mis on väga kantavad, et kõik Windows süsteemidega (nr DirectX kraam).

Iga üks õpetused ja raamatud (need, mida ma olen näinud) alguses ja lihtne viis, et nad ütlevad, “kasutage viisardi luua shell MFC-programmi, ja sealt edasi minna”… noh, see dokument ei tee seda. Ma kirjutan selle koodi plain vana C, kasutades tavaline vana Win32 API-t. See ei ole, sest ma vihkan MFC (kuigi see on tegur), kuid kuna see ei õpeta sind Windows programmeerimine. Palju nn Windows programmeerijad kasutada ainult MFC -, ja pole aimugi, alusvara Win32 liides (või kuidas Windows programm on ehitatud).

Võimaldab saada kuni punktini, tegelikult kirjutamist (ja mitte kritiseerimist Microsoft lollakas OS). Iga Windowsi programm hakkab läbi sees WinMain() function, mitte main() function, nagu see on enamiku C programmid. Windows programmi esimene loob akna klass a WNDCLASS struktuur), registreerib see, loob aken, et klassi, ja näitab, et aken. Lihtne?

Siis see peaks looma DIB jagu juhtida arvesse (double buffer) (DIB seisab Device Independent Bitmap). See on teinud esimese sätte elementi BITMAPINFO struktuuri, luua ja realiseerida palett, jne., ja siis helistab CreateDIBSection(), mis annab meile topelt puhvri juhtida.

ju, et meil on vaja ka blit() function! See on raskem kui see on DOS-is! Hakkame luua seade kontekstis, helistades CreateCompatibleDC(). Valides meie HBITMAP (bitmap handler), mis kontekstis. Blitting kasutades BitBlt() function (mis on üsna kiire enamik korda), ja tagasi seaded tavaline (teed puhastada, jne.).

programm jookseb sees samas kaarde (WinMain() function), mis kaart kuni programm saab WM_QUIT sõnum. Nüüd on hea aeg meeles, et kõik Windows on tehtud, kasutades sõnumite 😉 Meie programm see saadetakse sõnum, kui me püüame hävitada rakenduse aken. (sest me oleme kutsudes PostQuitMessage() function, kui WndProc() saab WM_DESTROY sõnum.)

See võib olla keerulisem kui DOS-is, ja see on IMHO! Kuid see, kuidas ta on ja seal on väga vähe sulle või mulle saate teha selle kohta. Nüüd, ma jätan teile, et aru saada, andmed kõik see, või ma annan teile allikas nagu näiteks? (sa oleks üllatunud, kuidas paljud raamatud “jäta välja andmed” tegeliku rakendamise midagi)

#include <windows.h>

typedef BAIT byte_t;

#define W_WIDTH 320
#define W_HEIGHT 240

struct pBITMAPINFO{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[256];
}BMInfo;

struct pLOGPALETTE{
SÕNA palVersion;
 SÕNA palNumEntries;
PALETTEENTRY palPalEntry[256];
}PalInfo;

HBITMAP hBM;
byte_t* double_buffer;

void blit(void);

void vline(int x,int y1,int y2,byte_t värvi,byte_t* kui){
for(;y1 <= y2;y1++)
kui[y1*320+x] = värv;
}

void p_update(){
int i;
static unsigned int k=0;
for(i=0;i<W_WIDTH;i++){
vline(i,0,W_HEIGHT-1,(byte_t)(c%256),double_buffer);
c = c > 512 ? 0:c+1;
}
blit();
}

void getpalette(RGBQUAD* p){
int i;
for(i=0;i<256;i++){
p[i].rgbRed = i;
p[i].rgbGreen = i;
p[i].rgbBlue = i;
p[i].rgbReserved = 0;
}
}

void init_double_buffer(){
 HPALETTE PalHan;
HWND ActiveWindow;
HDC hDC;
RGBQUAD palett[256];
int i;

ActiveWindow = GetActiveWindow();
psm-sse = GetDC(ActiveWindow);

BMInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BMInfo.bmiHeader.biWidth = W_WIDTH;
BMInfo.bmiHeader.biHeight = abs(W_HEIGHT);
BMInfo.bmiHeader.biPlanes = 1;
BMInfo.bmiHeader.biBitCount = 8;
BMInfo.bmiHeader.biCompression = BI_RGB;
BMInfo.bmiHeader.biSizeImage = 0;
BMInfo.bmiHeader.biXPelsPerMeter = 0;
BMInfo.bmiHeader.biYPelsPerMeter = 0;
BMInfo.bmiHeader.biClrUsed = 256;
BMInfo.bmiHeader.biClrImportant = 256;

getpalette(palette);

for(i=0;i<256;i++)
BMInfo.bmiColors[i] = palett[i];

PalInfo.palVersion = 0x300;
PalInfo.palNumEntries = 256;
for(i=0;i<256;i++){
PalInfo.palPalEntry[i].peRed = palett[i].rgbRed;
PalInfo.palPalEntry[i].peGreen = palett[i].rgbGreen;
PalInfo.palPalEntry[i].peBlue = palett[i].rgbBlue;
PalInfo.palPalEntry[i].peFlags = PC_NOCOLLAPSE;
}

/* luua palett */
PalHan = CreatePalette((LOGPALETTE*)&PalInfo);
/* valige see, et SM-sse */
SelectPalette(psm,PalHan,FALSE);
/* mõistad, palett, et SM-sse */
RealizePalette(psm);
/* kustuta palett menetleja */
DeleteObject(PalHan);

hBM = CreateDIBSection(psm-sse,(BITMAPINFO*)&BMInfo,
DIB_RGB_COLORS,(void**)&double_buffer,0,0);
ReleaseDC(ActiveWindow,hDC);
}

void blit(){
HWND ActiveWindow;
PSM psm-sse,Kontekstis;
RECT Dest;
HBITMAP DefaultBitmap;

if((ActiveWindow = GetActiveWindow()) == NULL)
tagasi pöörduda;
psm-sse = GetDC(ActiveWindow);
GetClientRect(ActiveWindow,&Dest);

Taust = CreateCompatibleDC(0);
DefaultBitmap = SelectObject(Kontekst,hBM);
BitBlt(psm,0,0,Dest.õige,Dest.põhja,Tausta,0,0,SRCCOPY);
SelectObject(Kontekst,DefaultBitmap);
DeleteDC(Kontekstis);
DeleteObject(DefaultBitmap);
ReleaseDC(ActiveWindow,hDC);
}

LRESULT HELISTA WndProc(HWND hWnd,UINT iMessage,
WPARAM wParam,LPARAM lParam){
switch(iMessage){
juhul WM_DESTROY:
PostQuitMessage(0);
return 0;
vaikimisi:
tagasi DefWindowProc(hWnd,iMessage,wParam,lParam);
}
}

int WINAPI WinMain(KÄEPIDE hInstance,KÄEPIDE hPrevInstance,
LPSTR lpszCmdParam,int nCmdShow){
WNDCLASS WndClass;
char szAppName[] = "CrazyWindow";
HWND hWnd;
MSG msg;
BOOL töötab = TRUE;

WndClass.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
 WndClass.cbWndExtra = 0;
WndClass.hbrBackground = GetStockObject(BLACK_BRUSH);
WndClass.hIcon = LoadIcon(hInstance,NULL);
WndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
WndClass.hInstance = hInstance;
WndClass.lpszClassName = szAppName;
WndClass.lpszMenuName = 0;

RegisterClass(&WndClass);

	hWnd = CreateWindow(szAppName,szAppName,
WS_CAPTION|WS_MINIMIZEBOX|WS_SYSMENU,
CW_USEDEFAULT,CW_USEDEFAULT,W_WIDTH,W_HEIGHT,
0,0,hInstance,0);
ShowWindow(hWnd,nCmdShow);

init_double_buffer();

while(töötab == TRUE){
p_update();
Magada(250);
kui(PeekMessage(&msg,0,0,0,PM_NOREMOVE) == TRUE){
töötab = GetMessage(&msg,0,0,0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
tagasi msg.wParam;
}

Noh, ei ole oodata suurt seletust kogu see värk siin; lõppude lõpuks, see ei ole Windows programmeerimine juhendaja. Kui teil on probleeme mõista eespool koodi, pakun, et sa saad hea Windows Programmeerimine raamat (kuigi nad on üsna raske saada). Ma loodan, et kui teil on kompilaator (Visual C++ v5 Pro) koostada käesoleva allikas, sa pead olema mõnevõrra rahul Windows värk… (Ja on MSDN-i CD-d, mida on TONNI kasulikku kraami umbes Windows ja viited kõik funktsioonid ja muutujad, mida kasutatakse selles programmis.)

muide, ma arvan, et ma olen teinud nii lihtne, kui ta võiks saada!

DirectX Graafika…

kellegi Jaoks, kes pole kunagi programmeeritud midagi, kasutades DirectX-i, saab seda meeles arusaamatu, et tegelikult proovida mõista, kuidas kogu see kraam. See on keeruline (seal on liiga palju)! Arvan, et kogu DirectX nagu kogumine raamatukogudes igasuguseid “mäng” seotud asjad (heli, graafika, sisend, jne.) Osa me teile olla tegemist käesolevas jaos on DirectDraw. Me kasutame seda sisestada täis ekraan, 256 värvi, topelt puhverdatud, režiimi all Windows, ja teha asju ekraanil.

Sa peaksid teadma, et DirectX ei ole liiga teisaldatavatele (vähemalt mitte samal ajal selle kirjalikult). Palju DirectX programmid lihtsalt ei tööta alusel WinNT4! (ja need, mis ei jookse, vaid toetada mõningaid video režiimid, ja ei muud), Siis on süsteem, mis pole ikka veel DirectX on installitud! (nagu mu Win95 masin kodus) Kõik see on umbes muuta siiski NT5 ja Win98 nii tulevad koos DirectX 5 toetada, ja selleks ajaks NT5 laevad, tõenäoliselt toetada DX6.

kirjutada midagi, kasutades DirectX aga sa pead olema see! Nii et, kui te ei ole juba, minge Microsoft web-site, download DirectX SDK-d (või et see CD-ROM) (see on üsna suur!). Koht alustamiseks otsin on see: http://www.microsoft.com/directx. Kui teil on üks uuemad versioonid Visual C++, võimalused on, et mõned DirectX-i versioon on juba rippus ümber sinu kõvaketas (või vähemalt library faile linkida) (ja mitte näited, jne.)

Enne kui me alustame, tahaksin välja tuua mõned asjad. Kuigi DirectX programmid töötavad ainult Windows, nende võim on ikka oma täisekraani režiimi. (jah, ei usu, et tuleb kirjalikult windowed rakendus kasutab DirectX igal ajal kiiresti…), Kui teil on vaja oma graafika programmi käivitada aknas, kasuta kirjeldatud lähenemisviis varem Windows Graafika jagu.

DirectX, enamik aega, meil on tegemist asi, mida nimetatakse Pinna. Juhime pindadele jne. Enne me ei saa midagi teha, aga on meil vaja luua DirectDraw objekt. Siis me täpsustama, kas me tahaks joosta täisekraan, jne. Siis me luua esmane pind (arvan, et esmane pind kui selline video_buffer meie eelmise näidised), ja siis me luua tagasi pind (arvan, et tagasi pind kui selline double_buffer). Teha, me kõigepealt mälu pointer tagasi pind (puldiga pind), joonistame, et kursor, ja hiljem avada pinna (ja teha midagi, mis on selline nagu blit() function…)

ülevalt on liiga lihtsustatud! Alljärgnev kood on natuke täpsem.

#include <windows.h>
#include <ddraw.h>

typedef BAIT byte_t;

#define W_WIDTH 640
#define W_HEIGHT 480

int b_pitch;
byte_t *double_buffer;

HWND hWnd;
PALETTEENTRY palett[256];
DDSURFACEDESC ddsd;
LPDIRECTDRAW lpDD;
LPDIRECTDRAWSURFACE lpDDSPrimary;
LPDIRECTDRAWSURFACE lpDDSBack;
LPDIRECTDRAWPALETTE lpDDPal;

void big_error(char* string){
MessageBox(hWnd,string,"suur & halb viga",
MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL);
ExitProcess(1);
}

void init_directdraw(){
DDSURFACEDESC ddsd_tmp;
HRESULT ddrval;
ddrval = DirectDrawCreate(NULL,&lpDD,NULL);
kui(ddrval != DD_OK)
big_error("ei suutnud init DirectDraw!");
ddrval = IDirectDraw_SetCooperativeLevel(lpDD,hWnd,
DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN|DDSCL_ALLOWREBOOT);
kui(ddrval != DD_OK)
big_error("couldn' t set DirectDraw eksklusiivne mode!");
 ddrval = IDirectDraw_SetDisplayMode(lpDD,W_WIDTH,W_HEIGHT,8);
kui(ddrval != DD_OK)
big_error("couldn' t set DirectDraw display mode!");
ddsd_tmp.dwSize = sizeof(ddsd_tmp);
ddsd_tmp.dwFlags = DDSD_CAPS;
ddsd_tmp.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
ddrval = IDirectDraw_CreateSurface(lpDD,&ddsd_tmp,
&lpDDSPrimary,NULL);
kui(ddrval != DD_OK)
big_error("ei suutnud luua esmane pind!");
ddsd_tmp.dwSize = sizeof(ddsd_tmp);
ddsd_tmp.dwFlags = DDSD_CAPS |DDSD_WIDTH|DDSD_HEIGHT;
ddsd_tmp.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN|DDSCAPS_SYSTEMMEMORY;
 ddsd_tmp.dwWidth = W_WIDTH;
ddsd_tmp.dwHeight = W_HEIGHT;
ddrval = IDirectDraw_CreateSurface(lpDD,&ddsd_tmp,
&lpDDSBack,NULL);
kui(ddrval != DD_OK)
big_error("ei suutnud luua tagasi pinnale!");
}

void kill_directdraw(){
kui(lpDD != NULL){
kui(lpDDSPrimary != NULL){
IDirectDrawSurface_Release(lpDDSPrimary);
lpDDSPrimary = NULL;
}
kui(lpDDSBack != NULL){
IDirectDrawSurface_Release(lpDDSBack);
lpDDSBack = NULL;
}
kui(lpDDPal != NULL){
IDirectDrawPalette_Release(lpDDPal);
lpDDPal = NULL;
}
IDirectDraw_Release(lpDD);
lpDD = NULL;
}
}

void set_palette(RGBQUAD* pal){
PALETTEENTRY must = {0,0,0,0},valge = {0xFF,0xFF,0xFF,0};
int i;
kui(pal != NULL){
for(i=1;i<0xFF;i++){
pal++;
palett[i].peRed = pal[i].rgbRed;
palett[i].peGreen = pal[i].rgbGreen;
palett[i].peBlue = pal[i].rgbBlue;
palett[i].peFlags = (byte_t)0;
}
}else{
for(i=1;i<0xFF;i++){
palett[i].peRed = i;
palett[i].peGreen = i;
palett[i].peBlue = i;
palett[i].peFlags = (byte_t)0;
}
}
palett[0] = must;
palett[0xFF] = valge;
IDirectDraw_CreatePalette(lpDD,DDPCAPS_8BIT,palett,
&lpDDPal,NULL);
 kui(lpDDPal != NULL)
IDirectDrawSurface_SetPalette(lpDDSPrimary,lpDDPal);
}

BOOL lock_surface(){
HRESULT ddrval;
ddsd.dwSize = sizeof(ddsd);
for(;;){
ddrval = IDirectDrawSurface_Lock(lpDDSBack,NULL,
&ddsd,DDLOCK_WAIT,NULL);
kui(ddrval == DD_OK)
break;
kui(ddrval == DDERR_SURFACELOST){
ddrval = IDirectDrawSurface_Restore(lpDDSPrimary);
kui(ddrval == DD_OK)
return FALSE;
}
kui(ddrval != DDERR_WASSTILLDRAWING)
return FALSE;
}
double_buffer = (byte_t*)(ddsd.lpSurface);
b_pitch = ddsd.lPitch;
tagasi TRUE;
}

void unlock_surface(){
HRESULT ddrval;
 RECT rc = {0,0,W_WIDTH,W_HEIGHT};

double_buffer = NULL;
for(;;){
ddrval = IDirectDrawSurface_Unlock(lpDDSBack,
ddsd.lpSurface);
kui(ddrval == DD_OK)
break;
kui(ddrval == DDERR_SURFACELOST){
ddrval = IDirectDrawSurface_Restore(lpDDSPrimary);
kui(ddrval != DD_OK)
tagasi pöörduda;
}
kui(ddrval != DDERR_WASSTILLDRAWING)
tagasi pöörduda;
}
for(;;){
ddrval = IDirectDrawSurface_BltFast(lpDDSPrimary,0,0,
lpDDSBack,&rc,DDBLTFAST_NOCOLORKEY);
kui(ddrval == DD_OK)
break;
kui(ddrval == DDERR_SURFACELOST){
ddrval = IDirectDrawSurface_Restore(lpDDSPrimary);
 kui(ddrval != DD_OK)
tagasi pöörduda;
}
kui(ddrval != DDERR_WASSTILLDRAWING)
tagasi pöörduda;
}
}

void vline(int x,int y1,int y2,byte_t värvi,byte_t* kui){
for(;y1 <= y2;y1++)
kui[y1*b_pitch+x] = värv;
}

void p_update(){
int i;
static unsigned int k=0;
kui(lock_surface()){

for(i=0;i<W_WIDTH;i++){
vline(i,0,W_HEIGHT-1,(byte_t)(c%256),double_buffer);
c = c > 512 ? 0:c+1;
}

unlock_surface();
}
}

LRESULT HELISTA WndProc(HWND hWnd,UINT iMessage,
WPARAM wParam,LPARAM lParam){
switch(iMessage){
juhul WM_DESTROY:
juhul WM_LBUTTONDOWN:
juhul WM_KEYDOWN:
PostQuitMessage(0);
return 0;
vaikimisi:
tagasi DefWindowProc(hWnd,iMessage,wParam,lParam);
}
}

int WINAPI WinMain(KÄEPIDE hInstance,KÄEPIDE hPrevInstance,
LPSTR lpszCmdParam,int nCmdShow){
WNDCLASS WndClass;
char szAppName[] = "CrazyWindow";
MSG msg;
BOOL töötab = TRUE;

WndClass.style = CS_HREDRAW|CS_VREDRAW|CS_OWNDC;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hbrBackground = GetStockObject(BLACK_BRUSH);
WndClass.hIcon = LoadIcon(hInstance,NULL);
WndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
 WndClass.hInstance = hInstance;
WndClass.lpszClassName = szAppName;
WndClass.lpszMenuName = 0;

RegisterClass(&WndClass);

hWnd = CreateWindow(szAppName,szAppName,
WS_CAPTION|WS_MINIMIZEBOX|WS_SYSMENU,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
0,0,hInstance,0);
ShowWindow(hWnd,nCmdShow);

init_directdraw();
set_palette(NULL);

while(töötab == TRUE){
p_update();
Magada(250);
kui(PeekMessage(&msg,0,0,0,PM_NOREMOVE) == TRUE){
töötab = GetMessage(&msg,0,0,0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

kill_directdraw();
tagasi msg.wParam;
}

ma soovitan teil minna üle allikas (mitu korda); lõpuks, sa hakkad aru saama. Programm teeb täpselt sama mõju programmi Windows Graafika. jagu (ainult täisekraani!). Koostada/link programmi, sa ‘ ll vaja DirectX raamatukogud, ja siduda see programm ddraw.lib

Teine asi, mida võiks kaaluda; kasutades DirectX teie programm on PALJU lihtsam, kui olete kirjalikult oma programme kasutades C++. Palju need pikad funktsioone, mis on muutunud küllaltki lühikese meetodid objektid. (see on palju puhtam kasutada C++ DirectX) (ma lihtsalt vihkan C++ <ma tegelikult kasutatud armastan seda paar aastat tagasi.>,, nii, ma tegin seda nii!)

Teate, enne kui me minna: See programm töötab enamik Windowsi platvormil, kuid see on tingitud asjaolust, et see on režiim 640x480 (standard Windows mode)! Kui te režiimiks 320x200 või Režiimile X (mis on: 320x240), programm EI tööta alusel NT4. Siiski, programm on töö tehtud Win95/98. Et muuta neid erinevaid režiime, muuta W_WIDTH ja W_HEIGHT määratleb ülaosas kood. (Ma tõesti vihkan seda, kui populaarne mäng ei tööta täisekraan 320x240 all NT4; st: Quake 2 <hei, mitte kõik meist on Pentium 2, 400Mhz, mille Voodoo 2 Kiirendi!>) Seal on lähenemisviise, et muuta see viga ära minna. Saate endiselt kasutada 640x480 mode, ja kas venitada pärast blitting. Ma kahtlen, et a 2x venitada tabab tulemuslikkuse liiga karmilt. Igatahes, ma loodan, et NT5 toetatakse kõiki neid madala resolutsiooniga režiimid… (ma olen kindlasti ei kavatse tagasi Win98 lihtsalt mängida täisekraanil!)

Java Graafika…

Jah! Java. Enamik inimesi arvan, et Java on liiga aeglane ja mõttetu graafika, ja neil võib õigus olla (ma pole veel kohanud, tõesti väga lahe graafika programm, mis edestasid see on C/C++ kolleegidega.) Siiski, Java on kõige elegantne objektorienteeritud keel, ma olen näinud (C++ on rämps võrreldes Java!).

“Kiire graafika Java” on mõnevõrra an oxymoron. Kuid see on üha kiirem ja mõnel juhul võib konkureerida C/C++. On kaks võimalust, et teeme graafika Java, kasutades raamatukogud, või luua double buffer juhtida arvesse (sarnane sellega, mida me oleme teinud eelmistes punktides). Teekide kasutamine on palju lihtsam ja mõnel juhul lihtne lahendus. See on palju lihtsam lihtsalt öelda, g.drawLine(0,0,100,100); joone, kui setup tonni kraami, ja kirjutada koodi optimeeritud line algoritm ise.

Esiteks, me muretsema Java graafika raamatukogu lähenemine, kuna me ilmselt kasutavad seda hiljem illustreerimiseks mõned kiired algoritmid. (See on lihtne kasutada!) Kui me oleme teinud õpe “raamatukogu” lähenemisviisi, ma näitan teile trikki kõige raamatud, õpetused ja näited proovige vältida. Rakendada meie enda ImageProducer ja luua üsna kiire graafika javaga.

näited käesolevas jaos, peate koopia JDK, mille saad tasuta http://java.sun.com. Ma soovitan teil viimase versiooni (isegi kui see on beta). Microsoft Visual J++ töötab ka enamik näiteid on siin, aga ma olen avastanud, et J++ on väga aegunud, kui tegemist on Java teekide ja ma arvan, et enamik inimesi on paremini välja tavaline ja lihtne JDK.

Noh, lähme kirjalikult koodi! Me kirjutada regulaarsetpplication, mis avab akna, ja juhib tonni suvalise hulknurga sinna. Siin see on:

impordi java.awt.*;
impordi java.awt.sündmus.*;

avalik klassi jDraw ulatub Raami
rakendab WindowListener,Runnable{
loogiline m_running;

avalik tühine windowOpened(WindowEvent e){}
public void windowClosing(WindowEvent e){
m_running = false;
}
avalik tühine windowClosed(WindowEvent e){}
avalik tühine windowIconified(WindowEvent e){}
avalik tühine windowDeiconified(WindowEvent e){}
avalik tühine windowActivated(WindowEvent e){}
avalik tühine windowDeactivated(WindowEvent e){}

 avalik jDraw(String nimi){
super(nimi);
setSize(320,240);
setResizable(false);
addWindowListener(this);
show();
}

public void paint(Graphics g){
int n = (int)(Matemaatika.random()*8);
int[] x = new int[n];
int[] y = new int[n];
for(int i=0;i < n;i++){
x[i] = (int)(Matemaatika.random()*getWidth());
y[i] = (int)(Matemaatika.random()*getHeight());
}
g.setColor(uus Värv((int)(Matemaatika.random()*0xFFFFFF)));
g.fillPolygon(x,y,n);
}

public void update(Graphics g){
värv(g);
}

public void run(){
m_running = true;
while(m_running){
värvida();
proovige{
Keere.currentThread().magada(50);
}catch(InterruptedException e){
Süsteem.välja.println(e);
}
}
}

avaliku staatilise void main(String[] args){
Lõng theApp = new Thread(new jDraw("Hull!"));
theApp.start();
proovige{
theApp.join();
}catch(InterruptedException e){
Süsteem.välja.println(e);
}
Süsteem.exit(0);
} 
}

Nagu näete, kood on üsna lihtne. Oleme avatud akna, set see on suurus, lisada kuulaja jne. Juhtida, et aken jne. ja see on see! (palju lihtsam kui eelmised näited) rääkimata see programm on süsteem, sõltumatu, ja isegi tööd tehtud UNIX kui ka Windows. Ma kahtlen, et see programm vajab palju selgitus (see on üsna lihtne) (jälgida seda, kui sa ei mõista seda). Põhjus, miks me ei vaja palett selles näites on, sest värvid on RGB formaadis. Kui me loome uue Värv, me täpsustada RGB täisarvuni. Nüüd, let ‘ s liikuda onto midagi keerulisem, meie enda ImageProdicer!

just nüüd, on aeg õppida, kuidas juhtida double_buffer javaga! Tegelikult, see on tegelikult saab olema kolmekordne puhver, kuna me teile esimesel setup double_buffer java.awt.Pilt ja siis (pärast blitting meie bait[] puhvri Pilt), me teile blit Pilt, et ekraanile. Seal on rohkem elegantne viisil käitlemise, aga ma lihtsalt ei taha kulutada palju aega (Hakkan puhkust pikendatud puhkust päris kiiresti, ja soovite saada nii palju teha, kui võimalik 😉

Hiljem (kui ma tunnen nagu see), ma näitan a JDK 1.2 lähenemine sellele, mis minu arvates on palju parem. Kahjuks see ei ole nii laialt kooskõlas ImageProducer üks. Noh, lähme õiguse allikas!

impordi java.awt.*;
impordi java.applet.*;
impordi java.awt.pilt.*;

avalik klassi jDrawApplet ulatub Apleti
rakendab Runnable,ImageProducer{

int m_width;
int m_height;
Lõng m_thread = null;
Pilt m_screen = null;

/* ImageProducer muutujad */
byte[] double_buffer;
ColorModel color_model;
ImageConsumer tarbija = null;

 /* ImageProducer interface */
avalik tühine addConsumer(ImageConsumer ic){
kui(tarbija != ic){
tarbija = ic;
tarbija.setDimensions(m_width,m_height);
tarbija.setColorModel(color_model);
tarbija.setHints(ImageConsumer.TOPDOWNLEFTRIGHT);
}
blit();
}
public boolean isConsumer(ImageConsumer ic){
tagasi ic == tarbija;
}
avalik tühine removeConsumer(ImageConsumer ic){}
avalik tühine startProduction(ImageConsumer ic){
addConsumer(ic);
}
avalik tühine requestTopDownLeftRightResend(ImageConsumer ic){}

/* meie blit() meetod */
void blit(){
kui(tarbija != null)
tarbija.setPixels(0,0,m_width,m_height,
color_model,double_buffer,0,m_width);
	}

/* meie vertial line meetod ;-) */
void vline(int x,int y1,int y2,bait värvi,byte[] kus){
for(;y1 <= y2;y1++)
kui[y1*m_width+x] = värv;
}

int k=0;
void do_interesting_stuff(){
for(int i=0;i<m_width;i++){
vline(i,0,m_height-1,(bait)(c%256),double_buffer);
c = c > 512 ? 0:c+1;
}
}

public void paint(Graphics g){
blit();
g.drawImage(m_screen,0,0,null);
}

public void update(Graphics g){
värv(g);
}

/* setup värk... */
void setupImageProducer(){
byte[] r = new byte[256];
byte[] g = new byte[256];
byte[] b = new byte[256];
 for(int i=0;i<256;i++)
r[i] = g[i] = b[i] = (byte)i;
color_model = uus IndexColorModel(8,256,r,g,b);
double_buffer = new byte[m_width*m_height];
}

public void init(){
m_width = getSize().laius;
m_height = getSize().kõrgus;
setupImageProducer();
m_screen = createImage(this);
}

public void start(){
kui(m_thread == null){
m_thread = new Thread(this);
m_thread.start();
}
}

public void run(){
while(true){
do_interesting_stuff();
värvida();
proovige{
m_thread.magada(250);
}catch(InterruptedException e){
Süsteem.välja.println(e);
}
}
}
}

Jah, see on apleti! Teil on luua HTML-faili käivitada. Kood, mis läheb, et HTML fail on:

<html>
<body>
<applet code="jDrawApplet.class" width="320"
height="240"></applet>
</body>
</html>

Ok, laseb korraks üle minna allikas, ja mida ta teeb jne., ja proovige liikuda. Kood algab see teostamise sees init() meetod, viisi tõttu java.applet.Apleti lähtestab värk. Sees init(), saame laius ja kõrgus ja helistage setupImageProducer(). Kuna kogu see klass on rakendamisel java.awt.pilt.ImageProducer, me oleme lihtsalt initializing klassi andmete liikmete sees see setupImageProducer() meetod. Täpsemalt, me luua hall skaala palett (Java tuntud kui a ColorModel), ja mälu eraldada double_buffer.

ColorModel ei ole just palett, see on Object, mis kirjeldab värvi konkreetne “mode”. Meie 256 color mode, see on VÄGA sarnane palett, kuid kõrge värvi režiimid (kõige standard Java värk), see on erinev tähendus ja eesmärkidel.

Pärast meie tulu setupImageProducer(), me luua Pilt, kui parameeter (createImage()). See tähendab, et meil on luua Pilt kasutades ja ImageProducer. See tegevus nõuab addConsumer()meetod või meie ImageProducer, annab see tarbijale, et andke meile setPixels(), et ImageConsumer (m_screen Pilt).

Me siis jagunevad run() meetod, loop forever, kutsudes värvida() ja do_interesting_stuff(). värvida() meetod asynchronously kõned uuenda(), mis omakorda nõuab paint(). Sees paint() meetod, kutsume blit(), mis blits meie double_buffer sisse m_screen Pilt ja siis g.drawImage(), m_screen Pilt (teine selline blit()) ekraaniga.

Sees do_interesting_stuff(), me ei tee midagi erilist, et me ei ole teinud enne. Me joonis vertikaalsed jooned double_buffer, samamoodi me teeme, DirectX Graphics demo eespool.

See lähenemine võib tunduda keeruline, kui esimese (võibolla sellepärast, et ma tegin halba tööd kell kirjeldades seda…), aga see on üsna lihtne. Kui sa arvad, hakkab ta teeb palju mõistust.

näiteks…

Me rääkisime sellest, et enamik aega, graafika on lihtsalt joonestamist pikslit mälu. See ei tohi olla liiga järsk, on samuti huvitav, kuni sa mõistad, et me peame valima pikslit mälu saab toota üsna huvitav ja lahe otsin mõju. See osa on õpetada teile ühtegi konkreetset algoritmi, vaid lihtsalt näidata, et lihtsalt joonestamist pikslit mällu, väga väike programm võib saavutada väga huvitavaid tulemusi. Ma ei tunne, et see, mida me oleme teinud nii palju on huvitavaid piisavalt inspireeriv, nii et siin on, kui see lihtne näide jõuab…

kas te olete kunagi mänginud malet? Ei ole tähtis, mida teie vastus on (tegelikult, see oli mõeldud olema retooriline küsimus ;-). Igatahes, näited oleme umbes luua läheb mingi malelaual (mitte standard suurus), nagu näha veealuse! Kuidas keeruline, kas te arvate, et programm saab? Noh, lubage mul anda teile allikas…

#include <stdlib.h>
#include <conio.h>
#include <matemaatika.h>
#include <dos.h>

int sin_x_table[640];
int sin_y_table[400];

void vid_mode(unsigned char mode){
union REGS regs;
regs.h.ah = 0;
regs.h.al = mode;
int86(0x10,&regs,&regs);
}

void make_chess(unsigned char palju* kui){
int x,y,tx,ty;
static int xcounter = 0;
static int ycounter = 0;
xcounter = xcounter > 311 ? 0:xcounter+8;
ycounter = ycounter > 195 ? 0:ycounter+4;
(y=0;y<200;y++)
for(x=0;x<320;x++){
tx = x + sin_y_table[y + ycounter]+40;
ty = y - sin_x_table[x + xcounter]+40;
 if((tx % 40 >= 20) ^ (ty % 40 >= 20))
kui[y*320+x] = 0;
muidu kui[y*320+x] = 15;
}
}

int main(){
int i;
for(i=0;i<320;i++)
sin_x_table[i] = (int)(sin(i * 6.28/320) * 10);
for(;i<640;i++)
sin_x_table[i] = sin_x_table[i-320];
for(i=0;i<200;i++)
sin_y_table[i] = (int)(sin(i * 6.28/200) * 10);
for(;i<400;i++)
sin_y_table[i] = sin_y_table[i-200];
vid_mode(0x13);
while(!kbhit())
make_chess((unsigned char palju*)0xA0000000);
vid_mode(0x03);
return 0;
}

see on see! Kui te kompileerida ja käivitada see programm (programmi Borland C++ v3.1 DOS) (kergesti kaasaskantav kõikjal, nagu on kirjeldatud eelmistes punktides) näete mõju. Ja see on väga tõhus, võttes arvesse, et see programm on nii väike.

Nagu näete, kõige rohkem on see programm on kulutatud sees make_chess() function. See on otse kirjutamine video mälu. Aga nagu sa märkad, make_chess() funktsioon ei tea, et ta on kirjalikult video mälu. Meil võib tegelikult asendada, et osuti osta midagi muud, ja on see ei mõju, et mõned puhver!

Teine oluline asi, mida sa peaksid teate allikas on kasutada sin_x_table[] ja sin_y_table[]. Enamik aega, kui me tegeleme sin() või cos() meie koodi, me tahaksime, et vältida nende funktsioonide (nad VÄGA aeglaselt!). On palju lähenemisviise, et vältida neid, ja kõige tavalisem on nende loomiseks “look-up” tabelid nende väärtused. Mõnikord, see on pingutust väärt, kuid mõnikord, arvestades CPU cache kiirused ja FPU sin ja cos kiirustel, see ei ole seda väärt. Selles näites see on kindlasti seda väärt, see töötab isegi kena alusel 486 (aeglane FPU töötleja). Integer matemaatika on kiire tahes protsessor, nii et proovige kasutada, et enamiku ajast, ja kasutada ainult ujukoma (FPU), kui sa tead, võite teha seda tööd paralleelselt CPU, seega saada FPU arvutusi tasuta. (aga see teema on kõige parem jätta endast optimeerimine juhendaja)

ma arvan, et see näide. Ma väga earge sa kompileerida ja käivitada. Hea kasutada oleks teha seda programmi tegema täpselt sama efekti kasutades vaid mõned pilti (ei ole chess board). (Tegelikult, me ilmselt lõpuks teeme seda millalgi sel juhendaja…)

– Ehitus –

Copyright © 1998, Osakese

Leave a Reply