summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/color.c20
-rw-r--r--src/core/color.h7
-rw-r--r--src/core/device.c339
-rw-r--r--src/core/device.h98
-rw-r--r--src/core/limits.h6
-rw-r--r--src/core/mem.c0
-rw-r--r--src/core/mem.h20
-rw-r--r--src/core/rasterizer.c180
-rw-r--r--src/core/rasterizer.h17
-rw-r--r--src/core/shader.c34
-rw-r--r--src/core/shader.h89
-rw-r--r--src/core/tris.c0
-rw-r--r--src/core/tris.h17
-rw-r--r--src/core/vert.c42
-rw-r--r--src/core/vert.h48
-rw-r--r--src/example/example.h21
-rw-r--r--src/example/example_cube.c73
-rw-r--r--src/example/example_dot.c36
-rw-r--r--src/example/example_texture.c101
-rw-r--r--src/extend/camera.c0
-rw-r--r--src/extend/camera.h10
-rw-r--r--src/extend/transform.c0
-rw-r--r--src/extend/transform.h14
-rw-r--r--src/main.c74
-rw-r--r--src/math/math.c21
-rw-r--r--src/math/math.h306
-rw-r--r--src/math/matrix.c741
-rw-r--r--src/math/quat.c314
-rw-r--r--src/math/vec2.c36
-rw-r--r--src/math/vec3.c120
-rw-r--r--src/math/vec4.c24
-rw-r--r--src/ssr.h6
-rw-r--r--src/test/test.h15
-rw-r--r--src/test/test_mat4.c208
-rw-r--r--src/test/test_quat.c82
-rw-r--r--src/util/assert.h9
-rw-r--r--src/util/time.c5
-rw-r--r--src/util/time.h24
-rw-r--r--src/util/type.h7
39 files changed, 3164 insertions, 0 deletions
diff --git a/src/core/color.c b/src/core/color.c
new file mode 100644
index 0000000..45ca555
--- /dev/null
+++ b/src/core/color.c
@@ -0,0 +1,20 @@
+#include "vert.h"
+#include "device.h"
+
+Color color32_tocolor(Color32* c) {
+ return ssr_color(0xff * c->r, 0xff * c->g, 0xff * c->b, 0xff * c->a);
+}
+
+void color_tocolor32(Color c, Color32* out) {
+ out->r = COLOR_R(c) / (float)0xff;
+ out->g = COLOR_G(c) / (float)0xff;
+ out->b = COLOR_B(c) / (float)0xff;
+ out->a = COLOR_A(c) / (float)0xff;
+}
+
+void color32_saturate(Color32* c) {
+ c->r = clamp(c->r, 0, 1);
+ c->g = clamp(c->g, 0, 1);
+ c->b = clamp(c->b, 0, 1);
+ c->a = clamp(c->a, 0, 1);
+}
diff --git a/src/core/color.h b/src/core/color.h
new file mode 100644
index 0000000..1c9f45c
--- /dev/null
+++ b/src/core/color.h
@@ -0,0 +1,7 @@
+#ifndef _SOFTSHADEROOM_COLOR_H_
+#define _SOFTSHADEROOM_COLOR_H_
+
+#define COLOR_WHITE 0xffffffff
+#define COLOR_BLACK 0xff000000
+
+#endif
diff --git a/src/core/device.c b/src/core/device.c
new file mode 100644
index 0000000..f5ed4eb
--- /dev/null
+++ b/src/core/device.c
@@ -0,0 +1,339 @@
+#include "device.h"
+#include "rasterizer.h"
+#include "../util/assert.h"
+
+ssr_Config config;
+
+typedef enum ssr_VertexAttrMask {
+ VERTEXATTR_POS = 1,
+ VERTEXATTR_COLOR = 1 << 1,
+ VERTEXATTR_UV = 1 << 2,
+ VERTEXATTR_NORMAL = 1 << 3,
+} ssr_VertexAttrMask;
+
+typedef struct VertexAttr {
+ int start;
+ int offset;
+} VertexAttr;
+
+/*
+** 状态结构
+*/
+struct {
+ /* MVP矩阵栈 */
+ Mat4 matrices[3][MATRIXDEPTH];
+ uint matrixtop[3];
+ ssr_MatrixMode matrixmode;
+
+ /* 屏幕缓冲区 */
+ Color* target;
+ Color* framebuffer;
+ uint buffersize; /*framebuffer size in bytess*/
+
+ /* zbuffer 深度会被映射到0~1的非线性区间*/
+ uint* zbuffer;
+
+ /* 顶点数据 */
+ Vert** verts; uint nverts;
+ uint* indices; uint nprims;
+
+ /* shader program */
+ Program* program;
+ UniformCollection uniforms;
+
+ uint enable;
+
+} state;
+
+/*
+** MVP矩阵栈
+*/
+#define MATRIXTOP state.matrixtop[state.matrixmode]
+#define MATRIX state.matrices[state.matrixmode][MATRIXTOP]
+#define MATRIXSTACK state.matrices[state.matrixmode]
+
+#define GETMATRIX(MODE) state.matrices[MODE][state.matrixtop[MODE]]
+
+#define BUFFER (state.framebuffer)
+
+#define contains(x, y, l, r, t, b) (x >= l && x <= r && y <= b && y >= t)
+
+void ssr_init(ssr_Config* conf) {
+ config = *conf;
+ ssrM_zero(state.matrixtop, sizeof(state.matrixtop));
+ state.target = conf->target;
+ if (config.dbuffer) {
+ state.framebuffer = ssrM_newvector(Color, config.width * config.height);
+ }
+ else {
+ state.framebuffer = conf->target;
+ }
+ state.buffersize = sizeof(Color) * config.width * config.height;
+ state.zbuffer = ssrM_newvector(uint, config.width * config.height);
+ memset(state.zbuffer, 0xff, sizeof(uint)*config.width*config.height);
+}
+
+int ssr_getframebufferw() {
+ return config.width;
+}
+
+int ssr_getframebufferh() {
+ return config.height;
+}
+
+void ssr_matrixmode(ssr_MatrixMode mode) {
+ state.matrixmode = mode;
+}
+
+void ssr_loadidentity() {
+ mat4_setidentity(&MATRIX);
+}
+
+/* push进去之后会将最新的拷贝一份放在栈顶 */
+void ssr_pushmatrix() {
+ ssr_assert(MATRIXTOP < MATRIXDEPTH - 1);
+ ++MATRIXTOP;
+ MATRIX = MATRIXSTACK[MATRIXTOP - 1];
+}
+
+void ssr_popmatrix() {
+ MATRIXTOP = clamp(--MATRIXTOP, 0, MATRIXDEPTH - 1);
+}
+
+/*用来做world->view的变换矩阵*/
+/*http://warmcat.org/chai/blog/?p=559*/
+void ssr_lookat(Vec3* pos, Vec3* target, Vec3* up) {
+ ssr_assert(pos && target && up);
+ Vec3 z;
+ vec3_minus(pos, target, &z); vec3_normalize(&z, &z); /*去除缩放影响*/
+ Vec3 x;
+ vec3_cross(up, &z, &x); vec3_normalize(&x, &x);
+ Vec3 y;
+ vec3_cross(&z, &x, &y); vec3_normalize(&y, &y);
+ Mat4 m = { /*注意这里是列主序*/
+ x.x, y.x, z.x, 0,
+ x.y, y.y, z.y, 0,
+ x.z, y.z, z.z, 0,
+ -vec3_dot(&x, pos), -vec3_dot(&y, pos), -vec3_dot(&z, pos), 1
+ };
+ mat4_multiply(&MATRIX, &m, &MATRIX);
+}
+
+/* scalematrix * matrix */
+void ssr_scale(float sx, float sy, float sz) {
+ Vec3 scale = { sx, sy, sz };
+ mat4_scale(&MATRIX, &scale, &MATRIX);
+}
+
+void ssr_rotate(float angle, float x, float y, float z) {
+ Vec3 axis = { x, y, z };
+ vec3_normalize(&axis, &axis);
+ mat4_rotate(&MATRIX, angle, &axis, &MATRIX);
+}
+
+void ssr_translate(float x, float y, float z) {
+ Vec3 trans = { x, y, z };
+ mat4_translate(&MATRIX, &trans, &MATRIX);
+}
+
+void ssr_loadmatrix(Mat4* m) {
+ ssr_assert(m);
+ MATRIX = *m;
+}
+
+void ssr_multmatrix(Mat4* m) {
+ ssr_assert(m);
+ mat4_multiply(&MATRIX, m, &MATRIX);
+}
+
+void ssr_getmvp(Mat4* out) {
+ ssr_assert(out);
+ mat4_multiply(&GETMATRIX(MATRIX_VIEW), &GETMATRIX(MATRIX_MODEL), out);
+ mat4_multiply(&GETMATRIX(MATRIX_PROJECTION), out, out);
+}
+
+void ssr_getmv(Mat4* out) {
+ ssr_assert(out);
+ mat4_multiply(&GETMATRIX(MATRIX_VIEW), &GETMATRIX(MATRIX_MODEL), out);
+}
+
+void ssr_enable(uint mask) {
+ state.enable |= mask;
+}
+
+void ssr_disable(uint mask) {
+ state.enable &= (~mask);
+}
+
+bool ssr_isenable(uint mask) {
+ return state.enable & mask;
+}
+
+void ssr_viewport(float l, float r, float b, float t) {
+}
+
+void ssr_frustum(float l, float r, float b, float t, float n, float f) {
+ Mat4 m;
+ mat4_setfrustum(l, r, b, t, n, f, &m);
+ mat4_multiply(&MATRIX, &m, &MATRIX);
+}
+
+void ssr_perspective(float fov, float aspect, float n, float f) {
+ Mat4 m;
+ mat4_setperspective(fov, aspect, n, f, &m);
+ mat4_multiply(&MATRIX, &m, &MATRIX);
+}
+
+void ssr_present() {
+ if (config.dbuffer) {
+ memcpy(state.target, state.framebuffer, state.buffersize);
+ }
+}
+
+void ssr_clearcolor(Color color) {
+ if (color == 0x00) {
+ memset(state.framebuffer, 0, state.buffersize);
+ }
+ else {
+ for (int i = 0; i < config.width*config.height; ++i)
+ state.framebuffer[i] = color;
+ }
+}
+
+void ssr_cleardepth() {
+ memset(state.zbuffer, 0xff, sizeof(uint)*config.width*config.height);
+}
+
+void ssr_putpoint(uint screenx, uint screeny, Color color) {
+ if (!contains(screenx, screeny, 0, config.width - 1, 0, config.height - 1))
+ return;
+ BUFFER[screeny * config.width + screenx] = color;
+}
+
+Color ssr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
+ unsigned int c = (a << 24) | (r << 16) | (g << 8) | b;
+ return c;
+}
+
+bool ssr_testdepth(uint x, uint y, uint depth) {
+ if (!contains(x, y, 0, config.width - 1, 0, config.height - 1))
+ return 0;
+ uint off = x + y * config.width;
+ if (state.zbuffer[off] < depth)
+ return 0;
+ state.zbuffer[off] = depth;
+ return 1;
+}
+
+bool ssr_testdepthf(uint x, uint y, float depth) {
+ uint d = UINT_MAX * (double)depth;
+ return ssr_testdepth(x, y, d);
+}
+
+void ssrU_viewport(Vec2* p, Vec2* out) {
+ ssr_assert(p && out);
+ int halfw = config.width >> 1, halfh = config.height >> 1;
+ out->x = p->x * halfw + halfw + 0.5f;
+ out->y = halfh - p->y * halfh + 0.5f;
+}
+
+void ssr_bindvertices(Vert** verts, int nverts, uint* indices, int nprims) {
+ ssr_assert(verts && indices);
+ state.verts = verts;
+ state.nverts = nverts;
+ state.indices = indices;
+ state.nprims = nprims;
+}
+
+void ssr_useprogram(Program* program) {
+ ssr_assert(program);
+ state.program = program;
+}
+
+void ssr_unuseprogram() {
+ state.program = NULL;
+}
+
+static Vec4* homos = 0;
+static uint tri[3]; /*三角形三个顶点的索引*/
+static Vec3 ab, ac;
+static Mat4 mvp, mv;
+void ssr_draw(ssr_PrimitiveType primitive) {
+ ssr_assert(state.verts && state.indices);
+
+ ssr_getmvp(&mvp);
+ ssr_getmv(&mv);
+ state.uniforms.model = &GETMATRIX(MATRIX_MODEL);
+ state.uniforms.view = &GETMATRIX(MATRIX_VIEW);
+ state.uniforms.projection = &GETMATRIX(MATRIX_PROJECTION);
+ state.uniforms.mvp = &mvp;
+ state.uniforms.mv = &mv;
+
+ VertexShaderIn vertIn = { NULL };
+ if (!homos)
+ homos = ssrM_newvector(Vec4, state.nverts);
+ for (int i = 0; i < state.nverts; ++i) {
+ Vert* vert = state.verts[i];
+ vertIn.vertex = vert;
+ state.program->vertexshader(&state.uniforms, &vertIn, &homos[i]);
+ }
+
+ if (primitive == PRIMITIVE_TRIANGLE) {
+ for (int i = 0; i < state.nprims; ++i) {
+ tri[0] = state.indices[i * 3];
+ tri[1] = state.indices[i * 3 + 1];
+ tri[2] = state.indices[i * 3 + 2];
+
+ /* back face culling */
+ if (ssr_isenable(ENABLEMASK_BACKFACECULL)) {
+ vec3_minus(&homos[tri[1]], &homos[tri[0]], &ab);
+ vec3_minus(&homos[tri[2]], &homos[tri[0]], &ac);
+ if (ab.x * ac.y - ab.y * ac.x <= 0) {
+ continue;
+ }
+ }
+
+ ssrR_triangle(
+ &homos[tri[0]],
+ &homos[tri[1]],
+ &homos[tri[2]],
+ state.verts[tri[0]],
+ state.verts[tri[1]],
+ state.verts[tri[2]],
+ state.program,
+ &state.uniforms
+ );
+ }
+ }
+ else if (primitive == PRIMITIVE_POINT) {
+
+ }
+ else if (primitive == PRIMITIVE_LINE) {
+
+ }
+ //ssrM_free(homos);
+}
+
+void ssr_setuniformmat4(uint idx, Mat4* src) {
+ ssr_assert(src);
+ if (idx < 0 || idx > 7) return;
+ state.uniforms.var_mat4[idx] = *src;
+}
+
+void ssr_setuniformvec4(uint idx, Vec4* src) {
+ ssr_assert(src);
+ if (idx < 0 || idx > 7) return;
+ state.uniforms.var_vec4[idx] = *src;
+}
+
+void ssr_setuniformvec3(uint idx, Vec3* src) {
+ ssr_assert(src);
+ if (idx < 0 || idx > 7) return;
+ state.uniforms.var_vec3[idx] = *src;
+}
+
+void ssr_setuniformvec2(uint idx, Vec2* src) {
+ ssr_assert(src);
+ if (idx < 0 || idx > 7) return;
+ state.uniforms.var_vec2[idx] = *src;
+}
diff --git a/src/core/device.h b/src/core/device.h
new file mode 100644
index 0000000..aa6e73f
--- /dev/null
+++ b/src/core/device.h
@@ -0,0 +1,98 @@
+#ifndef _SOFTSHADEROOM_DEVICE_H_
+#define _SOFTSHADEROOM_DEVICE_H_
+
+#include "../math/math.h"
+#include "../util/type.h"
+#include "mem.h"
+#include "limits.h"
+#include "shader.h"
+#include "rasterizer.h"
+#include "vert.h"
+
+typedef enum ssr_MatrixMode {
+ MATRIX_MODEL = 0,
+ MATRIX_VIEW = 1,
+ MATRIX_PROJECTION = 2,
+} ssr_MatrixMode;
+
+typedef struct ssr_Config {
+ int width, height;
+ bool dbuffer;/* double buffer? */
+ Color* target; /* screen target buffer */
+} ssr_Config;
+
+typedef enum ssr_PrimitiveType {
+ PRIMITIVE_POINT,
+ PRIMITIVE_LINE,
+ PRIMITIVE_TRIANGLE,
+} ssr_PrimitiveType;
+
+typedef enum ssr_EnableMask {
+ ENABLEMASK_BACKFACECULL = 1 ,
+ ENABLEMASK_DEPTHTEST = 1 << 1,
+} ssr_EnableMask;
+
+void ssr_init(ssr_Config* config);
+
+int ssr_getframebufferw();
+int ssr_getframebufferh();
+
+void ssr_matrixmode(ssr_MatrixMode mode);
+void ssr_loadidentity();
+void ssr_pushmatrix();
+void ssr_popmatrix();
+void ssr_lookat(Vec3* pos, Vec3* target, Vec3* up);
+
+/*后乘,意味着这些操作会被率先应用到物体上,应该按照反向顺序调用这些函数*/
+void ssr_translate(float x, float y, float z);
+void ssr_rotate(float angle, float x, float y, float z);
+void ssr_scale(float sx, float sy, float sz);
+
+void ssr_multmatrix(Mat4* m);/*右乘矩阵*/
+void ssr_loadmatrix(Mat4* m);
+void ssr_frustum(float l, float r, float b, float t, float n, float f);
+void ssr_perspective(float fov, float aspect, float n, float f);
+
+void ssr_viewport(float l, float r, float b, float t);
+
+void ssr_getmv(Mat4* out);
+void ssr_getmvp(Mat4* out);
+
+void ssr_enable(uint mask);
+void ssr_disable(uint mask);
+bool ssr_isenable(uint mask);
+
+/* 绑定顶点数据 */
+void ssr_bindvertices(Vert** verts, int nverts, uint* indices, int nprims);
+void ssr_unbindvertices();
+
+void ssr_useprogram(Program* program);
+void ssr_unuseprogram();
+
+void ssr_setuniformmat4(uint idx, Mat4* src);
+void ssr_setuniformvec4(uint idx, Vec4* src);
+void ssr_setuniformvec3(uint idx, Vec3* src);
+void ssr_setuniformvec2(uint idx, Vec2* src);
+
+void ssr_draw(ssr_PrimitiveType primitive);
+void ssr_clearcolor(Color color);
+void ssr_cleardepth();
+
+/*直接绘制到缓冲区*/
+void ssr_putpoint(uint screenx, uint screeny, Color color); /*直接修改某个位置的颜色*/
+
+void ssr_present();
+
+Color ssr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+
+//bool ssr_cutline(int* x0, int* y0, int* x1, int* y1);
+
+bool ssr_testdepth(uint x, uint y, uint depth); /*尝试写入深度,如果可绘制返回true,否则discard*/
+bool ssr_testdepthf(uint x, uint y, float depth01);
+
+/*
+** Utils
+*/
+void ssrU_viewport(Vec2* p, Vec2* out);
+
+#endif \ No newline at end of file
diff --git a/src/core/limits.h b/src/core/limits.h
new file mode 100644
index 0000000..4ef0b75
--- /dev/null
+++ b/src/core/limits.h
@@ -0,0 +1,6 @@
+#ifndef _SOFTSHADEROOM_LIMITS_H_
+#define _SOFTSHADEROOM_LIMITS_H_
+
+#define MATRIXDEPTH 32
+
+#endif \ No newline at end of file
diff --git a/src/core/mem.c b/src/core/mem.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/core/mem.c
diff --git a/src/core/mem.h b/src/core/mem.h
new file mode 100644
index 0000000..1a763f9
--- /dev/null
+++ b/src/core/mem.h
@@ -0,0 +1,20 @@
+#ifndef _SOFTSHADEROOM_MEM_H_
+#define _SOFTSHADEROOM_MEM_H_
+
+#include <memory.h>
+
+/*
+** 内存分配相关
+*/
+
+void ssrM_freemem();
+void ssrM_realloc();
+
+#define ssrM_zero(obj, size) memset(obj, 0, size)
+#define ssrM_new(T) (T*)malloc(sizeof(T))
+#define ssrM_newvector(T, c) ((T*)calloc(c, sizeof(T)))
+#define ssrM_free(obj) free(obj)
+
+#define cast(v, T) (*(T*)(&v))
+
+#endif \ No newline at end of file
diff --git a/src/core/rasterizer.c b/src/core/rasterizer.c
new file mode 100644
index 0000000..0c8c6eb
--- /dev/null
+++ b/src/core/rasterizer.c
@@ -0,0 +1,180 @@
+#include "rasterizer.h"
+#include "device.h"
+#include "shader.h"
+#include "../math/math.h"
+#include "../util/assert.h"
+
+void ssrR_putline(int x0, int y0, int x1, int y1, Color color) {
+ int steep = 0;
+ if (abs(x0 - x1) < abs(y0 - y1)) {
+ swapi(x0, y0);
+ swapi(x1, y1);
+ steep = 1;
+ }
+ if (x0 > x1) {
+ swapi(x0, x1);
+ swapi(y0, y1);
+ }
+ int dx = x1 - x0;
+ int dy = y1 - y0;
+ int derror2 = abs(dy) << 1;
+ int error2 = 0;
+ int y = y0;
+ for (int x = x0; x <= x1; ++x) {
+ if (steep) {
+ ssr_putpoint(y, x, color);
+ }
+ else {
+ ssr_putpoint(x, y, color);
+ }
+ error2 += derror2;
+ if (error2 > dx) {
+ y += (y1 > y0 ? 1 : -1);
+ error2 -= (dx << 1);
+ }
+ }
+}
+
+/*使用辅助梯形计算三角形面积,《3D数学基础》P245*/
+float ssrR_area(Vec2* v1, Vec2* v2, Vec2* v3) {
+ ssr_assert(v1 && v2 && v3);
+ float area = 0.5f * ((v1->y - v2->y) * (v3->x - v2->x) + (v3->y - v2->y) * (v2->x - v1->x));
+ return area;
+}
+
+/*from https://github.com/ssloy/tinyrenderer*/
+static Vec3 s[2], u;
+bool ssrR_barycentric(Vec2* A, Vec2* B, Vec2* C, Vec2* p, Vec3* out) {
+ ssr_assert(A && B && C && p && out);
+ s[0].x = C->x - A->x; s[0].y = B->x - A->x; s[0].z = A->x - p->x;
+ s[1].x = C->y - A->y; s[1].y = B->y - A->y; s[1].z = A->y - p->y;
+ vec3_cross(&s[0], &s[1], &u);
+ if (compare(u.z, 0)) {
+ return 0;
+ } else {
+ float uz = 1.f / u.z;
+ out->x = 1 - (u.x + u.y) * uz;
+ out->y = u.y * uz;
+ out->z = u.x * uz;
+ return 1;
+ }
+}
+
+bool ssrR_ispointintriangle(Vec2* A, Vec2* B, Vec2* C, Vec2* p) {
+ ssr_assert(A && B && C && p);
+ Vec3 c; ssrR_barycentric(A, B, C, p, &c);
+ return c.x >= 0 && c.y >= 0 && c.z >= 0;
+}
+
+void ssrR_center(Vec2* A, Vec2* B, Vec2* C, Vec2* out) {
+ ssr_assert(A && B && C && out);
+ float k = 1 / 3.f;
+ out->x = k * (A->x + B->x + C->x);
+ out->y = k * (A->y + B->y + C->y);
+}
+
+/*
+** clipc 按列排放的三角形三个顶点的齐次裁剪坐标
+** program shader程序
+*/
+static Vec3 SA, SB, SC; // screen coords
+static Vec3 bcp; // 重心坐标
+void _ssrR_triangle(Vec4* CA, Vec4* CB, Vec4* CC, Vert* A, Vert* B, Vert* C, Program* program, UniformCollection* uniforms) {
+ ssr_assert(CA && CB && CC && program);
+ vec4_dividew(CA, &SA); ssrU_viewport(&SA, &SA);
+ vec4_dividew(CB, &SB); ssrU_viewport(&SB, &SB);
+ vec4_dividew(CC, &SC); ssrU_viewport(&SC, &SC);
+ /*根据屏幕空间的y值排序, A的y最小,B居中,C最大*/
+ Vec3 *sa = &SA, *sb = &SB, *sc = &SC, *tmp; Vec4* v4tmp; Vert* vtemp;
+ if (sb->y < sa->y) { sa = &SB; sb = &SA; v4tmp = CA; CA = CB; CB = v4tmp; vtemp = A; A = B; B = vtemp; }
+ if (sc->y < sb->y) { tmp = sc; sc = sb; sb = tmp; v4tmp = CC; CC = CB; CB = v4tmp; vtemp = B; B = C; C = vtemp; }
+ if (sc->y < sa->y) { tmp = sc; sc = sa; sa = tmp; v4tmp = CC; CC = CA; CA = v4tmp; vtemp = C; C = A; A = vtemp; }
+
+ float invkAC = (SC.x - SA.x) / (SC.y - SA.y + EPSILON);
+ float invkAB = (SB.x - SA.x) / (SB.y - SA.y + EPSILON);
+ float invkBC = (SC.x - SB.x) / (SC.y - SB.y + EPSILON);
+
+ int order = 1; if (((sb->y - sa->y) / (sb->x - sa->x) - invkAC) * invkAC > 0) { order = -1; }
+
+ FragmentShaderIn in = {A, B, C, 0};
+ Color color;
+ Vec2 l, r, p;
+ float depth; Vec3 cdepth = {SA.z, SB.z, SC.z};
+ float CAw = 1.f / CA->w, CBw = 1.f / CB->w, CCw = 1.f / CC->w;
+ for (p.y = sa->y; p.y <= sc->y; ++p.y) {
+ l.y = p.y;
+ r.y = p.y;
+ if (compare(SC.y, SA.y)) r.x = sc->x;
+ else r.x = sa->x + invkAC * (p.y - sa->y); /*AC*/
+ if (p.y <= sb->y) {
+ if (compare(SB.y, SA.y)) l.x = sb->x;
+ else l.x = sa->x + invkAB * (p.y - sa->y);
+ } else {
+ if (compare(SC.y, SB.y)) l.x = sc->x;
+ else l.x = sb->x + invkBC * (p.y - sb->y);
+ }
+ for (p.x = l.x; order * (r.x - p.x) >= 0; p.x += order) {
+ /*计算线性的(齐次裁剪空间)的重心坐标,分三步*/
+ if (!ssrR_barycentric(sa, sb, sc, &p, &bcp)) {
+ continue; /*discard fragment*/
+ }
+ bcp.x *= CAw; bcp.y *= CBw; bcp.z *= CCw;
+ vec3_scale(&bcp, 1.f / (bcp.x + bcp.y + bcp.z), &bcp);
+ /*depth test*/
+ depth = vec3_dot(&bcp, &cdepth) * 0.5f + 0.5f;
+ if (!ssr_testdepthf(p.x, p.y, depth)) {
+ continue; /*discard fragment*/
+ }
+ /*enter fragment shader*/
+ in.bc = &bcp;
+ program->fragmentshader(uniforms, &in, &color);
+ ssr_putpoint(p.x, p.y, color);
+ }
+ }
+}
+
+static Vec2 bboxmin, bboxmax;
+void ssrR_triangle(Vec4* CA, Vec4* CB, Vec4* CC, Vert* A, Vert* B, Vert* C, Program* program, UniformCollection* uniforms) {
+ ssr_assert(CA && CB && CC && program);
+ vec4_dividew(CA, &SA); ssrU_viewport(&SA, &SA);
+ vec4_dividew(CB, &SB); ssrU_viewport(&SB, &SB);
+ vec4_dividew(CC, &SC); ssrU_viewport(&SC, &SC);
+ bboxmin.x = min(SA.x, min(SB.x, SC.x));
+ bboxmax.x = max(SA.x, max(SB.x, SC.x));
+ bboxmin.y = min(SA.y, min(SB.y, SC.y));
+ bboxmax.y = max(SA.y, max(SB.y, SC.y));
+ float CAw = 1.f / CA->w, CBw = 1.f / CB->w, CCw = 1.f / CC->w;
+ float depth; Vec3 cdepth = { SA.z, SB.z, SC.z };
+ FragmentShaderIn in = { A, B, C, 0 };
+ Vec2 p; Color color;
+ for (p.y = bboxmin.y; p.y <= bboxmax.y; ++p.y) {
+ for (p.x = bboxmin.x; p.x <= bboxmax.x; ++p.x) {
+ /*计算线性的(齐次裁剪空间)的重心坐标,分三步*/
+ if (!ssrR_barycentric(&SA, &SB, &SC, &p, &bcp)) {
+ continue; /*discard fragment*/
+ }
+ if (bcp.x < 0 || bcp.y < 0 || bcp.z < 0) {
+ continue; /*discard fragment*/
+ }
+ bcp.x *= CAw; bcp.y *= CBw; bcp.z *= CCw;
+ vec3_scale(&bcp, 1.f / (bcp.x + bcp.y + bcp.z), &bcp);
+
+ /*深度测试*/
+ if (ssr_isenable(ENABLEMASK_DEPTHTEST)) {
+ depth = vec3_dot(&bcp, &cdepth) * 0.5f + 0.5f;
+ if (!ssr_testdepthf(p.x, p.y, depth)) {
+ continue; /*discard fragment*/
+ }
+ }
+
+ /*enter fragment shader*/
+ in.bc = &bcp;
+ bool discad = program->fragmentshader(uniforms, &in, &color);
+ if (!discad)
+ ssr_putpoint(p.x, p.y, color);
+ }
+ }
+ //ssrR_putline(SA.x, SA.y, SB.x, SB.y, 0xffff0000);
+ //ssrR_putline(SA.x, SA.y, SC.x, SC.y, 0xffff0000);
+ //ssrR_putline(SC.x, SC.y, SB.x, SB.y, 0xffff0000);
+} \ No newline at end of file
diff --git a/src/core/rasterizer.h b/src/core/rasterizer.h
new file mode 100644
index 0000000..e35b24a
--- /dev/null
+++ b/src/core/rasterizer.h
@@ -0,0 +1,17 @@
+#ifndef _SOFTSHADEROOM_GEOMETRY_H_
+#define _SOFTSHADEROOM_GEOMETRY_H_
+
+#include "../math/math.h"
+#include "shader.h"
+
+void ssrR_putline(int x0, int y0, int x1, int y1, Color color);
+
+float ssrR_area(Vec2* v1, Vec2* v2, Vec2* v3); /*计算三角形面积,注意v1v2v3按逆时针顺序定义*/
+
+bool ssrR_barycentric(Vec2* A, Vec2* B, Vec2* C, Vec2* p, Vec3* out); /*计算重心坐标*/
+void ssrR_center(Vec2* A, Vec2* B, Vec2* C, Vec2* out); /*获得重心*/
+bool ssrR_ispointintriangle(Vec2* A, Vec2* B, Vec2* C, Vec2* p);
+
+void ssrR_triangle(Vec4* CA, Vec4* CB, Vec4* CC, Vert* A, Vert* B, Vert* C, Program* program, UniformCollection* uniforms); /*绘制三角形图元*/
+
+#endif \ No newline at end of file
diff --git a/src/core/shader.c b/src/core/shader.c
new file mode 100644
index 0000000..fe25408
--- /dev/null
+++ b/src/core/shader.c
@@ -0,0 +1,34 @@
+#include "shader.h"
+#include "vert.h"
+#include "device.h"
+
+void ssrS_bcpcolor(Vec3* bc, Color A, Color B, Color C, Color* out) {
+ ssr_assert(bc && out);
+ *out = ssr_color(
+ bc->A * COLOR_R(A) + bc->B * COLOR_R(B) + bc->C * COLOR_R(C),
+ bc->A * COLOR_G(A) + bc->B * COLOR_G(B) + bc->C * COLOR_G(C),
+ bc->A * COLOR_B(A) + bc->B * COLOR_B(B) + bc->C * COLOR_B(C),
+ bc->A * COLOR_A(A) + bc->B * COLOR_A(B) + bc->C * COLOR_A(C)
+ );
+}
+
+void ssrS_bcpvec2(Vec3* bc, Vec2* A, Vec2* B, Vec2* C, Vec2* out) {
+ ssr_assert(bc && A && B && C && out);
+ out->x = bc->A * A->x + bc->B * B->x + bc->C * C->x;
+ out->y = bc->A * A->y + bc->B * B->y + bc->C * C->y;
+}
+
+void ssrS_bcpvec3(Vec3* bc, Vec3* A, Vec3* B, Vec3* C, Vec3* out) {
+ ssr_assert(bc && A && B && C && out);
+ out->x = bc->A * A->x + bc->B * B->x + bc->C * C->x;
+ out->y = bc->A * A->y + bc->B * B->y + bc->C * C->y;
+ out->z = bc->A * A->z + bc->B * B->z + bc->C * C->z;
+}
+
+void ssrS_bcpvec4(Vec3* bc, Vec4* A, Vec4* B, Vec4* C, Vec4* out) {
+ ssr_assert(bc && A && B && C && out);
+ out->x = bc->A * A->x + bc->B * B->x + bc->C * C->x;
+ out->y = bc->A * A->y + bc->B * B->y + bc->C * C->y;
+ out->z = bc->A * A->z + bc->B * B->z + bc->C * C->z;
+ out->w = bc->A * A->w + bc->B * B->w + bc->C * C->w;
+}
diff --git a/src/core/shader.h b/src/core/shader.h
new file mode 100644
index 0000000..8da8ae3
--- /dev/null
+++ b/src/core/shader.h
@@ -0,0 +1,89 @@
+#ifndef _SOFTSHADEROOM_SHADER_H_
+#define _SOFTSHADEROOM_SHADER_H_
+
+#include "../math/math.h"
+#include "vert.h"
+
+typedef struct UniformCollection {
+ /*built in varaibles*/
+ Mat4* model;
+ Mat4* view;
+ Mat4* projection;
+ Mat4* mvp;
+ Mat4* mv;
+ /*userside variables*/
+ Mat4 var_mat4[8];
+ Vec4 var_vec4[8];
+ Vec3 var_vec3[8];
+ Vec2 var_vec2[8];
+} UniformCollection;
+
+#define ssrum4(i) (uniforms->var_mat4[i])
+#define ssruv2(i) (uniforms->var_vec2[i])
+#define ssruv3(i) (uniforms->var_vec3[i])
+#define ssruv4(i) (uniforms->var_vec4[i])
+
+typedef struct VertexShaderIn {
+ Vert* vertex;
+} VertexShaderIn;
+
+typedef void(*VertexShader)(UniformCollection* uniforms, VertexShaderIn* in, Vec4* homocoord);
+
+typedef struct FragmentShaderIn {
+ Vert *A, *B, *C;
+ Vec3* bc;
+} FragmentShaderIn;
+
+typedef bool(*FragmentShader)(UniformCollection* uniforms, FragmentShaderIn* in, Color* color);
+
+typedef struct Program {
+ VertexShader vertexshader;
+ FragmentShader fragmentshader;
+} Program;
+
+void ssrS_bcpcolor(Vec3* bc, Color A, Color B, Color C, Color* out);
+void ssrS_bcpvec2(Vec3* bc, Vec2* A, Vec2* B, Vec2* C, Vec2* out);
+void ssrS_bcpvec3(Vec3* bc, Vec3* A, Vec3* B, Vec3* C, Vec3* out);
+void ssrS_bcpvec4(Vec3* bc, Vec4* A, Vec4* B, Vec4* C, Vec4* out);
+
+/*
+** 顶点数据外,还提供额外的寄存器
+*/
+enum RegisterType {
+ REGTYPE_VEC2 = 1,
+ REGTYPE_VEC4 = 2,
+ REGTYPE_VEC3 = 3,
+};
+
+typedef struct Register {
+ uint length;
+ uint type;
+ union {
+ Vec4* v4;
+ Vec2* v2;
+ Vec3* v3;
+ };
+} Register;
+
+void ssrS_setregvec4_01i(uint idx, Vec4* value);
+void ssrS_setregvec4_02i(uint idx, Vec4* value);
+void ssrS_setregvec2_01i(uint idx, Vec2* value);
+void ssrS_setregvec2_02i(uint idx, Vec2* value);
+void ssrS_setregvec3_01i(uint idx, Vec3* value);
+void ssrS_setregvec3_02i(uint idx, Vec3* value);
+
+Vec4* ssrS_getregvec4_01i(uint idx);
+Vec4* ssrS_getregvec4_02i(uint idx);
+Vec2* ssrS_getregvec2_01i(uint idx);
+Vec2* ssrS_getregvec2_02i(uint idx);
+Vec3* ssrS_getregvec3_01i(uint idx);
+Vec3* ssrS_getregvec3_02i(uint idx);
+
+Vec4* ssrS_getregvec4_01(Vert* vert);
+Vec4* ssrS_getregvec4_02(Vert* vert);
+Vec2* ssrS_getregvec2_01(Vert* vert);
+Vec2* ssrS_getregvec2_02(Vert* vert);
+Vec3* ssrS_getregvec3_01(Vert* vert);
+Vec3* ssrS_getregvec3_02(Vert* vert);
+
+#endif \ No newline at end of file
diff --git a/src/core/tris.c b/src/core/tris.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/core/tris.c
diff --git a/src/core/tris.h b/src/core/tris.h
new file mode 100644
index 0000000..1f4208f
--- /dev/null
+++ b/src/core/tris.h
@@ -0,0 +1,17 @@
+#ifndef _SOFTSHADEROOM_TRIS_H_
+#define _SOFTSHADEROOM_TRIS_H_
+
+#include "../util/type.h"
+
+/* 用索引表示的三角形,在一系列顶点中索引 */
+typedef union Triangle
+{
+ uint v[3];
+ struct {
+ uint v1, v2, v3;
+ };
+} Triangle;
+
+
+
+#endif \ No newline at end of file
diff --git a/src/core/vert.c b/src/core/vert.c
new file mode 100644
index 0000000..0e62087
--- /dev/null
+++ b/src/core/vert.c
@@ -0,0 +1,42 @@
+#include "vert.h"
+
+Vert* vert_new(uint comp) {
+ Vert* vert = ssrM_new(Vert);
+ vert->comp = comp;
+ vert->position = ssrM_new(Vec3);
+ vert->normal = ssrM_new(Vec3);
+ vert->tangent = ssrM_new(Vec3);
+ vert->uv = ssrM_new(Vec2);
+ return vert;
+}
+
+void vert_init(Vert* v, uint comp) {
+ ssr_assert(v);
+ v->comp = comp;
+ v->index = 0;
+ if ((comp & VERTMASK_POSITION) && !v->position)
+ v->position = ssrM_new(Vec3);
+ else if (!(comp & VERTMASK_POSITION) && v->position)
+ ssrM_free(v->position);
+ if ((comp & VERTMASK_NORMAL) && !v->normal)
+ v->normal = ssrM_new(Vec3);
+ else if (!(comp & VERTMASK_NORMAL) && v->normal)
+ ssrM_free(v->normal);
+ if ((comp & VERTMASK_TANGENT) && !v->tangent)
+ v->tangent = ssrM_new(Vec3);
+ else if (!(comp & VERTMASK_TANGENT) && v->tangent)
+ ssrM_free(v->tangent);
+ if ((comp & VERTMASK_UV) && !v->uv)
+ v->uv = ssrM_new(Vec2);
+ else if (!(comp & VERTMASK_UV) && v->uv)
+ ssrM_free(v->uv);
+}
+
+void vert_free(Vert* v) {
+ ssr_assert(v);
+ if (v->position) ssrM_free(v->position);
+ if (v->normal) ssrM_free(v->normal);
+ if (v->tangent) ssrM_free(v->tangent);
+ if (v->uv) ssrM_free(v->uv);
+ ssrM_free(v);
+} \ No newline at end of file
diff --git a/src/core/vert.h b/src/core/vert.h
new file mode 100644
index 0000000..a2fdb74
--- /dev/null
+++ b/src/core/vert.h
@@ -0,0 +1,48 @@
+#ifndef _SOFTSHADEROOM_VERT_H_
+#define _SOFTSHADEROOM_VERT_H_
+
+#include "mem.h"
+#include "color.h"
+#include "../math/math.h"
+#include "../util/type.h"
+#include "../util/assert.h"
+
+//typedef uint Color; // ARGB by default
+
+typedef uint Color; // ARGB by default
+
+#define COLOR_A(c) ((c >> 24) & 0xff)
+#define COLOR_R(c) ((c >> 16) & 0xff)
+#define COLOR_G(c) ((c >> 8) & 0xff)
+#define COLOR_B(c) (c & 0xff)
+
+typedef Vec4 Color32; // 4个float的颜色
+
+Color color32_tocolor(Color32* c);
+void color_tocolor32(Color c, Color32* out);
+void color32_saturate(Color32* c);
+
+enum VertMask {
+ VERTMASK_POSITION = 1 ,
+ VERTMASK_NORMAL = 1 << 1,
+ VERTMASK_COLOR = 1 << 2,
+ VERTMASK_TANGENT = 1 << 3,
+ VERTMASK_UV = 1 << 4,
+};
+
+/*标准的顶点结构,禁止修改*/
+typedef struct Vert {
+ uint index;
+ uint comp;
+ Vec3* position;
+ Vec3* normal;
+ Vec3* tangent;
+ Vec2* uv;
+ Color color;
+} Vert;
+
+Vert* vert_new(uint comp); /*新建vert*/
+void vert_init(Vert* v, uint comp); /*如果某些component没创建,创建它*/
+void vert_free(Vert* v); /*释放vert*/
+
+#endif \ No newline at end of file
diff --git a/src/example/example.h b/src/example/example.h
new file mode 100644
index 0000000..7879257
--- /dev/null
+++ b/src/example/example.h
@@ -0,0 +1,21 @@
+#ifndef _SSR_EXAMPLE_H_
+#define _SSR_EXAMPLE_H_
+
+#include "../ssr.h"
+#include "../util/type.h"
+#include "SDL2/SDL.h"
+
+#define EXAMPLE(i)\
+extern void onload##i(void*);\
+extern void onevent##i(void*);\
+extern void onupdate##i(void*);\
+extern void ondraw##i(void*);
+
+#define EXAMPLECUR texture
+
+EXAMPLE(cube);
+EXAMPLE(line);
+EXAMPLE(dot);
+EXAMPLE(texture);
+
+#endif \ No newline at end of file
diff --git a/src/example/example_cube.c b/src/example/example_cube.c
new file mode 100644
index 0000000..caedd64
--- /dev/null
+++ b/src/example/example_cube.c
@@ -0,0 +1,73 @@
+#include "example.h"
+
+/*正方体*/
+Vec3 verts[] = {
+ // front face
+ {1, 1, 1}, {-1, 1, 1}, {-1, -1, 1}, {1, -1, 1},
+ // back face
+ {1, 1, -1}, {-1, 1, -1}, {-1, -1, -1}, {1, -1, -1},
+};
+
+Color colors[] = {
+ 0xffff0000, 0xff00ff00, 0xffff00ff, 0xff00ffff,
+ 0xff0000ff, 0xff000000, 0xffffff00, 0xffffffff,
+};
+
+int cube[] = {
+ 0, 2, 1, 0, 3, 2,
+ 1, 2, 5, 2, 6, 5,
+ 4, 5, 6, 4, 6, 7,
+ 0, 4, 7, 0, 7, 3,
+ 0, 1, 4, 1, 5, 4,
+ 2, 3, 6, 3, 7, 6
+};
+Mat4 m;
+void onloadcube(void* data) {
+}
+
+void oneventcube(void* data) {
+ SDL_Event* e = (SDL_Event*)data;
+}
+
+float _t = 0;
+
+void onupdatecube(void*data) {
+ uint dt = *(uint*)data;
+ ssr_matrixmode(MATRIX_MODEL);
+ ssr_loadidentity();
+ ssr_translate(0, 0, -3);
+ ssr_rotate(360 * sin(_t += 0.001f), 1, 1, 1);
+ ssr_matrixmode(MATRIX_PROJECTION);
+ ssr_loadidentity();
+ ssr_perspective(100 + 20 * sin(_t * 10), 1.25f, -0.1f, -100);
+ ssr_matrixmode(MATRIX_VIEW);
+ ssr_loadidentity();
+ Vec3 pos = { 0,0,0 }, target = { 0,0,-1 }, up = { 0,1,0 };
+ ssr_lookat(&pos, &target, &up);
+ ssr_getmvp(&m);
+}
+
+void ondrawcube(void*data) {
+ ssr_clearcolor(0);
+ Vec2 proj[8];
+
+ for (int i = 0; i < 8; ++i) {
+ Vec4 v = { verts[i].x, verts[i].y ,verts[i].z ,1 }, temp;
+ mat4_applytovec4(&m, &v, &temp);
+ temp.x /= temp.w;
+ temp.y /= temp.w;
+ temp.z /= temp.w;
+ //vec4_print(&temp);
+ proj[i].x = temp.x;
+ proj[i].y = temp.y;
+ }
+ for (int j = 1; j < sizeof(cube) / sizeof(int); ++j) {
+ int fromx = proj[cube[j]].x * 250.f + 250, fromy = 200 - proj[cube[j]].y * 200.f;
+ int tox = proj[cube[j - 1]].x * 250.f + 250, toy = 200 - proj[cube[j - 1]].y * 200.f;
+ ssrR_putline(fromx, fromy , tox, toy, 0xffff0000);
+ }
+
+ Vec2 v1 = { 0, 0 }, v2 = { 3, 1 }, v3 = {1, 5};
+ float area = ssrR_area(&v1, &v2, &v3);
+ printf("%f\n", area);
+}
diff --git a/src/example/example_dot.c b/src/example/example_dot.c
new file mode 100644
index 0000000..0a88084
--- /dev/null
+++ b/src/example/example_dot.c
@@ -0,0 +1,36 @@
+#include "example.h"
+#include "../core/rasterizer.h"
+
+Vec3 pos = { 0, 0, 2 }, target = { 0,0,-1 }, up = { 0, 1, 0 };
+
+float dot[] = { 0, 0, -2 };
+
+void onloaddot(void* data) {
+
+}
+
+void oneventdot(void* data) {
+ SDL_Event* e = (SDL_Event*)data;
+}
+
+void onupdatedot(void*data) {
+ uint dt = *(uint*)data;
+ ssr_matrixmode(MATRIX_VIEW);
+ ssr_lookat(&pos, &target, &up);
+ ssr_matrixmode(MATRIX_PROJECTION);
+}
+
+float j = 0;
+
+void ondrawdot(void*data) {
+ ssr_clearcolor(0xffffffff);
+
+ //for (int i = -50; i < 200; ++i) {
+ // ssr_putpoint(i * sin(j += 0.1f), 300 * cos(j), ssr_color(0xff, 0, 0xff, 0));
+ //}
+
+ ssrR_putline(-100, 0, 100, 200, 0xffff0000);
+
+// printf("%u\n", (UINT_MAX * (double)0.5F));
+
+}
diff --git a/src/example/example_texture.c b/src/example/example_texture.c
new file mode 100644
index 0000000..5411a12
--- /dev/null
+++ b/src/example/example_texture.c
@@ -0,0 +1,101 @@
+#include "example.h"
+
+Vert** quad;
+static Vec3 verts[] = {
+ // front face
+ {1, 1, 1}, {-1, 1, 1}, {-1, -1, 1}, {1, -1, 1},
+ // back face
+ {1, 1, -1}, {-1, 1, -1}, {-1, -1, -1}, {1, -1, -1},
+};
+static Color colors[] = {
+ 0xffff0000, 0xff00ff00, 0xff0000ff, 0xffff00ff,
+ 0xffaa28aa, 0xffFFC58E, 0xffA100FF, 0xffFAFF00,
+};
+
+int face[] = {
+ 0, 1, 2, 0, 2, 3,
+ 1, 5, 2, 2, 5, 6,
+ 4, 6, 5, 4, 7, 6,
+ 0, 7, 4, 0, 3, 7,
+ 0, 4, 1, 1, 4, 5,
+ 2, 6, 3, 3, 6, 7
+};
+
+static Mat4 m;
+
+void vert(UniformCollection* uniforms, VertexShaderIn* in, Vec4* homocoord) {
+ static Vec4 p; p.xyz = *in->vertex->position; p.w = 1;
+ mat4_applytovec4(uniforms->mvp, &p, homocoord);
+}
+bool frag(UniformCollection* uniforms, FragmentShaderIn* in, Color* color) {
+ ssrS_bcpcolor(in->bc, in->A->color, in->B->color, in->C->color, color);
+ //ssrum4(1);
+ //Vec2 uv;
+ //ssrS_bcpvec2(in->bc, in->A->uv, in->B->uv, in->C->uv, &uv);
+ //int x = uv.x * 10;
+ //int y = uv.y * 10;
+ //if (x % 2 && y % 2) {
+ // *color = 0xffffffff;
+ //} else {
+ // *color = 0xff111111;
+ //}
+ return 0;
+}
+Program program = { vert, frag };
+
+void onloadtexture(void* data) {
+ ssr_matrixmode(MATRIX_PROJECTION);
+ ssr_loadidentity();
+ ssr_perspective(100, 1.25f, 0.1f, 10);
+ ssr_matrixmode(MATRIX_VIEW);
+ ssr_loadidentity();
+ //Vec3 pos = { 0,0,0 }, target = { 0,0,-1 }, up = { 0,1,0 };
+ //ssr_lookat(&pos, &target, &up);
+
+ /*设置顶点数据*/
+ quad = ssrM_newvector(Vert*, 8);
+ quad[0] = vert_new(VERTMASK_POSITION | VERTMASK_COLOR);
+ quad[1] = vert_new(VERTMASK_POSITION | VERTMASK_COLOR);
+ quad[2] = vert_new(VERTMASK_POSITION | VERTMASK_COLOR);
+ quad[3] = vert_new(VERTMASK_POSITION | VERTMASK_COLOR);
+ quad[4] = vert_new(VERTMASK_POSITION | VERTMASK_COLOR);
+ quad[5] = vert_new(VERTMASK_POSITION | VERTMASK_COLOR);
+ quad[6] = vert_new(VERTMASK_POSITION | VERTMASK_COLOR);
+ quad[7] = vert_new(VERTMASK_POSITION | VERTMASK_COLOR);
+ *quad[0]->position = verts[0]; quad[0]->color = colors[0]; quad[0]->index = 0;
+ *quad[1]->position = verts[1]; quad[1]->color = colors[1]; quad[1]->index = 1;
+ *quad[2]->position = verts[2]; quad[2]->color = colors[2]; quad[2]->index = 2;
+ *quad[3]->position = verts[3]; quad[3]->color = colors[3]; quad[3]->index = 3;
+ *quad[4]->position = verts[4]; quad[4]->color = colors[4]; quad[4]->index = 4;
+ *quad[5]->position = verts[5]; quad[5]->color = colors[5]; quad[5]->index = 5;
+ *quad[6]->position = verts[6]; quad[6]->color = colors[6]; quad[6]->index = 6;
+ *quad[7]->position = verts[7]; quad[7]->color = colors[7]; quad[7]->index = 7;
+
+ ssr_bindvertices(quad, 8, face, 12);
+
+ ssr_useprogram(&program);
+ ssr_enable(ENABLEMASK_BACKFACECULL);
+ ssr_enable(ENABLEMASK_DEPTHTEST);
+}
+
+void oneventtexture(void* data) {
+ SDL_Event* e = (SDL_Event*)data;
+}
+
+static float _t = 0;
+
+void onupdatetexture(void*data) {
+ uint dt = *(uint*)data;
+ ssr_matrixmode(MATRIX_MODEL);
+ ssr_loadidentity();
+ ssr_translate(0, 0, -3);
+// ssr_rotate(-30, 1, 1, 0);
+ ssr_rotate(360 * sin(_t += dt/5000.f), 1, 1, 0);
+}
+
+void ondrawtexture(void*data) {
+ ssr_clearcolor(0x00);
+ ssr_cleardepth();
+
+ ssr_draw(PRIMITIVE_TRIANGLE);
+}
diff --git a/src/extend/camera.c b/src/extend/camera.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/extend/camera.c
diff --git a/src/extend/camera.h b/src/extend/camera.h
new file mode 100644
index 0000000..4f4ba47
--- /dev/null
+++ b/src/extend/camera.h
@@ -0,0 +1,10 @@
+#ifndef _SOFTSHADEROOM_CAMERA_H_
+#define _SOFTSHADEROOM_CAMERA_H_
+
+#include "../math/math.h"
+
+typedef struct Camera {
+ Vec3 front;
+} Camera;
+
+#endif \ No newline at end of file
diff --git a/src/extend/transform.c b/src/extend/transform.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/extend/transform.c
diff --git a/src/extend/transform.h b/src/extend/transform.h
new file mode 100644
index 0000000..b366305
--- /dev/null
+++ b/src/extend/transform.h
@@ -0,0 +1,14 @@
+#include "../math/math.h"
+
+/*
+** Transform要注意按 scale -> rotation -> position 顺序计算
+*/
+typedef struct Transform {
+ Vec3 position;
+ Vec3 scale;
+ Quat rotation;
+} Transform;
+
+void transformtranslate(Transform* trans, Vec4* v, Vec4* out);
+
+Vec4 transform_translate(Transform* trans, Vec4* v);
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..d06803a
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,74 @@
+#include <SDL2/SDL.h>
+#include <stdio.h>
+#include <windows.h>
+#include "math/math.h"
+#include "util/assert.h"
+#include "ssr.h"
+#include "example/example.h"
+
+SDL_Surface* suf;
+
+#define SCREEN_WIDTH 500
+#define SCREEN_HEIGHT 400
+
+typedef void(*F)(void*);
+F onload;
+F onupdate;
+F onevent;
+F ondraw;
+
+/*macro这里需要绕一下弯*/
+/*https://stackoverflow.com/questions/1489932/how-to-concatenate-twice-with-the-c-preprocessor-and-expand-a-macro-as-in-arg*/
+#define SETEXAMPLEF(f, e) \
+f = f##e;
+
+#define SETEXAMPLE(i) \
+SETEXAMPLEF(onload, i)\
+SETEXAMPLEF(ondraw, i)\
+SETEXAMPLEF(onevent, i)\
+SETEXAMPLEF(onupdate, i)
+
+int main(int argc, char* argv[])
+{
+ if (SDL_Init(SDL_INIT_VIDEO) < 0)
+ return 1;
+ SDL_Window* wnd = SDL_CreateWindow("Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
+ SDL_Event e;
+ suf = SDL_GetWindowSurface(wnd);
+ /* ARGB format */
+ ssr_assert(suf->format->BitsPerPixel == 32);
+ ssr_assert(suf->format->Rshift == 16);
+ ssr_assert(suf->format->Gshift == 8);
+ ssr_assert(suf->format->Bshift == 0);
+ /* init ssr */
+ ssr_Config config = {
+ SCREEN_WIDTH, SCREEN_HEIGHT,/* screen size */
+ 0, /* double buffer */
+ suf->pixels /* screen buffer */
+ };
+ ssr_init(&config);
+ SETEXAMPLE(EXAMPLECUR);
+ onload(0);
+ /* main loop */
+ uint previous = SDL_GetTicks();
+ uint dt = 0;
+ while (1) {
+ while (SDL_PollEvent(&e)) {
+ if (e.type == SDL_QUIT) {
+ goto quit;
+ } else {
+ onevent(&e);
+ }
+ }
+ dt = SDL_GetTicks() - previous;
+ previous = dt + previous;
+ onupdate(&dt);
+ ondraw(0);
+ ssr_present();
+ SDL_UpdateWindowSurface(wnd);
+ Sleep(10); /*100fps limit*/
+ }
+ quit:
+ SDL_Quit();
+ return 0;
+}
diff --git a/src/math/math.c b/src/math/math.c
new file mode 100644
index 0000000..4cca29e
--- /dev/null
+++ b/src/math/math.c
@@ -0,0 +1,21 @@
+#include "math.h"
+
+char printbuffer[2048] = { 0 };
+
+float rsqrt(float number) {
+ long i;
+ float x2, y;
+ const float threehalfs = 1.5F;
+
+ x2 = number * 0.5F;
+ y = number;
+ i = *(long *)&y;
+ i = 0x5f3759df - (i >> 1);
+ y = *(float *)&i;
+ y = y * (threehalfs - (x2 * y * y));
+ return y;
+}
+
+float lerp(float a, float b, float t) {
+ return a * (1 - t) + b * t;
+} \ No newline at end of file
diff --git a/src/math/math.h b/src/math/math.h
new file mode 100644
index 0000000..4498920
--- /dev/null
+++ b/src/math/math.h
@@ -0,0 +1,306 @@
+#ifndef _SOFTSHADEROOM_MATH_H_
+#define _SOFTSHADEROOM_MATH_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <limits.h>
+
+#include "../util/type.h"
+
+#define PI 3.141592653f
+#define RAD2DEG 57.295779523f /*180.f/PI*/
+#define DEG2RAG 0.0174532925f /*PI/180.f*/
+#define EPSILON 0.000001f
+
+/* 用来打印的公共buffer */
+extern char printbuffer[2048];
+
+/*
+** 数学函数
+*/
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define clamp(v, l, h) ((v) > (l) ? ((v) < (h) ? (v) : (h)) : (l))
+#define absf(v) ((v )> 0 ? (v ): -(v))
+#define radians(angle) (angle * DEG2RAG)
+#define degree(rad) (rad * RAD2DEG)
+#define compare(v1, v2) (absf((v1) - (v2)) < EPSILON)
+#define swapi(a, b) {int temp = a; a = b; b = temp;}
+float rsqrt(float n);
+float lerp(float from, float to, float t);
+
+/*
+** 二维向量,用来做屏幕上的一些计算
+*/
+typedef struct Vec2 {
+ float x, y;
+} Vec2;
+
+/*
+** 三维向量,用来做三维空间的计算
+*/
+typedef union Vec3 {
+ struct {
+ float x, y, z;
+ };
+ struct {
+ float A, B, C; /*重心坐标*/
+ };
+ Vec2 xy;
+} Vec3;
+
+/*
+** 齐次坐标,列主项,平移变换和透视投影需要
+*/
+typedef union Vec4 {
+ struct {
+ float x, y, z, w;
+ };
+ struct {
+ float r, g, b, a;
+ };
+ Vec3 xyz;
+} Vec4;
+
+/*
+** 用来可视化四元数,欧拉角默认使用角度存储,用euler_deg2rad()转弧度
+*/
+typedef union Euler {
+ struct {
+ float x, y, z;
+ };
+ struct {
+ float pitch, yaw, roll;
+ };
+} Euler;
+
+/*
+** 四元数,用来做旋转变换。在进行变换复合以及插值的时候用,但最终还是需要通过quat_mat4转换成矩阵和其他变换矩阵
+** 一起对向量进行变换
+*/
+typedef struct Quat {
+ float x, y, z, w;
+} Quat;
+
+/*
+** 4x4矩阵,列主项,用来做平移和缩放变换。之所以用列主序存储,是为了快速读取矩阵的基向量
+*/
+typedef union Mat4 {
+ float l[16];
+ float m[4][4];
+ struct {
+ float
+ e00, e10, e20, e30, /*colum 0*/
+ e01, e11, e21, e31,
+ e02, e12, e22, e32,
+ e03, e13, e23, e33;
+ };
+ struct {
+ Vec4 x;/*colum 0*/
+ Vec4 y;
+ Vec4 z;
+ Vec4 w;
+ } axis; /*轴*/
+ struct {
+ Vec4 x;/*colum 0*/
+ Vec4 y;
+ Vec4 z;
+ Vec4 w;
+ } basis; /*基向量*/
+ struct {
+ Vec4 axisx;
+ Vec4 axisy;
+ Vec4 axisz;
+ Vec4 pos;
+ };
+ Vec4 colums[4];
+} Mat4;
+
+typedef union Mat3 {
+ struct {
+ float
+ e00, e10, e20, /*colum 0*/
+ e01, e11, e21,
+ e02, e12, e22;
+ };
+} Mat3;
+
+typedef union Mat23 {
+ struct {
+ float
+ e00, e10, /*colum 0*/
+ e01, e11,
+ e02, e12;
+ };
+} Mat23;
+
+typedef union Mat43 {
+ struct {
+ float
+ e00, e10, e20, e30, /*colum 0*/
+ e01, e11, e21, e31,
+ e02, e12, e22, e32;
+ };
+ struct { /*三个齐次裁剪坐标*/
+ Vec4 p1;
+ Vec4 p2;
+ Vec4 p3;
+ };
+} Mat43;
+
+//#define MAT(m, r, c) (m->l[r + (c<<2)])
+#define MAT(M, r, c) (M->m[c][r])
+/************************************************************************/
+/* Vec */
+/************************************************************************/
+
+void vec2_scale(Vec2* v, float k, Vec2* out);
+void vec2_plus(Vec2* v1, Vec2* v2, Vec2* out);
+void vec2_offset(Vec2* v, float offset, Vec2* out);
+void vec2_rotate(Vec2* v, float angle, Vec2* out);
+
+float vec2_dot(Vec2* v1, Vec2* v2);
+
+void vec2_tostring(Vec2* v, char buf[]);
+void vec2_print(Vec2* v);
+
+#define vec3_xy(v) (v->xy)
+
+extern Vec3 vec3forward; /*(0,0,1)*/
+extern Vec3 vec3up; /*(0,1,0)*/
+extern Vec3 vec3left;/*(1,0,0)*/
+
+void vec3_tostring(Vec3* v, char buf[]);
+void vec3_print(Vec3* v);
+
+float vec3_intersection(Vec3* v1, Vec3* v2); /*夹角*/
+void vec3_projection(Vec3* v1, Vec3* v2, Vec3* out);/*v1在v2上的投影*/
+void vec3_scale(Vec3* v, float k, Vec3* out);
+void vec3_plus(Vec3* v1, Vec3* v2, Vec3* out);
+void vec3_offset(Vec3* v, float offset, Vec3* out);
+void vec3_normalize(Vec3* v, Vec3* out);
+void vec3_vec4(float w, Vec4* out);
+
+void vec3_minus(Vec3* v1, Vec3* v2, Vec3* out);
+float vec3_dot(Vec3* v1, Vec3* v2);
+void vec3_cross(Vec3* v1, Vec3* v2, Vec3* out);
+void vec3_multiply(Vec3* v1, Vec3* v2, Quat* out);// 向量的乘法,st=sxt-s*t,结果是一个四元数
+
+float vec3_magnitude(Vec3* v1);
+float vec3_magnitude2(Vec3* v1);
+
+void vec3_lerp(Vec3* v1, Vec3* v2, float t, Vec3* out);
+void vec3_slerp(Vec3* v1, Vec3* v2, float t, Vec3* out);
+
+void vec4_dividew(Vec4* v, Vec3* out);
+
+void vec4_tostring(Vec4* v, char buf[]);
+void vec4_print(Vec4* v);
+
+/************************************************************************/
+/* Matrix */
+/************************************************************************/
+
+extern Mat4 mat4identity;
+
+void mat4_tostring(Mat4* m, char str[]);
+void mat4_print(Mat4* m);
+
+void mat4_zero(Mat4* out);
+void mat4_setidentity(Mat4* out);
+void mat4_setfrustum(float l, float r, float b, float t, float n, float f, Mat4* out);
+void mat4_setperspective(float fov, float aspect, float near, float far, Mat4* out);
+void mat4_setscale(float kx, float ky, float kz, Mat4* out);
+void mat4_setposition(float x, float y, float z, Mat4* out);
+void mat4_setrotatez(float angle, Mat4* out);
+void mat4_setrotatex(float angle, Mat4* out);
+void mat4_setrotatey(float angle, Mat4* out);
+void mat4_setrotate(float angleX, float angleY, float angleZ, Mat4* out);/*RyRxRz*/
+void mat4_setaxisangle(Vec3* axis, float angle, Mat4* out);
+
+bool mat4_setlookrotation(Vec3* view, Vec3* up, Mat4* out);
+void mat4_setorthonormalbias(Vec3* x, Vec3* y, Vec3* z, Mat4* out); /*正交的三个轴*/
+
+void mat4_orthogonalize(Mat4* in, Mat4* out); /*解决矩阵蠕变,对左上角3x3矩阵进行正交化,结果是右手系的正交矩阵*/
+bool mat4_isorthogonal(Mat4* m); /*判断是不是正交矩阵*/
+bool mat4_isidentity(Mat4* m);
+
+void mat4_settr(Vec3* pos, Quat* rot, Mat4* out); /*用旋转和平移初始化mat4*/
+void mat4_settrs(Vec3* pos, Quat* rot, Vec3* scale, Mat4* out);
+void mat4_settrinverse(Vec3* pos, Quat* rot, Mat4* out);
+
+void mat4_multiply(Mat4* m1, Mat4* m2, Mat4* out); /* m1的行乘m2的列,意义是用m1变换m2 */
+
+void mat4_transpose(Mat4* m, Mat4* out);
+
+void mat4_scale(Mat4* m, Vec3* scale, Mat4* out);/* 后乘post-multiply scale */
+void mat4_translate(Mat4* m, Vec3* pos, Mat4* out); /* 后乘post-multiply translate */
+void mat4_rotate(Mat4*m, float angle, Vec3* rot, Mat4* out);/*后乘绕任意轴向量旋转矩阵*/
+
+bool mat4_invertfull(Mat4* in, Mat4* out); /* 并不是所有矩阵都能求逆 */
+bool mat4_invertgeneral3d(Mat4* in, Mat4* out); /* 对scale rotate translate求逆 */
+void mat4_invertscale(Mat4* scale, Mat4* out); /* 对缩放矩阵求逆 */
+void mat4_invertrot(Mat4* rot, Mat4* out); /* 对旋转矩阵求逆 */
+void mat4_invertpos(Mat4* pos, Mat4* out); /* 对平移矩阵求逆 */
+
+void mat4_decomposetrs(Mat4* src, Vec3* pos, Quat* quat, Vec3* scale); /*分解trs矩阵*/
+
+void mat4_applytovec4(Mat4* m, Vec4* v, Vec4* out);
+
+bool mat4_toeuler(Mat4* in, Euler* out); /* 计算YXZ旋转矩阵的欧拉角 */
+void mat4_toquat(Mat4* in, Quat* out); /*in是正交矩阵*/
+
+#define ROWMAT(A, ...)\
+Mat4 A={__VA_ARGS__};mat4_transpose(&A, &A);
+
+void mat3_applytovec3(Mat3* m, Vec3* v, Vec3* out);
+void mat23_applytovec3(Mat23* m, Vec3* v, Vec2* out);
+void mat43_applytovec3(Mat43* m, Vec3* v, Vec4* out);
+
+/************************************************************************/
+/* Quat */
+/************************************************************************/
+
+void quat_tostring(Quat* q, char str[]);
+void quat_print(Quat* q);
+
+void euler_toquat(Euler* e, Quat* out);
+void euler_deg2rad(Euler* in, Euler* out);
+void euler_rad2deg(Euler* in, Euler* out);
+
+void euler_tostring(Euler* v, char buf[]);
+void euler_print(Euler* v);
+
+void quat_fromaxisangle(Vec3* axis, float angle, Quat* out); /*轴角转四元数*/
+void quat_fromeuler(Euler* euler, Quat* out); /*按照zxy顺序*/
+
+void quat_tomat4(Quat* q, Mat4* out);
+void quat_toeuler(Quat*q, Euler* out);
+
+void quat_normalize(Quat* q, Quat* out); /*解决蠕变,保持四元数合法*/
+
+void quat_scale(Quat* q, float scale, Quat* out);
+void quat_rotate();
+
+void quat_minus(Quat* q1, Quat* q2, Quat* out);
+void quat_slerp(Quat* start, Quat* end, float t, Quat* out);
+void quat_lerp(Quat* start, Quat* end, float t, Quat* out);
+void quat_translate(Quat* q, Vec4* v, Vec4* out);
+void quat_invert(Quat* q, Quat* out);
+float quat_dot(Quat* q1, Quat* q2);
+void quat_multiply(Quat* q1, Quat* q2, Quat* out);
+void quat_devide(Quat* q, float k, Quat* out);
+void quat_negtive(Quat* in, Quat* out);
+bool quat_isidentity(Quat* q);
+
+void quat_applytovec3(Quat* q, Vec3* v, Vec3* out); /*用四元数直接旋转向量*/
+
+void quat_conjugate(Quat* in, Quat* out);
+
+bool quat_setlookrotation(Vec3* view, Vec3* up, Quat* out);
+
+float quat_magnitude(Quat* q);
+float quat_magnitude2(Quat* q);
+
+#endif \ No newline at end of file
diff --git a/src/math/matrix.c b/src/math/matrix.c
new file mode 100644
index 0000000..458f432
--- /dev/null
+++ b/src/math/matrix.c
@@ -0,0 +1,741 @@
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "math.h"
+#include "../util/assert.h"
+#include "../core/mem.h"
+
+
+static Mat4 sharedMat;
+static Mat4 sharedMat2;
+static Vec4 sharedVec4;
+
+Mat4 mat4identity = {
+ 1,0,0,0,
+ 0,1,0,0,
+ 0,0,1,0,
+ 0,0,0,1
+};
+
+#define shrmat(p) \
+do{\
+sharedMat = *p;\
+p = &sharedMat;\
+}while(0)
+
+#define shrmat2(p) \
+do{\
+sharedMat2 = *p;\
+p = &sharedMat2;\
+}while(0)
+
+void mat4_tostring(Mat4* m, char str[]) {
+ ssrM_zero(str, sizeof(str));
+ for (int r = 0; r < 4; ++r) {
+ for (int c = 0; c < 4; ++c) {
+ sprintf(str, "%8.3f ", MAT(m, r, c) == -0 ? +0 : MAT(m, r, c));
+ str += strlen(str);
+ }
+ if(r != 3) sprintf(str, "\n");
+ str += strlen(str);
+ }
+}
+
+void mat4_print(Mat4* m) {
+ mat4_tostring(m, printbuffer);
+ printf("\n%s\n", printbuffer);
+}
+
+void mat4_zero(Mat4* out) {
+ ssr_assert(out);
+ ssrM_zero(out, sizeof(Mat4));
+}
+
+void mat4_setidentity(Mat4* out) {
+ ssr_assert(out);
+ mat4_zero(out);
+ out->e00 = 1;
+ out->e11 = 1;
+ out->e22 = 1;
+ out->e33 = 1;
+}
+
+void mat4_setfrustum(float l, float r, float b, float t, float n, float f, Mat4* out) {
+ ssr_assert(out);
+ mat4_zero(out);
+ out->e00 = (2.f * n) / (r - l);
+ out->e02 = (r + l) / (r - l);
+ out->e11 = 2.f * n / (t - b);
+ out->e12 = (t + b) / (t - b);
+ out->e22 = -(f + n) / (f - n);
+ out->e23 = -2.f * f * n / (f - n);
+ out->e32 = -1;
+}
+
+void mat4_setperspective(float _fov, float aspect, float near, float far, Mat4* out) {
+ float fov = _fov * PI / 180.f;
+ float tanf = tan(fov * 0.5);
+ mat4_setfrustum(
+ -near*tanf*aspect,
+ near*tanf*aspect,
+ -near*tanf,
+ near*tanf,
+ near,
+ far,
+ out
+ );
+}
+
+static float _mul(float* r, float* c) {
+ return c[0] * r[0] + c[1] * r[4] + c[2] * r[8] + c[3] * r[12];
+}
+
+#define mul(r, c) _mul(&MAT(m1,r,0), &MAT(m2,0,c))
+
+void mat4_multiply(Mat4* m1, Mat4* m2, Mat4* out) {
+ ssr_assert(m1 && m2 && out);
+ if (mat4_isidentity(m1)) { if(m2 != out) *out = *m2; return; }
+ if (mat4_isidentity(m2)) { if(m1 != out) *out = *m1; return; }
+ if (m1 == out) shrmat(m1);
+ if (m2 == out) shrmat2(m2);
+
+ out->e00 = mul(0, 0); out->e01 = mul(0, 1); out->e02 = mul(0, 2); out->e03 = mul(0, 3);
+ out->e10 = mul(1, 0); out->e11 = mul(1, 1); out->e12 = mul(1, 2); out->e13 = mul(1, 3);
+ out->e20 = mul(2, 0); out->e21 = mul(2, 1); out->e22 = mul(2, 2); out->e23 = mul(2, 3);
+ out->e30 = mul(3, 0); out->e31 = mul(3, 1); out->e32 = mul(3, 2); out->e33 = mul(3, 3);
+}
+
+void mat4_setscale(float kx, float ky, float kz, Mat4* out) {
+ ssr_assert(out);
+ mat4_zero(out);
+ out->e00 = kx;
+ out->e11 = ky;
+ out->e22 = kz;
+ out->e33 = 1;
+}
+
+void mat4_setposition(float x, float y, float z, Mat4* out) {
+ ssr_assert(out);
+ mat4_setidentity(out);
+ out->e03 = x;
+ out->e13 = y;
+ out->e23 = z;
+}
+
+void mat4_setrotatez(float angle, Mat4* out) {
+ ssr_assert(out);
+ mat4_setidentity(out);
+ angle = radians(angle);
+ float s = sin(angle), c = cos(angle);
+ out->e00 = c; out->e01 = -s;
+ out->e10 = s; out->e11 = c;
+}
+
+void mat4_setrotatex(float angle, Mat4* out) {
+ ssr_assert(out);
+ mat4_setidentity(out);
+ angle = radians(angle);
+ float s = sin(angle), c = cos(angle);
+ out->e11 = c; out->e12 = -s;
+ out->e21 = s; out->e22 = c;
+}
+
+void mat4_setrotatey(float angle, Mat4* out) {
+ ssr_assert(out);
+ mat4_setidentity(out);
+ angle = radians(angle);
+ float s = sin(angle), c = cos(angle);
+ out->e00 = c; out->e02 = s;
+ out->e20 = -s; out->e22 = c;
+}
+
+/*https://www.geometrictools.com/Documentation/EulerAngles.pdf*/
+void mat4_setrotate(float angleX, float angleY, float angleZ, Mat4* out) {
+ ssr_assert(out);
+ mat4_setidentity(out);
+ angleX = radians(angleX); angleY = radians(angleY); angleZ = radians(angleZ);
+ float sx = sin(angleX), cx = cos(angleX);
+ float sy = sin(angleY), cy = cos(angleY);
+ float sz = sin(angleZ), cz = cos(angleZ);
+ out->e00 = cy * cz + sx * sy * sz; out->e01 = cz * sx*sy - cy * sz; out->e02 = cx * sy;
+ out->e10 = cx * sz; out->e11 = cx * cz; out->e12 = -sx;
+ out->e20 = -cz * sy + cy * sx * sz; out->e21 = cy * cz*sx + sy * sz; out->e22 = cx * cy;
+}
+
+void mat4_setaxisangle(Vec3* ax, float angle, Mat4* out) {
+ ssr_assert(ax && out);
+
+ float a = radians(angle);
+ float c = cos(a);
+ float s = sin(a);
+
+ Vec3 axis = *ax;
+ Vec3 temp;
+ vec3_normalize(&axis, &axis);
+ vec3_scale(&axis, 1 - c, &temp);
+
+ /*
+ rotation matrix 推导过程 https://zhuanlan.zhihu.com/p/56587491
+ X^2(1-c)+c, XY(1-c)-Zs, XZ(1-c)+Ys, 0
+ XY(1-c)+Zs, Y^2(1-c)+c, YZ(1-c)-Xs, 0
+ XZ(1-c)-Ys, YZ(1-c)+Xs, Z^2(1-c)+c, 0
+ 0, 0, 0, 1
+ */
+
+ mat4_setidentity(out);
+ out->m[0][0] = c + temp.x * axis.x;
+ out->m[0][1] = 0 + temp.x * axis.y + s * axis.z;
+ out->m[0][2] = 0 + temp.x * axis.z - s * axis.y;
+
+ out->m[1][0] = 0 + temp.y * axis.x - s * axis.z;
+ out->m[1][1] = c + temp.y * axis.y;
+ out->m[1][2] = 0 + temp.y * axis.z + s * axis.x;
+
+ out->m[2][0] = 0 + temp.z * axis.x + s * axis.y;
+ out->m[2][1] = 0 + temp.z * axis.y - s * axis.x;
+ out->m[2][2] = c + temp.z * axis.z;
+
+}
+
+void mat4_setorthonormalbias(Vec3* x, Vec3* y, Vec3* z, Mat4* out) {
+ ssr_assert(x && y && z);
+ mat4_setidentity(out);
+ Vec4 asix = { x->x, x->y, x->z, 0 };
+ Vec4 asiy = { y->x, y->y, y->z, 0 };
+ Vec4 asiz = { z->x, z->y, z->z, 0 };
+ out->colums[0] = asix;
+ out->colums[1] = asiy;
+ out->colums[2] = asiz;
+}
+
+bool mat4_isidentity(Mat4* m) {
+ ssr_assert(m);
+ //return memcmp(m, &mat4identity, sizeof(Mat4)) == 0;
+ return
+ compare(m->axisx.x, 1) && compare(m->axisx.y, 0) && compare(m->axisx.z,0) && compare(m->axisx.w, 0) &&
+ compare(m->axisy.x, 0) && compare(m->axisy.y, 1) && compare(m->axisy.z,0) && compare(m->axisy.w, 0) &&
+ compare(m->axisz.x, 0) && compare(m->axisz.y, 0) && compare(m->axisz.z,1) && compare(m->axisz.w, 0) &&
+ compare(m->pos.x, 0 ) && compare(m->pos.y, 0 ) && compare(m->pos.z, 0 ) &&compare( m->pos.w, 1);
+}
+
+bool mat4_isorthogonal(Mat4* m) {
+ ssr_assert(m);
+ Mat4 trans = {0}, res = { 0 };
+ mat4_transpose(m, &trans);
+ mat4_multiply(m, &trans, &res);
+ return mat4_isidentity(&res);
+}
+
+/*
+** 以z轴为准进行正交化,分为施密特正交化和叉乘正交化,施密特过程更加普遍,叉乘适用于三维空间,两种方法实际上等价
+** 如果用叉乘的方法,只需要关注yz,x通过叉乘得到
+*/
+void mat4_orthogonalize(Mat4* in, Mat4* out) {
+ ssr_assert(in && out);
+ if (in == out) {
+ shrmat(in);
+ }
+
+ mat4_setidentity(out);
+ Vec4 z = in->basis.z;
+ vec3_normalize(&z, &z);
+ Vec4 y = in->basis.y;
+ Vec4 x = {0};
+ vec3_cross(&y, &z, &x);
+ vec3_normalize(&x, &x);
+ vec3_cross(&z, &x, &y);
+ out->basis.x = x;
+ out->basis.y = y;
+ out->basis.z = z;
+
+ /*
+ mat4_setidentity(out);
+
+ Vec4 x = in->basis.x;
+ Vec4 y = in->basis.y;
+ Vec4 z = in->basis.z;
+ Vec3 temp, temp2;
+
+ vec3_normalize(&z, &z);
+ out->basis.z = z;
+
+ float dot = vec3_dot(&y, &z);
+ vec3_scale(&z, dot, &temp);
+ vec3_minus(&y, &temp, &y);
+ vec3_normalize(&y, &y);
+ out->basis.y = y;
+
+ vec3_cross(&y, &z, &out->basis.x);
+ */
+ /*针对右手系调整basis.x的方向*/
+ /*https://math.stackexchange.com/questions/1847465/why-to-use-gram-schmidt-process-to-orthonormalise-a-basis-instead-of-cross-produ*/
+ /*由于需要针对右手系,这里不这样计算,因为可能要对结果进行翻转
+ dot = vec3_dot(&x, &z);
+ vec3_scale(&z, dot, &temp);
+ vec3_minus(&x, &temp, &temp2);
+ dot = vec3_dot(&x, &y);
+ vec3_scale(&y, dot, &temp);
+ vec3_minus(&temp2, &temp, &x);
+ vec3_normalize(&x, &x);
+ out->basis.x = x;
+ */
+}
+
+bool mat4_setlookrotation(Vec3* view, Vec3* up, Mat4* out) {
+ ssr_assert(view && up && out);
+
+ /*正交化*/
+ float mag = vec3_magnitude(view);
+ if (mag < EPSILON) return 0;
+ Vec3 z;
+ vec3_scale(view, 1.f / mag, &z);
+
+ Vec3 x;
+ vec3_cross(up, &z, &x);
+ mag = vec3_magnitude(&x);
+ if (mag < EPSILON) return 0;
+ vec3_scale(&x, 1.f / mag, &x);
+
+ Vec3 y;
+ vec3_cross(&z, &x, &y);
+ mag = vec3_magnitude(&y);
+ if (!compare(mag, 1)) return 0;
+
+ mat4_setorthonormalbias(&x, &y, &z, out); /*xyz正交*/
+
+ return 1;
+}
+
+void mat4_applytovec4(Mat4* mat, Vec4* v, Vec4* out) {
+ ssr_assert(mat && v && out);
+ if (v == out) {
+ sharedVec4 = *v;
+ v = &sharedVec4;
+ }
+ out->x = mat->e00 * v->x + mat->e01 * v->y + mat->e02 * v->z + mat->e03 * v->w;
+ out->y = mat->e10 * v->x + mat->e11 * v->y + mat->e12 * v->z + mat->e13 * v->w;
+ out->z = mat->e20 * v->x + mat->e21 * v->y + mat->e22 * v->z + mat->e23 * v->w;
+ out->w = mat->e30 * v->x + mat->e31 * v->y + mat->e32 * v->z + mat->e33 * v->w;
+}
+
+#define trans(r, c) out->e##r##c = m->e##c##r
+
+void mat4_transpose(Mat4* m, Mat4* out) {
+ ssr_assert(m && out);
+ if (m == out) shrmat(m);
+
+ trans(0, 0); trans(0, 1); trans(0, 2); trans(0, 3);
+ trans(1, 0); trans(1, 1); trans(1, 2); trans(1, 3);
+ trans(2, 0); trans(2, 1); trans(2, 2); trans(2, 3);
+ trans(3, 0); trans(3, 1); trans(3, 2); trans(3, 3);
+}
+
+/*
+** 使用高斯消元法计算任意矩阵的逆矩阵。针对不含投影的3D变换矩阵,应该使用
+** mat4_invertgeneral3d()
+** 更快一些
+*/
+bool mat4_invertfull(Mat4* m, Mat4* out) {
+ ssr_assert(m && out);
+
+#define _m(r, c) MAT(m, r, c)
+ float wtmp[4][8] = {
+ { /*M*/ _m(0,0), _m(0, 1), _m(0, 2), _m(0, 3), /*I*/ 1, 0, 0, 0 },
+ { /*M*/ _m(1,0), _m(1, 1), _m(1, 2), _m(1, 3), /*I*/ 0, 1, 0, 0 },
+ { /*M*/ _m(2,0), _m(2, 1), _m(2, 2), _m(2, 3), /*I*/ 0, 0, 1, 0 },
+ { /*M*/ _m(3,0), _m(3, 1), _m(3, 2), _m(3, 3), /*I*/ 0, 0, 0, 1 },
+ };
+#undef _m
+ float m0, m1, m2, m3, s;
+ float *r0, *r1, *r2, *r3;
+ r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
+#define SWAP_ROWS(a, b) { float *_tmp = a; (a)=(b); (b)=_tmp; }
+
+ //#define optimize(block) if(s!=0.f){block}
+#define optimize(block) block
+
+ /* choose pivot - or die */
+ if (absf(r3[0]) > absf(r2[0])) SWAP_ROWS(r3, r2);
+ if (absf(r2[0]) > absf(r1[0])) SWAP_ROWS(r2, r1);
+ if (absf(r1[0]) > absf(r0[0])) SWAP_ROWS(r1, r0);
+ if (0.0f == r0[0]) return 0;
+
+ /* eliminate first variable */
+ m1 = r1[0] / r0[0]; m2 = r2[0] / r0[0]; m3 = r3[0] / r0[0];
+ s = r0[1]; optimize(r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s; )
+ s = r0[2]; optimize(r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s; )
+ s = r0[3]; optimize(r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s; )
+ s = r0[4]; optimize(r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; )
+ s = r0[5]; optimize(r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; )
+ s = r0[6]; optimize(r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; )
+ s = r0[7]; optimize(r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; )
+
+ /* choose pivot - or die */
+ if (absf(r3[1]) > absf(r2[1])) SWAP_ROWS(r3, r2);
+ if (absf(r2[1]) > absf(r1[1])) SWAP_ROWS(r2, r1);
+ if (0.0F == r1[1]) return 0;
+
+ /* eliminate second variable */
+ m2 = r2[1] / r1[1]; m3 = r3[1] / r1[1];
+ s = r1[2]; optimize(r2[2] -= m2 * s; r3[2] -= m3 * s; )
+ s = r1[3]; optimize(r2[3] -= m2 * s; r3[3] -= m3 * s; )
+ s = r1[4]; optimize(r2[4] -= m2 * s; r3[4] -= m3 * s; )
+ s = r1[5]; optimize(r2[5] -= m2 * s; r3[5] -= m3 * s; )
+ s = r1[6]; optimize(r2[6] -= m2 * s; r3[6] -= m3 * s; )
+ s = r1[7]; optimize(r2[7] -= m2 * s; r3[7] -= m3 * s; )
+
+ /* choose pivot - or die */
+ if (absf(r3[2])>absf(r2[2])) SWAP_ROWS(r3, r2);
+ if (0.0F == r2[2]) return 0;
+
+ /* eliminate third variable */
+ m3 = r3[2] / r2[2];
+ s = r2[3]; optimize(r3[3] -= m3 * s; )
+ s = r2[4]; optimize(r3[4] -= m3 * s; )
+ s = r2[5]; optimize(r3[5] -= m3 * s; )
+ s = r2[6]; optimize(r3[6] -= m3 * s; )
+ s = r2[7]; optimize(r3[7] -= m3 * s; )
+
+#undef optimize
+
+ /* last check */
+ if (0.0F == r3[3]) return 0;
+
+ s = 1.0F / r3[3]; /* now back substitute row 3 */
+ r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s;
+
+ m2 = r2[3]; /* now back substitute row 2 */
+ s = 1.0F / r2[2];
+ r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
+ r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
+ m1 = r1[3];
+ r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
+ r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
+ m0 = r0[3];
+ r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
+ r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
+
+ m1 = r1[2]; /* now back substitute row 1 */
+ s = 1.0F / r1[1];
+ r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
+ r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
+ m0 = r0[2];
+ r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
+ r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
+
+ m0 = r0[1]; /* now back substitute row 0 */
+ s = 1.0F / r0[0];
+ r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
+ r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
+
+ out->e00 = r0[4]; out->e01 = r0[5]; out->e02 = r0[6]; out->e03 = r0[7];
+ out->e10 = r1[4]; out->e11 = r1[5]; out->e12 = r1[6]; out->e13 = r1[7];
+ out->e20 = r2[4]; out->e21 = r2[5]; out->e22 = r2[6]; out->e23 = r2[7];
+ out->e30 = r3[4]; out->e31 = r3[5]; out->e32 = r3[6]; out->e33 = r3[7];
+
+#undef SWAP_ROWS
+
+ return 1;
+}
+
+/*
+** 对只包含基本3D变换的矩阵进行变换,先计算左上角3x3的RS矩阵的逆(通过伴随矩阵),然后
+** 乘上平移矩阵的逆矩阵,即
+** M^-1 = (T(RS))^-1 = (RS)^-1 * T^-1
+*/
+bool mat4_invertgeneral3d(Mat4* in, Mat4* out) {
+ ssr_assert(in && out);
+ if (in == out) shrmat(in);
+
+ mat4_setidentity(out);
+
+ /*计算左上角3x3矩阵的行列式*/
+ float pos = 0, neg = 0, t;
+ float det;
+
+ t = in->e00 * in->e11 * in->e22;
+ if (t >= 0) pos += t; else neg += t;
+ t = in->e10 * in->e21 * in->e02;
+ if (t >= 0) pos += t; else neg += t;
+ t = in->e20 * in->e01 * in->e12;
+ if (t >= 0) pos += t; else neg += t;
+
+ t = -in->e20 * in->e11 * in->e02;
+ if (t >= 0) pos += t; else neg += t;
+ t = -in->e10 * in->e01 * in->e22;
+ if (t >= 0) pos += t; else neg += t;
+ t = -in->e00 * in->e21 * in->e12;
+ if (t >= 0) pos += t; else neg += t;
+
+ det = pos + neg;
+
+ if (det * det < 1e-25)
+ return 0; /*行列式为0*/
+
+ det = 1.f / det;
+ MAT(out, 0, 0) = ((MAT(in, 1, 1)*MAT(in, 2, 2) - MAT(in, 2, 1)*MAT(in, 1, 2))*det);
+ MAT(out, 0, 1) = (-(MAT(in, 0, 1)*MAT(in, 2, 2) - MAT(in, 2, 1)*MAT(in, 0, 2))*det);
+ MAT(out, 0, 2) = ((MAT(in, 0, 1)*MAT(in, 1, 2) - MAT(in, 1, 1)*MAT(in, 0, 2))*det);
+ MAT(out, 1, 0) = (-(MAT(in, 1, 0)*MAT(in, 2, 2) - MAT(in, 2, 0)*MAT(in, 1, 2))*det);
+ MAT(out, 1, 1) = ((MAT(in, 0, 0)*MAT(in, 2, 2) - MAT(in, 2, 0)*MAT(in, 0, 2))*det);
+ MAT(out, 1, 2) = (-(MAT(in, 0, 0)*MAT(in, 1, 2) - MAT(in, 1, 0)*MAT(in, 0, 2))*det);
+ MAT(out, 2, 0) = ((MAT(in, 1, 0)*MAT(in, 2, 1) - MAT(in, 2, 0)*MAT(in, 1, 1))*det);
+ MAT(out, 2, 1) = (-(MAT(in, 0, 0)*MAT(in, 2, 1) - MAT(in, 2, 0)*MAT(in, 0, 1))*det);
+ MAT(out, 2, 2) = ((MAT(in, 0, 0)*MAT(in, 1, 1) - MAT(in, 1, 0)*MAT(in, 0, 1))*det);
+
+ // 乘T^-1
+ MAT(out, 0, 3) = -(MAT(in, 0, 3) * MAT(out, 0, 0) +
+ MAT(in, 1, 3) * MAT(out, 0, 1) +
+ MAT(in, 2, 3) * MAT(out, 0, 2));
+ MAT(out, 1, 3) = -(MAT(in, 0, 3) * MAT(out, 1, 0) +
+ MAT(in, 1, 3) * MAT(out, 1, 1) +
+ MAT(in, 2, 3) * MAT(out, 1, 2));
+ MAT(out, 2, 3) = -(MAT(in, 0, 3) * MAT(out, 2, 0) +
+ MAT(in, 1, 3) * MAT(out, 2, 1) +
+ MAT(in, 2, 3) * MAT(out, 2, 2));
+
+ return 1;
+}
+
+void mat4_invertpos(Mat4* in, Mat4* out) {
+
+}
+
+void mat4_invertscale(Mat4* in, Mat4* out) {
+
+}
+
+void mat4_invertrot(Mat4* in, Mat4* out) {
+ ssr_assert(in && out);
+ mat4_transpose(in, out);
+}
+
+void mat4_settr(Vec3* pos, Quat* rot, Mat4* out) {
+ ssr_assert(pos && rot && out);
+ mat4_zero(out);
+ quat_tomat4(rot, out);
+ out->e03 = pos->x;
+ out->e13 = pos->y;
+ out->e23 = pos->z;
+}
+
+void mat4_settrs(Vec3* pos, Quat* rot, Vec3* scale, Mat4* out) {
+ ssr_assert(pos && rot && scale && out);
+ mat4_zero(out);
+ quat_tomat4(rot, out); /*pos*rot*scale的顺序*/
+ out->e00 *= scale->x; out->e01 *= scale->y; out->e02 *= scale->z;
+ out->e10 *= scale->x; out->e11 *= scale->y; out->e12 *= scale->z;
+ out->e20 *= scale->x; out->e21 *= scale->y; out->e22 *= scale->z;
+ out->e03 = pos->x;
+ out->e13 = pos->y;
+ out->e23 = pos->z;
+}
+
+void mat4_settrinverse(Vec3* pos, Quat* rot, Mat4* out) {
+ ssr_assert(pos && rot && out);
+ mat4_zero(out);
+ quat_invert(rot, rot);
+ quat_tomat4(rot, out);
+ Vec3 reverse = { -pos->x, -pos->y, -pos->z};
+ mat4_translate(out, &reverse, out); /* (TR)^-1 = R^-1*T^-1所以这里是右乘*/
+}
+
+void mat4_scale(Mat4* m, Vec3* scale, Mat4* out) {
+ ssr_assert(m && scale && out);
+ if (out != m) {
+ *out = *m;
+ }
+ /*
+ scale matrix
+ x, 0, 0, 0,
+ 0, y, 0, 0,
+ 0, 0, z, 0,
+ 0, 0, 0, 1
+ */
+ out->e00 *= scale->x;
+ out->e10 *= scale->x;
+ out->e20 *= scale->x;
+ out->e30 *= scale->x;
+
+ out->e01 *= scale->y;
+ out->e11 *= scale->y;
+ out->e21 *= scale->y;
+ out->e31 *= scale->y;
+
+ out->e02 *= scale->z;
+ out->e12 *= scale->z;
+ out->e22 *= scale->z;
+ out->e32 *= scale->z;
+}
+
+void mat4_translate(Mat4* m, Vec3* pos, Mat4* out) {
+ ssr_assert(m && pos && out);
+ if (out != m) {
+ *out = *m;
+ }
+ /*
+ translate matrix
+ 1, 0, 0, x,
+ 0, 1, 0, y,
+ 0, 0, 1, z,
+ 0, 0, 0, 1,
+ */
+ out->e03 = out->e00 * pos->x + out->e01 * pos->y + out->e02 * pos->z + out->e03;
+ out->e13 = out->e10 * pos->x + out->e11 * pos->y + out->e12 * pos->z + out->e13;
+ out->e23 = out->e20 * pos->x + out->e21 * pos->y + out->e22 * pos->z + out->e23;
+ out->e33 = out->e30 * pos->x + out->e31 * pos->y + out->e32 * pos->z + out->e33;
+}
+
+void mat4_rotate(Mat4* m, float angle, Vec3* ax, Mat4* out) {
+ ssr_assert(m && ax && out);
+ Mat4 rot;
+ mat4_setaxisangle(ax, angle, &rot);
+ mat4_multiply(m, &rot, out);
+}
+
+void mat4_decomposetrs(Mat4* src, Vec3* pos, Quat* quat, Vec3* scale) {
+ ssr_assert(src && pos && quat && scale);
+
+ Vec3* x = &src->colums[0];
+ Vec3* y = &src->colums[1];
+ Vec3* z = &src->colums[2];
+ Vec3* w = &src->colums[3];
+
+ *pos = *w;
+
+ quat_setlookrotation(z, y, quat);
+
+ scale->x = vec3_magnitude(x);
+ scale->y = vec3_magnitude(y);
+ scale->z = vec3_magnitude(z);
+}
+
+static void MakePositive(Euler* euler) {/*弧度制欧拉角*/
+ const float negativeFlip = -0.0001F;
+ const float positiveFlip = (PI * 2.0F) - 0.0001F;
+
+ if (euler->x < negativeFlip)
+ euler->x += 2.0 * PI;
+ else if (euler->x > positiveFlip)
+ euler->x -= 2.0 * PI;
+
+ if (euler->y < negativeFlip)
+ euler->y += 2.0 * PI;
+ else if (euler->y > positiveFlip)
+ euler->y -= 2.0 * PI;
+
+ if (euler->z < negativeFlip)
+ euler->z += 2.0 * PI;
+ else if (euler->z > positiveFlip)
+ euler->z -= 2.0 * PI;
+}
+
+static void SanitizeEuler(Euler* e) {/*弧度制欧拉角*/
+ MakePositive(e);
+}
+
+/*from unity src*/
+bool mat4_toeuler(Mat4* in, Euler* out) {
+ ssr_assert(in && out);
+ // from http://www.geometrictools.com/Documentation/EulerAngles.pdf
+ // YXZ order
+ if (MAT(in, 1, 2) < 0.999F) // some fudge for imprecision
+ {
+ if (MAT(in, 1, 2) > -0.999F) // some fudge for imprecision
+ {
+ out->x = asin(-MAT(in, 1, 2));
+ out->y = atan2(MAT(in, 0, 2), MAT(in, 2, 2));
+ out->z = atan2(MAT(in, 1, 0), MAT(in, 1, 1));
+ //euler_rad2deg(out, out);
+ SanitizeEuler(out);
+ euler_rad2deg(out, out);
+ return 1;
+ }
+ else
+ {
+ // WARNING. Not unique. YA - ZA = atan2(r01,r00)
+ out->x = PI * 0.5F;
+ out->y = atan2(MAT(in, 0, 1), MAT(in, 0, 0));
+ out->z = 0.0F;
+ //euler_rad2deg(out, out);
+ SanitizeEuler(out);
+ euler_rad2deg(out, out);
+ return 0;
+ }
+ }
+ else
+ {
+ // WARNING. Not unique. YA + ZA = atan2(-r01,r00)
+ out->x = -PI * 0.5F;
+ out->y = atan2(-MAT(in, 0, 1), MAT(in, 0, 0));
+ out->z = 0.0F;
+ //euler_rad2deg(out, out);
+ SanitizeEuler(out);
+ euler_rad2deg(out, out);
+ return 0;
+ }
+}
+
+/*from unity src*/
+/*https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/*/
+void mat4_toquat(Mat4* in, Quat* out) {
+ // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+ // article "Quaternionf Calculus and Fast Animation".
+ float fTrace = MAT(in, 0, 0) + MAT(in, 1, 1) + MAT(in, 2, 2);
+ float fRoot;
+
+ if (fTrace > 0.0f)
+ {
+ // |w| > 1/2, may as well choose w > 1/2
+ fRoot = sqrt(fTrace + 1.0f); // 2w
+ out->w = 0.5f*fRoot;
+ fRoot = 0.5f / fRoot; // 1/(4w)
+ out->x = (MAT(in, 2, 1) - MAT(in, 1, 2))*fRoot;
+ out->y = (MAT(in, 0, 2) - MAT(in, 2, 0))*fRoot;
+ out->z = (MAT(in, 1, 0) - MAT(in, 0, 1))*fRoot;
+ }
+ else
+ {
+ // |w| <= 1/2
+ int s_iNext[3] = { 1, 2, 0 };
+ int i = 0;
+ if (MAT(in, 1, 1) > MAT(in, 0, 0))
+ i = 1;
+ if (MAT(in, 2, 2) > MAT(in, i, i))
+ i = 2;
+ int j = s_iNext[i];
+ int k = s_iNext[j];
+
+ fRoot = sqrt(MAT(in, i, i) - MAT(in, j, j) - MAT(in, k, k) + 1.0f);
+ float* apkQuat[3] = { &out->x, &out->y, &out->z };
+ ssr_assert(fRoot >= EPSILON);
+ *apkQuat[i] = 0.5f*fRoot;
+ fRoot = 0.5f / fRoot;
+ out->w = (MAT(in, k, j) - MAT(in, j, k)) * fRoot;
+ *apkQuat[j] = (MAT(in, j, i) + MAT(in, i, j))*fRoot;
+ *apkQuat[k] = (MAT(in, k, i) + MAT(in, i, k))*fRoot;
+ }
+ quat_normalize(out, out);
+}
+
+void mat3_applytovec3(Mat3* m, Vec3* v, Vec3* out) {
+ ssr_assert(m && v && out);
+ out->x = m->e00 * v->x + m->e01 * v->y + m->e02 * v->z;
+ out->y = m->e10 * v->x + m->e11 * v->y + m->e12 * v->z;
+ out->z = m->e20 * v->x + m->e21 * v->y + m->e22 * v->z;
+}
+
+void mat23_applytovec3(Mat23* m, Vec3* v, Vec2* out) {
+ ssr_assert(m && v && out);
+ out->x = m->e00 * v->x + m->e01 * v->y + m->e02 * v->z;
+ out->y = m->e10 * v->x + m->e11 * v->y + m->e12 * v->z;
+}
+
+void mat43_applytovec3(Mat43* m, Vec3* v, Vec4* out) {
+ ssr_assert(m && v && out);
+ out->x = m->e00 * v->x + m->e01 * v->y + m->e02 * v->z;
+ out->y = m->e10 * v->x + m->e11 * v->y + m->e12 * v->z;
+ out->z = m->e20 * v->x + m->e21 * v->y + m->e22 * v->z;
+ out->w = m->e30 * v->x + m->e31 * v->y + m->e32 * v->z;
+} \ No newline at end of file
diff --git a/src/math/quat.c b/src/math/quat.c
new file mode 100644
index 0000000..e68e254
--- /dev/null
+++ b/src/math/quat.c
@@ -0,0 +1,314 @@
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "math.h"
+#include "../util/assert.h"
+#include "../core/mem.h"
+
+static Vec3 sharedVec3;
+static Quat sharedQuat;
+static Quat sharedQuat2;
+static Euler sharedEuler;
+
+#define shrquat(q) \
+do{\
+sharedQuat = *q;\
+q = &sharedQuat;\
+}while(0)
+
+#define shrquat2(q) \
+do{\
+sharedQuat2 = *q;\
+q = &sharedQuat2;\
+}while(0)
+
+#define shrvec3(v) \
+do{\
+sharedVec3 = *v;\
+v = &sharedVec3;\
+}while(0)
+
+#define shreuler(v) \
+do{\
+sharedEuler = *v;\
+v = &sharedEuler;\
+}while(0)
+
+void quat_tostring(Quat* v, char buf[]) {
+ ssr_assert(v);
+ sprintf(buf, "%8.3f %8.3f %8.3f", v->x, v->y, v->z);
+}
+
+void quat_print(Quat* q) {
+ ssr_assert(q);
+ quat_tostring(q, printbuffer);
+ printf("\n%s\n", printbuffer);
+}
+
+void euler_tostring(Euler* v, char buf[]) {
+ sprintf(buf, "%8.3f %8.3f %8.3f", v->x, v->y, v->z);
+}
+
+void euler_print(Euler* v) {
+ euler_tostring(v, printbuffer);
+ printf("\n%s\n", printbuffer);
+}
+
+void euler_deg2rad(Euler* in, Euler* out) {
+ ssr_assert(in && out);
+ out->x = radians(in->x);
+ out->y = radians(in->y);
+ out->z = radians(in->z);
+}
+
+void euler_rad2deg(Euler* in, Euler* out) {
+ ssr_assert(in && out);
+ out->x = degree(in->x);
+ out->y = degree(in->y);
+ out->z = degree(in->z);
+}
+
+void euler_toquat(Euler* euler, Quat* out) {
+ ssr_assert(euler && out);
+ quat_fromeuler(euler, out);
+}
+
+bool quat_isidentity(Quat* q) {
+ return compare(quat_magnitude(q), 1.f);
+}
+
+void quat_fromaxisangle(Vec3* axis, float angle, Quat* out) {
+ ssr_assert(compare(vec3_magnitude2(axis), 1.f));
+ angle = radians(angle);
+ float half = angle * 0.5;
+ float s = sin(half);
+ out->w = cos(half);
+ out->x = s * axis->x;
+ out->y = s * axis->y;
+ out->z = s * axis->z;
+}
+
+void quat_fromeuler(Euler* el, Quat* out) {
+ ssr_assert(el && out);
+ Euler euler;
+ euler_deg2rad(el, &euler);
+ float cx = cos(euler.x * 0.5f);
+ float sx = sin(euler.x * 0.5f);
+ float cy = cos(euler.y * 0.5f);
+ float sy = sin(euler.y * 0.5f);
+ float cz = cos(euler.z * 0.5f);
+ float sz = sin(euler.z * 0.5f);
+ Quat qx = {sx, 0, 0,cx};
+ Quat qy = {0, sy, 0,cy};
+ Quat qz = {0, 0,sz,cz};
+ /*按ZXY顺序*/
+ quat_multiply(&qx, &qz, &qx);
+ quat_multiply(&qy, &qx, out);
+ ssr_assert(quat_isidentity(out));
+}
+
+/*
+** 四元数直接对向量进行旋转和先转成矩阵形式再旋转计算量一样
+*/
+void quat_applytovec3(Quat* q, Vec3* v, Vec3* out) {
+ ssr_assert(q && v && out);
+ if (v == out) {
+ shrvec3(v);
+ }
+ /* q[v,0]q^-1 */
+ /* https://gamedev.stackexchange.com/questions/28395/rotating-vector3-by-a-quaternion */
+ float x = q->x * 2.0F;
+ float y = q->y * 2.0F;
+ float z = q->z * 2.0F;
+ float xx = q->x * x;
+ float yy = q->y * y;
+ float zz = q->z * z;
+ float xy = q->x * y;
+ float xz = q->x * z;
+ float yz = q->y * z;
+ float wx = q->w * x;
+ float wy = q->w * y;
+ float wz = q->w * z;
+
+ /*从这里能看到矩阵形式*/
+ out->x = (1.0f - (yy + zz)) * v->x + (xy - wz) * v->y + (xz + wy) * v->z;
+ out->y = (xy + wz) * v->x + (1.0f - (xx + zz)) * v->y + (yz - wx) * v->z;
+ out->z = (xz - wy) * v->x + (yz + wx) * v->y + (1.0f - (xx + yy)) * v->z;
+}
+
+void quat_tomat4(Quat* q, Mat4* out) {
+ ssr_assert(q && out);
+ ssr_assert(quat_isidentity(q));
+ mat4_setidentity(out);
+
+ float x = q->x * 2.0F; /*从quat_applytovec3能得到矩阵形式*/
+ float y = q->y * 2.0F;
+ float z = q->z * 2.0F;
+ float xx = q->x * x;
+ float yy = q->y * y;
+ float zz = q->z * z;
+ float xy = q->x * y;
+ float xz = q->x * z;
+ float yz = q->y * z;
+ float wx = q->w * x;
+ float wy = q->w * y;
+ float wz = q->w * z;
+
+ /*和mat4_setaxisangle实际上结果一样*/
+ out->l[0] = 1.0f - (yy + zz);
+ out->l[1] = xy + wz;
+ out->l[2] = xz - wy;
+
+ out->l[4] = xy - wz;
+ out->l[5] = 1.0f - (xx + zz);
+ out->l[6] = yz + wx;
+
+ out->l[8] = xz + wy;
+ out->l[9] = yz - wx;
+ out->l[10] = 1.0f - (xx + yy);
+}
+
+void quat_toeuler(Quat* q, Euler* out) {
+ ssr_assert(q && out);
+ Mat4 mat;
+ quat_tomat4(q, &mat); /*计算变换矩阵*/
+ mat4_toeuler(&mat, out); /*mat是按照RyRxRz顺序(z->y->x)的旋转矩阵*/
+}
+
+void quat_normalize(Quat* q, Quat* out) {
+ ssr_assert(q && out);
+ float mag = quat_magnitude(q);
+ quat_scale(q, 1.f/mag, out);
+}
+
+void quat_scale(Quat* q, float scale, Quat* out) {
+ ssr_assert(q && out);
+ out->x = q->x * scale;
+ out->y = q->y * scale;
+ out->z = q->z * scale;
+ out->w = q->w * scale;
+}
+
+void quat_negtive(Quat* in, Quat* out) {
+ ssr_assert(in && out);
+ out->w = -in->w;
+ out->x = -in->x;
+ out->y = -in->y;
+ out->z = -in->z;
+}
+
+void quat_devide(Quat* q, float k, Quat* out) {
+ ssr_assert(q && out);
+ k = 1 / k;
+ out->w = q->w * k;
+ out->x = q->x * k;
+ out->y = q->y * k;
+ out->z = q->z * k;
+}
+
+void quat_invert(Quat* q, Quat* out) {
+ ssr_assert(q && out);
+ float mag2 = quat_magnitude2(q);
+ quat_conjugate(q, out);
+ quat_devide(out, mag2, out);
+ /*实际上如果是单位四元数,共轭就是逆*/
+}
+
+bool quat_setlookrotation(Vec3* view, Vec3* up, Quat* out) {
+ ssr_assert(view && up && out);
+ Mat4 m;
+ mat4_setlookrotation(view, up, &m); /*先以view为准构建正交矩阵*/
+ mat4_toquat(&m, out);
+ return 1;
+}
+
+/*q1 * q2^-1*/
+void quat_minus(Quat* q1, Quat* q2, Quat* out) {
+ ssr_assert(q1 && q2 && out);
+ Quat q2i; quat_invert(q2, &q2i);
+ quat_multiply(q1, &q2i, out);
+}
+
+void quat_multiply(Quat* q1, Quat* q2, Quat* out) {
+ ssr_assert(q1 && q2 && out);
+
+ float w1 = q1->w, x1 = q1->x, y1 = q1->y, z1 = q1->z,
+ w2 = q2->w, x2 = q2->x, y2 = q2->y, z2 = q2->z;
+ out->x = x1 * w2 + x2 * w1 + y1 * z2 - z1 * y2;
+ out->y = w1 * y2 + w2 * y1 + z1 * x2 - z2 * x1;
+ out->z = w1 * z2 + w2 * z1 + x1 * y2 - x2 * y1;
+ out->w = w1 * w2 - x1 * x2 - y1 * y2 - z1 * z2;
+}
+
+/*
+** 共轭的几何意义是颠倒旋转轴方向,代表了和q相反的角位移
+*/
+void quat_conjugate(Quat* in, Quat* out) {
+ ssr_assert(in && out);
+ out->w = in->w;
+ out->x = -in->x;
+ out->y = -in->y;
+ out->z = -in->z;
+}
+
+float quat_dot(Quat* q1, Quat* q2) {
+ ssr_assert(q1 && q2);
+ return (q1->x*q2->x + q1->y*q2->y + q1->z*q2->z + q1->w*q2->w);
+}
+
+float quat_magnitude(Quat* q) {
+ ssr_assert(q);
+ return sqrt(quat_dot(q, q));
+}
+
+float quat_magnitude2(Quat* q) {
+ ssr_assert(q);
+ return quat_dot(q, q);
+}
+
+void quat_slerp(Quat* q1, Quat* q2, float t, Quat* out) {
+ ssr_assert(q1 && q2 && out);
+ ssr_assert(quat_isidentity(q1) && quat_isidentity(q2)); /*适用于单位四元数*/
+ float dot = quat_dot(q1, q2);
+ Quat temp;
+ if (dot < 0.0f) {
+ dot = -dot;
+ temp.x = -q2->x;
+ temp.y = -q2->y;
+ temp.z = -q2->z;
+ temp.w = -q2->w;
+ } else {
+ temp = *q2;
+ }
+ if (dot < 0.95f) {
+ float angle = acos(dot);
+ float sinadiv, sinat, sinaomt;
+ sinadiv = 1.0f / sin(angle);
+ sinat = sin(angle*t);
+ sinaomt = sin(angle*(1.0f - t));
+ out->x = (q1->x*sinaomt + temp.x*sinat)*sinadiv;
+ out->y = (q1->y*sinaomt + temp.y*sinat)*sinadiv;
+ out->z = (q1->z*sinaomt + temp.z*sinat)*sinadiv;
+ out->w = (q1->w*sinaomt + temp.w*sinat)*sinadiv;
+ } else { /*小范围时使用lerp*/
+ quat_lerp(q1, &temp, t, out);
+ }
+}
+
+void quat_lerp(Quat* q1, Quat* q2, float t, Quat* out) {
+ ssr_assert(q1 && q2 && out);
+ float t2 = 1 - t;
+ if (quat_dot(q1, q2) < 0.f) { /*点乘不能是负的,翻转一个四元数的符号,使得落回360°*/
+ out->x = q1->x * t2 - t * q2->x;
+ out->y = q1->y * t2 - t * q2->y;
+ out->z = q1->z * t2 - t * q2->z;
+ out->w = q1->w * t2 - t * q2->w;
+ } else {
+ out->x = q1->x * t2 + t * q2->x;
+ out->y = q1->y * t2 + t * q2->y;
+ out->z = q1->z * t2 + t * q2->z;
+ out->w = q1->w * t2 + t * q2->w;
+ }
+ quat_normalize(out, out);
+}
diff --git a/src/math/vec2.c b/src/math/vec2.c
new file mode 100644
index 0000000..86192dc
--- /dev/null
+++ b/src/math/vec2.c
@@ -0,0 +1,36 @@
+#include "math.h"
+#include "../util/assert.h"
+#include "../core/mem.h"
+
+void vec2_scale(Vec2* v, float k, Vec2* out) {
+ ssr_assert(v && out);
+ out->x = v->x * k;
+ out->y = v->y * k;
+}
+
+void vec2_plus(Vec2* v1, Vec2* v2, Vec2* out) {
+ ssr_assert(v1 && v2 && out);
+ out->x = v1->x + v2->x;
+ out->y = v1->y + v2->y;
+}
+
+void vec2_offset(Vec2* v, float offset, Vec2* out) {
+ ssr_assert(v && out);
+ out->x = v->x + offset;
+ out->y = v->y + offset;
+}
+
+float vec2_dot(Vec2* v1, Vec2* v2) {
+ ssr_assert(v1 && v2);
+ float d = v1->x * v2->x + v1->y * v2->y;
+ return d;
+}
+
+void vec2_tostring(Vec2* v, char buf[]) {
+ sprintf(buf, "%8.3f %8.3f", v->x, v->y);
+}
+
+void vec2_print(Vec2* v) {
+ vec2_tostring(v, printbuffer);
+ printf("%s", printbuffer);
+} \ No newline at end of file
diff --git a/src/math/vec3.c b/src/math/vec3.c
new file mode 100644
index 0000000..4d77b96
--- /dev/null
+++ b/src/math/vec3.c
@@ -0,0 +1,120 @@
+#include <math.h>
+
+#include "math.h"
+#include "../util/assert.h"
+#include "../core/mem.h"
+
+Vec3 vec3forward = {0,0,1};
+Vec3 vec3up = {0, 1, 0};
+Vec3 vec3left = {1, 0, 0};
+
+void vec3_cross(Vec3* v1, Vec3* v2, Vec3* out) {
+ ssr_assert(v1 && v2 && out);
+ out->x = v1->y*v2->z - v1->z*v2->y;
+ out->y = v1->z*v2->x - v1->x*v2->z;
+ out->z = v1->x*v2->y - v1->y*v2->x;
+}
+
+void vec3_scale(Vec3* v, float k, Vec3* out) {
+ ssr_assert(v && out);
+ out->x = v->x * k;
+ out->y = v->y * k;
+ out->z = v->z * k;
+}
+
+void vec3_plus(Vec3* v1, Vec3* v2, Vec3* out) {
+ ssr_assert(v1 && v2 && out);
+ out->x = v1->x + v2->x;
+ out->y = v1->y + v2->y;
+ out->z = v1->z + v2->z;
+}
+
+void vec3_offset(Vec3* v, float offset, Vec3* out) {
+ ssr_assert(v && out);
+ out->x = v->x + offset;
+ out->y = v->y + offset;
+ out->z = v->z + offset;
+}
+
+float vec3_magnitude(Vec3* v) {
+ ssr_assert(v);
+ float l2 = vec3_magnitude2(v);
+ return sqrt(l2);
+}
+
+float vec3_magnitude2(Vec3* v) {
+ ssr_assert(v);
+ return v->x*v->x + v->y*v->y + v->z*v->z;
+}
+
+void vec3_lerp(Vec3* v1, Vec3* v2, float t, Vec3* out) {
+ ssr_assert(v1 && v2 && out);
+ float t2 = 1 - t;
+ out->x = v1->x * t2 + v2->x * t;
+ out->y = v1->y * t2 + v2->y * t;
+ out->z = v1->z * t2 + v2->z * t;
+}
+
+void vec3_slerp(Vec3* v1, Vec3* v2, float t, Vec3* out) {
+ ssr_assert(v1 && v2 && out);
+ float mag1 = vec3_magnitude(v1);
+ float mag2 = vec3_magnitude(v2);
+ if (mag1 < EPSILON || mag2 < EPSILON) {
+ vec3_lerp(v1, v2, t, out);
+ return;
+ }
+ float lerplen = lerp(mag1, mag2, t);
+ /*分为长度上的lerp和角度上的slerp*/
+ float dot = vec3_dot(v1, v2) / (mag1 * mag2);
+ if (dot > 1.f - EPSILON) { /*几乎是同向*/
+ vec3_lerp(v1, v2, t, out);
+ return;
+ } else if (dot < -1 + EPSILON) { /*几乎是反向*/
+
+ } else {
+ Vec3 axis; vec3_cross(v1, v2, &axis); vec3_normalize(&axis, &axis);
+ Vec3 v1n; vec3_normalize(v1, &v1n);
+ float angle = acos(dot) * t;
+ //Mat4 m; mat4_setaxisangle(&axis, angle, &m);
+ //mat4_applytovec4(&m, &v1n, &v1n);
+ Quat q; quat_fromaxisangle(&axis, angle, &q);
+ quat_applytovec3(&q, &v1n, &v1n);
+ vec3_scale(&v1n, lerplen, out);
+ }
+}
+
+float vec3_dot(Vec3* v1, Vec3* v2) {
+ ssr_assert(v1 && v2);
+ return v1->x * v2->x + v1->y * v2->y + v1->z * v2->z;
+}
+
+void vec3_multiply(Vec3* v1, Vec3* v2, Quat* out) {
+ ssr_assert(v1 && v2 && out);
+ vec3_cross(v1, v2, out);
+ out->w = -vec3_dot(v1, v2);
+}
+
+void vec3_normalize(Vec3* v, Vec3* out) {
+ ssr_assert(v && out);
+ //float mag = rsqrt(v->x * v->x + v->y * v->y + v->z * v->z);
+ float mag = 1.f / vec3_magnitude(v);
+ out->x = v->x * mag;
+ out->y = v->y * mag;
+ out->z = v->z * mag;
+}
+
+void vec3_tostring(Vec3* v, char buf[]) {
+ sprintf(buf, "%8.3f %8.3f %8.3f", v->x, v->y, v->z);
+}
+
+void vec3_print(Vec3* v) {
+ vec3_tostring(v, printbuffer);
+ printf("\n%s\n", printbuffer);
+}
+
+void vec3_minus(Vec3* v1, Vec3* v2, Vec3* out) {
+ ssr_assert(v1 && v2 && out);
+ out->x = v1->x - v2->x;
+ out->y = v1->y - v2->y;
+ out->z = v1->z - v2->z;
+} \ No newline at end of file
diff --git a/src/math/vec4.c b/src/math/vec4.c
new file mode 100644
index 0000000..4216a08
--- /dev/null
+++ b/src/math/vec4.c
@@ -0,0 +1,24 @@
+#include <math.h>
+
+#include "math.h"
+#include "../util/assert.h"
+#include "../core/mem.h"
+
+
+
+void vec4_dividew(Vec4* v, Vec3* out) {
+ ssr_assert(out && v);
+ float w = 1.f / v->w;
+ out->x = v->x * w ;
+ out->y = v->y * w;
+ out->z = v->z * w;
+}
+
+void vec4_tostring(Vec4* v, char buf[]) {
+ sprintf(buf, "%8.3f %8.3f %8.3f %8.3f", v->x, v->y, v->z, v->w);
+}
+
+void vec4_print(Vec4* v) {
+ vec4_tostring(v, printbuffer);
+ printf("\n%s\n", printbuffer);
+} \ No newline at end of file
diff --git a/src/ssr.h b/src/ssr.h
new file mode 100644
index 0000000..5f80e92
--- /dev/null
+++ b/src/ssr.h
@@ -0,0 +1,6 @@
+#ifndef _SSR_H_
+#define _SSR_H_
+
+#include "core/device.h"
+
+#endif \ No newline at end of file
diff --git a/src/test/test.h b/src/test/test.h
new file mode 100644
index 0000000..4e7d77e
--- /dev/null
+++ b/src/test/test.h
@@ -0,0 +1,15 @@
+#ifndef _SOFTSHADEROOM_TEST_H_
+#define _SOFTSHADEROOM_TEST_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define print(str) printf("%s", str)
+#define TEST(f) void f(){print(#f);print("\n");
+#define END }
+
+void test_mat4();
+void test_quat();
+
+#endif \ No newline at end of file
diff --git a/src/test/test_mat4.c b/src/test/test_mat4.c
new file mode 100644
index 0000000..e7a65fc
--- /dev/null
+++ b/src/test/test_mat4.c
@@ -0,0 +1,208 @@
+#include "test.h"
+#include "../math/math.h"
+#include "../util/time.h"
+
+Mat4 m1 = {
+ 1, 5, 9,13,
+ 2, 6,10,14,
+ 3, 7,11,15,
+ 4, 8,12,16
+};
+
+Mat4 m2 = {
+ 16,12, 8, 4,
+ 15,11, 7, 3,
+ 14,10, 6, 2,
+ 13, 9, 5, 1
+};
+
+static void test_multiply() {
+ print("test_multiply\n");
+ Mat4 res;
+ mat4_multiply(&m1, &m2, &res);
+ mat4_print(&res);
+}
+
+static void test_invert() {
+ print("test_invert\n");
+ Mat4 m = {
+ 0, 3, 0, 0,
+ 2, 7, 0, 1,
+ 8, 1, 1, 0,
+ 6, 0, 2, 1,
+ };
+ Mat4 res, res2;
+ mat4_invertfull(&m, &res);
+ mat4_print(&res);
+ mat4_multiply(&m1, &m, &res2);
+ mat4_multiply(&res2, &res, &res2);
+ mat4_print(&res2);
+ /*
+ -0.250 0.333 1.667 -1.833
+ 0.083 0.000 -0.667 0.833
+ 0.167 -0.000 -0.333 -0.333
+ -0.083 0.000 0.667 0.167
+ */
+}
+
+static void test_transpose() {
+ print("test_transpose\n");
+ Mat4 res;
+ mat4_transpose(&m1, &res);
+ mat4_print(&res);
+}
+
+static void test_scale() {
+ print("test_scale\n");
+ Mat4 scale;
+ mat4_setscale(1, 2, 3, &scale);
+ Mat4 res;
+ mat4_multiply(&scale, &m1, &res);
+ mat4_print(&scale);
+}
+
+static void test_position() {
+ print("test_position\n");
+ Mat4 pos;
+ mat4_setposition(1, 2, 3, &pos);
+ mat4_print(&pos);
+}
+
+static void test_rotation() {
+ print("test_rotation\n");
+ Mat4 i;
+ mat4_setidentity(&i);
+ Vec3 axis = { 0, 0, 1 };
+ mat4_rotate(&i, 90, &axis, &i);
+ mat4_print(&i);
+}
+
+static void test_invertgeneral3d() {
+ print("test_invertgeneral3d\n");
+ Mat4 trans;
+ mat4_setidentity(&trans);
+ print("original matrix"); mat4_print(&m1);
+ Vec3 v;
+ v.x = 1; v.y = 3.3; v.z = 0; mat4_translate(&trans, &v, &trans);
+ v.x = 1; v.y = 0; v.z = 0; mat4_rotate(&trans, 23, &v, &trans);
+ v.x = 1; v.y = 1.2; v.z = 1; mat4_scale(&trans, &v, &trans);
+ v.x = 1; v.y = 3; v.z = 0; mat4_rotate(&trans, 23, &v, &trans);
+ v.x = 2; v.y = 3.3; v.z = 0; mat4_translate(&trans, &v, &trans);
+ print("transform matrix"); mat4_print(&trans);
+ Mat4 res;
+ mat4_multiply(&trans, &m1, &res);
+ mat4_invertgeneral3d(&trans, &trans);
+ print("inverse transform matrix"); mat4_print(&trans);
+ mat4_multiply(&trans, &res, &res);
+ print("inverted result"); mat4_print(&res);
+}
+
+void test_invertrot() {
+ print("test_invertrot\n");
+ print("original matrix"); mat4_print(&m1);
+ Mat4 rot; mat4_setidentity(&rot);
+ Vec3 axis = { 1,2,3 }; mat4_rotate(&rot, 90, &axis, &rot);
+ print("rotation matrix"); mat4_print(&rot);
+ Mat4 res;
+ mat4_multiply(&rot, &m1, &res);
+ print("result matrix"); mat4_print(&res);
+ mat4_invertgeneral3d(&rot, &rot);
+ print("inverse rotation matrix"); mat4_print(&rot);
+ mat4_multiply(&rot, &res, &res);
+ print("result matrix"); mat4_print(&res);
+}
+
+TEST(test_orthogonalize)
+ ROWMAT(A0,
+ 1, 2, 4, 0,
+ 0, 0, 5, 0,
+ 0, 3, 6, 0,
+ 0, 0, 0, 0
+ );
+ Mat4 A;
+
+ TIME_STAMP("mat4_orthogonalize time used")
+ for (int i = 0; i < 1000000; ++i) {
+ mat4_orthogonalize(&A0, &A);
+ }
+ TIME_STAMP_END
+
+ TIME_STAMP("mat4_isorthogonal time used")
+ for (int i = 0; i < 1000000; ++i) {
+ mat4_isorthogonal(&A0);
+ }
+ TIME_STAMP_END
+
+ mat4_print(&A);
+ float res = vec3_dot(&A.basis.y, &A.basis.x);
+ printf("%f\n", res);
+ printf("%d\n", mat4_isorthogonal(&A));
+ Mat4 rev;
+ mat4_transpose(&A, &rev);
+ mat4_multiply(&A, &rev, &rev);
+ mat4_print(&rev);
+END
+
+TEST(test_toeuler)
+ Euler euler = { 90, 0, 33 };
+ Quat rot;
+ quat_fromeuler(&euler, &rot);
+ Mat4 m;
+ quat_tomat4(&rot, &m);
+ Euler res;
+ quat_toeuler(&rot, &res);
+ euler_print(&res);
+END
+
+TEST(test_rotatematrix)
+ Euler euler = { 10, 20, 30 };
+ Quat rot;
+ quat_fromeuler(&euler, &rot);
+ Mat4 m;
+ quat_tomat4(&rot, &m);
+ mat4_print(&m);
+ Mat4 mz, mx, my;
+ mat4_setrotatez(30, &mz);
+ mat4_setrotatex(10, &mx);
+ mat4_setrotatey(20, &my);
+ mat4_multiply(&mx, &mz, &mx);
+ mat4_multiply(&my, &mx, &m);
+ mat4_print(&m);
+ mat4_setrotate(10, 20, 30, &m);
+ mat4_print(&m);
+END
+
+TEST(test_isidentity)
+ ROWMAT(mat,
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ )
+ bool res;
+ TIME_STAMP_1000000("test is isidentity")
+ res = mat4_isidentity(&mat);
+ TIME_STAMP_END
+ printf("%d\n", res);
+END
+
+void test_mat4() {
+ print("================================================\n");
+ print("test_mat4\n");
+ print("================================================\n");
+
+ //test_transpose();
+ //test_multiply();
+ //test_invert();
+ //test_scale();
+ //test_position();
+ //test_rotation();
+ //test_invertgeneral3d();
+
+ //test_invertrot();
+ //test_orthogonalize();
+ //test_toeuler();
+ test_rotatematrix();
+
+ //test_isidentity();
+}
diff --git a/src/test/test_quat.c b/src/test/test_quat.c
new file mode 100644
index 0000000..c932082
--- /dev/null
+++ b/src/test/test_quat.c
@@ -0,0 +1,82 @@
+#include "test.h"
+#include "../math/math.h"
+
+TEST(test_euler)
+
+Euler e = {90, 90, 0};
+Vec3 p = {2,3,4}, res;
+Quat qut;
+quat_fromeuler(&e, &qut);
+quat_applytovec3(&qut, &p, &res);
+vec3_print(&res);
+
+/*用轴角定义*/
+Vec3 axis = { 1, 0,0 };
+Quat qut2;
+quat_fromaxisangle(&axis, 90, &qut2);
+quat_applytovec3(&qut, &p, &res);
+vec3_print(&res);
+
+Mat4 mat;
+quat_tomat4(&qut, &mat);
+mat4_print(&mat);
+
+Vec4 p2 = { 2,3,4,1 };
+Vec4 res2;
+mat4_applytovec4(&mat, &p2, &res2);
+vec4_print(&res2);
+
+END
+
+TEST(test_quat2euler)
+Euler e = { 10, 20, 30};
+
+Quat q;
+euler_toquat(&e, &q);
+euler_deg2rad(&e, &e);
+quat_print(&q);
+euler_print(&e);
+
+Euler res;
+quat_toeuler(&q, &res);
+
+euler_print(&res);
+
+quat_fromeuler(&res, &q);
+quat_print(&q);
+
+END
+
+TEST(test_conjugate)
+Quat rot;
+Vec3 axis = {2,3,4};
+vec3_normalize(&axis, &axis);
+quat_fromaxisangle(&axis, 46, &rot);
+Vec3 p = {12, 3, 55};
+vec3_print(&p);
+Vec3 res;
+quat_applytovec3(&rot, &p, &res);
+vec3_print(&res);
+Quat rev;
+quat_invert(&rot, &rev);
+quat_applytovec3(&rev, &res, &res);
+vec3_print(&res);
+END
+
+TEST(test_lookrotation)
+Vec3 view = {1, 0, 0};
+Vec3 up = {0, 1, 0};
+Quat rot;
+quat_setlookrotation(&view, &up, &rot);
+quat_print(&rot);
+Euler euler;
+quat_toeuler(&rot, &euler);
+euler_print(&euler);
+END
+
+void test_quat() {
+ //test_euler();
+ //test_quat2euler();
+ //test_conjugate();
+ //test_lookrotation();
+} \ No newline at end of file
diff --git a/src/util/assert.h b/src/util/assert.h
new file mode 100644
index 0000000..563e991
--- /dev/null
+++ b/src/util/assert.h
@@ -0,0 +1,9 @@
+#ifndef _SOFTSHADEROOM_ASSERT_H_
+#define _SOFTSHADEROOM_ASSERT_H_
+
+#include <assert.h>
+
+#define ssr_assert assert
+
+
+#endif \ No newline at end of file
diff --git a/src/util/time.c b/src/util/time.c
new file mode 100644
index 0000000..5bfc936
--- /dev/null
+++ b/src/util/time.c
@@ -0,0 +1,5 @@
+#include "time.h"
+
+clock_t sharedTick;
+
+const char* sharedTickHint;
diff --git a/src/util/time.h b/src/util/time.h
new file mode 100644
index 0000000..6b850b4
--- /dev/null
+++ b/src/util/time.h
@@ -0,0 +1,24 @@
+#ifndef _SOFTSHADEROOM_TIME_H_
+#define _SOFTSHADEROOM_TIME_H_
+
+#include <time.h>
+#include "assert.h"
+
+extern clock_t sharedTick;
+extern const char* sharedTickHint;
+
+#define TIME_STAMP(hint) \
+ssr_assert(!sharedTickHint);\
+sharedTickHint = hint;\
+sharedTick = clock();{
+#define TIME_STAMP_END \
+}\
+sharedTick= clock()-sharedTick;\
+printf("%s : %.10fs %ldtick\n", sharedTickHint, sharedTick / (double)CLOCKS_PER_SEC, sharedTick);\
+sharedTickHint = 0;
+#define TIME_STAMP_i(hint, i)\
+TIME_STAMP(hint);}\
+for(int _i = 0; _i < i; ++_i){
+#define TIME_STAMP_1000000(hint) TIME_STAMP_i(hint, 1000000)
+
+#endif \ No newline at end of file
diff --git a/src/util/type.h b/src/util/type.h
new file mode 100644
index 0000000..709cb32
--- /dev/null
+++ b/src/util/type.h
@@ -0,0 +1,7 @@
+#ifndef _SOFTSHADEROOM_TYPE_H_
+#define _SOFTSHADEROOM_TYPE_H_
+
+typedef unsigned int uint;
+typedef int bool;
+
+#endif \ No newline at end of file