#include #include /* #include */ #include "draw.h" #include "sim.h" /*#define SHADOW*/ #define TRIANGLELINES #define MAXTRIANGLE 2048 #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define INTTOCOL(C) (C>>16), ((C>>8)%256), (C%256) #define P(a,b,c) ((Point){a, b, c}) const int shadowcol = 0x191919ff; int w, h; SDL_Point *pts_queue; int pts_queue_cnt; float *pts_depth; Triangle tgs[MAXTRIANGLE]; int tgs_cnt; typedef struct { int x, y; } Point2d; void add_triangle(Point, Point, Point, unsigned int); void add_obj(const char *path, Point off) { char s[1024]; FILE *f; /* CAP of 1024 vertecies */ Point v[1024]; Point t[3]; int pc = 0; int a, b, c; float mult = 1; unsigned int col; if ((f = fopen(path, "r")) == NULL) { printf("%s:%d add_obj(...): Error opening file %s\n", __FILE__, __LINE__, path); return; } while (fgets(s, 1024, f) != NULL) { switch (s[0]) { case 'M': sscanf(s, "%*c %f", &mult); break; case 'v': sscanf(s, "%*c %f%f%f", &v[pc].x, &v[pc].y, &v[pc].z); v[pc].x = v[pc].x * mult + off.x; v[pc].y = v[pc].y * mult + off.y; v[pc].z = v[pc].z * mult + off.z; ++pc; break; case 'f': sscanf(s, "%*c %d%d%d", &a, &b, &c); add_triangle(v[a-1], v[b-1], v[c-1], 0x808080ff); t[0] = v[a-1]; t[0].y = 0; t[1] = v[b-1]; t[1].y = 0; t[2] = v[c-1]; t[2].y = 0; #ifdef SHADOW add_triangle(t[0], t[1], t[2], shadowcol); #endif break; case 'F': sscanf(s, "%*c %d%d%d%x", &a, &b, &c, &col); add_triangle(v[a-1], v[b-1], v[c-1], col); t[0] = v[a-1]; t[0].y = 0; t[1] = v[b-1]; t[1].y = 0; t[2] = v[c-1]; t[2].y = 0; #ifdef SHADOW add_triangle(t[0], t[1], t[2], shadowcol); #endif break; } } fclose(f); } void add_obj_interactive() { char path[1024]; int i; Point offset; printf("PATH: "); fflush(stdout); do fgets(path, 1024, stdin); while (path[0] == '\n'); printf("OFFSET X Y Z: "); fflush(stdout); scanf("%f%f%f", &offset.x, &offset.y, &offset.z); for (i = 0; i < 1024; ++i) if (path[i] == '\n') path[i] = '\0'; add_obj(path, offset); } void redo_obj() { tgs_cnt = 0; add_obj("obj/car.obj", P(0,0,0)); } void make_point_relative(Point *a) { double x, y, z; double b, c; x = a->x - cam.pos.x; y = a->y - cam.pos.y; z = a->z - cam.pos.z; b = cos(cam.rad) * x + sin(cam.rad) * z; c = cos(cam.rad) * z - sin(cam.rad) * x; x = b; z = c; b = cos(cam.azim) * x + sin(cam.azim) * y; c = cos(cam.azim) * y - sin(cam.azim) * x; x = b; y = c; a->x = x; a->y = y; a->z = z; } Point2d get_point(Point a) { Point2d r; if (a.x > 0) { if (a.x < 0.01) a.x = 0.01; } else if (a.x > -0.01) a.x = -0.01; r.x = ((float) w) * a.z / (a.x * 2.0 * hfov); r.x += w/2; r.y = ((float) h) * a.y / (a.x * 2.0 * vfov); r.y = h/2 - r.y; return r; } int det(Point2d a, Point2d b, Point2d c) { /* TODO Better */ int d = 0; int L = 3200; d = MAX(-L, MIN(L, a.x)) * MAX(-L, MIN(L, b.y - c.y)); d += MAX(-L, MIN(L, a.y)) * MAX(-L, MIN(L, c.x - b.x)); d += MAX(-L, MIN(L, b.x)) * MAX(-L, MIN(L, c.y)); d -= MAX(-L, MIN(L, b.y)) * MAX(-L, MIN(L, c.x)); return a.x * (b.y - c.y) - a.y * (b.x - c.x) + b.x * c.y - b.y * c.x; } void draw_point2d(Point2d a, int d) { SDL_Rect r; if (a.x < 0 || a.x > w) return; if (a.y < 0 || a.y > h) return; r.x = a.x - d; r.y = a.y - d; r.w = 2 * d + 1; r.h = 2 * d + 1; /* SDL_RenderDrawPoint(ren, a.x, a.y);*/ SDL_RenderFillRect(ren, &r); } float getdep(Point a, Point b, Point c, Point d) { Point cp; float r; b.x -= a.x; c.x -= a.x; b.y -= a.y; c.y -= a.y; b.z -= a.z; c.z -= a.z; b.z = -b.z; a.z = -a.z; c.z = -c.z; d.z = -d.z; cp.x = - ( - b.y * c.z + b.z * c.y ); cp.y = - ( - b.z * c.x + b.x * c.z ); cp.z = - ( - b.x * c.y + b.y * c.x ); r = cp.x * a.x + cp.y * a.y + cp.z * a.z; r = r / (cp.x * d.x + cp.y * d.y + cp.z * d.z); return r; } void draw_triangle(Point x, Point y, Point z) { int i, j; int mnx, mny, mxx, mxy; float d; Point2d a, b, c; a = get_point(x); b = get_point(y); c = get_point(z); if (det(a, b, c) >= 0) return; mnx = MIN(a.x, MIN(b.x, c.x)); mxx = MAX(a.x, MAX(b.x, c.x)); mny = MIN(a.y, MIN(b.y, c.y)); mxy = MAX(a.y, MAX(b.y, c.y)); /* Fake depth :> */ for(i = MAX(mnx, 0); i <= MIN(mxx, w-1); ++i) { for (j = MAX(mny, 0); j <= MIN(mxy, h-1); ++j) { if (det(a, b, (Point2d){i, j}) <= 0 && det(b, c, (Point2d){i, j}) <= 0 && det(c, a, (Point2d){i, j}) <= 0) { d = getdep(x, y, z, P(((float)w)/(2.0*hfov), h/2 - j, i - w/2)); if (d < pts_depth[j*w+i]) { pts_queue[pts_queue_cnt++] = (SDL_Point){i, j}; pts_depth[j*w+i] = d; } } } } SDL_RenderDrawPoints(ren, pts_queue, pts_queue_cnt); #ifdef TRIANGLELINES SDL_SetRenderDrawColor(ren, 0xff, 0xff, 0xff, 0xff); SDL_SetRenderDrawColor(ren, 0x00, 0x00, 0x00, 0xff); SDL_RenderDrawLine(ren, a.x, a.y, b.x, b.y); SDL_RenderDrawLine(ren, c.x, c.y, b.x, b.y); SDL_RenderDrawLine(ren, a.x, a.y, c.x, c.y); #endif } void draw_triangle3d(Point a, Point b, Point c) { int x, y, z; int i, j; pts_queue_cnt = 0; Point2d m, n, o; make_point_relative(&a); make_point_relative(&b); make_point_relative(&c); if (a.x < 0 && b.x < 0 && c.x < 0) return; if (a.x >= 0 && b.x >= 0 && c.x >= 0) return draw_triangle(a, b, c); return; x = (a.x >= 0) ? 1 : -1; m = get_point(a); y = (b.x >= 0) ? 1 : -1; n = get_point(b); z = (c.x >= 0) ? 1 : -1; o = get_point(c); /* TODO: Better, not entire screen */ if (x * y * z * det(m,n,o) >= 0) return; for(i = 0; i <= w; ++i) { for (j = 0; j <= h; ++j) { if ((x * y * det(m, n, (Point2d){i, j}) <= 0) && (z * y * det(n, o, (Point2d){i, j}) <= 0) && (z * x * det(o, m, (Point2d){i, j}) <= 0)) SDL_RenderDrawPoint(ren, i, j); } } } void add_triangle(Point a, Point b, Point c, unsigned int col) { tgs[tgs_cnt].p[0] = a; tgs[tgs_cnt].p[1] = b; tgs[tgs_cnt].p[2] = c; tgs[tgs_cnt].col = col; tgs_cnt++; } int draw_init() { /* TODO: error handling */ pts_queue = malloc(w * h * (sizeof *pts_queue)); pts_depth = malloc(w * h * (sizeof *pts_depth)); tgs_cnt = 0; add_triangle((Point){3,16,2}, (Point){10,8,-5}, (Point){10,6,6}, 0xff0040ff); add_triangle((Point){10,8,-5}, (Point){5,4,2}, (Point){10,6,6}, 0xff0040ff); add_triangle((Point){10,0,-5}, (Point){5,0,2}, (Point){10,0,6}, shadowcol); int u = 7; return 0; } int draw_screen() { int i; for (i = 0; i < w*h; ++i) { pts_depth[i] = 250000.0; } /* Background */ SDL_SetRenderDrawColor(ren, INTTOCOL(0x404040), 255); SDL_RenderClear(ren); /* SDL_SetRenderDrawColor(ren, 25, 25, 25, 255); draw_triangle3d((Point){cam.pos.x-1.5,0,cam.pos.z-1.5}, (Point){cam.pos.x-1.5,0,cam.pos.z+1.5}, (Point){cam.pos.x+2.0,0,cam.pos.z}); */ for (i = 0; i < tgs_cnt; ++i) { SDL_SetRenderDrawColor(ren, INTTOCOL((tgs[i].col)>>8), tgs[i].col%256); draw_triangle3d(tgs[i].p[0], tgs[i].p[1], tgs[i].p[2]); } SDL_RenderPresent(ren); return 0; }