Skip to content

Instantly share code, notes, and snippets.

Created July 9, 2011 20:18
Show Gist options
  • Save anonymous/1073922 to your computer and use it in GitHub Desktop.
Save anonymous/1073922 to your computer and use it in GitHub Desktop.
donut.c
#include <math.h>
#include <stdio.h>
#include <string.h>
// buffer constraints
#define BUFFER_WIDTH 80
#define BUFFER_HEIGHT 22
#define BUFFER_SIZE (BUFFER_WIDTH*BUFFER_HEIGHT)
#define IMAGE_SCALE 15
#define TWO_PI 6.28
// rotation increment around each axis
#define DELTA_A 0.04
#define DELTA_B 0.02
// donut point traversal increment (inverse of density)
#define DELTA_J 0.07
#define DELTA_I 0.02
// blit the provided pixel buffer to the screen
void blit_buffer(char pixel_buffer[]) {
int buffer_pos;
// put cursor at home position
printf("\x1b[H");
// for every char in the buffer
for (buffer_pos = 0; buffer_pos < 1+BUFFER_SIZE; buffer_pos++) {
// newline if necessary
if (buffer_pos % BUFFER_WIDTH == 0) {
putchar('\n');
}
else {
putchar(pixel_buffer[buffer_pos]);
}
}
}
// return a char that represents the provided floating point intensity.
// assumption: 0 < intensity < 1.5
char intensity_char(float intensity) {
char gradient[] = ".,-~:;=!*#$@";
int gradient_position = 12 * (intensity / 1.5);
if (0 < gradient_position && gradient_position < 12) {
return gradient[gradient_position];
}
return gradient[0];
}
void main() {
float A = 0; // rotation around one axis (radians)
float B = 0; // rotation around other axis (radians)
float i;
float j;
float z_buffer[BUFFER_SIZE];
char pixel_buffer[BUFFER_SIZE];
// clear the screen
printf("\x1b[2J");
for (;;) {
// reset the pixel and z buffers
memset(pixel_buffer, 32, BUFFER_SIZE);
memset(z_buffer, 0, sizeof(float) * BUFFER_SIZE);
float sin_A = sin(A);
float cos_A = cos(A);
float cos_B = cos(B);
float sin_B = sin(B);
// for every point on the surface of the donut
for (j = 0; j < TWO_PI; j += DELTA_J) {
float cos_j = cos(j);
float sin_j = sin(j);
for (i = 0; i < TWO_PI; i += DELTA_I) {
float sin_i = sin(i);
float cos_i = cos(i);
float h = cos_j + 2;
float D = 1 / (sin_i * h * sin_A + sin_j * cos_A + 5);
float t = sin_i * h * cos_A - sin_j * sin_A;
// project onto buffer surface point (x,y)
int x = (BUFFER_WIDTH/2) + 2*IMAGE_SCALE * D * (cos_i * h * cos_B - t * sin_B);
int y = (BUFFER_HEIGHT/2) + IMAGE_SCALE * D * (cos_i * h * sin_B + t * cos_B);
// only consider points that occur on the defined surface
if (0 < x && x < BUFFER_WIDTH && 0 < y && y < BUFFER_HEIGHT) {
// calculate position on linear buffer
int buffer_pos = (BUFFER_WIDTH * y) + x;
// if this point is closer to the viewer than previous point at this position, overwrite it
if (D > z_buffer[buffer_pos]) {
z_buffer[buffer_pos] = D;
// calculate intensity of this point
float intensity = (cos_B * (sin_j * sin_A - sin_i * cos_j * cos_A)
- sin_i * cos_j * sin_A - sin_j * cos_A
- cos_i * cos_j * sin_B);
// write the intensity to the buffer
pixel_buffer[buffer_pos] = intensity_char(intensity);
}
}
}
}
blit_buffer(pixel_buffer);
A += DELTA_A;
B += DELTA_B;
}
}
@javid-aliyev
Copy link

thank you so much!

@Ppang0405
Copy link

Thank you so much too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment