Skip to content

Commit

Permalink
Add 3D rotating cube example
Browse files Browse the repository at this point in the history
  • Loading branch information
maximecb committed Apr 23, 2023
1 parent 27cbf79 commit 297bf07
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 2 deletions.
150 changes: 150 additions & 0 deletions ncc/examples/3dcube.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#include <stdio.h>
#include <stdlib.h>
#include <uvm/syscalls.h>
#include <uvm/utils.h>
#include <uvm/3dmath.h>
#include <uvm/graphics.h>

#define FRAME_WIDTH 800
#define FRAME_HEIGHT 600

#define remap(v, a0, a1, b0, b1) (b0 + (b1 - b0) * ((v) - a0) / (a1 - a0))

// RGBA pixels
u32 frame_buffer[FRAME_HEIGHT][FRAME_WIDTH];

// Cube vertices in [-1, 1]
float verts[8][3] = {
{-1.0f, 1.0f, 1.0f },
{ 1.0f, 1.0f, 1.0f },
{ 1.0f,-1.0f, 1.0f },
{-1.0f,-1.0f, 1.0f },
{-1.0f, 1.0f,-1.0f },
{ 1.0f, 1.0f,-1.0f },
{ 1.0f,-1.0f,-1.0f },
{-1.0f,-1.0f,-1.0f },
};

vec3 cube_pos = { 0.0f, 0.0f, -6.0f };

float angle = 0.0f;

// Perspective projection matrix
mat44 persp;

// Translation matrix for the cube
mat44 trans;

// Rotation matrices for the cube
mat44 rotx;
mat44 roty;
mat44 rot;

mat44 m_cube;

vec3 v_tmp;

vec3 v0;
vec3 v1;

// Draw a line between two 3D points
void draw_line3d(vec3 v0, vec3 v1, u32 color)
{
mat44_transform(persp, v0, v_tmp);
int x0 = (int)remap(v_tmp[0], -1.0f, 1.0f, 0.0f, (float)FRAME_WIDTH);
int y0 = (int)remap(v_tmp[1], -1.0f, 1.0f, 0.0f, (float)FRAME_HEIGHT);
//printf("x0=%d, y0=%d\n", x0, y0);

mat44_transform(persp, v1, v_tmp);
int x1 = (int)remap(v_tmp[0], -1.0f, 1.0f, 0.0f, (float)FRAME_WIDTH);
int y1 = (int)remap(v_tmp[1], -1.0f, 1.0f, 0.0f, (float)FRAME_HEIGHT);

// TODO: we should handle coordinates that are outside the screen

draw_line(
(u32*)frame_buffer,
FRAME_WIDTH,
FRAME_HEIGHT,
(u32)x0,
(u32)y0,
(u32)x1,
(u32)y1,
color
);
}

void trans_line3d(mat44 trans, vec3 _v0, vec3 _v1)
{
mat44_transform(trans, _v0, v0);
mat44_transform(trans, _v1, v1);
draw_line3d(v0, v1, COLOR_PURPLE);
}

void anim_callback()
{
u64 start_time = time_current_ms();

// Clear the frame buffer, set all pixels to black
memset32(frame_buffer, 0, 800 * 600);

angle = angle + 0.01f;

mat44_rotx(angle, rotx);
mat44_roty(angle, roty);

mat44_mul(roty, rotx, rot);
mat44_mul(rot, trans, m_cube);

trans_line3d(m_cube, verts[0], verts[1]);
trans_line3d(m_cube, verts[1], verts[2]);
trans_line3d(m_cube, verts[2], verts[3]);
trans_line3d(m_cube, verts[3], verts[0]);

trans_line3d(m_cube, verts[4], verts[5]);
trans_line3d(m_cube, verts[5], verts[6]);
trans_line3d(m_cube, verts[6], verts[7]);
trans_line3d(m_cube, verts[7], verts[4]);

trans_line3d(m_cube, verts[0], verts[4]);
trans_line3d(m_cube, verts[1], verts[5]);
trans_line3d(m_cube, verts[2], verts[6]);
trans_line3d(m_cube, verts[3], verts[7]);

window_draw_frame(0, frame_buffer);

u64 end_time = time_current_ms();
printf("render time: %dms\n", end_time - start_time);

// Schedule a fixed rate update for the next frame (60fps)
fixed_rate_update(start_time, 1000 / 60, anim_callback);
}

void keydown(u64 window_id, u16 keycode)
{
if (keycode == KEY_ESCAPE)
{
exit(0);
}
}

int main()
{
window_create(FRAME_WIDTH, FRAME_HEIGHT, "Rotating 3D Cube Example", 0);
window_on_keydown(0, keydown);
time_delay_cb(0, anim_callback);
enable_event_loop();

// Setup the perspective projection matrix
perspective(
degtorad(40.0f),
(float)FRAME_WIDTH / (float)FRAME_HEIGHT,
0.1f, // near,
100.0f, // far,
persp
);

mat44_translate(cube_pos, trans);


return 0;
}
20 changes: 19 additions & 1 deletion ncc/include/uvm/3dmath.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,25 @@ void mat44_translate(vec3 v, mat44 result)
result[3][2] = v[2];
}

// Matrix for a rotation about the Y axis
// Matrix for a rotation around the X axis
void mat44_rotx(float theta, mat44 result)
{
// Set the matrix to the identity
memcpy(result, MAT44_IDENT, sizeof(mat44));

float cost = cosf(theta);
float sint = sinf(theta);

// Second column
result[1][1] = cost;
result[1][2] = sint;

// Third column
result[2][1] = -sint;
result[2][2] = cost;
}

// Matrix for a rotation around the Y axis
void mat44_roty(float theta, mat44 result)
{
// Set the matrix to the identity
Expand Down
2 changes: 1 addition & 1 deletion ncc/include/uvm/graphics.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#define COLOR_ORANGE 0xFF_FF_A5_00
#define COLOR_YELLOW 0xFF_FF_FF_00
#define COLOR_MAGENTA 0xFF_FF_00_FF
#define COLOR_PURPLE 0xFF_CC_88_99
#define COLOR_PURPLE 0xFF_D6_00_FF
#define COLOR_TURQUOISE 0xFF_40_E0_D0

// Convert RGB values in the range [0, 255] to a u32 encoding
Expand Down

0 comments on commit 297bf07

Please sign in to comment.