Introduction to SDL_bgi

SDL_bgi is a graphics library (GRAPHICS.H) for C, C++, WebAssembly, and Python. It’s based on SDL2 and it’s portable on many platforms.

If you’re familiar with BGI, the Borland Graphics Interface provided by Turbo C or Borland C++, then using SDL_bgi along with gcc or clang will be straighforward. If you don’t even know what BGI was, don’t worry: you will find SDL_bgi an easy and fun way to do graphics programming.

This document shows how to get started with SDL_bgi; please consult sdl_bgi-quickref.pdf for a complete function reference.

Compiling Programs

The following sections only apply to C and WebAssembly; Python, of course, is not compiled.

Native Code

To compile a C or C++ program on GNU/Linux, macOS or Raspios you can use the gcc,clang, or tcc compilers. With gcc or clang:

$ gcc -o program program.c -lSDL_bgi -lSDL2

With tcc:

$ tcc -o program program.c -w -D SDL_DISABLE_IMMINTRIN_H \
    -I /usr/include/SDL2 -lSDL_bgi -lSDL2

You may get compilation errors affecting libpulsecommon; they can be safely ignored.

tcc can also be invoked from scripts. You just need to add the following line (it can’t be split with \) at the start of your C source (GNU/Linux):

#!/usr/bin/tcc -run -w -D SDL_DISABLE_IMMINTRIN_H -I /usr/include/SDL2 -lSDL_bgi -lSDL2

but for better compatibility, please have a look at the demo/tccrun script.

To compile a program in MSYS2 + MINGW64:

$ gcc -o program.exe program.c -lmingw32 -L/mingw64/bin \
    -lSDL_bgi -lSDL2main -lSDL2 # -mwindows

The -mwindows switch creates a window-only program, i.e. a terminal is not started. Beware: functions provided by stdio.h will not work if you don’t start a terminal; your program will have to rely on mouse input only.

Code::Blocks users should read the file howto_CodeBlocks.md.

Dev-C++ users should read the file howto_Dev-Cpp.md.

WebAssembly

To compile a program to WebAsssembly using emcc, provided by Emscripten:

$ emcc -o program.html program.c \
    -std=gnu99 -O2 -Wall -lSDL_bgi -lm \
    -s USE_SDL=2             `# uses SDL2 module` \
    -s ALLOW_MEMORY_GROWTH=1 `# needed for the argb palette` \
    -s ASYNCIFY              `# implement loops` \
    -s SINGLE_FILE           `# standalone html files`

where SDL_bgi.bc is the precompiled SDL_bgi wasm module. The resulting program.html can be loaded and run in web browsers, without the need of starting a local web server:

$ firefox program.html

Compilation Details

Windows users must declare the main() function as:

int main (int argc, char *argv[])

even if argc and argv are not going to be used. Your program will not compile if you use a different main() definition (i.e. int main (void)), because of conflict with the WinMain() definition. It’s an SDL2 feature; please consult https://wiki.libsdl.org/FAQWindows for details.

Python Usage

The sdl_bgi.py module implements nearly all functions. In general, Python functions have the same name and arguments as their C counterparts. For more details, please see howto_Python.md.

Using SDL_bgi

Although SDL_bgi is almost perfectly compatible with the original GRAPHICS.H by Borland, a few minor differences have been introduced. The original BGI library mainly targeted the VGA video display controller, which was quite limited and provided at most 16 colours. SDL_bgi uses modern graphics capabilities provided by SDL2, while retaining backwards compatibility as much as possible.

Most old programs that use the original BGI library should compile unmodified. For instance,

int gd = DETECT, gm;
initgraph (&gd, &gm, "");

creates an 800x600 window, mimicking SVGA graphics. If the environment variable SDL_BGI_RES is set to VGA, window resolution will be 640x480.

Minimal dos.h and conio.h are provided in the demo/ directory; they’re good enough to compile the original bgidemo.c.

Please note that non-BGI functions are not implemented. If you need conio.h for GNU/Linux, please have a look at one of these:

To specify the window size, you can use the new SDL driver:

gd = SDL;
gm = <mode>;

where <mode> can be one of the following:

CGA             320x200
SDL_320x200     320x200
EGA             640x350
SDL_640x480     640x350
VGA             640x480
SDL_640x480     640x480
SVGA            800x600
SDL_800x600     800x600
SDL_1024x768    1024x768
SDL_1152x900    1152x900
SDL_1280x1024   1280x1024
SDL_1366x768    1366x768
SDL_FULLSCREEN  fullscreen

More less common resolutions are listed in SDL_bgi.h. You may want to use initwindow(int width, int height) instead.

SDL_bgi.h defines the _SDL_BGI_H constant. You can check for its presence and write programs that employ SDL_bgi extensions; please have a look at the test program fern.c.

Screen Refresh

The only real difference between the original BGI and SDL_bgi is the way the screen is refreshed. In BGI, every graphics element drawn on screen was immediately displayed. This was a terribly inefficient way of drawing stuff: the screen should be refreshed only when the drawing is done. For example, in SDL2 this action is performed by SDL_RenderPresent().

You can choose whether to open the graphics system using initgraph(), which toggles BGI compatibility on and forces a screen refresh after every graphics command, or using initwindow() that leaves you in charge of refreshing the screen when needed, using the new function refresh().

The first method is fully compatible with the original BGI, but it also painfully slow. An experimental feature is ‘auto mode’: if the environment variable SDL_BGI_RATE is set to auto, screen refresh is automatically performed; this is much faster than the default. This variable may also contain a refresh rate; e.g. 60. Unfortunately, auto mode may not work on some NVIDIA graphic cards.

As a tradeoff between performance and speed, a screen refresh is also performed by getch(), kbhit(), and delay(). Functions sdlbgifast(void), sdlbgislow(void), and sdlbgiauto(void) are also available. They trigger fast, slow, and auto mode, respectively.

Documentation and sample BGI programs are available at this address:

https://winbgim.codecutter.org/V6_0/doc/

Nearly all programs can be compiled with SDL_bgi.

The original Borland Turbo C 2.0 manual is also available here:

https://archive.org/details/bitsavers_borlandturReferenceGuide1988_19310204.

Avoid Slow Programs

This is possibly the slowest SDL_bgi code one could write:

while (! event ()) {
  putpixel (random(x), random(y), random(col));
  refresh ();
}

This code, which plots pixels until an event occurs (mouse click or key press), is extremely inefficient. First of all, calling event() is relatively expensive; secondly, refreshing the screen after plotting a single pixel is insane. You should write code like this:

counter = 0;
stop = 0;
while (! stop) {
  putpixel (random(x), random(y), random(col));
  if (1000 == ++counter) {
    if (event())
      stop = 1;
    refresh ();
    counter = 0;
  }
}

In general, you should use kbhit(), mouseclick() and event() sparingly, because they’re slow.

Differences

Please see the accompanying document compatibility.

Colours

SDL_bgi has two colour palettes: one for compatibility with old BGI, the other for ARGB colours. Colour depth is always 32 bit; SDL_bgi has not been tested on lesser colour depths.

The default BGI palette includes 16 named colours (BLACKWHITE); standard BGI functions, like setcolor() or setbkcolor(), use this palette. By default, colours in the default palette don’t have the same RGB values as the original BGI colours; the palette is brighter and (hopefully) better looking. The original RGB values will be used if the environment variable SDL_BGI_PALETTE is set to BGI.

An extended ARGB palette can be used by functions like setrgbcolor() or setbkrgbcolor() described below; please note the rgb in the function names. The size of the palette is given by getrgbpalettesize(); default value is 4096, but it can be increased using resizepalette().

Please see the example programs in the demo/ directory.

Fonts

Fonts that are almost pixel-perfect compatible with the original Borland Turbo C++ 3.0 CHR fonts are built in. Characters in the ASCII range 32 - 254 are available. Loading CHR fonts from disk is also possible.

CHR fonts support was added by Marco Diego Aurélio Mesquita.

Additions

Some functions and macros have been added to add functionality and provide compatibility with other BGI implementations (namely, Xbgi and WinBGIm).

Further, the following variables (declared in SDL_bgi.h) are accessible to the programmer:

SDL_Window   *bgi_window;
SDL_Renderer *bgi_renderer;
SDL_Texture  *bgi_texture;

and can be used by native SDL2 functions; see example in demo/sdlbgidemo.c.

Screen and Windows Functions

setwinoptions ("", -1, -1, SDL_WINDOW_FULLSCREEN);
initwindow (800, 600);

Multiple Windows Functions

Subsequent calls to initgraph() or initwindow() make it possible to open several windows; only one of them is active (i.e. being drawn on) at any given moment, regardless of mouse focus.

Functions setvisualpage() and setactivepage() only work properly in single window mode.

Colour Functions

Buffer Functions

Mouse Functions

WM_LBUTTONDOWN
WM_MBUTTONDOWN
WM_RBUTTONDOWN
WM_WHEEL
WM_WHEELUP
WM_WHEELDOWN
WM_MOUSEMOVE

Miscellaneous Functions

The Real Thing

You may want to try the online Borland Turbo C 2.01 emulator at the Internet Archive:

https://archive.org/details/msdos_borland_turbo_c_2.01.

The bgidemo.c program demonstrates the capabilities of the BGI library. You can download it and compile it using SDL_bgi; in Windows, you will have to change its main() definition.

Bugs & Issues

Please see the accompanying document BUGS.

Probably, this documentation is not 100% accurate. Your feedback is more than welcome.

Back to document index