This repository has been archived by the owner on Oct 30, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cube.c
143 lines (128 loc) · 4.26 KB
/
cube.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <math.h>
#include <stdio.h>
#include <string.h>
#ifndef _WIN32
#include <unistd.h>
#else
#include <windows.h>
void usleep(__int64 usec) {
HANDLE timer;
LARGE_INTEGER ft;
ft.QuadPart = -(10 * usec); // Convert to 100 nanosecond interval, negative
// value indicates relative time
SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
WaitForSingleObject(timer, INFINITE);
CloseHandle(timer);
}
#endif
// To give the 3D depth
int CAM_DISTANCE = 100;
float CUBE_SCALE = 20;
float INCREMENT_SPEED = 0.3;
float rollAngle; // X-axis rotation
float pitchAngle; // Y-axis rotation
float yawAngle; // Z-Axis rotation
float pointX3D, pointY3D, pointZ3D;
int pointX2D, pointY2D;
int pointIndex;
float closeness;
int screenWidth = 80, screenHeight = 22;
float cubeWidth = 20;
float horizontalOffSet;
// Buffer to deal with the depth, to know if something is in front or behind
float zBuffer[80 * 22];
// Buffer to store the current frame
char output[80 * 22];
/**
* See: https://en.wikipedia.org/wiki/Rotation_matrix#Basic_3D_rotations
*/
float calculateRotatedXPoint(int x, int y, int z) {
return y * sin(rollAngle) * sin(pitchAngle) * cos(yawAngle) -
z * cos(rollAngle) * sin(pitchAngle) * cos(yawAngle) +
y * cos(rollAngle) * sin(yawAngle) +
z * sin(rollAngle) * sin(yawAngle) +
x * cos(pitchAngle) * cos(yawAngle);
}
float calculateRotatedYPoint(int x, int y, int z) {
return y * cos(rollAngle) * cos(yawAngle) +
z * sin(rollAngle) * cos(yawAngle) -
y * sin(rollAngle) * sin(pitchAngle) * sin(yawAngle) +
z * cos(rollAngle) * sin(pitchAngle) * sin(yawAngle) -
x * cos(pitchAngle) * sin(yawAngle);
}
float calculateRotatedZPoint(int x, int y, int z) {
return z * cos(rollAngle) * cos(pitchAngle) -
y * sin(rollAngle) * cos(pitchAngle) + x * sin(pitchAngle);
}
/**
* Receives the x, y, z points in the 3D space, converts it to 2d
* and add to the buffer.
*/
void computeAndDrawPixel(float x, float y, float z, char ch) {
pointX3D = calculateRotatedXPoint(x, y, z);
pointY3D = calculateRotatedYPoint(x, y, z);
pointZ3D = calculateRotatedZPoint(x, y, z) + CAM_DISTANCE;
/**
* I'm calling "closeness" because it's easier for me to understand it,
* in reality is the depth of the pixel and bigger == closer.
*/
closeness = 1 / pointZ3D;
/**
* Projecting 3D points onto 2d space
* See: https://en.wikipedia.org/wiki/3D_projection#Diagram
*/
pointX2D = (int)(screenWidth / 2 + horizontalOffSet +
pointX3D * closeness * CUBE_SCALE * 2);
pointY2D = (int)(screenHeight / 2 + pointY3D * closeness * CUBE_SCALE);
/**
* Needed to multiplicate by the width because
* i'm using a 1-D array (which len = width * height) as a buffer
*/
pointIndex = pointX2D + pointY2D * screenWidth;
/**
* When the "closeness" of a pixel is bigger, it will replace the one that
* already is there. This is what z-buffer is about.
* See: https://www.geeksforgeeks.org/z-buffer-depth-buffer-method/
*/
if (pointIndex >= 0 && pointIndex < screenWidth * screenHeight) {
if (closeness > zBuffer[pointIndex]) {
zBuffer[pointIndex] = closeness;
output[pointIndex] = ch;
}
}
}
int main() {
// Clear terminal and escape
printf("\x1b[2J");
while (1) {
memset(output, ' ', screenWidth * screenHeight);
memset(zBuffer, 0, screenWidth * screenHeight * 4);
cubeWidth = 20;
horizontalOffSet = -cubeWidth;
for (float x = -cubeWidth; x < cubeWidth; x += INCREMENT_SPEED) {
for (float y = -cubeWidth; y < cubeWidth; y += INCREMENT_SPEED) {
// Front
computeAndDrawPixel(x, y, -cubeWidth, '@');
// Back Face
computeAndDrawPixel(-x, y, cubeWidth, '#');
// Left Face
computeAndDrawPixel(-cubeWidth, y, -x, '~');
// Right Face
computeAndDrawPixel(cubeWidth, y, x, '$');
// Top Face
computeAndDrawPixel(x, -cubeWidth, -y, ';');
// Bottom face
computeAndDrawPixel(x, cubeWidth, y, '+');
}
}
printf("\x1b[H");
for (int i = 0; i < screenWidth * screenHeight; i++) {
putchar(i % screenWidth ? output[i] : 10);
}
rollAngle += 0.05;
pitchAngle += 0.05;
yawAngle += 0.01;
usleep(3000);
}
return 0;
}