half-assed 3D graphics attempt underway
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Sun, 9 Apr 2017 11:55:30 +0000 (14:55 +0300)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Sun, 9 Apr 2017 11:55:30 +0000 (14:55 +0300)
Makefile
fixed.h [new file with mode: 0644]
sincos.c [new file with mode: 0644]
sincos.h [new file with mode: 0644]
test.c
x3d.c [new file with mode: 0644]
x3d.h [new file with mode: 0644]

index 33323b6..6352238 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ src = $(wildcard *.c)
 obj = $(src:.c=.o)
 bin = regis_test
 
-CFLAGS = -pedantic -Wall -g
+CFLAGS = -pedantic -Wall -g -DWIDTH=480 -DHEIGHT=480
 LDFLAGS = -lm
 
 $(bin): $(obj)
diff --git a/fixed.h b/fixed.h
new file mode 100644 (file)
index 0000000..dbc8bbe
--- /dev/null
+++ b/fixed.h
@@ -0,0 +1,18 @@
+#ifndef FIXED_H_
+#define FIXED_H_
+
+#include <stdint.h>
+
+#define ftox16(x)              (int32_t)((x) * 65536.0f)
+#define itox16(x)              (int32_t)((x) << 16)
+
+#define x16tof(x)              (float)((x) / 65536.0f)
+#define x16toi(x)              ((x) >> 16)
+
+#define x16mul(a, b)   (int32_t)(((int32_t)(a) >> 8) * ((int32_t)(b) >> 8))
+/*int32_t x16div(register int32_t num, register int32_t denom);*/
+#define x16div(a, b)   (int32_t)(((int64_t)(a) << 16) / (b))
+
+#define x16sq(x)               x16mul(x, x)
+
+#endif /* FIXED_H_ */
diff --git a/sincos.c b/sincos.c
new file mode 100644 (file)
index 0000000..6ca93ce
--- /dev/null
+++ b/sincos.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <math.h>
+#include "fixed.h"
+#include "sincos.h"
+
+int16_t sinlut[SINLUT_SIZE] = {
+       0, 6, 12, 18, 25, 31, 37, 43, 50, 56, 62, 68, 75, 81, 87, 93,
+       99, 106, 112, 118, 124, 130, 136, 142, 148, 154, 160, 166, 172, 178, 184, 190,
+       195, 201, 207, 213, 218, 224, 230, 235, 241, 246, 252, 257, 263, 268, 273, 279,
+       284, 289, 294, 299, 304, 310, 314, 319, 324, 329, 334, 339, 343, 348, 353, 357,
+       362, 366, 370, 375, 379, 383, 387, 391, 395, 399, 403, 407, 411, 414, 418, 422,
+       425, 429, 432, 435, 439, 442, 445, 448, 451, 454, 457, 460, 462, 465, 468, 470,
+       473, 475, 477, 479, 482, 484, 486, 488, 489, 491, 493, 495, 496, 498, 499, 500,
+       502, 503, 504, 505, 506, 507, 508, 508, 509, 510, 510, 511, 511, 511, 511, 511,
+       512, 511, 511, 511, 511, 511, 510, 510, 509, 508, 508, 507, 506, 505, 504, 503,
+       502, 500, 499, 498, 496, 495, 493, 491, 489, 488, 486, 484, 482, 479, 477, 475,
+       473, 470, 468, 465, 462, 460, 457, 454, 451, 448, 445, 442, 439, 435, 432, 429,
+       425, 422, 418, 414, 411, 407, 403, 399, 395, 391, 387, 383, 379, 375, 370, 366,
+       362, 357, 353, 348, 343, 339, 334, 329, 324, 319, 314, 310, 304, 299, 294, 289,
+       284, 279, 273, 268, 263, 257, 252, 246, 241, 235, 230, 224, 218, 213, 207, 201,
+       195, 190, 184, 178, 172, 166, 160, 154, 148, 142, 136, 130, 124, 118, 112, 106,
+       99, 93, 87, 81, 75, 68, 62, 56, 50, 43, 37, 31, 25, 18, 12, 6,
+       0, -6, -12, -18, -25, -31, -37, -43, -50, -56, -62, -68, -75, -81, -87, -93,
+       -99, -106, -112, -118, -124, -130, -136, -142, -148, -154, -160, -166, -172, -178, -184, -190,
+       -195, -201, -207, -213, -218, -224, -230, -235, -241, -246, -252, -257, -263, -268, -273, -279,
+       -284, -289, -294, -299, -304, -310, -314, -319, -324, -329, -334, -339, -343, -348, -353, -357,
+       -362, -366, -370, -375, -379, -383, -387, -391, -395, -399, -403, -407, -411, -414, -418, -422,
+       -425, -429, -432, -435, -439, -442, -445, -448, -451, -454, -457, -460, -462, -465, -468, -470,
+       -473, -475, -477, -479, -482, -484, -486, -488, -489, -491, -493, -495, -496, -498, -499, -500,
+       -502, -503, -504, -505, -506, -507, -508, -508, -509, -510, -510, -511, -511, -511, -511, -511,
+       -512, -511, -511, -511, -511, -511, -510, -510, -509, -508, -508, -507, -506, -505, -504, -503,
+       -502, -500, -499, -498, -496, -495, -493, -491, -489, -488, -486, -484, -482, -479, -477, -475,
+       -473, -470, -468, -465, -462, -460, -457, -454, -451, -448, -445, -442, -439, -435, -432, -429,
+       -425, -422, -418, -414, -411, -407, -403, -399, -395, -391, -387, -383, -379, -375, -370, -366,
+       -362, -357, -353, -348, -343, -339, -334, -329, -324, -319, -314, -310, -304, -299, -294, -289,
+       -284, -279, -273, -268, -263, -257, -252, -246, -241, -235, -230, -224, -218, -213, -207, -201,
+       -195, -190, -184, -178, -172, -166, -160, -154, -148, -142, -136, -130, -124, -118, -112, -106,
+       -99, -93, -87, -81, -75, -68, -62, -56, -50, -43, -37, -31, -25, -18, -12, -6
+};
+
+void sincos_init(void)
+{
+       int i;
+
+       printf("int16_t sinlut[SINLUT_SIZE] = {");
+
+       for(i=0; i<SINLUT_SIZE; i++) {
+               float angle = 2.0 * M_PI * ((float)i / (float)SINLUT_SIZE);
+               float val = sin(angle);
+               sinlut[i] = (int16_t)(val * SINLUT_SCALE);
+
+               if((i & 0xf) == 0) {
+                       printf("%s\t%d", i ? ",\n" : "\n", sinlut[i]);
+               } else {
+                       printf(", %d", sinlut[i]);
+               }
+       }
+       printf("\n};");
+}
+
+int16_t sin_int(int16_t norm_angle)
+{
+       norm_angle %= SINLUT_SIZE;
+       if(norm_angle < 0) {
+               norm_angle += SINLUT_SIZE;
+       }
+       return sinlut[norm_angle];
+}
+
+int16_t cos_int(int16_t norm_angle)
+{
+       return sin_int(norm_angle + SINLUT_SIZE / 4);
+}
+
+int32_t sin_x16(int32_t radians)
+{
+       int32_t na = x16div(radians, M_PI_X16 * 2);
+       return (sin_int((na * SINLUT_SIZE) >> 16) << 16) / SINLUT_SCALE;
+}
+
+int32_t cos_x16(int32_t radians)
+{
+       int32_t na = x16div(radians, M_PI_X16 * 2);
+       return (cos_int((na * SINLUT_SIZE) >> 16) << 16) / SINLUT_SCALE;
+}
diff --git a/sincos.h b/sincos.h
new file mode 100644 (file)
index 0000000..82d7c5e
--- /dev/null
+++ b/sincos.h
@@ -0,0 +1,27 @@
+#ifndef SINCOS_H_
+#define SINCOS_H_
+
+#include <stdint.h>
+
+/*#define M_PI_X16     (int32_t)(M_PI * 65536.0) */
+#define M_PI_X16       (int32_t)((31416 << 16) / 10000)
+
+#define SINLUT_SCALE   512
+#define SINLUT_SIZE            512
+int16_t sinlut[SINLUT_SIZE];
+
+void sincos_init(void);
+
+/* takes angle in [0, SINLUT_SIZE] and returns:
+ * sin(2 * angle / SINLUT_SIZE / pi) * SINLUT_SCALE
+ */
+int16_t sin_int(int16_t norm_angle);
+int16_t cos_int(int16_t norm_angle);
+
+/* takes angle in fixed point 16.16 radians [0, 2pi << 16]
+ * and returns 16.16 fixed point in [-1 << 16, 1 << 16]
+ */
+int32_t sin_x16(int32_t radians);
+int32_t cos_x16(int32_t radians);
+
+#endif /* SINCOS_H_ */
diff --git a/test.c b/test.c
index c134b3f..72b6029 100644 (file)
--- a/test.c
+++ b/test.c
@@ -3,35 +3,38 @@
 #include <math.h>
 #include <unistd.h>
 #include "regis.h"
+#include "sincos.h"
+#include "x3d.h"
 
+#define X16INT(x)      ((x) << 16)
+
+static void draw(void);
 static void sig(int s);
 
 static volatile int done;
+int tm = 0;
 
 int main(int argc, char **argv)
 {
        int pg = 1;
-       float tm = 0.0f;
        signal(SIGINT, sig);
 
+       x3d_projection(45.0, (WIDTH << 16) / HEIGHT, 65536 / 2, 65536 * 500);
+
        while(!done) {
-               float dx = cos(tm) * 50.0;
-               float dy = sin(tm * 2.0) * 50.0;
-               tm += 0.01f;
 
                regis_enter();
                regis_draw_page(pg);
                regis_clear();
-               regis_abspos(100 + dx, 100 + dy);
-               regis_begin_vector(REGIS_BOUNDED | REGIS_FILL);
-               regis_absv(300 + dx, 300 + dy);
-               regis_absv(80 + dx, 400 + dy);
-               regis_end_vector();
+
+               draw();
+
                regis_show_page(pg);
                pg = (pg + 1) & 1;
                regis_leave();
 
                usleep(10000);
+               ++tm;
        }
 
        regis_enter();
@@ -40,6 +43,17 @@ int main(int argc, char **argv)
        return 0;
 }
 
+static void draw(void)
+{
+       x3d_load_identity();
+       x3d_translate(0, 0, X16INT(6));
+       x3d_rotate(X16INT(25), 65536, 0, 0);
+       x3d_rotate(tm << 10, 0, 65536, 0);
+
+       x3d_color_index(3);
+
+}
+
 static void sig(int s)
 {
        done = 1;
diff --git a/x3d.c b/x3d.c
new file mode 100644 (file)
index 0000000..53faa9b
--- /dev/null
+++ b/x3d.c
@@ -0,0 +1,265 @@
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "x3d.h"
+#include "fixed.h"
+#include "sincos.h"
+#include "regis.h"
+
+typedef struct pvec3 {
+       int32_t x, y, z;
+} pvec3;
+
+typedef struct pvec2 {
+       int32_t x, y;
+} pvec2;
+
+
+#define MAT_STACK_SIZE 4
+
+struct matrix {
+       int32_t m[12];
+};
+
+static void proc_vertex(const int32_t *vin, pvec3 *vout);
+
+void draw_poly(int num, const pvec3 *verts, int color);
+void draw_point(const pvec3 *v, int color);
+
+
+static int32_t proj_fov = M_PI_X16;
+static int32_t proj_aspect = 65536;
+static int32_t inv_proj_aspect = 65536;
+static int32_t proj_near = ftox16(0.5);
+static int32_t proj_far = 500 << 16;
+static int32_t inv_tan_half_xfov, inv_tan_half_yfov;
+
+#define ID_INIT {65536, 0, 0, 0, 0, 65536, 0, 0, 0, 0, 65536, 0}
+
+static struct matrix identity = { ID_INIT };
+
+static short mtop;
+static struct matrix mstack[MAT_STACK_SIZE] = { {ID_INIT}, {ID_INIT} };
+
+static const int32_t *vertex_array;
+static unsigned short vertex_count;
+
+static uint8_t im_color_index;
+
+
+void x3d_projection(int fov, int32_t aspect, int32_t nearz, int32_t farz)
+{
+       proj_fov = (M_PI_X16 * fov) / 180;
+       proj_aspect = aspect;
+       inv_proj_aspect = x16div(65536, proj_aspect);
+       proj_near = nearz;
+       proj_far = farz;
+
+       inv_tan_half_yfov = (int32_t)(65536.0 / tan(0.5 * proj_fov / 65536.0));
+       inv_tan_half_xfov = x16mul(inv_tan_half_yfov, aspect);
+}
+
+int x3d_push_matrix(void)
+{
+       short newtop = mtop + 1;
+       if(newtop >= MAT_STACK_SIZE) {
+               return -1;
+       }
+       memcpy(mstack + newtop, mstack + mtop, sizeof *mstack);
+       mtop = newtop;
+       return 0;
+}
+
+int x3d_pop_matrix(void)
+{
+       if(mtop <= 0) {
+               return -1;
+       }
+       --mtop;
+       return 0;
+}
+
+void x3d_load_matrix(int32_t *m)
+{
+       memcpy(mstack[mtop].m, m, sizeof *mstack);
+}
+
+
+#define M(i,j) (((i) << 2) + (j))
+void x3d_mult_matrix(int32_t *m)
+{
+       int i, j;
+       struct matrix tmp;
+
+       memcpy(tmp.m, mstack[mtop].m, sizeof tmp);
+
+       for(i=0; i<3; i++) {
+               for(j=0; j<4; j++) {
+                       mstack[mtop].m[M(i, j)] =
+                               x16mul(m[M(0, j)], tmp.m[M(i, 0)]) +
+                               x16mul(m[M(1, j)], tmp.m[M(i, 1)]) +
+                               x16mul(m[M(2, j)], tmp.m[M(i, 2)]);
+               }
+               mstack[mtop].m[M(i, 3)] += tmp.m[M(i, 3)];
+       }
+}
+
+void x3d_load_identity(void)
+{
+       memcpy(mstack[mtop].m, identity.m, sizeof identity);
+}
+
+void x3d_translate(int32_t x, int32_t y, int32_t z)
+{
+       int32_t m[] = ID_INIT;
+       m[3] = x;
+       m[7] = y;
+       m[11] = z;
+
+       x3d_mult_matrix(m);
+}
+
+void x3d_rotate(int32_t deg, int32_t x, int32_t y, int32_t z)
+{
+       int32_t xform[] = ID_INIT;
+
+       int32_t angle = x16mul(M_PI_X16, deg) / 180;
+       int32_t sina = sin_x16(angle);
+       int32_t cosa = cos_x16(angle);
+       int32_t one_minus_cosa = 65536 - cosa;
+       int32_t nxsq = x16sq(x);
+       int32_t nysq = x16sq(y);
+       int32_t nzsq = x16sq(z);
+
+       xform[0] = nxsq + x16mul(65536 - nxsq, cosa);
+       xform[4] = x16mul(x16mul(x, y), one_minus_cosa) - x16mul(z, sina);
+       xform[8] = x16mul(x16mul(x, z), one_minus_cosa) + x16mul(y, sina);
+       xform[1] = x16mul(x16mul(x, y), one_minus_cosa) + x16mul(z, sina);
+       xform[5] = nysq + x16mul(65536 - nysq, cosa);
+       xform[9] = x16mul(x16mul(y, z), one_minus_cosa) - x16mul(x, sina);
+       xform[2] = x16mul(x16mul(x, z), one_minus_cosa) - x16mul(y, sina);
+       xform[6] = x16mul(x16mul(y, z), one_minus_cosa) + x16mul(x, sina);
+       xform[10] = nzsq + x16mul(65536 - nzsq, cosa);
+
+       x3d_mult_matrix(xform);
+}
+
+void x3d_scale(int32_t x, int32_t y, int32_t z)
+{
+       int32_t m[] = ID_INIT;
+
+       m[0] = x;
+       m[5] = y;
+       m[10] = z;
+
+       x3d_mult_matrix(m);
+}
+
+void x3d_vertex_array(int count, const int32_t *ptr)
+{
+       vertex_array = ptr;
+       vertex_count = count;
+}
+
+int x3d_draw(int prim, int vnum)
+{
+       int i, j, pverts = prim;
+       const int32_t *vptr = vertex_array;
+       uint16_t color;
+
+       if(!vertex_array) return -1;
+
+       if(vnum > vertex_count) {
+               vnum = vertex_count;
+       }
+
+       for(i=0; i<vnum; i+=pverts) {
+               /* process vertices */
+               pvec3 vpos[4];
+
+               for(j=0; j<pverts; j++) {
+                       proc_vertex(vptr, vpos + j);
+
+                       if(vpos[j].z <= proj_near) {
+                               goto skip_prim;
+                       }
+
+                       vptr += 3;
+               }
+
+               color = im_color_index;
+
+               /* project & viewport */
+               for(j=0; j<pverts; j++) {
+                       int32_t x, y;
+
+                       x = x16mul(vpos[j].x, inv_tan_half_xfov);
+                       x = x16div(x, vpos[j].z);
+                       vpos[j].x = (x16mul(x, inv_proj_aspect) + 65536) * (WIDTH / 2);
+
+                       y = x16mul(vpos[j].y, inv_tan_half_yfov);
+                       y = x16div(y, vpos[j].z);
+                       vpos[j].y = (65536 - y) * (HEIGHT / 2);
+               }
+
+               switch(pverts) {
+               case X3D_POINTS:
+                       draw_point(vpos, color);
+                       break;
+
+               case X3D_LINES:
+                       break;
+
+               case X3D_TRIANGLES:
+               case X3D_QUADS:
+                       draw_poly(pverts, vpos, im_color_index);
+                       break;
+               }
+skip_prim: ;
+       }
+
+       return 0;
+}
+
+static void proc_vertex(const int32_t *vin, pvec3 *vout)
+{
+       int i;
+       int32_t tvert[3];
+       int32_t *mvmat = mstack[mtop].m;
+
+       /* transform vertex with current matrix */
+       for(i=0; i<3; i++) {
+               tvert[i] = x16mul(mvmat[0], vin[0]) +
+                       x16mul(mvmat[1], vin[1]) +
+                       x16mul(mvmat[2], vin[2]) +
+                       mvmat[3];
+               mvmat += 4;
+       }
+
+       vout->x = tvert[0];
+       vout->y = tvert[1];
+       vout->z = tvert[2];
+}
+
+void x3d_color_index(int cidx)
+{
+       im_color_index = cidx;
+}
+
+
+void draw_poly(int num, const pvec3 *verts, int color)
+{
+       int i;
+       regis_abspos(verts[0].x, verts[0].y);
+       regis_begin_vector(REGIS_BOUNDED);
+
+       for(i=0; i<num-1; i++) {
+               ++verts;
+               regis_absv(verts->x, verts->y);
+       }
+       regis_end_vector();
+}
+
+void draw_point(const pvec3 *v, int color)
+{
+}
diff --git a/x3d.h b/x3d.h
new file mode 100644 (file)
index 0000000..2b5ac2b
--- /dev/null
+++ b/x3d.h
@@ -0,0 +1,31 @@
+#ifndef X3D_H_
+#define X3D_H_
+
+#include <stdint.h>
+
+enum {
+       X3D_POINTS = 1,
+       X3D_LINES = 2,
+       X3D_TRIANGLES = 3,
+       X3D_QUADS = 4
+};
+
+void x3d_projection(int fov, int32_t aspect, int32_t nearz, int32_t farz);
+
+int x3d_push_matrix(void);
+int x3d_pop_matrix(void);
+void x3d_load_matrix(int32_t *m);
+void x3d_mult_matrix(int32_t *m);
+void x3d_load_identity(void);
+void x3d_translate(int32_t x, int32_t y, int32_t z);
+void x3d_rotate(int32_t angle, int32_t x, int32_t y, int32_t z);
+void x3d_scale(int32_t x, int32_t y, int32_t z);
+
+void x3d_vertex_array(int count, const int32_t *ptr);
+
+int x3d_draw(int prim, int vnum);
+int x3d_draw_indexed(int prim, int count, uint16_t *ptr);
+
+void x3d_color_index(int cidx);
+
+#endif /* X3D_H_ */