K
TADA, da bin ich!
ich habe früher auch mal die karten per assembler und direktem hardwarezugriff programmiert. aber das macht keinen sinn. denn mit dem veso bios hat man alles was man braucht. das vesabios bietet zwar keine "echte hardwareprogrammierung" an, aber das spielt für die performance keine rolle. mit dem vesabios kannst du alle notwendigen daten der grafikarten ermitteln und dann auf sie zugreifen. grunsätzlich muss man sich zuerst einen zeiger auf den "flat-screen" speicher holen, in dem das bild (grafikspeicher) linear dargestellt wird. das funktioniert aber nur, wenn du eine karte hast die das kann. allerdings sollte das jede "moderne" karte 100% unterstützen. ich hatte damls eine superschlechte noname und die konnte das auch...
wenn du dann den zeiger auf den videospeicher hast, dann kannst du da einfach linear reinschreiben. ich habe das damals immer mit einem backpuffer gemacht, da ich meine engine als 3d-engine benutzt habe und nicht als 2d-engine (also als gui-engine oder so).
ein problem ist noch, das das ganze nur funktioniert, wenn sich die cpu im protected mode befindest (klar...) denn im realmode hast man nur 64k segmente und da ist nix mit linearem speicherzugriff von 4 mbyte oder so :). man braucht dann noch ein DPMI (DosProtectedModeInterface) um an realmode speicher ranzukommen (braucht das vesabios) und das macht das alles noch etwas komplizierter. falls du dich damit nicht auskennst, dann besorg dir ersteinmal informationen über DPMI.
hier mal ein bischen code aus meiner alten "engine"
so in der form nicht wirklich lauffähig, da noch andere teile und der dazugehörige c code fehlt, aber du siehst alles was mann braucht um eine minimalversion zum laufen zu bringen.
.data
extrn screen :dword ;zeiger auf virtuelles vram
extrn screen_x :dword ;breite des vram
extrn screen_y :dword ;höhe des vram
extrn freemem :dword ;freier protected mode speicher
blockh dd 0
rmi db 50 dup (0)
rms_sel dw 0
rms_seg dw 0
flatscreen dd 0
h_sel dw 0
h_off dd 0
sliste dd 2048 dup (0) ;1024 speicherblöcke
mliste db 48 dup (0) ;speicherinformationen
.code
public init_watcom
init_watcom proc near
mov ax,0501h ;dpmi-function 501h (getmem)
mov bx,60h ;6 MB = 600000h
mov cx,0000h
int 31h
mov word ptr screen+2,bx
mov word ptr screen,cx
mov word ptr blockh+2,si
mov word ptr blockh,di
mov ax,100h ;reserviere realmode-speicher
mov bx,20h ;für den vesamodusinfopuffer
int 31h
mov rms_seg,ax
mov rms_sel,dx
mov ax,013h ;aktiviere Grafikmodus
int 10h
mov eax,0 ;lösche speicherliste
mov ecx,2048
mov edi,offset sliste
rep stosd
mov ax,500h ;ermittle freien speicher
mov edi,offset mliste
int 31h
mov eax,dword ptr mliste[0]
mov freemem,eax
ret
init_watcom endp
public close_watcom
close_watcom proc near
mov ax,0502h ;dpmi-function 502h (freemem)
mov si,word ptr blockh+2
mov di,word ptr blockh
int 31h
mov ax,101h ;realmode-speicher freigeben
mov dx,rms_sel
int 31h
mov ax,03h ;aktiviere Textmodus
int 10h
mov edx,0 ;lösche alle speicherblöcke
@@ch_lp:
cmp dword ptr sliste[edx],0
je @@ch_weiter
mov ax,0502h ;dpmi-function 502h (freemem)
mov si,word ptr sliste[edx+6]
mov di,word ptr sliste[edx+4]
int 31h
@@ch_weiter:
add edx,8
cmp edx,1024*8
jne @@ch_lp
ret
close_watcom endp
public svga_modus
svga_modus proc near
push ebp
mov ebp,esp
push es
cmp dword ptr [ebp+8],0
jne @@sm_320_240
mov ax,04f02h
mov bx,0c136h
int 10h ;vesabios funktion zum setzen eines grafikmodus
;das kann man natürlich auch mit ports und direkter
;hardwareporgrammierung machen, aber das bringt keine vorteile
mov screen_x,320
mov screen_y,240
mov eax,136h
jmp @@sm_initneuermodus
@@sm_320_240:
cmp dword ptr [ebp+8],1
jne @@sm_640_480
mov ax,04f02h
mov bx,0c112h
int 10h
mov screen_x,640
mov screen_y,480
mov eax,112h
jmp @@sm_initneuermodus
@@sm_640_480:
cmp dword ptr [ebp+8],2
jne @@sm_800_600
mov ax,04f02h
mov bx,0c115h
int 10h
mov screen_x,800
mov screen_y,600
mov eax,115h
jmp @@sm_initneuermodus
@@sm_800_600:
cmp dword ptr [ebp+8],3
jne @@sm_1024_768
mov ax,04f02h
mov bx,0c118h
int 10h
mov screen_x,1024
mov screen_y,768
mov eax,118h
jmp @@sm_initneuermodus
@@sm_1024_768:
jmp @@sm_ende
@@sm_initneuermodus:
mov dword ptr rmi[24],eax
mov dword ptr rmi[28],4f01h
mov ax,rms_seg
mov word ptr rmi[34],ax
mov dword ptr rmi[0],0
mov dword ptr rmi[20],0
mov ax,300h
mov bx,10h
mov cx,0
mov dx,seg rmi
mov es,dx
mov edi,offSET rmi
int 31h
mov ax,rms_sel ;lade flatscreen
mov es,ax
mov ebx,es:40 ;steht im modusinfopuffer an offset 40
mov ecx,ebx
shr ebx,16
mov di,0000
mov si,60
mov ax,0800h
int 31h
shl ebx,16
mov bx,cx
mov flatscreen,ebx
mov ecx,0
mov edx,screen_x
shl edx,1
dec edx
mov ax,7
int 33h
mov ecx,0
mov edx,screen_y
dec edx
mov ax,8
int 33h
@@sm_ende:
pop es
mov esp,ebp
pop ebp
ret
svga_modus endp
//diese funktion könnte man heutzutage, wo es ja sowas wie pentium und mmx gibt optimieren...
public svga_show
svga_show proc near
mov esi,screen ;lade adresse des grafik-puffer
mov edi,flatscreen ;lade adresse des linear-frame-buffer
mov ecx,screen_x ;berechne anzahl der pixel
imul ecx,screen_y
rep movsd
ret
svga_show endp
public get_mem
get_mem proc near
push ebp
mov ebp,esp
mov edx,0
@@gm_lp:
mov eax,dword ptr sliste[edx]
cmp eax,0
jne @@gm_weiter
mov ax,0501h ;dpmi-function 501h (getmem)
mov bx,[ebp+14]
mov cx,[ebp+12]
int 31h
mov eax,[ebp+8] ;lade adresse des zeiger auf speicherbereich
mov [eax+2],bx ;schreibe adresse in zeiger (zeiger auf neuen speicher)
mov [eax],cx
mov dword ptr sliste[edx],eax ;sichere zeiger
mov word ptr sliste[edx+6],si ;sichere handle des speicherblocks
mov word ptr sliste[edx+4],di
jmp @@gm_ende
@@gm_weiter:
add edx,8
cmp edx,1024*8
jne @@gm_lp
@@gm_ende:
mov esp,ebp
pop ebp
ret
get_mem endp
public free_mem
free_mem proc near
push ebp
mov ebp,esp
mov edx,0
@@fm_lp:
mov eax,dword ptr sliste[edx]
cmp eax,[ebp+8]
jne @@fm_weiter
mov ax,0502h ;dpmi-function 502h (freemem)
mov si,word ptr sliste[edx+6]
mov di,word ptr sliste[edx+4]
int 31h
mov dword ptr sliste[edx],0 ;lösche listeneintrag
mov dword ptr sliste[edx+4],0 ;lösche handle
jmp @@fm_ende
@@fm_weiter:
add edx,8
cmp edx,1024*8
jne @@fm_lp
@@fm_ende:
mov esp,ebp
pop ebp
ret
free_mem endp
bischen c code
void *screen; //virtuelles grafikram//
long screen_x; //breite//
long screen_y; //höhe//
long freemem; //freier speicher//
extern void init_watcom(void);
extern void close_watcom(void);
extern void svga_modus(long modvar);
extern void svga_show(void);
extern void get_mem(void *zeiger, long size);
extern void free_mem(void *zeiger);
aber...
ehrlich gesagt würde ich diesen "mist" nicht mehr machen, da es einfach viel zu viel arbeit ist und man besser mit directx oder opengl DAS macht was man eigentlich möchte... grafik programmieren
man kann zwar mit dem vesa bios recht gut und sogar sehr schnell 2d grafik realisieren, aber nicht hardwareunterstützt. und 3d grafik erst recht nicht. vielleicht gibt es mittlerweile sogar einen vesa standard für 3d grafik, aber der wird dem, was moderne karten an neuen funktionen unterstützen immer hinterherhinken und das meilenweit. ausserdem dürfte es extrem viel arbeit sein 3d-funktionen zum laufen zu bekommen, wenn man diese mit assembler anspricht.
3d grafik habe ich früher auch alles mit assembler und c realisiert. man lernt abei viel, z.b. wenn man sich selbst eine funktion zum zeichnen eines texturierten und schattierten polygons schreibt, oder sich um die beleuchtung kümmert, aber es ist extrem viel aufwand.
ich benutze seit ca. 2 jahren directx und bin glücklich mit meinen 500 fps mit einer 1280x1024er auflösung bei 32bit und geiler 3d-grafik...