diff options
Diffstat (limited to 'draw.c')
-rw-r--r-- | draw.c | 340 |
1 files changed, 340 insertions, 0 deletions
@@ -0,0 +1,340 @@ +#include <SDL2/SDL.h> +#include <math.h> +/* #include <SDL2/SDL_render.h> */ + +#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; +} |