aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c151
1 files changed, 139 insertions, 12 deletions
diff --git a/main.c b/main.c
index d5a4773..b25c212 100644
--- a/main.c
+++ b/main.c
@@ -1,7 +1,10 @@
+#include <limits.h>
+#include <float.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
+#include <math.h>
typedef enum {
kRetSucc,
@@ -14,6 +17,17 @@ typedef struct {
float *buffer;
} Picture;
+typedef struct {
+ float r;
+ float g;
+ float b;
+} Color;
+
+typedef struct {
+ int x;
+ int y;
+} Vec2i;
+
Picture new_picture(int width, int height) {
Picture ret;
@@ -27,11 +41,11 @@ void delete_picture(Picture pic) {
free(pic.buffer);
}
-void set_pixel(Picture pic, int x, int y, float r, float g, float b) {
- int idx = y * pic.width * 3 + x * 3;
- pic.buffer[idx] = b;
- pic.buffer[idx+1] = g;
- pic.buffer[idx+2] = r;
+void set_pixel(Picture pic, Vec2i pos, Color c) {
+ int idx = pos.y * pic.width * 3 + pos.x * 3;
+ pic.buffer[idx] = c.b;
+ pic.buffer[idx+1] = c.g;
+ pic.buffer[idx+2] = c.r;
}
Ret fwrite_word16le(FILE* fp, uint16_t x) {
@@ -128,14 +142,127 @@ end:
return ret;
}
+typedef struct {
+ float x;
+ float y;
+ float z;
+} Vec3f;
+
+Vec3f screen_proj(int width, int height, Vec2i sp) {
+ Vec3f ret;
+ float maxlen = width > height ? width : height;
+ ret.z = 1;
+ ret.x = (sp.x - width / 2.0) / maxlen;
+ ret.y = (-sp.y + height / 2.0) / maxlen;
+ return ret;
+}
+
+Color icolor(int r, int g, int b) {
+ return (Color){.r = r/255.0, .g = g/255.0, .b = b/255.0};
+}
+
+typedef struct {
+ Vec3f center;
+ float r;
+ Color color;
+} Ball;
+
+Ball balls[] = {
+ {
+ .center = {.x = 0, .y = -1, .z = 3},
+ .r = 1,
+ },
+ {
+ .center = {.x = 2, .y = 0, .z = 4},
+ .r = 1,
+ },
+ {
+ .center = {.x = -2, .y = 0, .z = 4},
+ .r = 1,
+ },
+};
+
+
+Color gBackgroupColor = {0,0,0};
+
+void init_color() {
+ balls[0].color = icolor(0x95, 0xe1, 0xe3);
+ balls[1].color = icolor(0xfc, 0xe3, 0x8a);
+ balls[2].color = icolor(0xf3, 0x81, 0x81);
+ gBackgroupColor = icolor(0xea, 0xea, 0xea);
+}
+
+Vec3f vec3f_sub(Vec3f lhs, Vec3f rhs) {
+ return (Vec3f){
+ .x = lhs.x - rhs.x,
+ .y = lhs.y - rhs.y,
+ .z = lhs.z - rhs.z,
+ };
+}
+
+float vec3f_dot(Vec3f lhs, Vec3f rhs) {
+ return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
+}
+
+float ball_intersect(Vec3f start, Vec3f ray, Ball *ball) {
+ Vec3f sc = vec3f_sub(start, ball->center);
+ float a = vec3f_dot(ray, ray);
+ float b = 2 * vec3f_dot(sc, ray);
+ float c = vec3f_dot(sc, sc) - ball->r * ball->r;
+ float delta = b*b - 4*a*c;
+ if (delta < 0) {
+ return -1;
+ }
+ float t1 = (-b + sqrt(delta)) / 2*a;
+ float t2 = (-b - sqrt(delta)) / 2*a;
+ return t1 < t2 ? t1 : t2;
+}
+
+Color calc_color(Vec3f v) {
+ Vec3f start = {.x = 0, .y = 0, .z = 0};
+ float tmin = 0.1;
+ float tmax = FLT_MAX;
+
+ int nearest_idx = -1;
+ float t_nearest = FLT_MAX;
+ for (int i = 0; i < sizeof(balls) / sizeof(Ball); i++) {
+ float t = ball_intersect(start, v, &balls[i]);
+ // printf("t:%f\n", t);
+ if (t < t_nearest && t < tmax && t > tmin) {
+ t_nearest = t;
+ nearest_idx = i;
+ }
+ }
+ if (nearest_idx >= 0) {
+ return balls[nearest_idx].color;
+ } else {
+ return gBackgroupColor;
+ }
+}
+
+void normalize_picture(Picture pic) {
+ float maxval = 0;
+ for (size_t i = 0; i < pic.width * pic.height * 3; i++) {
+ float val = pic.buffer[i];
+ if (val < 0) val = 0;
+ if (val > maxval) maxval = val;
+ }
+ if (maxval < 1.0) return;
+ for (size_t i = 0; i < pic.width * pic.height * 3; i++) {
+ pic.buffer[i] = pic.buffer[i] / maxval;
+ }
+}
+
int main() {
- Picture pic = new_picture(1600, 900);
- for (int i = 0; i < 900; i++) {
- for (int j = 0; j < 1600; j++) {
- float r = (i + j) % 177 / 177.0;
- float g = (i + j) % 71 / 71.0;
- float b = (i + j) % 337 / 337.0;
- set_pixel(pic, j, i, r, g, b);
+ init_color();
+ int img_w = 1280;
+ int img_h = 720;
+ Picture pic = new_picture(img_w, img_h);
+ for (int x = 0; x < img_w; x++) {
+ for (int y = 0; y < img_h; y++) {
+ Vec2i screen_pos = {x, y};
+ Vec3f v = screen_proj(img_w, img_h, screen_pos);
+ set_pixel(pic, screen_pos, calc_color(v));
}
}
writeBMP("test.bmp", pic);