Cristian Adam

Introducing C++ experimental io2d

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 smile 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 smile

#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 smile

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! tada

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 disappointed

I really do hope that SG13’s Graphics TS will be part of C++ sooner than later, because graphics programming is so much fun!

Comments