How to draw a red square in Magnum — in one statement

Af­ter read­ing the “How to draw a red square in Qt Quick” blog post show­cas­ing the sim­plic­i­ty of Qt API I thought it would be in­ter­est­ing to try some­thing sim­i­lar in Mag­num for com­par­i­son.

The fol­low­ing state­ment cre­ates and ren­ders a red square in Mag­num. The state­ment is wrapped on four lines for bet­ter read­abil­i­ty:

        .setTransformationProjectionMatrix(Matrix3::scaling({0.2f, 0.3f}))

Copy-past­ing it in­to draw event of the ba­sic boos­t­rap ap­pli­ca­tion and do­ing a bunch of #include and li­brary link­ing bu­reau­cra­cy will re­sult in this im­age:

Magnum One Statement Red Square
import QtQuick 2.0

Item {
    Rectangle {
        color: "red"
        width: 100
        height: 100
        x: 100
        y: 100
Draw­ing a red square in Qt Quick

Be sure to read the orig­i­nal blog post as well so you can do a fair com­par­i­son. The code in ques­tion is above.

The Qt Quick code, shown on the right, is slight­ly short­er, but the C++ ver­sion of com­pa­ra­ble per­for­mance shown in the post is far more ver­bose in Qt than in Mag­num. A cou­ple things worth not­ing:

  • Un­like in the Qt code we aren’t us­ing any scene graph but do ev­ery­thing di­rect­ly. In this par­tic­u­lar case the scene graph would com­pli­cate things rather than make them sim­pler.
  • Thanks to ex­pres­sion-ori­ent­ed (and not state­ment-ori­ent­ed) API and method chain­ing it’s pos­si­ble to con­cate­nate many calls on one line.
  • In C++ all tem­po­raries are kept un­til the end of the state­ment (the ; char­ac­ter), so the code doesn’t re­ly on any un­de­fined be­hav­ior, even though it might look like that.
  • This is ob­vi­ous­ly on­ly per­for­mant as an one-off draw, recre­at­ing all ob­jects ev­ery frame wouldn’t be ex­act­ly ef­fi­cient.
  • This ex­act thing can be done even sim­pler (and faster) us­ing scis­sor test and frame­buffer clear, but that’s not the point.

The fol­low­ing code is the ex­act equiv­a­lent of the above, with ex­plic­it tem­po­raries for bet­ter un­der­stand­ing:

Trade::MeshData2D meshData = Primitives::squareSolid();
GL::Mesh mesh = MeshTools::compile(meshData);

Shaders::Flat2D shader;
shader.setTransformationProjectionMatrix(Matrix3::scaling({0.2f, 0.3f}))


The set­up and ac­tu­al draw­ing is now clear­ly sep­a­rat­ed. You can now see that we abused method chain­ing to cre­ate, con­fig­ure and pass the shad­er to GL::Mesh::draw() in a sin­gle ex­pres­sion, but that’s a per­fect­ly le­gal thing to do. Hav­ing 2D equiv­a­lents of ev­ery­thing al­so makes things a bit sim­pler, on the oth­er hand dis­play­ing a 3D cube would on­ly need a dif­fer­ent prim­i­tive, a dif­fer­ent shad­er with more in­volved con­fig­u­ra­tion and en­abling the depth test. The code is al­so as fast as it could get, un­less you have a very spe­cif­ic use case (like draw­ing thou­sands of squares in a par­ti­cle sys­tem).

Go­ing deep­er

As not­ed be­fore, there is pre­cise­ly no low­er lev­el in which we could do things more ef­fici­tent­ly. The on­ly low­er lev­el are raw OpenGL calls, which would have com­pa­ra­ble per­for­mance but with far more ver­bosi­ty and less er­ror check­ing. The on­ly thing we can do is to recre­ate parts of the set­up by hand.

Man­u­al­ly cre­at­ing the mesh

The Mesh­Tools::com­pile() func­tion is an all-in-one tool for cre­at­ing gener­ic mesh­es from im­port­ed da­ta. In this case the prepa­ra­tion is very sim­ple, so we can re­place it with the fol­low­ing. Note that we need on­ly the ver­tex buf­fer (the in­dex buf­fer above was nullptr as it was al­so not need­ed).

constexpr Vector2 data[]{{ 1.0f, -1.0f}, { 1.0f,  1.0f},
                         {-1.0f, -1.0f}, {-1.0f,  1.0f}};

GL::Buffer buffer;

GL::Mesh mesh{MeshPrimitive::TriangleStrip};
    .addVertexBuffer(buffer, 0, Shaders::Flat2D::Position{});

Man­u­al­ly cre­at­ing the shad­er

The stock Shaders::Flat2D shad­er in­ter­nal­ly em­ploys a bunch of com­pat­i­bil­i­ty stuff to make it work­ing on all sup­port­ed OpenGL, OpenGL ES and We­bGL sys­tems. To make things sim­pler we will re­strict our shad­er to GLSL 4.30 on­ly. Al­so all er­ror check­ing is omit­ted for brevi­ty:

struct FlatShader: GL::AbstractShaderProgram {
    typedef GL::Attribute<0, Vector2> Position;

    FlatShader() {
        GL::Shader vert{GL::Version::GL430, GL::Shader::Type::Vertex};
layout(location = 0) uniform mat3 matrix;
layout(location = 0) in vec4 position;

void main() {
    gl_Position = vec4(matrix*position.xyw, 0.0).xywz;

        GL::Shader frag{GL::Version::GL430, GL::Shader::Type::Fragment};
layout(location = 1) uniform vec4 color;
out vec4 fragmentColor;

void main() {
    fragmentColor = color;


    FlatShader& setTransformationProjectionMatrix(const Matrix3& matrix) {
        setUniform(0, matrix);
        return *this;

    FlatShader& setColor(const Color4& color) {
        setUniform(1, color);
        return *this;

The ac­tu­al code is then just slight­ly mod­i­fied to use our shad­er, i.e. FlatShader in­stead of Shaders::Flat2D:

// ...

GL::Mesh mesh{MeshPrimitive::TriangleStrip};
    .addVertexBuffer(buffer, 0, FlatShader::Position{});

FlatShader shader;
shader.setTransformationProjectionMatrix(Matrix3::scaling({0.2f, 0.3f}))

// ...


The code above shows that:

  • The li­brary is low-lev­el, but low-lev­el doesn’t nec­ces­sar­i­ly mean ver­bose.
  • High­er-lev­el con­cepts are built on top of low­er-lev­el fea­tures, they are not re­plac­ing them. So when you want to e.g. use scene graph, you just take your low­er-lev­el code as is, wrap it in the Scene­Graph API and you are done.
  • Many fea­tures are there to sim­pli­fy com­mon tasks (such as pre-made prim­i­tives or stock shaders), but it doesn’t mean that they will get in the way when you want to do some­thing more in­volved.
  • Sig­nif­i­cant por­tions of the li­brary can be re­placed with cus­tom or low­er-lev­el so­lu­tions and the rest of the code will just work with them.

That’s all. Hap­py hack­ing!