diff --git a/Makefile b/Makefile index f77cad8..4b35150 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ test2: bin/back test3: bin/back bin/back templates_lv3.txt 33 -bin/back: obj/main.o obj/generation.o obj/display.o obj/base.o obj/hash.o obj/move.o +bin/back: obj/main.o obj/generation.o obj/display.o obj/base.o obj/hash.o obj/move.o obj/threed.o mkdir -p bin $(CC) $(FLAGS) $^ $(LFLAGS) -o $@ @@ -30,6 +30,7 @@ obj/display.o: src/display.c obj/base.o: src/base.c obj/hash.o: src/hash.c obj/move.o: src/move.c +obj/threed.o: src/threed.c .PHONY: clean mrproper diff --git a/bin/back b/bin/back index 594527e..abf8e86 100755 Binary files a/bin/back and b/bin/back differ diff --git a/obj/base.o b/obj/base.o new file mode 100644 index 0000000..44784a8 Binary files /dev/null and b/obj/base.o differ diff --git a/obj/display.o b/obj/display.o new file mode 100644 index 0000000..98b1f40 Binary files /dev/null and b/obj/display.o differ diff --git a/obj/generation.o b/obj/generation.o new file mode 100644 index 0000000..6386bf0 Binary files /dev/null and b/obj/generation.o differ diff --git a/obj/hash.o b/obj/hash.o new file mode 100644 index 0000000..4633f4e Binary files /dev/null and b/obj/hash.o differ diff --git a/obj/main.o b/obj/main.o new file mode 100644 index 0000000..e7b4d2d Binary files /dev/null and b/obj/main.o differ diff --git a/obj/move.o b/obj/move.o new file mode 100644 index 0000000..61c6ad8 Binary files /dev/null and b/obj/move.o differ diff --git a/obj/threed.o b/obj/threed.o new file mode 100644 index 0000000..4760302 Binary files /dev/null and b/obj/threed.o differ diff --git a/src/base.c b/src/base.c index aba5b62..34a5e9a 100644 --- a/src/base.c +++ b/src/base.c @@ -68,6 +68,18 @@ int convex_seg(int x1, int x2, double theta) { return (int)(((1.0f - theta) * x1 + theta * x2)); } +double convex_seg_double(double x1, double x2, double theta) { + return ((1.0f - theta) * x1 + theta * x2); +} + +pt_3d convex_3d(pt_3d p1, pt_3d p2, double theta) { + pt_3d res ; + res.x = convex_seg_double(p1.x, p2.x, theta); + res.y = convex_seg_double(p1.y, p2.z, theta); + res.z = convex_seg_double(p1.z, p2.z, theta); + return res ; +} + bool is_an_integer(char c) { return ((int)c >= 48 && (int)c <= 57); } @@ -84,6 +96,11 @@ double distance_pt(int x1, int x2, int y1, int y2) { return sqrt(to_double(pw(x2 - x1, 2) + pw(y2 - y1, 2))); } + +double distance_pt_double(double x1, double x2, double y1, double y2) { + return sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); +} + int line_count(char* filename) { FILE* ptr = fopen(filename, "r"); char c = 'd'; diff --git a/src/base.h b/src/base.h index c693eb7..bf4db1b 100644 --- a/src/base.h +++ b/src/base.h @@ -15,6 +15,10 @@ double absf(double n); int convex_seg(int x1, int x2, double theta); +double convex_seg_double(double x1, double x2, double theta); + +pt_3d convex_3d(pt_3d p1, pt_3d p2, double theta); + bool is_an_integer(char c); double to_double(int n); @@ -23,6 +27,8 @@ int to_int(double n); double distance_pt(int x1, int x2, int y1, int y2); +double distance_pt_double(double x1, double x2, double y1, double y2); + int line_count(char* filename); int str_to_int(char* s); diff --git a/src/display.c b/src/display.c index ff17c0c..bfc6754 100644 --- a/src/display.c +++ b/src/display.c @@ -15,6 +15,7 @@ #include "structure.h" #include "base.h" #include "generation.h" +#include "threed.h" #include "display.h" void updateRenderer(SDL_Renderer* renderer) { diff --git a/src/main.c b/src/main.c index 98bedf3..b20633e 100644 --- a/src/main.c +++ b/src/main.c @@ -16,6 +16,7 @@ #include "base.h" #include "display.h" #include "generation.h" +#include "threed.h" #include "move.h" int main(int argc, char** argv) { @@ -55,6 +56,8 @@ int main(int argc, char** argv) { parse_configs(filename, length); initialize(rend); + init_3d(); + init_sincos(); int temp = render_distance ; for(int i = 1; i <= temp; i++) { @@ -63,9 +66,29 @@ int main(int argc, char** argv) { drawMapToRenderer(rend, -300 * 250/zoom + to_int(50 * (8*player_cx + player_x + εx)), 300 * 250/zoom + to_int(50 * (8*player_cx + player_x + εx)), -300 * 250/zoom + to_int(50 * (8*player_cy + player_y + εy)), 300 * 250/zoom + to_int(50 * (8*player_cy + player_y + εy))); }; - moveFunctionMaster(rend); + printf("entering\n"); + + pt_3d p1 ; + pt_3d p2 ; + pt_3d p3 ; + pt_3d p4 ; + + p1.x = 0.0 ; p1.y = 0.0 ; p1.z = 1.0 ; + p2.x = 12.0 ; p2.y = 0.0 ; p2.z = 1.0 ; + p3.x = 12.0 ; p3.y = 8.0 ; p3.z = 1.0 ; + p4.x = 0.0 ; p4.y = 8.0 ; p4.z = 1.0 ; + + project_rectangle(p1, p2, p3, p4); + bufferUpdateRenderer(rend); + + printf("pass\n"); + usleep(3000000); + + //moveFunctionMaster(rend); destroy(); + destroy_3d(); + destroy_sincos(); /* -------------------------------------------------------- */ diff --git a/src/structure.h b/src/structure.h index b33afd8..a5576a0 100644 --- a/src/structure.h +++ b/src/structure.h @@ -11,6 +11,18 @@ typedef struct array { int len ; } array ; +typedef struct pt_3d { + double x; + double y; + double z; +} pt_3d ; + +typedef struct pt_3d_int { + int x; + int y; + double z; +} pt_3d_int ; + typedef enum cardinal {NORTH, EAST, SOUTH, WEST} cardinal ; extern Grid map ; @@ -47,4 +59,17 @@ extern imgs letters ; extern template full ; +extern double** screen_zbuffer ; +extern uint8_t** screen_red ; +extern uint8_t** screen_green ; +extern uint8_t** screen_blue ; + +extern double three_render_distance ; +extern int three_angle ; + +extern double* cosinuses ; +extern double* sinuses ; + +extern double ar ; + #endif \ No newline at end of file diff --git a/src/threed.c b/src/threed.c new file mode 100644 index 0000000..eec0abe --- /dev/null +++ b/src/threed.c @@ -0,0 +1,442 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hash.h" +#include "structure.h" +#include "base.h" +#include "generation.h" // initialize constants +#include "display.h" +#include "threed.h" + +// ----------------------------------------------- // + +double** screen_zbuffer ; +uint8_t** screen_red ; +uint8_t** screen_green ; +uint8_t** screen_blue ; + +double three_render_distance = 20.0 ; +int three_angle = 0 ; + +double* cosinuses ; +double* sinuses ; + +static pt_3d* polygon_b ; +static int poly_length ; + +static double epsilon = 0.75; + +static pt_3d* projected ; +static pt_3d* projected2 ; +static int pt_count ; + +static double draw_const ; + +static double tfov ; + +double ar ; + +// ----------------------------------------------- // + +void init_3d() { + printf("initializing 3d matrixes... "); + screen_zbuffer = malloc(sizeof(double*) * __width__); + screen_red = malloc(sizeof(uint8_t*) * __width__); + screen_green = malloc(sizeof(uint8_t*) * __width__); + screen_blue = malloc(sizeof(uint8_t*) * __width__); + + for(int i = 0; i < __width__; i++) { + screen_zbuffer[i] = malloc(sizeof(double) * __height__); + screen_red[i] = malloc(sizeof(uint8_t) * __height__); + screen_green[i] = malloc(sizeof(uint8_t) * __height__); + screen_blue[i] = malloc(sizeof(uint8_t) * __height__); + + for(int j = 0; j < __height__; j++) { + screen_zbuffer[i][j] = three_render_distance ; + screen_red[i][j] = 0 ; + screen_green[i][j] = 0 ; + screen_blue[i][j] = 0 ; + } + }; + polygon_b = malloc(sizeof(pt_3d)*20); + poly_length = 0 ; + + projected = malloc(sizeof(pt_3d)*12); + projected2 = malloc(sizeof(pt_3d)*12); + pt_count = 0 ; + + ar = ((double)__height__) / ((double)__width__); + + tfov = tan((75.0 * 3.14159265358 / 180.0) / 2.0) ; + + draw_const = 1.0 ; + + printf("done\n"); +} + +void init_sincos() { + cosinuses = malloc(sizeof(double)*360); + sinuses = malloc(sizeof(double)*360); + for(int i = 0; i < 360; i++) { + cosinuses[i] = cos(((double)i) * 3.14159265358 / 180.0); + sinuses[i] = sin(((double)i) * 3.14159265358 / 180.0); + } +} + +int cropx(int x) { + return max(min(__width__-1, x), 0) ; +} + +int cropy(int y) { + return max(min(__height__-1, y), 0) ; +} + +void placeRectToBuffer(int x, int y, double z, int width, int height, int R, int G, int B) { + for(int w = 0; w < width; w++) { + for(int h = 0; h < height; h++) { + if(z >= 0 && z < screen_zbuffer[cropx(x+w)][cropy(y+h)] && cropx(x+w) == x+w && cropy(y+h) == y+h) { + //printf("(%d, %d)\n", x+w, y+h); + screen_zbuffer[cropx(x+w)][cropy(y+h)] = z ; + screen_red[cropx(x+w)][cropy(y+h)] = R ; + screen_green[cropx(x+w)][cropy(y+h)] = G ; + screen_blue[cropx(x+w)][cropy(y+h)] = B ; + } + } + } +} + +void drawLineWithThiccToBuffer(int width, double x1, double x2, int y1, int y2, int z1, int z2, int R, int G, int B) { + // draw projected 3D line to buffer + double theta = 0.0; + double seglen = distance_pt(z1, z2, y1, y2); + while(theta < 1.0) { + placeRectToBuffer(convex_seg(z1, z2, theta)-width/2, convex_seg(y1, y2, theta)-width/2, convex_seg_double(x1, x2, theta), width, width, R, G, B); + theta += 1 / seglen; + } +} + +double get_zdepth_on_edge(int py, int pz) { + for(int i = 0; i < poly_length; i++) { + //[ Ax * (By - Cy) + Bx * (Cy - Ay) + Cx * (Ay - By) ] + if((double)py * (polygon_b[i].z - polygon_b[(i+1)%poly_length].z) + polygon_b[i].y * (polygon_b[(i+1)%poly_length].z - (double)pz) + polygon_b[(i+1)%poly_length].y * ((double)pz - polygon_b[i].z) < epsilon) { + return convex_seg_double(polygon_b[i].x, polygon_b[(i+1)%poly_length].x, (pz - polygon_b[i].z)/(polygon_b[(i+1)%poly_length].z - polygon_b[i].z)); + } + } + fprintf(stderr, "ERROR : point is nowhere near an edge of the polygon\n"); + exit(1); +} + +int getLeftMost() { + double my = polygon_b[0].y ; + int mi = 0 ; + for(int i = 1; i < pt_count; i++) { + if(my > polygon_b[i].y) { + my = polygon_b[i].y ; + mi = i ; + } + } + return mi ; +} + +int getRightMost() { + double my = polygon_b[0].y ; + int mi = 0 ; + for(int i = 1; i < pt_count; i++) { + if(my < polygon_b[i].y) { + my = polygon_b[i].y ; + mi = i ; + } + } + return mi ; +} + +bool is_in_convex(int px, int py) { + double previous = 0.0 ; + for(int i = 0; i < poly_length; i++) { + double nw = (polygon_b[(i+1)%poly_length].y - polygon_b[i].y) * ((double)py - polygon_b[i].z) - ((double)px - polygon_b[i].y) * (polygon_b[(i+1)%poly_length].z - polygon_b[i].z); + //(x2 - x1) * (yp - y1) - (xp - x1) * (y2 - y1) + if(nw * previous < 0.0) { + return false ; + } else { + previous = nw ; + } + } + return true ; +} + +void drawPolygonToBuffer(int count, ...) { + // takes a 'list' of pt_3d and draws the coresponding polygon to renderer + // /!\ : this draws PROJECTED polygons + if(count > 20) { + fprintf(stderr, "ERROR : polygon has too many vertexes (%d)\n", count); + exit(1); + } else if(count >= 3) { + poly_length = count ; + + va_list list; + va_start(list, count); + for(int j = 0; j < count; j++) { + polygon_b[j] = va_arg(list, pt_3d); + } + va_end(list); + + /*int pmin = getLeftMost() ; + int pmax = getRightMost() ; + + printf("(%d -> %d)\n", pmin, pmax);*/ + + for(int i = 0; i < poly_length; i++) { + drawLineWithThiccToBuffer(4, polygon_b[i].x, polygon_b[(i+1)%poly_length].x, (int)polygon_b[i].y, (int)polygon_b[(i+1)%poly_length].y, (int)polygon_b[i].z, (int)polygon_b[(i+1)%poly_length].z, 255, 255, 255); + } + } +} + +pt_3d adjust(pt_3d p) { + pt_3d res; + res.x = p.x - (player_cx * 8 + player_x + εx) ; + res.y = p.y - (player_cy * 8 + player_y + εy) ; + res.z = p.z - 1.8 ; // height of player + + res.x = res.y * sinuses[three_angle] + res.x * cosinuses[three_angle]; + res.y = (p.y - (player_cy * 8 + player_y + εy)) * cosinuses[three_angle] + res.x * sinuses[three_angle] ; + + return res; +} + +/* +let reduce xmin xmax ymin ymax segx segy (dx : int) (dy : int) = + (* + line crossing rectangles + *) + + let ps = [|-dx; dx; -dy; dy|] in + let qs = [|segx - xmin; xmax - segx; segy - ymin; ymax - segy|] in + let ts = [|None; None; None; None|] in + for k = 0 to 3 do + if ps.(k) <> 0 then + ts.(k) <- Some ((float_of_int qs.(k)) /. (float_of_int ps.(k))) + done ; + + let u1 = ref (-. 1. /. 0.) + and u2 = ref (1. /. 0.) in + + for k = 0 to 3 do + if ps.(k) < 0 then + opt_max ts.(k) u1 + else if ps.(k) > 0 then + opt_min ts.(k) u2 + done ; + + if 0. < !u1 && !u1 < 1. then + (segx + int_of_float (!u1 *. float_of_int dx), segy + int_of_float (!u1 *. float_of_int dy)) + else if 0. < !u2 && !u2 < 1. then + (segx + int_of_float (!u2 *. float_of_int dx), segy + int_of_float (!u2 *. float_of_int dy)) + else + (segx + dx, segy + dy) ;; +*/ + +void opt_max(double *ts_k, double *u1) { + if (ts_k && *ts_k > *u1) { + *u1 = *ts_k; + } +} + +void opt_min(double *ts_k, double *u2) { + if (ts_k && *ts_k < *u2) { + *u2 = *ts_k; + } +} + +void reduce(int xmin, int xmax, int ymin, int ymax, int segx, int segy, int dx, int dy, double *result_x, double *result_y, double *result_x2, double *result_y2) { + int ps[4] = {-dx, dx, -dy, dy}; + int qs[4] = {segx - xmin, xmax - segx, segy - ymin, ymax - segy}; + double ts[4] = {DBL_MAX, DBL_MAX, DBL_MAX, DBL_MAX}; // Initialize to some large value + + for (int k = 0; k < 4; k++) { + if (ps[k] != 0) { + ts[k] = (double)qs[k] / (double)ps[k]; + } + } + + double u1 = -DBL_MAX; + double u2 = DBL_MAX; + + for (int k = 0; k < 4; k++) { + if (ps[k] < 0) { + opt_max(&ts[k], &u1); + } else if (ps[k] > 0) { + opt_min(&ts[k], &u2); + } + } + + if (0.0 < u1 && u1 < 1.0) { + *result_x = (double)segx + (u1 * dx); + *result_y = (double)segy + (u1 * dy); + } else if (0.0 < u2 && u2 < 1.0) { + *result_x2 = (double)segx + (u2 * dx); + *result_y2 = (double)segy + (u2 * dy); + } else if (0.0 < u1 && u1 < u2 && u2 < 1.0) { + *result_x = (double)segx + (u1 * dx); + *result_y = (double)segy + (u1 * dy); + *result_x2 = (double)segx + (u2 * dx); + *result_y2 = (double)segy + (u2 * dy); + } else { + // nah + } +} + +void project_front(pt_3d p) { + double ppy = p.y / (p.x * tfov) ; + double ppz = p.z / (ar * p.x * tfov) ; + projected[pt_count].x = p.x ; + projected[pt_count].y = (__height__ * (1.0 + ppy) / 2); + projected[pt_count].z = (__width__ * (1.0 + ppz) / 2); + pt_count += 1; +} + +void project_back(pt_3d p) { + double ppy = p.y / (draw_const * tfov) ; + double ppz = p.z / (ar * draw_const * tfov) ; + projected[pt_count].x = p.x ; + projected[pt_count].y = (__height__ * (1.0 + ppy) / 2); + projected[pt_count].z = (__width__ * (1.0 + ppz) / 2); + pt_count += 1; +} + +void project_seg(pt_3d p1, pt_3d p2, bool first) { + if(p1.x >= draw_const && p2.x >= draw_const) { + printf("+/+\n"); + project_front(p1); + if(first) { + project_front(p2); + } + } else if(p1.x >= draw_const) { + printf("+/-\n"); + project_front(p1); + project_front(convex_3d(p1, p2, (draw_const - p1.x)/(p2.x - p1.x))); + if(first) { + project_back(p2); + } + } else if(p2.x >= draw_const) { + printf("-/+\n"); + project_back(p1); + project_front(convex_3d(p2, p1, (draw_const - p2.x)/(p1.x - p2.x))); + if(first) { + project_front(p2); + } + } else { + printf("-/-\n"); + // else do nothing + } +} + +void project_and_render(pt_3d p1, pt_3d p2, pt_3d p3, pt_3d p4) { + pt_count = 0 ; + + printf("rect :\n"); + printf("%lf, %lf, %lf\n", p1.x, p1.y, p1.z); + printf("%lf, %lf, %lf\n", p2.x, p2.y, p2.z); + printf("%lf, %lf, %lf\n", p3.x, p3.y, p3.z); + printf("%lf, %lf, %lf\n\n", p4.x, p4.y, p4.z); + + printf("(%lf)\n", ar); + + project_seg(p1, p2, true); + project_seg(p2, p3, true); + project_seg(p3, p4, true); + project_seg(p4, p1, true); + + printf("C : %d\n\n", pt_count); + for(int i = 0; i < pt_count; i++) { + printf("pt %d : (%lf, %lf, %lf)\n", i, projected[i].x, projected[i].y, projected[i].z); + projected2[i] = projected[i] ; + reduce(0, __width__, 0, __height__, (int)projected[i].y, (int)projected[i].z, (int)(projected[(i+1)%pt_count].y - projected[i].y), (int)(projected[(i+1)%pt_count].z - projected[i].z), &(projected2[i].y), &(projected2[i].z), &(projected2[(i+1)%pt_count].y), &(projected2[(i+1)%pt_count].z)); + } + printf("\n"); + for(int i = 0; i < pt_count; i++) { + printf("pt %d+ : (%lf, %lf, %lf)\n", i, projected2[i].x, projected2[i].y, projected2[i].z); + } + + if(pt_count == 2) { + drawPolygonToBuffer(2, projected2[0], projected2[1]); + } else if(pt_count == 3) { + drawPolygonToBuffer(3, projected2[0], projected2[1], projected2[2]); + } else if(pt_count == 4) { + drawPolygonToBuffer(4, projected2[0], projected2[1], projected2[2], projected2[3]); + } else if(pt_count == 5) { + drawPolygonToBuffer(5, projected2[0], projected2[1], projected2[2], projected2[3], projected2[4]); + } else if(pt_count == 6) { + drawPolygonToBuffer(6, projected2[0], projected2[1], projected2[2], projected2[3], projected2[4], projected2[5]); + } else if(pt_count == 7) { + drawPolygonToBuffer(7, projected2[0], projected2[1], projected2[2], projected2[3], projected2[4], projected2[5], projected2[6]); + } else if(pt_count == 8) { + drawPolygonToBuffer(8, projected2[0], projected2[1], projected2[2], projected2[3], projected2[4], projected2[5], projected2[6], projected2[7]); + } else if(pt_count == 9) { + drawPolygonToBuffer(9, projected2[0], projected2[1], projected2[2], projected2[3], projected2[4], projected2[5], projected2[6], projected2[7], projected2[8]); + } +} + +void project_rectangle(pt_3d p1, pt_3d p2, pt_3d p3, pt_3d p4) { + printf("rawRect :\n"); + printf("%lf, %lf, %lf\n", p1.x, p1.y, p1.z); + printf("%lf, %lf, %lf\n", p2.x, p2.y, p2.z); + printf("%lf, %lf, %lf\n", p3.x, p3.y, p3.z); + printf("%lf, %lf, %lf\n\n", p4.x, p4.y, p4.z); + + project_and_render(adjust(p1), adjust(p2), adjust(p3), adjust(p4)); +} + +void resetBuffer() { + for(int i = 0; i < __width__; i++) { + for(int j = 0; j < __height__; j++) { + screen_blue[i][j] = 0 ; + screen_red[i][j] = 0 ; + screen_green[i][j] = 0 ; + screen_zbuffer[i][j] = three_render_distance ; + } + } +} + +void bufferUpdateRenderer(SDL_Renderer* renderer) { + resetRenderer(renderer); + for(int i = 0; i < __height__; i++) { + for(int j = 0; j < __width__; j++) { + SDL_SetRenderDrawColor(renderer, screen_red[i][j], screen_green[i][j], screen_blue[i][j], SDL_ALPHA_OPAQUE); + SDL_RenderDrawPoint(renderer, j, __height__ - i); + } + } + updateRenderer(renderer); +} + +void destroy_3d() { + for(int i = 0; i < __width__; i++) { + free(screen_zbuffer[i]); + free(screen_red[i]); + free(screen_green[i]); + free(screen_blue[i]); + }; + free(screen_zbuffer); + free(screen_red); + free(screen_green); + free(screen_blue); + + free(polygon_b); +} + +void destroy_sincos() { + free(cosinuses); + free(sinuses); + free(projected); + free(projected2); +} \ No newline at end of file diff --git a/src/threed.h b/src/threed.h new file mode 100644 index 0000000..c2dca38 --- /dev/null +++ b/src/threed.h @@ -0,0 +1,42 @@ +#ifndef BACK_3D_H +#define BACK_3D_H + +void init_3d(); + +void init_sincos(); + +void placeRectToBuffer(int x, int y, double z, int width, int height, int R, int G, int B); + +void drawLineWithThiccToBuffer(int width, double x1, double x2, int y1, int y2, int z1, int z2, int R, int G, int B); + +bool is_in_convex(int px, int py); + +void drawPolygonToBuffer(int count, ...); + +pt_3d adjust(pt_3d p); + +void opt_max(double *ts_k, double *u1); + +void opt_min(double *ts_k, double *u2); + +void reduce(int xmin, int xmax, int ymin, int ymax, int segx, int segy, int dx, int dy, double *result_x, double *result_y, double *result_x2, double *result_y2); + +void project_front(pt_3d p); + +void project_back(pt_3d p); + +void project_seg(pt_3d p1, pt_3d p2, bool first) ; + +void project_and_render(pt_3d p1, pt_3d p2, pt_3d p3, pt_3d p4); + +void project_rectangle(pt_3d p1, pt_3d p2, pt_3d p3, pt_3d p4); + +void resetBuffer(); + +void bufferUpdateRenderer(SDL_Renderer* renderer); + +void destroy_3d(); + +void destroy_sincos(); + +#endif \ No newline at end of file