Created
July 9, 2011 20:18
-
-
Save anonymous/1073922 to your computer and use it in GitHub Desktop.
donut.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thank you so much!