GraphicC – What’s so special about graphics anyway?

I have done graphics libraries off and on over the past few decades of programming.  I wanted to take one more crack at it, just because it’s a fun pasttime.  My efforts are on github in the graphicc repository.  This time around, I had some loose design criteria to work from.

  • Use the simplest C constructs as possible
  • Make it small enough to work on a microcontroller
  • Make it flexible enough to be included in any project
  • Make it composable, so that different design tradeoffs can be made
  • Do 2D basics
  • Do 3D basics

These aren’t exactly hard core criteria, but they’re good enough of a constraint for me to get started.  What followed was a lot of fumbling about, writing, rewriting, trying out, testing, and rewriting.  It continues to evolve, and shrink in size.  What of the key aspects of the project is trying to discover the elegant design.  This is something that I have tried to do over the years, no matter what piece of engineering I’m working on, whether it be a machine, workbench, software system, or what have you.  It’s relatively easy to come up with brute force designs that get the job done.  It’s relatively hard to come up with the design that gets the job done with at minimal expense.

When doing a graphics system, it’s really easy to lose focus and get locked into things that you might find on the host platform.  For example, Simple Direct Media Layer (SDL) is available everywhere, so why would anyone build a window and basic graphics interface today?  Well, SDL is more than I’m shooting for.  Over time, my design constraints may line up with those of SDL, and at such time I’ll have a decision to make about switching to using it.  But, to begin, it’s more than I need.

There are tons of other libraries that might suit the bill as well:

There are literally hundreds to choose from.  Some are commercial, some very mature, some old and abandoned.  Some rely on platform specifics, whether it be X or OpenGL, or DirectX.  Some are completely independent, but are tightly integrated with frameworks.  Some are just right, and exactly what I would use, but have some very stiff license terms that are unpleasant.  This is not to say that a perfect solution does not exist, but there’s enough leeway for me to justify to myself that I can spend time on writing this code.

How to start?  Well, first, I consider my various criteria.  The 3D aspects can easily dominate the entirety of the library.  I’m not after creating a gaming library, but I have similar criteria.  I want to be able to simply display 3D models, whether they be renderings of .stl files, or simple ray traces.  I’m not after creating a library that will support the next Destiny on its own, but creating such a library should be possible standing on the shoulders of graphicc.  That means taking care of some basic linear algebra at the very least, and considering various structures.

In the beginning, there was graphicc.h

Here’s a snippet:

#pragma once 

#ifndef graphicc_h
#define graphicc_h

#include <stdint.h>

typedef double REAL;

// Some useful constants
#ifndef M_PI
#define M_PI			3.14159265358979323846264338327950288
#define M_ROOT_PI		1.772453850905516027
#define M_HALF_PI		1.57079632679489661923132169163975144
#define M_QUARTER_PI	0.785398163397448309615660845819875721
#define M_ONE_OVER_PI	0.318309886183790671537767526745028724

#define M_E				2.71828182845904523536
#define M_EULER			0.577215664901532860606

#define M_GOLDEN_RATIO	1.61803398874989484820458683436563811

#endif

#define DEGREES(radians) ((180 / M_PI) * radians)
#define RADIANS(degrees) ((M_PI/180)*degrees)

From the very first lines, I am making some design decisions about the language environments in which this code will operate. The ‘pragma once’ is fairly typical of modern C++ compilers. It takes care of only including a header file once in a mass compilation. But, since not all compilers deal with that, there’s the more classic ‘ifndef’ as well.

I do make other assumptions.  including stdint.h.  I’m going to assume this file exists, and contains things like uint8_t.  I’m going to assume that whomever is compiling this code can make sure stdint.h is available, or substitutes appropriate typedefs to make it so.

Then there’s those monsterous constants done as #define statements.  I could do them as const double XXX, but who knows if that’s right for the platform or not.  Again, it’s easily changeable by whomever is compiling the unit.

Then there’s the ‘typedef double REAL’.  I use ‘REAL’ throughout the library because I don’t want to assume ‘double’ is the preferred type on any given platform.  This makes it relatively easy to change to ‘typedef float REAL’ if you so choose.  Of course each one has a different level of precision, and range, so that needs to be accounted for.  The assumption here is that whomever is doing the compilation will know what they want, and if they don’t sticking with a double is a good default.

The various constants are there mainly because they come up time and again when doing simple math for graphics, so they might as well be readily available.  Same goes for the two conversion routines between degrees and radians.  Of course I should change the divisions to be constants for increased speed.

The rest of this header contains some basic types:


typedef REAL real2[2];
typedef REAL real3[3];
typedef REAL real4[4];

typedef struct _mat2 {
REAL m11, m12;
REAL m21, m22;
} mat2;

typedef struct _mat3 {
REAL m11, m12, m13;
REAL m21, m22, m23;
REAL m31, m32, m33;
} mat3;

typedef struct _mat4 {
REAL m11, m12, m13, m14;
REAL m21, m22, m23, m24;
REAL m31, m32, m33, m34;
REAL m41, m42, m43, m44;
} mat4;

enum pixellayouts {
rgba
};

All of these, except the ‘pixellayouts’ are related primarily to 3D graphics.  They are widely used though, so they find themselves in this central header.  Later, there are decisions about doing things like Catmull-Rom splines using matrices.  These are best done using 4×4 matrices, even if you’re just calculating for 2D curves.

Before I go any further, a picture is worth a thousand words no?

test_blender

This is demonstrating a few things.  Here’s the code:


#include "test_common.h"

void checkerboard(pb_rgba *pb, const size_t cols, const size_t rows, const size_t width, const size_t height, int color1, int color2)
{
size_t tilewidth = width / cols;
size_t tileheight = (height / rows);

for (size_t c = 0; c < cols; c++){
for (size_t r = 0; r < rows; r++){
raster_rgba_rect_fill(pb, c*tilewidth, r*tileheight, tilewidth / 2, tileheight / 2, color1);
raster_rgba_rect_fill(pb, (c*tilewidth) + tilewidth / 2, r*tileheight, tilewidth / 2, tileheight / 2, color2);
raster_rgba_rect_fill(pb, c*tilewidth, (r*tileheight) + tileheight / 2, tilewidth / 2, tileheight / 2, color2);
raster_rgba_rect_fill(pb, (c*tilewidth) + tilewidth / 2, (r*tileheight) + tileheight / 2, tilewidth / 2, tileheight / 2, color1);
}
}
}

void test_blender()
{
size_t width = 800;
size_t height = 600;

pb_rgba pb;
pb_rgba_init(&pb, width, height);

// Red background
raster_rgba_rect_fill(&pb, 0, 0, width, height, pRed);

// create checkerboard background
checkerboard(&pb, 16, 16, width, height, pLightGray, pYellow);

// Draw some blended rectangles atop the whole
for (int offset = 10; offset < 400; offset += 40) {
float factor = offset / 400.0f;
int alpha = (int)(factor * 255);
//printf("factor: %f alpha: %d\n", factor, alpha);

int fgColor = RGBA(0, 255, 255, alpha);
raster_rgba_rect_fill_blend(&pb, offset, offset, 100, 100, fgColor);
}


// Now we have a simple image, so write it to a file
int err = write_PPM("test_blender.ppm", &pb);
}

int main(int argc, char **argv)
{
test_blender();

return 0;
}

Initializing a pixel buffer (a rendering surface), filling it with a checkerboard pattern, then blending progressively opaque rectangles atop that.  Finally, it writes the result out to a ‘.ppm’ file.  There’s a long way from some constant definitions to doing blended rectangle rendering, but each step is pretty simple, and builds upon the previous.  So, that’s what I’ll focus on next.  In the meanwhile, there’s always to code.

Advertisements


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s