Printing strings in graphics mode (320x200)

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Printing strings in graphics mode (320x200)

Post by Benjamin1996 »

Creature wrote:Or you could use a bitmap version of the Bochs font instead and load that from disk (or through multiboot modules). But it's probably faster to do it through the BIOS (no disk loading involved, so no errors can occur following from that).
Thanks, but I think I'll just stick with the fonts the BIOS can provide through interrupts :).
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Printing strings in graphics mode (320x200)

Post by Benjamin1996 »

To start off, here's a screenshot of me trying to implement the 8x14 font in 320x200 screen resolution, provided by the BIOS:
8x14 font.PNG
This is my main routine:

Code: Select all

chooseBootingMode db "Would you like to perform a verbose boot?", 0x000d, 0x000a, 0

main:
    xor ax, ax
    mov ds, ax

    call mode13h ;Enter mode 13 (320x200)
    call clearScreen ;Clear screen by writing 0s to a000
    call getFont
	
    mov si, chooseBootingMode
    call printString
	
    jmp $
This is the 'getFont' + 'printString' function:

Code: Select all

getFont:
    mov ax, 0x1130
	mov bh, 0x0002
	int 0x0010
	
	push es
	pop ds
	mov si, bp
	
	push cs
	pop es
	mov di, fontBuffer
	
	mov cx, 256
	
	populateBuffer:
	    movsw
		movsw
		movsw
		movsw
		movsw
		movsw
		movsw
		movsw
	loop populateBuffer
	
	mov bp, fontBuffer
	xor dx, dx
	mov cx, 256
	mov bh, 16
	mov bl, 1
	mov ax, 0x1100
	int 0x0010
	
	mov bx, 0x0100
	mov cx, bx
	shl bh, 2
	or bl, bh
	mov ax, 0x1103
	int 0x0010
	
	mov bx, 0x0f12
	cmp cl, ch
	jz short update
	mov bh, 0x0007
	
	update:
	    mov ax, 0x1000
		int 0x0010
	ret
printString:
    mov ah, 0x000f
	int 0x0010
	
	mov ah, 0x0003
	int 0x0010

	print:
	    lodsb
	    cmp al, 0
	    je printed
	    mov ah, 0x000e
	    mov bh, 0x0000
	    mov bl, 0x0007
	    int 0x0010
		jmp print
	printed:
	    ret
I'm pretty sure this is a common problem trying to accomplish what I'm trying to.. yet, I can't seem to find any info or solutions for this problem.
Please help me :).
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Printing strings in graphics mode (320x200)

Post by Gigasoft »

First of all, you're loading the font into video RAM while in graphics mode. What would that be good for? You're just overwriting certain columns on the screen. Then you set the block specifier, which does nothing in graphics mode. Then you enable color planes 0, 1 and 2 but not 3 (why?).

Then, when printing, you retrieve the current cursor position and size and do nothing with it before you try to print the string (with DS still pointing at the video ROM and with the controller set to the wrong addressing mode after trying to load the font).

You don't need to retrieve or set any fonts to print characters using the BIOS. You only need to retrieve the font if you intend to draw characters manually without using the BIOS.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: Printing strings in graphics mode (320x200)

Post by Combuster »

Time to plug a reference to bochs' debugger. Since you consider yourself expert enough to develop an os, you know how to use it :wink:
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Printing strings in graphics mode (320x200)

Post by Benjamin1996 »

Gigasoft wrote:First of all, you're loading the font into video RAM while in graphics mode. What would that be good for? You're just overwriting certain columns on the screen. Then you set the block specifier, which does nothing in graphics mode. Then you enable color planes 0, 1 and 2 but not 3 (why?).

Then, when printing, you retrieve the current cursor position and size and do nothing with it before you try to print the string (with DS still pointing at the video ROM and with the controller set to the wrong addressing mode after trying to load the font).

You don't need to retrieve or set any fonts to print characters using the BIOS. You only need to retrieve the font if you intend to draw characters manually without using the BIOS.
To be honest, it isn't much of your reply that makes any sense to me, Gigasoft. Maybe because I have a major headache, I don't know..
BUT, a lot of things did come to my mind reading your reply. Like how much of the code I actually wrote "without thinking about it". Firstly, I remembered that I'm in mode 13h, not mode 12h. Therefore, I don't have to use bit planes, as they're only present in mode 0dh, 0eh, 10h, and 12h. Secondly, after you stating that I didn't take use of the cursor size & position and the video mode I retrieved from the interrupts at the top of my 'printString' function, the penny finally fell. I had wrote my 'printString' function the way I usually do it in text-mode, when I was actually supposed to use function number 13h. The problem probably is I wrote this function when it was like 2:30 AM in Denmark. My bad.. anyway, with my new code the problem is that it simply doesn't print out anything.
Here's the code:
'main' routine:

Code: Select all

chooseBootingMode db "Would you like to perform a verbose boot?", 0x000d, 0x000a, 0

main:
    xor ax, ax
    mov ds, ax

    call getFont
    call mode13h
    call clearScreen
	
    mov bp, chooseBootingMode
    call printString
	
    jmp $
'getFont' & 'printString':

Code: Select all

getFont:
    mov ax, 0x1130
	mov bh, 0x0002
	int 0x0010
	
	push es
	pop ds
	mov si, bp
	
	push cs
	pop es
	mov di, fontBuffer
	
	mov cx, 256
	
	populateBuffer:
	    movsw
		movsw
		movsw
		movsw
		movsw
		movsw
		movsw
		movsw
	loop populateBuffer
	
	mov bp, fontBuffer
	xor dx, dx
	mov cx, 256
	mov bh, 16
	mov bl, 1
	mov ax, 0x1100
	int 0x0010
	
	mov bx, 0x0100
	mov cx, bx
	shl bh, 2
	or bl, bh
	mov ax, 0x1103
	int 0x0010
	ret
printString:
    mov ah, 0x000f
	int 0x0010
	
	mov ah, 0x0003
	int 0x0010
	
	mov cx, 44
	mov bl, 0x0007
	mov ax, 0x1301
	int 0x0010
	ret
fontBuffer:
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Printing strings in graphics mode (320x200)

Post by Gigasoft »

Well, the essential problems I was trying to point out were:

- Using a text mode font upload service while in graphics mode. This causes screen corruption, since plane 2, where the text mode font resides while in text mode, now contains pixels. More importantly, the BIOS will set the card back to text mode addressing after uploading the font, so that further accesses to the display memory will affect the wrong memory locations.
- When you print the string, DS points to the wrong segment. It points to the ROM font's segment instead of your own segment.
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Printing strings in graphics mode (320x200)

Post by Benjamin1996 »

Gigasoft wrote:Well, the essential problems I was trying to point out were:

- Using a text mode font upload service while in graphics mode. This causes screen corruption, since plane 2, where the text mode font resides while in text mode, now contains pixels. More importantly, the BIOS will set the card back to text mode addressing after uploading the font, so that further accesses to the display memory will affect the wrong memory locations.
- When you print the string, DS points to the wrong segment. It points to the ROM font's segment instead of your own segment.
I was aware of the thing 'bout DS. but I wasn't aware of the things you said about the BIOS, so thanks for enlightening me :). So with my newest code (which you can see in the post above yours) I'll have to call the mode13h function to make the switch after I did the "text-mode related" stuff, and after I 'uploaded' the font?
EDIT: Nope, no changes if I move the 'call mode13h' call from the 'main' routine to right above the 'ret' statement in the 'getFont' function (if that's what you meant).
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Printing strings in graphics mode (320x200)

Post by Gigasoft »

Well, no. I'm not sure why you're trying to upload the font. That would only be useful in text mode. When changing to graphics mode, the font is erased because the memory is used for something else. The block specifier is also meaningless in graphics mode.

To change the font used to print text in graphics mode, you should use one of the functions 1120h through 1124h. This should be done after switching to graphics mode.
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Printing strings in graphics mode (320x200)

Post by Benjamin1996 »

Gigasoft wrote:Well, no. I'm not sure why you're trying to upload the font. That would only be useful in text mode. When changing to graphics mode, the font is erased because the memory is used for something else. The block specifier is also meaningless in graphics mode.

To change the font used to print text in graphics mode, you should use one of the functions 1120h through 1124h. This should be done after switching to graphics mode.
So would I be able to (to get a first time example going) go into mode 13h, then use function 1130h of int 10h to move a pointer to the specified font bitmap into ES:BP, and right after that make a call to function 1120h of int 10h, to apply the bitmap pointed to by ES:BP, and then use the standard character/string printing functions of the BIOS to print a string?
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Printing strings in graphics mode (320x200)

Post by Gigasoft »

Well, almost. Function 1120h is for loading an 8x8 font, so it should be function 1121h (or function 1122h to use the ROM 8x14 font.)

And you should make sure you don't print beyond the right side of the screen with function 13h, because the text will continue on the next screen row instead of advancing by the correct number of rows (the character height).
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Printing strings in graphics mode (320x200)

Post by Benjamin1996 »

Gigasoft wrote:Well, almost. Function 1120h is for loading an 8x8 font, so it should be function 1121h (or function 1122h to use the ROM 8x14 font.)

And you should make sure you don't print beyond the right side of the screen with function 13h, because the text will continue on the next screen row instead of advancing by the correct number of rows (the character height).
Well, of course.
But my problem is that my doesn't print out anything! :(
This is really starting to wear on my nerves!
'main':

Code: Select all

chooseBootingMode db "Would you like to perform a verbose boot?", 0x000d, 0x000a, 0

main:
    xor ax, ax
    mov ds, ax

	call mode13h
	call getFont
    call clearScreen
	
	mov bp, chooseBootingMode
    call printString
	
    jmp $
'getFont' + 'printString':

Code: Select all

getFont:
    mov ax, 0x1130
	xor bh, bh
	int 0x0010

	mov ax, 0x1120
	int 0x0010
	ret
printString:
    mov ah, 0x000f
	int 0x0010
	
	mov ah, 0x0003
	int 0x0010
	
	mov cx, 44
	mov bl, 0x0007
	mov ax, 0x1301
	int 0x0010
	ret
This doesn't print out anything, AND the cursor is not showing..
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Printing strings in graphics mode (320x200)

Post by Gigasoft »

Your getFont function does nothing right now. It basically sets the font used for CGA mode to what it was before.

Does ES point to your segment when calling printString? Try setting DX to 0 before invoking function 13h, just to make sure that this isn't the problem.

And there is no visible cursor in graphics mode. The cursor is only displayed in text mode.
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Printing strings in graphics mode (320x200)

Post by Benjamin1996 »

Gigasoft wrote:Your getFont function does nothing right now. It basically sets the font used for CGA mode to what it was before.

Does ES point to your segment when calling printString? Try setting DX to 0 before invoking function 13h, just to make sure that this isn't the problem.

And there is no visible cursor in graphics mode. The cursor is only displayed in text mode.
Uhhmm.. I decided to use function number 1121h, but it's causing me problems. When I run the following code I get this ear blowing constant BEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEP, that never stops, and the screen is filled with a bunch of garbage, like smilies etc etc..
I assume you're already pretty familiar with my 'main' routine, so I'm just going to tell you the changes: I added a 'xor dx, dx' before the call to 'mode13h'.
Other than that everything in the 'main' routine is the same.
The 'printString' function is also unchanged, so I'll just show you the 'getFont' function.

Code: Select all

getFont:
    mov ax, 0x1130
	mov bh, 0x0002
	int 0x0010

	mov ax, 0x1121
	mov cx, 256
	xor bl, bl
	mov dl, 200
	int 0x0010
	ret
If you're wondering about the values I put in as arguments for the 1121h function, here's an explanation:
*CX should be the amount of bytes per character. As I am in mode 13h (320x200x256) it's value is 256.
*BL should be the row set, I don't know what they mean by that but they said 0 meant user set, so I went with that. :P
*DL should be the number of rows, as there's 200 rows in mode 13h, I put a 200 in there :).
Gigasoft
Member
Member
Posts: 856
Joined: Sat Nov 21, 2009 5:11 pm

Re: Printing strings in graphics mode (320x200)

Post by Gigasoft »

No, what I meant was xor dx,dx before this (to starting printing a column 0, row 0), not before the call to mode13h:
mov ax, 0x1301
int 0x0010
But now it at least prints something, so that wasn't the problem.

The garbage printed indicates that ES is set to the wrong value when calling printString.

The parameters to function 1121h are wrong. Bytes per character (CX) should be 14. DL should be 01, for 14 text rows (the maximum that will fit in 200 screen rows).
Benjamin1996
Member
Member
Posts: 78
Joined: Sat Apr 10, 2010 7:00 am
Location: Denmark

Re: Printing strings in graphics mode (320x200)

Post by Benjamin1996 »

Gigasoft wrote:No, what I meant was xor dx,dx before this (to starting printing a column 0, row 0), not before the call to mode13h:
mov ax, 0x1301
int 0x0010
But now it at least prints something, so that wasn't the problem.

The garbage printed indicates that ES is set to the wrong value when calling printString.

The parameters to function 1121h are wrong. Bytes per character (CX) should be 14. DL should be 01, for 14 text rows (the maximum that will fit in 200 screen rows).
Nope. Now we're just back to it not printing anything. This is my 'main' routine:

Code: Select all

chooseBootingMode db "Would you like to perform a verbose boot?", 0x000d, 0x000a, 0

main:
    xor ax, ax
    mov ds, ax
	
	call mode13h
	call getFont
    call clearScreen
	
	mov bp, chooseBootingMode
    call printString
	
    jmp $
'getFont' & 'printString':

Code: Select all

getFont:
    mov ax, 0x1130
	mov bh, 0x0002
	int 0x0010
	
	mov ax, 0x1121
	mov cx, 14
	xor bl, bl
	mov dl, 0x0001
	int 0x0010
    ret
printString:
    xor dx, dx
	
    mov ah, 0x000f
	int 0x0010
	
	mov ah, 0x0003
	int 0x0010
	
	mov cx, 44
	mov bl, 0x0007
	mov ax, 0x1301
	int 0x0010
	ret
Oh and by the way, I have one little convenience question: When I'm in graphics mode, will the position of the cursor still affect where the text is printed even though the cursor is not visible?
Post Reply