Skip to main content

SDL-based 'GRAPHICS.H' implementation

Project description

About

SDL_bgi is a graphics library (GRAPHICS.H) for C, C++, WebAssembly, and Python. It comes in two versions based on SDL2 and SDL3, and it runs on many platforms; the two versions have identical functionality.

Its name refers to BGI, the Borland Graphics Interface that was the 'de facto' standard in PC graphics back in DOS days; it was made popular by Borland Turbo C/C++ compilers. I wrote SDL_bgi because I wanted a simple to use but fast graphics library for my experiments with fractals and cellular automata, using the BGI syntax I'm used to.

SDL_bgi is functionally compatible with the BGI implementation in Turbo C 2.01 and Borland C++ 1.0; for instance, it compiles and runs the original bgidemo.c. It also provides nearly full compatibility with another BGI implementation, WinBGIm (see links below). One of the aims of SDL_bgi is the preservation of old software written for BGI; but not only that.

SDL_bgi provides graphics primitives, and is much easier to use than plain SDL; it should be especially useful for beginners, i.e. in introductory programming courses. SDL_bgi is pretty fast, and in addition to BGI compatibility it provides extensions for ARGB colours, mouse support, vector fonts, and multiple windows. Native SDL2 or SDL3 functions can be used alongside SDL_bgi functions. The library can also be used in programs written in C++ or Python.

SDL_bgi is written in C, and it should compile on any platform supported by SDL2 or SDL3. It has been tested on GNU/Linux, MS Windows (MSYS2 and ucrt64, CodeBlocks, Dev-C++), macOS (High Sierra and Catalina), Raspios (ARM, i386), and WebAssembly (Emscripten). A few example programs in C and Python are provided in the demo/ directory.

Requirements

The C version requires the SDL2 or SDL3 library development packages. The Python module requires the SDL_bgi binaries and the SDL2 or SDL3 library binaries.

How to Install

Once the dependencies above are met, just do:

$ pip install sdl_bgi

How to use SDL_bgi in Python programs

Please make sure that you installed the SDL_bgi binaries for your platform before proceeding.

Implementation Details

SDL_bgi Python bindings are implemented via the ctypes library. In general:

  • functions in Python have the same name as their C counterparts;

  • constants and enums are implemented as variables;

  • standard C types (int, float, char *, etc.) are mapped to Python types;

  • structs are available as ctypes classes that have the same name and field names. For example:

\small

C struct                     Python class
--------                     ------------
struct arccoordstype {       class arccoordstype (Structure):
  int x;                         _fields_ = [ ("x", c_int),    
  int y;                                      ("y", c_int),    
  int xstart;                                 ("xstart", c_int)
  int ystart;                                 ("ystart", c_int)
  int xend;                                   ("xend", c_int), 
  int yend;                                   ("yend", c_int) ]
};

\normalsize

There are minor differences explained below.

Syntax differences

ctypes implements new types that are mapped to equivalent Python types; for example, c_int is equivalent to int. Please refer to ctypes' Reference.

2D arrays can be implemented via Numpy; please see for example demo/life.py or demo/buffers_numpy.py. Strictly speaking, Numpy is not required; but working with arrays without it is a pain.

Memory buffers, used for example by getimage() or getbuffer(), are implemented using function create_string_buffer().

The byref() function can be used to pass variables by reference, as in the following functions:

\small

# void detectgraph (int *graphdriver, int *graphmode);
graphdriver, graphmode = c_int (), c_int ()
detectgraph (byref (graphdriver), byref (graphmode))
print ("graphdriver, graphmode: ", graphdriver.value, graphmode.value)

# void getarccoords (struct arccoordstype *arccoords);
ac = arccoordstype ()
getarccoords (byref (ac))
print ("x, y, xstart, ystart, xend, yend: ", ac.x, ac.y, 
        ac.xstart, ac.ystart, ac.xend, ac.yend)

# void getaspectratio (int *xasp, int *yasp);
xasp, yasp = c_int (), c_int ()
getaspectratio (byref (xasp), byref (yasp))
print ("xasp, yasp: ", xasp.value, yasp.value)

# void getfillsettings (struct fillsettingstype *fillinfo);
fillinfo = fillsettingstype ()
getfillsettings (byref (fillinfo))
print ("pattern, color: ", fillinfo.pattern, fillinfo.color)

# void getimage ()
isize = imagesize (0, 0, len, 16)
image = create_string_buffer (isize)
getimage (0, 0, len, 16, image)

# void getlinesettings (struct linesettingstype *lineinfo);
lineinfo = linesettingstype ()
getlinesettings (byref (lineinfo))
print ("linestyle, thickness: ", ls.linestyle, ls.thickness)

# void getmoderange (int graphdriver, int *lomode, int *himode);
lomode, himode = c_int (), c_int ()
getmoderange (0, byref (lomode), byref (himode))
print ("lomode, himode: ", lomode.value, lomode.value)

# void getmouseclick (int btn, int *x, int *y);
kind, x, y = c_int (), c_int (), c_int ()
getmouseclick (kind, byref (x), byref (y))
print ("mouse x, mouse y: ", x.value, y.value)

# void getscreensize (int x, int y);
x, y = c_int (), c_int ()
getscreensize (byref (x), byref (y))
print ("size x, size y: ", x, y)

\normalsize

Pythonic Syntax

The following functions provide a more Pytonic syntax that only uses standard Python types:

\small

# void detectgraph (int *graphdriver, int *graphmode);
graphdriver, graphmode = detectgraph ()
print ("graphdriver, graphmode: ", graphdriver, graphmode);

# void getarccoords (struct arccoordstype *arccoords);
ac = arccoordstype ()
ac = getarccoords ()
print ("x, y, xstart, ystart, xend, yend: ", ac.x, ac.y, 
        ac.xstart, ac.ystart, ac.xend, ac.yend)

# void getaspectratio (int *xasp, int *yasp);
xasp, yasp = getaspectratio ()
print ("xasp, yasp: ", xasp, yasp)

# void getfillsettings (struct fillsettingstype *fillinfo);
fs = fillsettingstype ()
fs = getfillsettings ()
print ("pattern, color: ", fs.pattern, fs.color)

# void getlinesettings (struct linesettingstype *lineinfo);
ls = linesettingstype ()
ls = getlinesettings ()
print ("linestyle, thickness: ", ls.linestyle, ls.thickness)

# void getmoderange (int graphdriver, int *lomode, int *himode);
lomode, himode = getmoderange ()
print ("lomode, himode: ", lomode, lomode)

# void getmouseclick (int btn, int *x, int *y);
x, y = getmouseclick (WM_LBUTTONDOWN)
print ("mouse x, mouse y: ", x, y)

# void getscreensize (int x, int y);
x, y = getscreensize ()
print ("size x, size y: ", x, y)

# void initgraph (int *graphdriver, int *graphmode, char *pathtodriver)
initgraph ()

\normalsize

Helper Functions

The following functions can be useful:

list2vec (list): converts a Python list of integers to a vector; used for example by drawpoly()

vec2buf (vector): returns a string buffer that contains the values stored in vector. This is a 1-dimensional array that can be obtained from a Numpy 2D array 'matrix' with reshape (matrix, -1).

sizeofint (): equivalent to C sizeof (int). Please note that this is not the same as sys.getsizeof()!

Missing Features

SDL2-based variables bgi_window, bgi_renderer, bgi_texture, PALETTE_SIZE, and function copysurface() are not available.

Speeding Things Up

Python is an interpreted language, and its performance is quite poor if compared to compiled code. The PyPy interpreter should make Python code run faster, but SDL_bgi programs run much slower with PyPy than with CPython. Another Python implementation, Pyston, actually runs SDL_bgi programs definitely faster than CPython.

To give your programs a real boost, I strongly suggest that module Numba be used. Numba is a high performance Python JIT compiler that can translate a large subset of Python and NumPy code into fast machine code. It uses simple function decorators; please have a look at demo/mandelbrot.py to see how it works.

Making Standalone Binaries

To deploy a Python program as a standalone executable file, you may use PyInstaller or Nuitka.

Pyinstaller

Run it as in the following example:

test$ pyinstaller -F fern.py 
121 INFO: PyInstaller: 5.4.1
121 INFO: Python: 3.10.4
...
7373 INFO: Building EXE from EXE-00.toc completed successfully.
test$ _

The resulting executable will be created in directory dist/.

Nuitka

Run it as in the following example:

test$ nuitka3 --onefile --remove-output fern.py
Nuitka-Options:INFO: Used command line options: --onefile \
  --remove-output fern.py
Nuitka:INFO: Starting Python compilation with Nuitka '1.1.3' \
  on Python '3.10' commercial grade 'not installed'.
...
Nuitka:INFO: Successfully created 'fern.bin'.
test$ _

When run on Windows, you get fern.exe and fern.cmd, which is a batch file that sets up the proper runtime environment for the executable. Run fern.cmd to start the program; on MSYS2, use:

test$ start fern.cmd

On my GNU/Linux Mint 21.2 box, Nuitka creates a much smaller executable than Pyinstaller does.

Links

  1. SDL_bgi home page: https://sdl-bgi.sourceforge.io/; https://pypi.org/project/sdl-bgi

  2. The SDL library: https://www.libsdl.org/

  3. BGI on Wikipedia: https://en.wikipedia.org/wiki/Borland_Graphics_Interface

  4. WinBGIm, a BGI port for Windows: https://winbgim.codecutter.org/

  5. Borland Turbo C 2.01 online emulator: https://archive.org/details/msdos_borland_turbo_c_2.01

  6. PyEasyGraphics, a BGI-like Python port: https://github.com/royqh1979/PyEasyGraphics

This library is released under the Zlib license; please see the enclosed file LICENSE.

Brought to you by Guido Gonzato, PhD

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sdl_bgi-3.0.4.tar.gz (30.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sdl_bgi-3.0.4-py3-none-any.whl (17.9 kB view details)

Uploaded Python 3

File details

Details for the file sdl_bgi-3.0.4.tar.gz.

File metadata

  • Download URL: sdl_bgi-3.0.4.tar.gz
  • Upload date:
  • Size: 30.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for sdl_bgi-3.0.4.tar.gz
Algorithm Hash digest
SHA256 b5f4562d6c68b41641553cf58b9a006518e4682f4f2f5657ab180418bee866e8
MD5 e2725645b5816e98f147c3a8ffcc143e
BLAKE2b-256 53f10b3d16e8e01b5f1dbb820effb85072956fadff864dc3c97e0cc56e7f7c87

See more details on using hashes here.

File details

Details for the file sdl_bgi-3.0.4-py3-none-any.whl.

File metadata

  • Download URL: sdl_bgi-3.0.4-py3-none-any.whl
  • Upload date:
  • Size: 17.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for sdl_bgi-3.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 eb4081b242d073f43fed4f415e868db353017908c2972e5edf9dbc4a987ed06a
MD5 f15aae159a0af76724aa75e25b7ffe28
BLAKE2b-256 e7c2bc9509775de75a750f396bd8a75b0794a522bd0fbf1f0aea2aed928c0c86

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page