aboutsummaryrefslogtreecommitdiff
path: root/draw.c
diff options
context:
space:
mode:
Diffstat (limited to 'draw.c')
-rw-r--r--draw.c340
1 files changed, 340 insertions, 0 deletions
diff --git a/draw.c b/draw.c
new file mode 100644
index 0000000..9e79b93
--- /dev/null
+++ b/draw.c
@@ -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;
+}