Printing strings in graphics mode (320x200)
-
- Member
- Posts: 78
- Joined: Sat Apr 10, 2010 7:00 am
- Location: Denmark
Printing strings in graphics mode (320x200)
Hi folks!
Lately I switched to graphics mode number 13h.
Before I did this, I was aware this would require me to plot pixel by pixel for every graphical operation I did. Yet, I was silly enough to think that I could just switch back to text mode whenever I wanted, print some stuff, and still have my graphics on the screen. Making the discovery that this would just clear all graphics off the screen, made it clear to me I had to find a way to print text in graphics mode.
Even though I have a pretty clear idea of what this implies, I can't seem to find a resource that explains nor shows this.
So I would really appreciate if any of you could direct me to a bare-bones NASM example of this. - That is, printing text in 320x200 graphics mode .
-Benjamin.
Lately I switched to graphics mode number 13h.
Before I did this, I was aware this would require me to plot pixel by pixel for every graphical operation I did. Yet, I was silly enough to think that I could just switch back to text mode whenever I wanted, print some stuff, and still have my graphics on the screen. Making the discovery that this would just clear all graphics off the screen, made it clear to me I had to find a way to print text in graphics mode.
Even though I have a pretty clear idea of what this implies, I can't seem to find a resource that explains nor shows this.
So I would really appreciate if any of you could direct me to a bare-bones NASM example of this. - That is, printing text in 320x200 graphics mode .
-Benjamin.
- piranha
- Member
- Posts: 1391
- Joined: Thu Dec 21, 2006 7:42 pm
- Location: Unknown. Momentum is pretty certain, however.
- Contact:
Re: Printing strings in graphics mode (320x200)
Well, theres http://wiki.osdev.org/Drawing_In_Protected_Mode. It's not nasm, it's in C. However, it gives a very clear way of printing strings in graphics mode...it's pretty easy. Start at one spot on the screen, and simply move across and down checking a font encoding array as you go to see if a pixel should be there. It's really pretty easy.
-JL
-JL
SeaOS: Adding VT-x, networking, and ARM support
dbittman on IRC, @danielbittman on twitter
https://dbittman.github.io
dbittman on IRC, @danielbittman on twitter
https://dbittman.github.io
-
- Member
- Posts: 78
- Joined: Sat Apr 10, 2010 7:00 am
- Location: Denmark
Re: Printing strings in graphics mode (320x200)
Thanks a lot for the quick reply piranha . Unfortunatly I already read the article you linked to, and I don't seem to understand the concept, at all .
- Combuster
- 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)
Time for a pop quiz then:
1: what is a bitmap?
2: how can you get the bit at position (x,y) from that bitmap?
3: what is the desired foreground and background color?
4: how do you draw a pixel at (x,y)
5: if you start a bitmap at (x,y), what point on the screen corresponds to point (a,b) in the bitmap?
6: how do you iterate over all points in a bitmap?
7: when would you use the foreground color, when would you use the background color, and when would you not draw at all?
8: how would you store 256 bitmaps of 8x16 pixels?
Once you've got all the answers, try to fit the pieces together
1: what is a bitmap?
2: how can you get the bit at position (x,y) from that bitmap?
3: what is the desired foreground and background color?
4: how do you draw a pixel at (x,y)
5: if you start a bitmap at (x,y), what point on the screen corresponds to point (a,b) in the bitmap?
6: how do you iterate over all points in a bitmap?
7: when would you use the foreground color, when would you use the background color, and when would you not draw at all?
8: how would you store 256 bitmaps of 8x16 pixels?
Once you've got all the answers, try to fit the pieces together
-
- Member
- Posts: 78
- Joined: Sat Apr 10, 2010 7:00 am
- Location: Denmark
Re: Printing strings in graphics mode (320x200)
As far as I'm concerned a bitmap representing a letter is just a two-dimensional array, that can be accesed through an index, like a normal array. Then you should simply loop through every index in that 2D array, check if the bit at that location is 1, if it is, draw a pixel on the correct screen location ((yIndex * 640) + xIndex), if it's a 0 simply skip and go to the next index. Is this correct? - If it is, then how would you define a bitmap in NASM assembler?Combuster wrote:Time for a pop quiz then:
1: what is a bitmap?
2: how can you get the bit at position (x,y) from that bitmap?
3: what is the desired foreground and background color?
4: how do you draw a pixel at (x,y)
5: if you start a bitmap at (x,y), what point on the screen corresponds to point (a,b) in the bitmap?
6: how do you iterate over all points in a bitmap?
7: when would you use the foreground color, when would you use the background color, and when would you not draw at all?
8: how would you store 256 bitmaps of 8x16 pixels?
Once you've got all the answers, try to fit the pieces together
Oh and by the way, I also switched to mode 12 (640x480)... hence the above equation .
Re: Printing strings in graphics mode (320x200)
Did you check the manual?
Re: Printing strings in graphics mode (320x200)
No, simply skipping is not correct, because it only works if you assume that the screen is initially black.Benjamin1996 wrote:As far as I'm concerned a bitmap representing a letter is just a two-dimensional array, that can be accesed through an index, like a normal array. Then you should simply loop through every index in that 2D array, check if the bit at that location is 1, if it is, draw a pixel on the correct screen location ((yIndex * 640) + xIndex), if it's a 0 simply skip and go to the next index. Is this correct?
If there's already a white pixel (or whatever color suits your taste) at this location, skipping will result in this pixel remaining white, while you want it to become black if you do not aim for translucency.
Re: Printing strings in graphics mode (320x200)
IMHO having a text-mode-like-interface in graphics mode has a couple of things that make it substantially more difficult than normal text mode, such as:
- You can't JUST move the cursor around, if you put it on a character and have to move it out, you will probably need to redraw parts of that character because it was partially overwritten.
- For scrolling around in text mode, you can just keep a buffer of 2-byte integers (e.g. words), but in graphics mode, parsing an entire buffer full of characters (with, possibly a lot of colors shipped with them) and drawing them on the screen is pretty slow (and you can't just memcpy like you can in text mode). Usually you'll need to redraw the entire screen too (because everything moves up or down), which can be a performance hit. Better get those graphics blitters in shape!
- When will you redraw the screen? After plotting each character? That will probably give you a noticeable slowdown (especially in emulators, I've noticed). You could redraw after a shell command has finished, but what if the shell command waits for input during the process? The text will need to be redrawn before that. You could also have a thread that updates the screen every once in a while, but threads mean overhead, so...
- You'll need some sort of text-mode font that fits the resolution (or you need to skip a few pixels at the end of each character row).
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
-
- Member
- Posts: 78
- Joined: Sat Apr 10, 2010 7:00 am
- Location: Denmark
Re: Printing strings in graphics mode (320x200)
Thanks a lot for all of the quick replies folks!
I think I'm going to take use of extern function calls in Assembly (calling the C function, printChar, from my bootloader). Simply because I think a such function would be a lot easier to write in C, but of course that requires a 16-bit C compiler and linker. Does anybody have any suggestions?
EDIT: Oh sorry, I clearly didn't make any research before saying I had to get a 16-bit C compiler & linker. I got it working with GCC (32-bit). The only thing I'm uncertain of is how to pass arguments to the C function. I know C uses the stack for parameters, but I'm uncertain of how I can restore the stack after the function has been executed. As far as I'm concerned, C pops the parameters of the stack automatically, so all I have to do it to restore the stack pointer. Sooooo, the thing I'm confused of, is this example:
If stating that C automatically pops its parameters is correct, I suppose it automatically gets rid of 'text' and 'strformat'?
What confuses me, is this line:
Is there some particular reason it adds 8 to the stack pointer? -Or is this just always the case? (Sorry if my question is stupid).
I think I'm going to take use of extern function calls in Assembly (calling the C function, printChar, from my bootloader). Simply because I think a such function would be a lot easier to write in C, but of course that requires a 16-bit C compiler and linker. Does anybody have any suggestions?
EDIT: Oh sorry, I clearly didn't make any research before saying I had to get a 16-bit C compiler & linker. I got it working with GCC (32-bit). The only thing I'm uncertain of is how to pass arguments to the C function. I know C uses the stack for parameters, but I'm uncertain of how I can restore the stack after the function has been executed. As far as I'm concerned, C pops the parameters of the stack automatically, so all I have to do it to restore the stack pointer. Sooooo, the thing I'm confused of, is this example:
Code: Select all
global _main
extern _printf
section .data
text db "291 is the best!", 10, 0
strformat db "%s", 0
section .code
_main
push dword text
push dword strformat
call _printf
add esp, 8
ret
What confuses me, is this line:
Code: Select all
add esp, 8
-
- Member
- Posts: 78
- Joined: Sat Apr 10, 2010 7:00 am
- Location: Denmark
Re: Printing strings in graphics mode (320x200)
I've put together a first try at making a printA function. Unfortunatly, I can't call it a successful first try, because nothing is displayed. Here's the "main" routine from boot.asm:
This is the "printA" function, from graphics.inc:
"plotPixel" function:
This is all the functions in graphics.c:
"aFont" is just a two-dimensional integer array, forming an A out of 1s and 0s.
This is assemble.bat:
And this is what I get running assemble.bat:
I know the code is pretty much pathetic, but it's just to get somewhat like my first A printed in graphics mode.
And as said, the above code doesn't produce any screen output.
Code: Select all
main:
xor ax, ax
mov ds, ax
call mode12h
call clearScreen
mov al, 10
mov dx, 10
mov cx, 10
call printA
jmp $
Code: Select all
extern _printCharA
printA:
call _printCharA
ret
Code: Select all
global _plotPixel
_plotPixel:
push ebp
mov ebp, esp
mov ah, 0x000c
int 0x0010
leave
ret
Code: Select all
void addX(int x){
asm("push %ax");
asm("movw %0, %%ebx" : : "a" (x));
asm("add %bx, %cx");
asm("pop %ax");
}
void addY(int y){
asm("push %ax");
asm("movw %0, %%ebx" : : "a" (y));
asm("add %bx, %dx");
asm("pop %ax");
}
void printCharA(){
int y;
int x;
for(y = 0; y < 8; y++){
for(x = 0; x < 8; x++){
if(aFont[y][x] == 1){
int yLocation = y * 640;
addY(yLocation);
addX(x);
plotPixel();
}
}
}
}
This is assemble.bat:
Code: Select all
@echo off
nasm -f elf "../boot/boot.asm" -o "../temp/boot.elf"
"C:\MinGW\bin\gcc.exe" -c "../boot/graphics.c" -o "../temp/graphics.o"
ld -Ttext 0x7c00 "../temp/boot.elf" "../temp/graphics.o" -o "../temp/boot.o"
objcopy -O binary "../temp/boot.o" "../temp/boot.bin"
pause
Code: Select all
C:\Users\Benjamin\AppData\Local\Temp/ccmsTYSI.s: Assembler messages:
C:\Users\Benjamin\AppData\Local\Temp/ccmsTYSI.s:81: Warning: using `%bx' instead
of `%ebx' due to `w' suffix
C:\Users\Benjamin\AppData\Local\Temp/ccmsTYSI.s:81: Warning: using `%ax' instead
of `%eax' due to `w' suffix
C:\Users\Benjamin\AppData\Local\Temp/ccmsTYSI.s:97: Warning: using `%bx' instead
of `%ebx' due to `w' suffix
C:\Users\Benjamin\AppData\Local\Temp/ccmsTYSI.s:97: Warning: using `%ax' instead
of `%eax' due to `w' suffix
Press any key to continue . . .
And as said, the above code doesn't produce any screen output.
- Combuster
- 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)
Please don't put C code in a bootsector unless you know exactly what you are doing. Chances are you either screw up your C environment, or overrun the 512 byte boundary in trying to do so. Grab a debugger and you'll notice that what you coded does not get executed.
-
- Member
- Posts: 78
- Joined: Sat Apr 10, 2010 7:00 am
- Location: Denmark
Re: Printing strings in graphics mode (320x200)
Alright everyone, I'm back with some updates .
I trashed the C idea (under reasonable recommendations from Combuster). And decided to do it in NASM. I plan on storing the fonts in simple arrays, and pretty much do it the same way I did it in C. Yet, I've run into complications right from the beginning. I can't seem to get a simple array working. I know it sounds retarded.. .
Here's the 'aFont' array I surprisingly enough plan on using for my A font.
Here it is from graphics.inc so far: (Just a test array, to see if I could even make one)
And here's what I do to print out the 5 stored in the array (again, just for testing purposes):
But this doesn't print out a 5, it prints a 3?? Moving aFont+1 into al, prints a 4 etc etc.. why?
EDIT: This was actually as retarded as it sounds. I turns out I forgot to put square brackets around aFont to refer to the value pointed to by the memory.
Sorry for wasting your time. I'll return once I wrote some code to (hopefully) print an A.
I trashed the C idea (under reasonable recommendations from Combuster). And decided to do it in NASM. I plan on storing the fonts in simple arrays, and pretty much do it the same way I did it in C. Yet, I've run into complications right from the beginning. I can't seem to get a simple array working. I know it sounds retarded.. .
Here's the 'aFont' array I surprisingly enough plan on using for my A font.
Here it is from graphics.inc so far: (Just a test array, to see if I could even make one)
Code: Select all
aFont:
db 5
And here's what I do to print out the 5 stored in the array (again, just for testing purposes):
Code: Select all
mov ah, 0x000e
mov al, aFont
add al, 0x0030
mov bh, 0x0000
mov bl, 0x0007
int 0x0010
EDIT: This was actually as retarded as it sounds. I turns out I forgot to put square brackets around aFont to refer to the value pointed to by the memory.
Sorry for wasting your time. I'll return once I wrote some code to (hopefully) print an A.
Re: Printing strings in graphics mode (320x200)
You can retrieve the standard font from the BIOS using the following service, in case you don't feel like making your own:
http://www.ctyme.com/intr/rb-0158.htm
http://www.ctyme.com/intr/rb-0158.htm
-
- Member
- Posts: 78
- Joined: Sat Apr 10, 2010 7:00 am
- Location: Denmark
Re: Printing strings in graphics mode (320x200)
Thanks a bunch Gigasoft! You're a lifesafer!Gigasoft wrote:You can retrieve the standard font from the BIOS using the following service, in case you don't feel like making your own:
http://www.ctyme.com/intr/rb-0158.htm
So I could just move 0x1130 into ax, and then let's say 6h into bh to get a 8x16 font, and then make a call to interrupt number 10h and then I'll have the font in ES:BP?
EDIT: I did some research on the subject and it seems that it leaves an offset into the ASCII table (starting at 0) of the selected character set, is this correct?
EDIT2: I've run into some implementation issues... I thought once I had set ax to 0x1130, bh to 0x0002 (8x14 font) & made a call to int 0x0010, I could use ES:BP as an offset (starting at 0) into the ASCII table, so that this code:
Code: Select all
mov ah, 0x000e
mov al, [es:bp + 65]
mov bh, 0x0000
mov bl, 0x0007
int 0x0010
Re: Printing strings in graphics mode (320x200)
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).
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.