I have a framework I use for (mainly) graphics. I used to use the olcpge for that, but performance issues, some incompatibilities, and the sheer size of the thing (which is an ironic complaint to have about a single-header library) rubbed me the wrong way, so I made my own. I ended up using a similar design (initialise, supply function, call loop), the internals are a bit different. I don’t really have a name for it (the file is called libv2.h
, the class Framework
- never needed anything more specific), though I’m tempted to call it frave
(since it’s the framework of ave), in old unix fashion.
For the technical aspect, it is itself a wrapper around SDL2 (which I believe is also what olcpge used?). This makes it very portable, as its two dependencies (SDL2 and stdio.h
- technically I also use time.h
(to keep 24fps), math.h
(log10
used to estimate integer length), and string.h
(good ol' malloc
), but mainly out of convenience - all three of them can be removed with minimal modifications if I ever got arsed).
General Use
The library includes:
- Framework
class - the one used for GUIs etc
- img
class - loads/saves and stores images. Uses ppm
format because of how dead simple it is to use, uses 12 bits/pixel (aka short
- uppermost nibble internally used for alpha)
- _max, _min
as defines and mod, mdiv
as functions, doing pretty much what you’d think, but without the overhead of the standard ones - also, mod
and mdiv
return positives, which is way more intuitive than the builtin %
operator
To use:
- create an instance of Framework(int,int,int,unsigned char(*)(int)=0)
. First three arguments are screen width, height, and scale. The last argument is an optional sound synthesis function, which should take a timestamp (as an integer) and return an unsigned char as a sample (at 8000hz)
- optionally, modify internal variables. The default transparent value is 0xf000
, I often prefer setting it to 0xf0f
. You can also manually set the user function here (aptly named userfunc
)
- the run(bool(*)(Framework*)=0)
function is the one that does the heavy lifting. If you didn’t supply a user function in the previous step, you can give it as an argument here. It should take a framework as an argument (used for key events etc), and return whether the application should keep running. It enters an endless loop, handling key events, executing the userfunc, then handling rendering and delay (if your function returns 0, it exits the loop and terminates)
Functions
img class
img
has four initialisers:
- img()
creates an empty object
- img(int,int)
creates a blank (black) image of the specified dimensions
- img(int,int,short*)
creates an image, loading it with the provided data (buffer gets used/modified internally). It is up to the user to make sure the buffer is large enough to contain the image
- img(const char*)
loads the file given (assuming it’s a ppm
image)
clear(short=0)
can be used to overwrite image data with a specified color, by default black.
load(const char*)
can be used to load a ppm
file into a preexisting image
save(const char*)
saves the image contents to a ppm
file
short&operator[](int i)
can be used to index individual pixels of the image. You can also directly use the internal variables int sx,sy;short*data;
for that (since I’m not maniacally/idiotically orthodox about encapsulation)
As mentioned above, it internally stores images as 12 bits/pixel (it saves them as 24bpp to comply with the usual use of ppm
). The framework uses the free uppermost nibble for transparency.
Framework
The General Use
gave a broad overview of how to use this class. Here a list of functions:
- clear(short=0)
overwrites the screen with a single color (by default black)
- p(short,int,int)
colors a single pixel (uppermost nibble used as alpha yadda yadda)
- pc(char,int,int,short=0xfff,short=0,bool=0)
draws a single ASCII character to screen using codepage 473. Optional arguments are foreground and background color, and whether the coordinates are in text- or screen-space
- pcm(char,int,int,short=0xfff,short=0)
draws a single character (between 32 (space) and 96 (backtick)) to screen using a custom, 3px high, variable width font made to be teensy. Adressing is always screen-space. Returns character width.
- pcmid(char,int,int,short=0xfff,short=0)
draws a single character (as above) to screen using simplifier0’s custom 4x4px font (fixed-width).
- ps(const char*,int,int,short=0xfff,short=0,bool=0)
, psm(same)
, and psmid(same)
use the above to render entire (null-terminated) strings. Signature of all three is the same (except for the bool
XXX), all return the string length.
- pi(int,int,int,short=0xfff,short=0)
draws an integer using pc
- pis(as pi)
does the same, using pcm
- pi(short*,int,int,int,int)
renders an image to screen. First pair are screen coordinates, second are image size.
- pi(img,int,int)
as above, using img
- phl
, pvl
, pbox
use codepage473’s extended box characters to draw horisontal and vertical lines, and a box respectively
- snap(const char*=0)
saves a screenshot of the screen under the given filename (or snap.ppm
if none given)
- key, keyh, keyp, keyr
all take an int
and return a bool
signifying whether the key given (as an SDL_SCANCODE
) is pressed/was held/pressed/released
- the mouse
instance variable (encapsulation yadda yadda) can be used to check mouse position (instance variables int x,y
) and state (instance variables bool left,right
) (iow the mouse’s horisontal position is Framework->mouse.x
)
Implementation
For those among you that are religious about object-oriented data encapsulation, here is a space to vent your frustrations at the following segment:
With that out of the way, let’s discuss internal variables. img
was explained above, so this is mainly concerned with Framework
. Most of those are peripherals that SDL2 needs to work, though a couple might be of interest.
const char fontdata[],minifontdata[],midfontdata[]
contain the data used to generate the fonts used by the text functions (shocking, I know). It is stored as base64-compressed binary data, and decompressed into unsigned char font[],minifont[],midfont[]
at initialisation.
int _sx,_sy,_ss
store the width, height, and scale. They are quite useful to calculate positions at runtime if they are not otherwise defined or shoould be flexible (window scaling not supported)
short*newmap,*oldmap
are the screen buffers. newmap
is where the current frame is rendered to (useful for manual visual tricks), oldmap
stores the previous frame in order to figure out drawcall optimisations. Will probably remove it at some point.
short transparent
tells us what a completely transparent pixel is set to. By default its value is 0xf000
(aka a fully transparent black pixel), though I often manually set it to 0xf0f
(saturated purple - a lot of software uses it (sometimes with black) to indicate a missing texture (it also sounds like “four-oh-four”)), which is convenient eg for storing transparency in ppms which do not support alpha channels (ExhiBotanist uses this trick)