In this post I will be talking about P0267R0: A Proposal to Add 2D Graphics Rendering and Display to C++. This proposal will be discussed next week at the next ISO C++ Standardization meeting in Jacksonville.
P0267R0 comes out of C++’s SG13 HMI: Development of new proposals in selected human-machine interaction such as low-level graphics/pointing I/O primitives.
SG13 was created by Herb Sutter after the One C++ keynote talk he gave at GoingNative 2013.
Personal history
I started programming twenty years ago in high school. Back then I didn’t even have my own computer
Below you have the cover of the book that was used to teach us Turbo Pascal:
Please notice the graphics on the book’s cover. That drawing was presented as an example in the book by the means of Borland Graphics Interface (BGI).
A couple of years ago I had to port a car navigation engine to an Unix-like operating system. The target computer had support for OpenGL ES, the navigation engine could display images on the map, but none of them came with a 2D graphics engine.
I ended up porting Cairo Graphics just to render some text into PNG images, and to rotate a car image on the map.
N3888
SG13 also used Cairo Graphics as base for their first proposal - N3888. In the meantime the proposal matured as P0267R0, and the API has changed a bit.
Fork
The reference implementation has been done by Michael B. McLaughlin - MVP Microsoft.
The implementation has Visual C++ project files with pre-compiled binaries for Windows, and autotools support for Linux. This is due to the fact that Cairo Graphics comes from Linux world and they provide a makefile to compile on Windows. Michael McLaughlin has documented his work to build Cairo Graphics for Windows. Shiver.
Luckily there is a tool for cross platform C++ project building – CMake! This week I added CMake support for the reference implementation, see my fork at github: https://github.com/cristianadam/io2d.
Hello World
As it turns out the application code Michael B. McLaughlin used to test the implementation doesn’t compile out of the box. So I decided to write a simple “Hello World” application.
I had a look at the minimal C program using Cairo and decided to do the same with io2d. In the example the “Hello World” string is being rendered with a blue brush and saved as a PNG graphics file.
io2d doesn’t have support for PNG graphics files, or other graphics file format for that matter. So I had to come up with something
easy. I choose the TGA file format, because one just has to write a 18 bytes header and then dump the raw image bytes.
And no, BMP file format is not easy
#include <io2d.h> #include <fstream> #include "tga_header.h" namespace io2d = std::experimental::io2d; void save_surface_to_tga_file(io2d::image_surface& surface, std::string const& fileName) { tga::header tga_header; tga_header.image_type = tga::image_type::true_color; tga_header.image_spec.width = surface.width(); tga_header.image_spec.height = surface.height(); tga_header.image_spec.depth = 32; tga_header.image_spec.descriptor.top = 1; std::ofstream ofs(fileName, std::ofstream::binary); ofs.write(reinterpret_cast<const char*>(&tga_header), sizeof(tga_header)); auto bytes = surface.data(); ofs.write(reinterpret_cast<const char*>(&bytes[0]), bytes.size()); } int main () { io2d::image_surface image(io2d::format::argb32, 240, 80); io2d::simple_font_face consolas("Consolas", io2d::font_slant::normal, io2d::font_weight::bold); image.font_face(consolas); image.font_size(32.0); io2d::brush cyan(io2d::rgba_color::cyan()); image.brush(cyan); image.render_text("Hello World", {20.0, 50.0}); save_surface_to_tga_file(image, "hello.tga"); }
The code used to save the TGA file is bigger than the code used to render the image
tga_header.h
contains the code found at this StackOverflow question.
Thank you Brandon!
The CMakeLists.txt
file looks like this:
cmake_minimum_required(VERSION 2.8.12) project(hello CXX) add_executable(hello hello.cpp) target_link_libraries(hello ${IO2D_LIBRARY}) target_include_directories(hello PRIVATE ${IO2D_INCLUDE_DIR}) if (WIN32) target_compile_definitions(hello PRIVATE CAIRO_WIN32_STATIC_BUILD _WIN32_WINNT=0x0600) endif()
After running hello.exe
I ended up with hello.tga
which looks like
this when opened with The GIMP:
It worked!
C++17?
From Michael Wong’s blog post: C++17 content (a prediction)
we can see that Graphics TS is not meant to be included in C++17
I really do hope that SG13’s Graphics TS will be part of C++ sooner than later, because graphics programming is so much fun!