FTR is a portable and ported library for opening a window, drawing
pixels to it, and reading keyboard and mouse input. It is
crippled, slow, and extremely minimal. The main goal is to write tiny
portable programs that open windows and show images. It is a thin wrapper
around native libraries, intended to be as thin as possible, but not thinner.
Current ports include X11 (tested on linux, freebsd and openbsd) and any
platform supporting freeglut (tested on linux, should work on Windows and
OSX after installing freeglut). Planned ports include native Windows in the
short term and native OSX on the long term.
Examples
mini.c
This is the simplest program using FTR:
To compile and run this program on a unix system with X, place the file "ftr.c"
besides "mini.c" and run
This should open a black window of size 320×200 that can be closed by
pressing ESC.
events.c
A useful program is obtained by capturing some events on the window:
This program opens a black window and prints a line when an "event" happens
on that window. Events include key-presses, mouse motions and clicks, and
window resizing. The key-presses are represented by the ASCII value of the
corresponding key (using the correct keyboard configuration).
greenpixel.c
The following program opens a black window with a green pixel at the position
(10,10):
First, notice that the struct FTR is not an opaque data type, but it
has data that can be read and written explicitly, such as the framebuffer
rgb and the image size.
Second, observe the line f.changed = 1, that tells "the system" that
the framebuffer contents have changed. This line is necessary
because, as opposed to many other "widget" toolkits, the call to
ftr_new_window actually opens the window. The call to
ftr_loop_run is optional, and only needed so that the program does
not exit immediately. To understand that, try comenting the line
f.changed=1. The window will be opened but the green pixel will not
appear immediately; it will appear only when the window is redrawn, such as
when moving another window in front of this one. Another way to understand
this is to run the following program:
This program opens a window for three seconds, and then it exists and closes
the window. This observation is very important: FTR is not an event-based
library, it is multi-paradigm. You can write perfectly useful programs
without a main loop, or with many main loops in different places. There are
API functions like ftr_wait_for_mouse_click that allow a synchronous
programming style, which is impossible in other toolkits such as GLUT:
fire.c
The "idle" event is called continuously. This allows, for example, to run
simulations in realtime. However, it is dangerous because the CPU is used
100%. The following program draws a fire effect (compile with optimizations
to obtain an acceptable framerate)
(Javascript fire by Pau Gargallo)
ftr.h
Besides the examples above, the header file ftr.h is a useful and
complete source of information:
Principles
Goals of FTR
Be written in standard C
No global state in the API
The "ftr.h" file is as small as possible (ideally, one printed
page)
The "ftr.c" file contains the whole library
The "ftr.c" file can be directly included, so the header is
unnecessary
Deal only with WINDOWS, KEYBOARD and MOUSE
The keyboard input is read in ascii, when possible
The mouse wheel works, somehow
It works "natively" in unix, windows and mac
The same API hides different backends: Xlib, windows, cocoa,
glut, text
In Unix, it uses only Xlib (already implemented)
In Windows, it uses the Windows Api (not yet implemented)
In mac, it uses the COCOA C interface (not yet implemented)
There is a fall-back GLUT backend (not yet implemented)
There is a fall-back freeglut backend (already implemented)
There is a fall-back text-based backend, where events are read
from stdin
Programs must have exactly the same behaviour on all
backends
The complete API is implemented on all supported backends
Multiple user interface paradigms are supported:
event-based, automatic loop (set event handlers and call
ftr_loop)
event based, explicit loop (write the event loop
yourself)
blocking calls (explicitly wait for user input)
forked windows (each window has its own process, and
communication is done via signals and shared memory)
contiuously-redrawn window showing the evolution of an
image
A pixel is defined as three bytes containing the RGB components.
An image is an array of pixels
Do not use typedef structs, useless casts or otherwise ugly C code
80 columns, tabs are 8 spaces, functions have less than 25 lines
To port FTR to a new unix backend, you have to write only 7 "core"
functions: ftr_new_window ftr_change_title ftr_set_handler ftr_loop_run ftr_notify_that_the_framebuffer_has_changed ftr_notify_the_desire_to_stop_this_loop ftr_close_window
To port FTR to a non-unix backend, this other function has to be
re-written: ftr_fork_window
Non-goals of FTR
Be written in other languages than C
Image input/output
Any kind of image processing
Drawing widgets (e.g., buttons)
Drawing text
Drawing primitives (segments, disks, ...)
OpenGL access
Accelerated or otherwise efficient operations
Deal with anything else than WINDOWS, KEYBOARD or MOUSE
Pixel types other than 24bit RGB
Transparency, broken pixels (separate color channels), gray-level images,
etc
Floating-point samples
The API may change to adapt to future needs, and new functions may be added
without problem. However, the non-goals are strong decisions and I accept no
compromise on them. For example, FTR will never perform a contrast change.
This is up to the user of the library. On the other hand, some "helper" and
"convenience" functions are defined to ease common usages. For example, the
"ftr_open_window_with_image" function.
Status of ports
The X11 interface is tested and working in linux and mac.
The freeglut interface should be working in any platform that has glut, but
needs some testing, specially in the keyboard handler.
Back-end
Type
Status
X11
native
Working, tested in linux and OSX--Quartz
cocoa
native
not written
windows
native
not written
glut
semi-native
not written
glfw
semi-native
not written
freeglut
semi-native
Working, tested in linux (some keyboard issues)
gdk
experimental
not written
fltk
experimental
not written
qt
experimental
not written
xcb
experimental
not written
Motivation
FTR is inspired and tries to imitate many other libraries. The principal
sources of inspiration are CImg
and GLUT.
Why not use CImg?
CImg is essentially perfect.
There's no real reason to not use CImg in C++. Sometimes I would
like to use CImgDdisplay only, without need for CImg. For example, when I want
to publish an image processing algorithm of my own (that does not use the CImg
image processing capabilities), and I want to provide a small interface. CImg
is perfect for that, but a bit overkill if you do not work with the CImg class.
CImg.h is 46.000 lines of code. My objective is that ftr.c should never go
beyond 1000.
Why not use GLUT?
GLUT is essentially perfect, it has a very beautiful API
and provides a neat cross-platform way to open a window and show pixels on it.
There are, however a few problems: you can not exit easily the main loop, the
mouse wheel does not generate events, and you are forced to draw your pixels
using OpenGL. The freeglut re-implementation of GLUT solves the problem of the
mouse wheel (but is not native on mac osx) and it lets you exit the event loop
(but it closes the window when you do that). Freeglut is about 20.000 lines of
code in about 30 files, including font data and widget-drawing stuff.
How is FTR different?
Besides its limited scope (no widgets, no image processing, no opengl
access), FTR gives you more flexibility in the way you write your program.
The idea is that you write your whole program (e.g., an algorithm in image
processing), without needing FTR at all. Then, as an afterthought, you
decide to add, at some scattered places in your program, a few calls to FTR
to do things like:
1. Nested deep inside your algorithm, you want to open a window
containing a temporary image, and then continue running the program.
The window is kept open until it is closed by the user or until the
program ends. This involves a single call to this function:
ftr_new_window_with_image(char *rgb, int w, int h);
and nothing else. No initialization, no boilerplate. This function
returns immediately.
2. In the main loop of your program, you want to see how the iterations
progress. Thus, you open a window with the image before the loop, and
inside the loop you update the pixels of the image and then call the
function ftr_notify_that_the_framebuffer_has_changed.
3. Your example program uses a hard-coded pixel position. By calling
ftr_wait_for_mouse_click you let the user to click on a pixel.
4. See the tutorial for further examples.
Download, etc.
FTR is under heavy development and has not yet released a distribution.
By "distribution" I mean a single file ftr.c. Right now, I have two
files
ftr_x11.cftr_freeglut.c,
containing the respective implementations, that help me understand the required
symmetries.
You can find these files inside the "other" subdirectory of imscript
Prize
The first user who guesses correcly the meaning of the acronym "FTR" will be
invited to a beer of his choice.
Last updated: 4 March 2016, Enric Meinhardt-Llopis