01-29-2026, 02:36 PM
(This post was last modified: 01-29-2026, 03:10 PM by The Joyful Programmer.)
WALTER'S EDIT: Updated where the spoiler tag is placed. It's funny. I have never seen you do this to anyone else's long posts, Steve, so it appears that you are picking on me because of our past. But, that's Stevie for you.
STEVE EDIT: As this is a very long post and requires a lot of scrolling and large images, I tossed [ spolier ] tags around it so it won't be as hard to navigate past once read once. Click the spoiler box below to expand it.
I remember when I taught you and the community in 2014 on how to add keywords to QB64. The first keyword I added in a copy of QB64, which I still have, was the filled circle. I remember the "Circle War" we had at that time, trying to come up with the fastest way of filling a circle. I still have screenshots of all of that. Those were the days of fun and good competition.
The filled circle keyword I added, "FCIRCLE", was coded in C and used scanlines to draw them. Each line drawn in the circle actually used QB64's LINE keyword, at least the internal version of it.
On the CPU, scanlines are the fastest and best way to fill polygons of any shape, including circles. Michael Abrash taught this technique in his books in the 1990s, which some had been compiled into his one big book: "Graphics Programming Black Book: Special Edition".
Once you get the hang of scanlines, then rendering glyphs from fonts becomes easy since they are nothing more than complex polygons, as seen in the following screenshot:
That demo was created on my Android phone and uses the SDL2 library. It simply drew lines from one point to another, skipping the control points, which defines the Bezier curve used to curve the edges of the glyph. Here is a screenshot of a glyph with the Bezier curves being drawn:
Of course, coding on a small Android phone can lead to more mistakes because typing is extremely slow unlike on a PC keyboard. An example of that is when I did a filled glyph with scanlines, and the first iteration had an issue. Can you spot the issue in the following screenshot?
Here's a screenshot showing the points and control points of a glyph:
You could do scanlines on the GPU as well. Have the scanlines generated by a Compute shader and stored in a buffer, and use fragment shaders to render those lines. However, that would use a substantial amount of memory and GPU power when it isn't needed.
You could do what QB64 does internally and convert the glyphs into a spritesheet and draw each glyph as needed with a quad (two triangles - think two _MAPTRIANGLEs to make a box in QB64), and draw those images to the screen as needed. By that too takes up more memory and GPU power than it really needs to. If you're drawing with textured triangles, it is better to use a single, but larger triangle than two triangles. This is a technique I am using in my GPU visual projects. Since I got to the visual aspect of the web browser project I am working on, it was time to get back to the graphical parts of my "Starship BASIC" and "Star Quest BASIC 45" projects, which will also be used as parts of the web browser project.
I have shared a simple QB64 demo where I convert a full-color image to a palette-index colored image, which you can find at https://qb64phoenix.com/forum/showthread.php?tid=4139. I finally rewrote the conversion and dithering aspects of that demo into its GPU counterpart. For the sake of brevity, I'll post more about that GPU project in that thread instead of here. However, here is a screenshot showing the demo:
That screenshot shows the demo being rendered in full-color mode and has four layers being rendered, though the first one is hidden by the second (game) layer.
The following screenshot shows the 1st layer being rendered behind the game layer. The game layer is at 95% transparency.
If you look at the title bar of that demo, you will see that it is being rendered in palette-index mode, using 256 perceptual colors. To make it more interesting, the following screenshot shows the demo being rendered using 16 perceptual colors.
The next screenshot shows the demo being rendered with 256 colors, using the VGA256 original palette colors:
The next screenshot shows the demo using the same VGA256 256-color palette, but with each pixel being draw as 4x4 pixels.
With all that is going on and being rendered, the demo still runs at 60 FPS.
On a side note, the circular demo being drawn behind the game layer looks like this by itself:
That is a shader I found on ShaderToy.com. No scan lines used in the making of that demo.
Also, each layer is rendered to a single triangle which is larger than the window itself. This demonstrates what I was talking about earlier.
Now, touching on the subject of speed. The way QB64 is rendering text to the screen works well with older GPUs (video cards). However, with more modern video cards, it's no longer necessary. Matter of fact, it is an archaic way of doing things.
For example, my PC has a NVIDIA GeForce GTX 1650 video card installed, which was first released in April 2019. It has 4GiB or RAM and supports OpenGL v4.6, Vulkan v1.4, and DirectX 12.1. It can render over 1.6 Billion colored triangles per second, which means at 60 FPS, that's nearly 27 million triangles per frame. The resolution my monitor currently supports is 1920x1080. If we continue with the math and want to fill that resolution with the common 9x16 font (9 pixels wide by 16 pixels high), we would need to draw 14,552 characters on the screen. Let's say that each glyph (character) is built with an average of 100 triangles (without tessellation), that's 1,452,200 triangles that need to be rendered, which is only 5% of the total number of triangles that can be rendered on screen per frame.
Since modern GPUs offer tessellation, which breaks triangles up into multiple triangles, which in turn can be manipulated, can increase the rendering speed even more. Let's not forget about instancing, which can draw multiple triangular objects (of the same type), like a glyph (character), at one time, which in turn, also speeds up rendering. The sphere of cubes demo I shared before in the https://qb64phoenix.com/forum/showthread.php?tid=3945 thread uses instancing to speed up rendering.
The main reason I can think of for drawing text on screen with triangles on modern GPUs is scalability. You can scale the text to any size without losing quality. Other features you can create with triangulated glyphs are 3D text, faster outlining and special effects, and rotated text, like you would see in a Star Wars intro demo.
I hope this post provides some inspiration to people.
Walter W. Whitman
The Joyful Programmer (tm)
AstroCosmic Systems (tm)
etc...
STEVE EDIT: As this is a very long post and requires a lot of scrolling and large images, I tossed [ spolier ] tags around it so it won't be as hard to navigate past once read once. Click the spoiler box below to expand it.
(01-28-2026, 02:27 PM)SMcNeill Wrote: I've been working on filling in some of the missing tools in my draw library and one thing I noticed that I was missing was a really good filled arc routine. QB64's method was to draw a circle, choose a point inside the arc, and then use PAINT to fill that circle....
and it didn't work as it never seemed to properly close the arcs and then the paint bled out and colored the entire screen.
The CircleFill that I shared and everyone has used for ages and ages works off LINE statements and thus can never bleed outside the circle itself. It's fast and lovely and nice.
And so, I thought, can I come up with a similar way to do ARCs?
After a few different tries, this is what I've came up with -- a scanline polygon fill routine for arcs.
It does all the math first and calculates all those points which make up the edges of the circle and the lines of the sides of the arc, and then it draws the lines which makes up the circle.
This seems to work for me, and it seems to work nice and fast enough as to be usable in any program I might have.
You math guru's make take a look at this, go over it with a fine tooth comb like everyone did the CircleFill routine and see what might be improved with it, and share your thoughts with us, if you would. Without a whole lot of other versions to compare against, I don't know whether to call this really speedy or not.
At the moment, it seems suitable for my personal usage. I dunno if others have better or faster versions which do the same thing. If so, please share and let's compare!
(Note that you can really see the polygon code in action if you change the CONST inside the routine. Heck, there might even be times where you WANT to do so, for some particular reason or the other. Change it to something like 10! or 20! and then see how our circle looks. It'll be obvious with those values as to what it's doing for us. (You can also make the routine *faster* if desired by going with a rougher circle. Change the value to 2 or 5 and it's not that visually different, but it changes our polygon count by that step.)
CircleFill is nice and fast. This is my attempt to see if I can do the same style fastness for an ArcFill. Let me know what you guys think about it.
I remember when I taught you and the community in 2014 on how to add keywords to QB64. The first keyword I added in a copy of QB64, which I still have, was the filled circle. I remember the "Circle War" we had at that time, trying to come up with the fastest way of filling a circle. I still have screenshots of all of that. Those were the days of fun and good competition.
The filled circle keyword I added, "FCIRCLE", was coded in C and used scanlines to draw them. Each line drawn in the circle actually used QB64's LINE keyword, at least the internal version of it.
On the CPU, scanlines are the fastest and best way to fill polygons of any shape, including circles. Michael Abrash taught this technique in his books in the 1990s, which some had been compiled into his one big book: "Graphics Programming Black Book: Special Edition".
Once you get the hang of scanlines, then rendering glyphs from fonts becomes easy since they are nothing more than complex polygons, as seen in the following screenshot:
That demo was created on my Android phone and uses the SDL2 library. It simply drew lines from one point to another, skipping the control points, which defines the Bezier curve used to curve the edges of the glyph. Here is a screenshot of a glyph with the Bezier curves being drawn:
Of course, coding on a small Android phone can lead to more mistakes because typing is extremely slow unlike on a PC keyboard. An example of that is when I did a filled glyph with scanlines, and the first iteration had an issue. Can you spot the issue in the following screenshot?
Here's a screenshot showing the points and control points of a glyph:
You could do scanlines on the GPU as well. Have the scanlines generated by a Compute shader and stored in a buffer, and use fragment shaders to render those lines. However, that would use a substantial amount of memory and GPU power when it isn't needed.
You could do what QB64 does internally and convert the glyphs into a spritesheet and draw each glyph as needed with a quad (two triangles - think two _MAPTRIANGLEs to make a box in QB64), and draw those images to the screen as needed. By that too takes up more memory and GPU power than it really needs to. If you're drawing with textured triangles, it is better to use a single, but larger triangle than two triangles. This is a technique I am using in my GPU visual projects. Since I got to the visual aspect of the web browser project I am working on, it was time to get back to the graphical parts of my "Starship BASIC" and "Star Quest BASIC 45" projects, which will also be used as parts of the web browser project.
I have shared a simple QB64 demo where I convert a full-color image to a palette-index colored image, which you can find at https://qb64phoenix.com/forum/showthread.php?tid=4139. I finally rewrote the conversion and dithering aspects of that demo into its GPU counterpart. For the sake of brevity, I'll post more about that GPU project in that thread instead of here. However, here is a screenshot showing the demo:
That screenshot shows the demo being rendered in full-color mode and has four layers being rendered, though the first one is hidden by the second (game) layer.
The following screenshot shows the 1st layer being rendered behind the game layer. The game layer is at 95% transparency.
If you look at the title bar of that demo, you will see that it is being rendered in palette-index mode, using 256 perceptual colors. To make it more interesting, the following screenshot shows the demo being rendered using 16 perceptual colors.
The next screenshot shows the demo being rendered with 256 colors, using the VGA256 original palette colors:
The next screenshot shows the demo using the same VGA256 256-color palette, but with each pixel being draw as 4x4 pixels.
With all that is going on and being rendered, the demo still runs at 60 FPS.
On a side note, the circular demo being drawn behind the game layer looks like this by itself:
That is a shader I found on ShaderToy.com. No scan lines used in the making of that demo.
Also, each layer is rendered to a single triangle which is larger than the window itself. This demonstrates what I was talking about earlier.
Now, touching on the subject of speed. The way QB64 is rendering text to the screen works well with older GPUs (video cards). However, with more modern video cards, it's no longer necessary. Matter of fact, it is an archaic way of doing things.
For example, my PC has a NVIDIA GeForce GTX 1650 video card installed, which was first released in April 2019. It has 4GiB or RAM and supports OpenGL v4.6, Vulkan v1.4, and DirectX 12.1. It can render over 1.6 Billion colored triangles per second, which means at 60 FPS, that's nearly 27 million triangles per frame. The resolution my monitor currently supports is 1920x1080. If we continue with the math and want to fill that resolution with the common 9x16 font (9 pixels wide by 16 pixels high), we would need to draw 14,552 characters on the screen. Let's say that each glyph (character) is built with an average of 100 triangles (without tessellation), that's 1,452,200 triangles that need to be rendered, which is only 5% of the total number of triangles that can be rendered on screen per frame.
Since modern GPUs offer tessellation, which breaks triangles up into multiple triangles, which in turn can be manipulated, can increase the rendering speed even more. Let's not forget about instancing, which can draw multiple triangular objects (of the same type), like a glyph (character), at one time, which in turn, also speeds up rendering. The sphere of cubes demo I shared before in the https://qb64phoenix.com/forum/showthread.php?tid=3945 thread uses instancing to speed up rendering.
The main reason I can think of for drawing text on screen with triangles on modern GPUs is scalability. You can scale the text to any size without losing quality. Other features you can create with triangulated glyphs are 3D text, faster outlining and special effects, and rotated text, like you would see in a Star Wars intro demo.
I hope this post provides some inspiration to people.
Walter W. Whitman
The Joyful Programmer (tm)
AstroCosmic Systems (tm)
etc...
The Joyful Programmer has changed call signs. The Joyful Programmer is now called "AstroCosmic Systems".



