Giter Site home page Giter Site logo

drwonky / vgalib Goto Github PK

View Code? Open in Web Editor NEW
20.0 1.0 4.0 2.68 MB

Cross platform DOS/Linux/Web VGA/EGA/CGA graphics library

Home Page: https://apsoft.com/archives/introduction-to-vgalib/

License: GNU Lesser General Public License v3.0

Makefile 8.91% C++ 41.99% C 43.70% HTML 3.28% Objective-C 2.12%

vgalib's Introduction

VGALIB

This is a cross platform graphics library written to compile for DOS, Linux+SDL, and Web (emscripten+SDL).

This project started out as a simple screensaver written in 1995, then brought back to life in late 2018 after discovering an old hard drive with all of my old DOS files.

The library and programs compile under Borland C++ 4.0 and later. If std::string support is removed, it will compile under BC3.1, since BC3.1 is missing cstring.h.

The library supports VGA, VGA 160x100 16 color text mode, CGA 160x100 16 color text mode, TEXT as graphics (80x25), and MDA as graphics (80x25).

Video update is coordinated with vsync and the library detects if you have a VGA or CGA card and is able to perform the correct setup for 160x100 text mode.

The DOS portions of this code run in Dosbox, however BC4.0 doesn't run entirely in Dosbox due to DPMI issues and emulation problems.

To compile this for DOS, I've been running BC4.0/4.5/5.0 under a Windows 2000 VM, but you could create a DOS VM just the same or use QEMU.

The code uses inline assembler to speed up certain operations when compiled for DOS. This inline assembler is written for i386 or later, in the future 16bit assembler will be selectable via compile time define.

Under Linux it uses SDL2 to render the graphics to the screen. The library is versatile because it implements an 8bpp off screen buffer for all graphics operations, then it translates or copies these offscreen buffers to the screen buffer during vsync.

There are 2 offscreen buffers, the primary buffer which is drawn to with vga::drawimage, and the sprite buffer which is drawn to with vga::drawsprite.

When compositing the output, vga::syncsprites copies the _os_buffer to the _sprite_buffer, then sprites are drawn onto the _sprite_buffer with the background color used as a mask. Finally, the _sprite_buffer is translated or copied to the _screen buffer.

The rotate and scale routines are quite intensive, so it's best to not perform a lot of realtime scaling or rotation if targetting DOS.

On modern systems and web browsers, performance seems to be very good and CPU usage is much less than on emulators.

--Perry Harrington

Few notes about the code enclosed

png.h/cpp are a full standalone PNG decoder. libpng doesn't compile for 16bit DOS, so I wrote my own PNG decoder. The decoder first loads a PNG into the PNG class, then you call png::convert to convert it into an image object. This will decode indexed images, grayscale, and RGB truecolor. Transparency is respected, but note that if the source image shares a color in the image with the color marked transparent in the palette, it won't render like you expect. PNG uses the deflate algorithm, the correct header and LIB files are included to compile with the HUGE memory model on DOS. If you target something else, you'll need to download and build ZLIB for that model. I found my color quantizing algorithm produces a nicer result than GIMP, however if you target DOS, I recommend converting your images to indexed color mode prior to building the application, since RGB conversion is very intensive. For images less than 262144 (512x512) pixels, a palette compare/lookup is done for every pixel, for larger images a cache is built for all possible colors, which consumes 256KB of memory. Since the library doesn't support larger display modes, the less-memory hungry method is more cycle hungry -- but this can all be ignored if you pre-convert the images. I have provided the VGA palette as VGA.gpl and modified-SNES pallete as RRRGGGBBw.gpl, as well as SNES.gpl, which implements a straight RRRGGGBB 8Bpp direct mapped palette.

direct8bpp.c is a palette generator. I spent a lot of time toying with different palettes. If you have bold colors without many grays, the modified SNES palette does a good job. To modify the palette I pushed the steps around to get 4 shades of gray, which the SNES pallette has none. You can see the tweaks I tried out in the palette_values.ods spreadsheet.

vgalib's People

Contributors

drwonky avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

vgalib's Issues

Rework image format to support 1bpp and 4bpp formats

When VGALIB was designed, the screen was the primary buffer, and mode 13h was the principal target. Having an 8bpp linear framebuffer makes programming very simple and updating of the video memory quite fast. You can use 32bit instructions to read and write data to video memory, if the underlying bus is 8bit, then waits are inserted while the data is shuffled each clock cycle, but if the bus is 16bit, it's 2 clocks, and if you have a local bus like VLB, PCI, EISA, or something else, the write can be done in one shot.

The video card in my 486dx4-120 retro PC is a VLB ET4000/W32p and memory accesses are really fast, on topbench the MemoryTest is 55us while the VidramTest is 61us. The identical motherboard is used on my testbench PC which has an Everex 8-bit EGA card. The VidramTest is 1600us (1.6ms) on the EGA card in a 486dx2-66. Using the conventional approach to write nibbles to EGA memory involves a mask register on the EGA card and a read to populate the main 32-bit register. I'm seeing about 1-2fps update with this method on an EGA while the CGA version of the program runs 5-10fps (I haven't added benchmarks to the demo programs yet).

Games like Commander Keen used a tile based approach, a packed bitmap was written to EGA memory and the EGA hardware was used to pan the memory around. Sprites were updated directly, but when you've got maybe 10 sprites on the screen, the amount of data written is pretty small.

So, the EGA write mode 2 isn't going to be very fast and I have serious doubts about the performance of double buffering an offscreen buffer to an EGA screen buffer. It's possible to have 2 screen pages in the address space of EGA with 320x200x16 mode.

This issue really is about adding 1bpp and 4bpp support to the image type internally, so here are some thoughts:

  • Image doesn't really implement much of an interface, originally most of the canvas functionality was in Image, but I moved that into Canvas because I imagined display adapters could be a subclass of Canvas, each implementing the Cavas API calls where needed. This may still be a viable approach with double buffered EGA and it may be the fastest solution. The downside to this approach is that as you optimize for speed, you become more specialized and specific in each implementation. Pushing the access down to Image or Adapter classes can improve things but at the cost of bulk operations. Copying images around is the underlying design approach to VGALIB, using offscreen buffers to blit images and composite a final image, then copy the offscreen buffer to the video memory.

  • Image could be redesigned to have access methods for each of the 1bpp, 4bpp, and 8bpp color depths, if the array operator [] was overloaded, then Canvas could treat the Image as a linear buffer and Image could translate the access to the appropriate memory underneath. The display adapters would expect the image buffer to be the same depth as the video memory, so 1bpp modes would expect 1bpp buffers, 4bpp modes would expect 4bpp buffers, etc. I expect the fastest way to update EGA is to write an entire plane at once, bypassing the internal registers and switching planes just 4 times. Writing to I/O ports is slow and selecting the bit mask register for every pixel is a performance killer. To make EGA and VGA mode 12h fast, the Image buffer really needs to be in a planar format, R, G, B, and I representing contiguous regions of 1bpp data. Then updating the screen simply involves copying each of the bitmaps. This mode would also mimic the 1bpp modes, since EGA and VGA really just implement them the same way. Doing contiguous 1bpp allocations would also solve the hires problem, since no single color plane would be bigger than 1 segment, and far pointers would still work (fast). A 1bpp image could just implement 1 plane, 4bpp just requires 4 times the work as 1bpp modes.

  • Implementing a planar image format in the Image class would mean pushing memcopy routines down to Image, so it knows how to deal with source Images of 8bpp, 1bpp, and 4bpp. This only applies to Image-to-Image copying, which is the bread and butter of the underlying design. The display drivers will need to have the implementation specific code for writing to video memory.

  • Implementing 1bpp and 4bpp planar Image formats should have each plane allocated to a new pointer so there are no segment overruns.

  • Canvas implements setpixel, this needs to be pushed down to Image

  • Canvas implements image to image copy with the assumption that images are 8bpp linear, the image to image copy needs to be push down to Image

  • Canvas implements transparency, this needs to be implemented in the pushed-down Image methods

  • Image should be able to handle arbitrary source and destination color depths; no palette munging will be done on image copy, the assumption is that a lower color depth will be a subset of a higher color depth. Image palettes can be specified when an image is instantiated, the png loader obeys the target palette and does its best to remap. This means 4 color CGA images will remap correctly into a 16 color or 256 color Image target as long as the palettes are the same. The convention is to set the default canvas palette to match the display's palette, if you do this and load a 4 color CGA image into a 16 color Image buffer, the colors will be remapped to the palette entries of the 16 color Image. If you then draw this 16 color image onto a 256 color image, as long as the 16 color image palette is a subset of the 256 color palette, the colors will be compatible.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.