it's me again. And another thing to be considered. I've tried to implement two components of picture to be drawn on screen. First component must be persitent, "background". Second component should be re-drawn every main cycle's step. First component is drawn first. I decided to use video pages to get this effect, but failed. VGA adapter has 256 kB memory. Problem is that to use video pages i have to enable bit planes. It means that i have to change video pages every pixel, if i draw line by line. If it would be usual addressing, to put pixels to first page i should write to es:0000,es:0004,es:0008,es:000C,...; to put pixels to second page i should write to es:0001,es:0005,es:0009,es:000D,...; to put pixels to third page i should write to es:0002,es:0006,es:000A,es:000E,...; and so on. But i need this memory to be addressed continually. First 64000 bytes must match first video page, next 64000 bytes must match second video page, and so on. Is that possible?
For the VGA you are limited to a 64KB window in the host address space, and basically all of your accesses into the display buffer must be through that window. If what you are trying to do is move a "sprite" over a fixed background, nondestructively, while the VGA probably supports multiple more or less complex methods of doing it, there is a simple method. Basically, the code that draws the sprite needs to save the portion of the background image that the sprite will overlay, and restore the saved background each time the sprite is moved. Implementing this for mode 13h should be fairly simple.
Hi ghjjkl,
as Michael mentioned, in Real Mode you're limited to 64 KB. Another approach would be the Protected Mode with the linear frame buffer above 1 MB. So you can use 2 or 3 screens at the same time.
Gunther
but why couldn't they organize memory as i wrote?I wonder, why are these "bit planes"? Why didn't they do continuous space? In that case i could simply change video page and stored data to A000h:XXXX as usual :(
Hi ghjjkl,
Quote from: ghjjkl on July 18, 2014, 09:33:59 PM
but why couldn't they organize memory as i wrote?I wonder, why are these "bit planes"?
it's a question of simple arithmetics. You have a 64 KB memory window starting at A000h for your graphics data. The standard VGA with 640x480 and 16 colors needs 640 * 480 * 4 = 1228800 bit = 153600 byte = 150 KB. That doesn't fit into the 64 KB window and must be organized in 4 bit planes.
If you would like to experiment with VGA graphics programming, you should read first the standard book by Michael Abrash (http://www.phatcode.net/res/224/files/html/). That's my advice.
Gunther
Quote from: ghjjkl on July 18, 2014, 09:33:59 PM
Why didn't they do continuous space?
They did do a continuous space, but unless someone has developed a "trick" for doing so, it's not accessible from Real Mode. See Gunther's post in reply #2, specifically "Protected Mode with the linear frame buffer". In Real Mode, for some of the display modes the handling of the bit planes is automatic, for example mode 13h, but for others you must effectively program the VGA hardware to do it (or use the VGA BIOS functions) . This code uses one of several possible methods to write the color for a single pixel to all four bit planes in mode 12h:
;==============================================================================
.model small,c
.386
.stack
;==============================================================================
SetPixel_12 PROTO x:WORD,y:WORD,color:WORD
WaitKey PROTO
;==============================================================================
;--------------------------------------------------------------------
; Host I/O ports for Graphics Controller Address and Data Registers:
;--------------------------------------------------------------------
GraphicsAddressRegister equ 3ceh
GraphicsDataRegister equ 3cfh
;---------------------------------------------------------
; Index value for Graphics Controller Set/Reset Register:
;---------------------------------------------------------
SetResetIndex equ 0
;----------------------------------------------------------------
; Index value for Graphics Controller Enable Set/Reset Register:
;----------------------------------------------------------------
EnableSetResetIndex equ 1
;--------------------------------------------------------
; Index value for Graphics Controller Bit Mask Register:
;--------------------------------------------------------
BitMaskIndex equ 8
;-------------------------------------------------------------------
; Macro to wite a value to an 8-bit I/O port in a single statement.
;-------------------------------------------------------------------
outp MACRO port, val
mov dx, port
mov ax, val
out dx, al
ENDM
;==============================================================================
.data
.code
.startup
;==============================================================================
mov ax, 0a000h
mov es, ax
mov ax, 12h
int 10h
invoke SetPixel_12, 320, 240, 15
call waitkey
.exit
;----------------------------------------------------------
; This proc assumes that the VGA is operating in mode 12h,
; and that ES has been loaded with the segment address of
; the graphics display buffer.
;
; This proc uses the Set/Reset function to write the color
; value for a single pixel to all four bit planes. This
; entails enabling all four bit planes in the Set/Reset
; register, loading the color value into the Set/Reset
; register, and setting the Bit Mask register so the
; write operation will affect only the target pixel.
;----------------------------------------------------------
SetPixel_12 proc uses ax bx cx dx x:WORD,y:WORD,color:WORD
outp GraphicsAddressRegister,EnableSetResetIndex
outp GraphicsDataRegister,0fh
outp GraphicsAddressRegister,SetResetIndex
outp GraphicsDataRegister, color
outp GraphicsAddressRegister,BitMaskIndex
mov cx, x ; bit mask = 80h>>(x&7)
and cx, 7
mov ax, 80h
shr ax, cl
outp GraphicsDataRegister,ax
mov ax, y ; pixel byte address = y*80+(x>>3)
mov cx, 80
mul cx
mov bx, ax
mov cx, x
shr cx, 3
add bx, cx
;--------------------------------------------------
; Perform a dummy write to the addressed byte.
; The color value for the addressed pixel will be
; supplied by the Set/Reset register.
;--------------------------------------------------
mov BYTE PTR es:[bx], 0
;------------------------------------------------------
; Restore the Bit Mask and Enable Set/Reset registers
; to their default values.
;------------------------------------------------------
outp GraphicsAddressRegister,BitMaskIndex
outp GraphicsDataRegister,0ffh
outp GraphicsAddressRegister,EnableSetResetIndex
outp GraphicsDataRegister,0
ret
SetPixel_12 endp
; ---------------------------------------------------------
; This proc calls the BIOS Read Keyboard Status and Read
; Keyboard Input functions to flush the keyboard buffer,
; wait for a key press, and then flush the buffer again,
; leaving it empty. The BIOS scan code for the key pressed
; is returned in AH and the character code in AL.
; ---------------------------------------------------------
WaitKey proc
@@:
mov ah, 1
int 16h ; Check for key press
jz @F ; Jump if buffer empty
mov ah, 0
int 16h ; Get key
jmp @B ; Repeat
@@:
mov ah, 1
int 16h ; Check for key press
jz @B ; Repeat
mov ah, 0
int 16h ; Get key
push ax ; Preserve it
@@:
mov ah, 1
int 16h ; Check for key press
jz @F ; Jump if buffer empty
mov ah, 0
int 16h ; Get key
jmp @B ; Repeat
@@:
pop ax ; Recover key
ret
WaitKey endp
end
MichaelW, thanks for that code! I've tried something like that, but i used mode 0dh. But there's too many actions for single pixel still :(
Where could i read about ports like 3ceh,3dfh,3c4h and so on?
Quote from: ghjjkl on July 19, 2014, 04:30:37 PM
I've tried something like that, but i used mode 0dh.
Here:
mov dx,3c4h
mov ax,0102h ;ah - color as i suppose, al - index for port 3c5h (02 means map mask register)
out dx,ax
mov di,0
xor bx,bx
mov byte ptr es:[bx],10000000b ;to put blue point to upper left corner
but it's too complicated, if i want to draw several images. For every pixel i must access port 3c4h. For mode 13h i could simply read data from buffer and store that color i want, without any "extra" actions, like this
buffer db 0,1,2,3,4,5,6,7,8,9
(...)
mov ax,offset buffer
mov ds, ax
mov ax,0a000h
mov es,ax
xor si,si
xor di,di
mov cx,10
rep movsb
Quote from: ghjjkl on July 19, 2014, 04:30:37 PM
Where could i read about ports like 3ceh,3dfh,3c4h and so on?
The reference I use is available, among other places, here (http://www.amazon.com/Programmers-Guide-Super-Cards-Edition/dp/0201624907).
Quote
I've tried something like that, but i used mode 0dh. But there's too many actions for single pixel still
I think at least in the general case there is no need to access the map mask register for each pixel. In one of the code examples from Richard Ferraro's book, he sets the map mask register once per bit plane, and then writes an entire plane of data.
Doing VGA graphics there is no way to avoid executing a large number of instructions, but because I/O port accesses are relatively slow you should avoid doing them unnecessarily.
Quote from: ghjjkl on July 19, 2014, 06:30:11 PM
Here:
mov dx,3c4h
mov ax,0102h ;ah - color as i suppose, al - index for port 3c5h (02 means map mask register)
out dx,ax
mov di,0
xor bx,bx
mov byte ptr es:[bx],10000000b ;to put blue point to upper left corner
but it's to complicated, if i want to draw several images. For every pixel i must access port 3c4h.
Your code is not accessing the map mask register correctly. For the VGA, to avoid using an excessive number of I/O port addresses, the Sequencer, CRT Controller, Graphics Controller, and Attribute Controller (*) registers are accessed indirectly, using an address port and a data port. To access a register you output the register index to the address port and then do the access through the data port. My mode 12h code above shows how to do this.
* all but one group
It would be a lot easier for us to answer your questions if you would provide a detailed description of what you are trying to do.
Quote from: MichaelW on July 21, 2014, 04:35:09 PM
It would be a lot easier for us to answer your questions if you would provide a detailed description of what you are trying to do.
well, then i tell you about some problems i've met.
Lets imagine that we need to draw some image:
img BYTE 0,0,0,1,0,0,0,0
BYTE 0,1,0,0,4,1,0,0
BYTE 0,0,1,1,0,0,1,0
BYTE 0,2,0,1,1,0,0,0
BYTE 1,0,0,0,1,3,0,0
BYTE 0,0,0,1,0,0,0,0
BYTE 0,1,0,3,0,0,1,0
BYTE 0,0,1,0,0,1,0,3
so its width is 8, height is 8 too.
if i need it to be drawn, i could use this:
screenWidth equ 320
draw_ proc near c uses cx pos:WORD,_off:WORD,_width:WORD,height:WORD
mov di,pos
mov si,_off
mov ax,height
.while ax>0
mov cx,_width
rep movsb
sub di,slice
add di,screenWidth
dec ax
.endw
ret
draw_ endp
but there are several problems:
- if i dont want image's zero bytes to cover other images, i have to skip these bytes so all images are drawn more slowly
- 256 colors are too many for my needings. 16 would be nice, but in that case i have to pack two colors into one byte, and this means i have to perform many extra actions to draw such images, it's bad for performance too
to meet my demands i decided to use another video mode instead 13h.
But problem is that there are no modes that have memory space which could be whether addressed or accessed as easy as 13h and would demand significantly less memory than 13h.
Quote from: ghjjkl on July 21, 2014, 06:43:29 PM
to meet my demands i decided to use another video mode instead 13h.
But problem is that there are no modes that have memory space which could be whether addressed or accessed as easy as 13h and would demand significantly less memory than 13h.
There are only 2 ways to go:
- Use a SVGA mode with a VESA driver.
- Try ModX (http://graphmodex.sourceforge.net/files/graph.h)
Gunther
Quote from: ghjjkl on July 21, 2014, 06:43:29 PM
but there are several problems:
- if i dont want image's zero bytes to cover other images, i have to skip these bytes so all images are drawn more slowly
- 256 colors are too many for my needings. 16 would be nice, but in that case i have to pack two colors into one byte, and this means i have to perform many extra actions to draw such images, it's bad for performance too
Hi,
If you do not need more than 16 colors, you can use multiple
palettes in mode 13H. You can assign the background to the first
sixteen entries (low nybble of color byte). Then assign colors for
the foreground objects to the high four bits (with redundant entries
in the low bits). XORing the foreground object with the background
will leave the background unchanged with zero bytes in the foreground
object. Of course, after doing this, some of the high bits will be set,
so you will have to work around that before the next round of XORing.
Steve
Hi,
QuoteIf you do not need more than 16 colors, you can use multiple
palettes in mode 13H. You can assign the background to the first
sixteen entries (low nybble of color byte). Then assign colors for
the foreground objects to the high four bits (with redundant entries
in the low bits). XORing the foreground object with the background
will leave the background unchanged with zero bytes in the foreground
object.
Well, I implemented a variation on this idea. Just to see how it
works out. The background is a 16 color TGA picture. The sprite
uses a simple palette and shows transparency. Clumsy, and not
too practical, but it is what it is.
Cheers,
Steve
If I recall correctly in mode 13h, and assuming the default palette and color register values, the first 16 colors (0-15) by design match the colors for the 16-color modes.
if i remember correctly, the DAC values are 6-bits only
so, 0 is for no luminance in that color, and 3Fh is full luminance
i don't remember the order for colors, but guessing R, G, B
;
; set video mode 13h
;
MOV AX,13h
INT 10h
;
; set DAC registers
;
XOR BX,BX
MOV CX,COLORS ;number of colors
MOV DX,OFS PAL13A ;address of pallette
MOV AX,1012h
INT 10h
;
; set overscan register
;
MOV BH,0
MOV AX,1001h
INT 10h
HI,
Quote from: MichaelW on July 31, 2014, 09:33:00 AM
If I recall correctly in mode 13h, and assuming the default palette and color register values, the first 16 colors (0-15) by design match the colors for the 16-color modes.
Yes, you are correct. Wikipedia has a picture of the default palette
on their Mode 13H page. If you use only the other 240 palette
entries, your program may be more compatible with an OS or the
BIOS when displaying text or the like.
Quote from: dedndave on July 31, 2014, 09:59:09 AM
if i remember correctly, the DAC values are 6-bits only
so, 0 is for no luminance in that color, and 3Fh is full luminance
i don't remember the order for colors, but guessing R, G, B
Right, you remember correctly, the VGA color registers are 6-bits
each. And they are in RGB order. An image using a 256 color
palette normally stores 8-bit values. So you divide by four (usually
by shifting to the right) to convert those palette entries when using
Mode 13H. Targa TGA images muddle things a bit by using a BGR
ordering.
Regards,
Steve N.
Steve,
Quote from: FORTRANS on July 31, 2014, 10:07:33 PM
Targa TGA images muddle things a bit by using a BGR ordering.
for most TGA images is that true. But it's not the only case for BGR color ordering (http://www.gamedev.net/topic/494153-rgb-is-actually-bgr/).
Gunther
bitmap files, bitmaps in general, use BGR order, too :P
Quote from: dedndave on August 01, 2014, 07:40:26 AM
bitmap files, bitmaps in general, use BGR order, too :P
:t
Gunther
Few things excite me more than 16 bit MS-DOS programming. Yippee-ki-yay!