Skip to content

Corg-Labs/cube

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Spinning 3-D Cube in C

A real-time 3‑D cube rendered with filled faces and white wireframe edges, tumbling under dual-axis rotation. Each face is a different colour. Rendered via SDL2 using the painter's algorithm for correct depth ordering.

Eight vertices, twelve edges, six faces — pure geometry, no GPU.


Features

  • 8-vertex cube geometry with dual-axis rotation (Y then X)
  • Perspective projection with true 3‑D divide
  • Painter's algorithm: faces sorted by average Z, drawn back to front
  • Barycentric triangle rasterisation for solid face fill
  • White wireframe edges overlaid on filled faces
  • Six-face colour palette: red, blue, green, yellow, cyan, magenta
  • True 24‑bit color rendering via SDL2 framebuffer
  • 960 × 640 window
  • Keyboard and Ctrl-C quit handling
  • Written entirely in C

How It Works

Every frame, the eight cube vertices are rotated around the Y axis, then the X axis at 0.7× speed to produce a tumbling motion. Each vertex is projected to 2‑D via perspective divide. The six faces are sorted by their average rotated Z (painter's algorithm) and drawn back-to-front as filled quads (split into two triangles). White edges are then drawn over the faces for a clean wireframe finish.


Tutorial / 3-D Pipeline

1. Cube Geometry

Eight vertices at ±1 on each axis, centred at the origin:

double v[8][3] = {
    {-1,-1,-1}, { 1,-1,-1}, { 1, 1,-1}, {-1, 1,-1},
    {-1,-1, 1}, { 1,-1, 1}, { 1, 1, 1}, {-1, 1, 1},
};

Six faces, each defined by four vertex indices:

int faces[6][4] = {
    {0,1,2,3},  /* back   (z = -1) */
    {4,5,6,7},  /* front  (z = +1) */
    {0,1,5,4},  /* bottom (y = -1) */
    {2,3,7,6},  /* top    (y = +1) */
    {1,2,6,5},  /* right  (x = +1) */
    {0,3,7,4},  /* left   (x = -1) */
};

Twelve edges connecting the vertices:

int edges[12][2] = {
    {0,1},{1,2},{2,3},{3,0},
    {4,5},{5,6},{6,7},{7,4},
    {0,4},{1,5},{2,6},{3,7},
};

2. Dual-Axis Rotation

Each frame the angle a increments by 0.05 radians. Every vertex is rotated around Y, then X:

double xz =  x * cos(a) - z * sin(a);        /* rotate Y */
double zz =  x * sin(a) + z * cos(a);
double yz =  y * cos(a*0.7) - zz * sin(a*0.7); /* rotate X */
zz         =  y * sin(a*0.7) + zz * cos(a*0.7);

The X-axis rotates at 0.7× the Y-axis speed, producing a non-repeating tumble.


3. Perspective Projection

A virtual camera at Z = 4.0 looks at the origin. The perspective divide maps 3‑D to 2‑D:

double f = 4.0 / (4.0 + zz);        /* perspective factor */
p[i][0] = xz * f * FOV + WIN_W / 2;
p[i][1] = yz * f * FOV + WIN_H / 2;

FOV = 180 scales the projected coordinates to fill the window. Near points (small zz) are magnified; far points are compressed.


4. Painter's Algorithm (Z-Sorting)

Faces are sorted by their average rotated Z coordinate, far to near:

for (int i = 0; i < 6; i++) {
    avg_z[i] = 0;
    for (int j = 0; j < 4; j++)
        avg_z[i] += rz[faces[i][j]];
    avg_z[i] /= 4.0;
}
/* Simple bubble sort — 6 items, negligible cost */

Faces are drawn in sorted order so nearer faces correctly occlude farther ones.


5. Barycentric Triangle Fill

Each quad face is split into two triangles (v0,v1,v2) and (v0,v2,v3), then filled using barycentric coordinates:

static void fill_tri(Uint32 *pixels, int x0, int y0,
                     int x1, int y1, int x2, int y2, Uint32 color)
{
    /* compute bounding box */
    for (each pixel in bounding box) {
        double denom = 1.0 / ((y1-y2)*(x0-x2) + (x2-x1)*(y0-y2));
        double w0 = ((y1-y2)*(x-x2) + (x2-x1)*(y-y2)) * denom;
        double w1 = ((y2-y0)*(x-x2) + (x0-x2)*(y-y2)) * denom;
        double w2 = 1.0 - w0 - w1;
        if (w0 >= -ε && w1 >= -ε && w2 >= -ε)
            row[x] = color;
    }
}

6. Face and Edge Colours

Six faces, six colours:

Face RGB
Back 200, 60, 60
Front 60, 60, 200
Bottom 60, 200, 60
Top 200, 200, 60
Right 60, 200, 200
Left 200, 60, 200

Wireframe edges are drawn in near-white (230, 230, 240) on top of the filled faces, at full per-pixel resolution.


7. Line Rasterisation

Edges use a simple digital line walk:

static void draw_line(Uint32 *pixels, int x0, int y0, int x1, int y1, Uint32 color)
{
    int dx = x1 - x0, dy = y1 - y0;
    int steps = (int)(fmax(abs(dx), abs(dy)));
    for (int i = 0; i <= steps; i++) {
        int x = x0 + dx * i / steps;
        int y = y0 + dy * i / steps;
        if (in bounds) pixels[y * pitch + x] = color;
    }
}

The step count equals the longer axis span so no gaps appear.


8. Frame Timing

A 40 fps cap keeps the tumble smooth:

Uint32 elapsed = SDL_GetTicks() - frame_start;
if (elapsed < 25) SDL_Delay(25 - elapsed);

Build

git clone <this-repo>
cd cube
make

Or manually:

gcc cube.c -o cube -lm $(sdl2-config --cflags --libs)

Dependencies: SDL2 and a C compiler (gcc/clang).

Install SDL2 via Homebrew:

brew install sdl2

Or apt:

sudo apt install libsdl2-dev

Run

./cube

Controls:

  • ESC or Q — quit
  • Ctrl-C — quit (fallback)

Customizing

Edit constants at the top of cube.c:

  • WIN_W, WIN_H — window resolution
  • FOV — projection scale factor
  • Rotation speeds (a += 0.05, X-axis multiplier 0.7)
  • Face colours face_col[] — any RGB triple
  • Edge colour col_edge and background col_bg

Concepts Practiced

  • 3‑D vertex geometry and edge/face topology
  • Dual-axis rotation via 2‑D rotation matrices
  • Perspective projection with homogeneous divide
  • Painter's algorithm for hidden-surface removal
  • Barycentric triangle rasterisation
  • Digital differential analyser (DDA) line drawing
  • SDL2 surface/pixel-buffer graphics
  • Real-time animation with frame-rate capping

Dependencies

  • SDL.h — window management and pixel buffer
  • stdio.h — stderr diagnostics
  • stdlib.hNULL
  • string.hmemset
  • math.hcos, sin, fmin, fmax, fabs
  • signal.hSIGINT handler

About

► Spinning 3D wireframe cube rendered as ASCII in C.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors