├── .clang-format ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.org ├── assets ├── ca1d.png ├── chull.png ├── dla-color.png ├── dla.png ├── glfw01.jpg ├── iris-poisson.png ├── iris-voronoi.png ├── iris.jpg ├── poisson-voronoi.png ├── polyclip.png ├── polyoffset-all-small.png ├── suzanne.stl ├── vatti.png └── verlet.png ├── autotest ├── browse ├── cleanup ├── compile ├── compile-bc ├── examples ├── ca │ ├── ca1d.c │ └── ca2d.c ├── common │ ├── stb.h │ └── stb_image.h ├── convexhull │ └── main.c ├── dla │ └── main.c ├── glfw │ ├── ex01.c │ ├── glfw_example.h │ ├── phong.c │ └── utils.c ├── poisson │ └── main.c ├── polyclip │ └── main.c ├── polyoffset │ └── main.c ├── verlet │ ├── cpack.c │ └── main.c └── voronoi │ └── main.c ├── geom-cljs ├── externs.js ├── project.clj ├── protocol.org ├── resources │ └── public │ │ └── index.html └── src │ └── thi │ └── ng │ └── geomc │ ├── core.cljs │ └── macros.clj ├── index.html ├── makevideo ├── postprocess.js ├── premake5.lua ├── src ├── cthing.h ├── data │ ├── adjacency.c │ ├── adjacency.h │ ├── array.c │ ├── array.h │ ├── cons.c │ ├── cons.h │ ├── consrc.c │ ├── consrc.h │ ├── hashset.c │ ├── hashset.h │ ├── hashtable.c │ ├── hashtable.h │ ├── object.c │ ├── object.h │ ├── octree.c │ ├── octree.h │ ├── quadtree.c │ ├── quadtree.h │ ├── soa.c │ ├── soa.h │ ├── spatialgrid.c │ ├── spatialgrid.h │ ├── tree.h │ ├── vector.c │ └── vector.h ├── geom │ ├── aabb.h │ ├── circle.c │ ├── circle.h │ ├── clip │ │ ├── liangbarsky.c │ │ └── liangbarsky.h │ ├── halfedge.c │ ├── hull.c │ ├── hull.h │ ├── isec.c │ ├── isec.h │ ├── mesh.c │ ├── polygon.c │ ├── polygon.h │ ├── protocols.h │ ├── quadedge.c │ ├── quadedge.h │ ├── rect.c │ ├── rect.h │ ├── triangle.c │ ├── triangle.h │ ├── voronoi.c │ └── voronoi.h ├── io │ ├── svg.c │ └── svg.h ├── math │ ├── hashfn.c │ ├── hashfn.h │ ├── math.c │ ├── math.h │ ├── matrix.c │ ├── matrix.h │ ├── poisson.c │ ├── poisson.h │ ├── swizzle.h │ ├── vec.c │ ├── vec.h │ ├── vec2.h │ ├── vec3.h │ ├── vec3_common.h │ ├── vec3_sse.h │ ├── vec4.h │ ├── vec4_common.h │ ├── vec4_sse.h │ └── vec_arrayops.h ├── mem │ ├── mem.h │ ├── mpool.c │ ├── mpool.h │ └── ref.h ├── rt_cthing.js └── sim │ ├── ca.c │ ├── ca.h │ ├── verlet.c │ └── verlet.h └── test ├── adjacency.c ├── circle.c ├── clip.c ├── cons.c ├── consrc.c ├── hash.c ├── hashset.c ├── hashtable.c ├── hull.c ├── main.c ├── matrix.c ├── mpool.c ├── octree.c ├── poisson.c ├── qedge.c ├── quadtree.c ├── random.c ├── soa.c ├── spatialgrid.c ├── vec.c └── vector.c /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | AllowAllParametersOfDeclarationOnNextLine: false 3 | AlignConsecutiveAssignments: true 4 | AllowShortBlocksOnASingleLine: false 5 | AllowShortFunctionsOnASingleLine: false 6 | AllowShortIfStatementsOnASingleLine: false 7 | AllowShortLoopsOnASingleLine: false 8 | BinPackParameters: false 9 | BreakBeforeBraces: Attach 10 | ColumnLimit: 80 11 | ReflowComments: false 12 | SortIncludes: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /geom-cljs/resources/public/js/ 2 | *.d 3 | *.o 4 | *.make 5 | bin 6 | *.log 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ext/ct-head"] 2 | path = ext/ct-head 3 | url = https://github.com/thi-ng/ct-head 4 | branch = master 5 | -------------------------------------------------------------------------------- /assets/ca1d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/ca1d.png -------------------------------------------------------------------------------- /assets/chull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/chull.png -------------------------------------------------------------------------------- /assets/dla-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/dla-color.png -------------------------------------------------------------------------------- /assets/dla.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/dla.png -------------------------------------------------------------------------------- /assets/glfw01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/glfw01.jpg -------------------------------------------------------------------------------- /assets/iris-poisson.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/iris-poisson.png -------------------------------------------------------------------------------- /assets/iris-voronoi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/iris-voronoi.png -------------------------------------------------------------------------------- /assets/iris.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/iris.jpg -------------------------------------------------------------------------------- /assets/poisson-voronoi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/poisson-voronoi.png -------------------------------------------------------------------------------- /assets/polyclip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/polyclip.png -------------------------------------------------------------------------------- /assets/polyoffset-all-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/polyoffset-all-small.png -------------------------------------------------------------------------------- /assets/suzanne.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/suzanne.stl -------------------------------------------------------------------------------- /assets/vatti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/vatti.png -------------------------------------------------------------------------------- /assets/verlet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thi-ng/c-thing/9c0762b115fffe81a705a1d5d59f1c19e033203e/assets/verlet.png -------------------------------------------------------------------------------- /autotest: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | readonly target=${1:-test_asan} 4 | readonly config=${2:-release} 5 | readonly qualifier=${3:-sse} 6 | readonly profile=${config}_${qualifier} 7 | 8 | retest() { 9 | printf "\033c" 10 | echo "----------------------------------------" 11 | date +%Y-%m-%d-%H:%M:%S 12 | echo "----------------------------------------" 13 | make -j3 config=$2_$3 $1 && bin/$2/$1; 14 | } 15 | 16 | make verbose=1 config=$profile clean 17 | retest $target $config $qualifier 18 | 19 | export -f retest 20 | fswatch -o src test | xargs -n1 -I{} bash -c "retest $target $config $qualifier" _ {} 21 | -------------------------------------------------------------------------------- /browse: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | find src -name '*.[ch]' > cscope.files 3 | cscope -b -q -k 4 | cscope -d 5 | -------------------------------------------------------------------------------- /cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | find . \( -name \*.c -or -name \*.cpp -or -name \*.cc -or -name \*.h \) \ 3 | -not -path "./ext/*" \ 4 | | xargs -n12 -P4 clang-format -i 5 | -------------------------------------------------------------------------------- /compile: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # compile with SIMD: 4 | # ./compile.sh -asd 5 | 6 | SRC=; 7 | SRC_DIRS="src/data src/geom src/geom/clip src/math src/mem src/sim" 8 | for d in $SRC_DIRS; do for f in `ls $d/*.c`; do SRC="$SRC $f"; done; done; 9 | 10 | TESTS= 11 | CFLAGS="-std=c11 -O3 -Isrc -Iext" 12 | EMFLAGS="-s ASM_JS=1 -s ASSERTIONS=0 -s INVOKE_RUN=0 -s AGGRESSIVE_VARIABLE_ELIMINATION=1 -s MODULARIZE=1 -s NO_EXIT_RUNTIME=1 -s TOTAL_MEMORY='48*1024*1024' --js-library src/rt_cthing.js" 13 | OUT=cthing.js 14 | MIN=cthing.min.js 15 | 16 | usage() 17 | { 18 | cat <&2 62 | usage 63 | exit 1 64 | ;; 65 | :) echo "$opt missing argument" >&2 66 | usage 67 | exit 1 68 | ;; 69 | esac 70 | done 71 | 72 | echo "cflags: $CFLAGS" 73 | echo "emflags: $EMFLAGS" 74 | echo "src: $SRC" 75 | echo "test: $TESTS" 76 | 77 | time emcc $CFLAGS \ 78 | --memory-init-file 0 \ 79 | --emit-symbol-map \ 80 | $EMFLAGS \ 81 | -s "TOTAL_STACK=1*1024*1024" \ 82 | -s "EXPORT_NAME='cthing'" \ 83 | -o $OUT \ 84 | $SRC \ 85 | $TESTS 86 | 87 | ls -la $OUT 88 | echo "postprocessing... $OUT -> $MIN" 89 | node postprocess.js $OUT $MIN 90 | ls -la $MIN 91 | cp $OUT geom-cljs/resources/public/js/ 92 | cp $MIN geom-cljs/resources/public/js/ 93 | 94 | # -s EXPORTED_FUNCTIONS=@exports.json 95 | # -s ELIMINATE_DUPLICATE_FUNCTIONS_DUMP_EQUIVALENT_FUNCTIONS=1 96 | -------------------------------------------------------------------------------- /compile-bc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | SRC=; 4 | SRC_DIRS="src/data src/geom src/geom/clip src/math src/mem src/sim" 5 | for d in $SRC_DIRS; do for f in `ls $d/*.c`; do SRC="$SRC $f"; done; done; 6 | 7 | CFLAGS="-std=c11 -Os -Isrc -Iext -DCT_NO_EXPORT" 8 | EMFLAGS="-s ASM_JS=1 -s ASSERTIONS=0 --js-library src/rt_cthing.js" 9 | BUILD_DIR=obj 10 | OUT=$BUILD_DIR/libcthing.bc 11 | 12 | usage() 13 | { 14 | cat <&2 38 | usage 39 | exit 1 40 | ;; 41 | :) echo "$opt missing argument" >&2 42 | usage 43 | exit 1 44 | ;; 45 | esac 46 | done 47 | 48 | echo "cflags: $CFLAGS" 49 | echo "emflags: $EMFLAGS" 50 | echo "src: $SRC" 51 | 52 | mkdir -p $BUILD_DIR 53 | time emcc $CFLAGS $EMFLAGS -o $OUT $SRC 54 | 55 | ls -la $OUT 56 | -------------------------------------------------------------------------------- /examples/ca/ca1d.c: -------------------------------------------------------------------------------- 1 | #include "io/svg.h" 2 | #include "math/math.h" 3 | #include "sim/ca.h" 4 | 5 | int main(int argc, char** argv) { 6 | srand(time(0)); 7 | const size_t rule_id = (argc > 1) ? atol(argv[1]) : rand(); 8 | const size_t states = (argc > 2) ? atol(argv[2]) : 2; 9 | const size_t kw = (argc > 3) ? atol(argv[3]) : 1; 10 | const size_t width = (argc > 4) ? atol(argv[4]) : 128; 11 | const float d = 600.0f / width; 12 | const float r = d * 0.5; 13 | CT_CARule1D rule = {.numStates = states, 14 | .kernelWidth = kw, 15 | .rule = rule_id, 16 | .flags = CT_CA_TILING}; 17 | CT_CAMatrix mat = {.width = width, .height = 1}; 18 | ct_carule1d_init(&rule); 19 | ct_camatrix_init(&mat); 20 | ct_camatrix_seed_noise(&mat, 0.5f); 21 | char fname[64]; 22 | snprintf(fname, 64, "assets/ca-%zu.svg", rule_id); 23 | FILE* out = fopen(fname, "w"); 24 | ct_svg_start_doc( 25 | out, ct_svg_attribs(1, 2, SVG_INT("width", 600), SVG_INT("height", 600))); 26 | ct_svg_start_group(out, ct_svg_attribs(1, 2, SVG_STR("stroke", "none"), 27 | SVG_HEX("fill", 0x0000ff))); 28 | for (size_t i = 0; i < width; i++) { 29 | for (size_t j = 0; j < width; j++) { 30 | if (mat.matrix[j]) { 31 | ct_svg_write_circle(out, j * d + r, i * d + r, r, NULL); 32 | } 33 | } 34 | ct_carule1d_evolve(&rule, &mat); 35 | } 36 | ct_svg_end_group(out); 37 | ct_svg_end_doc(out); 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /examples/ca/ca2d.c: -------------------------------------------------------------------------------- 1 | #include "io/svg.h" 2 | #include "math/math.h" 3 | #include "sim/ca.h" 4 | 5 | int main(int argc, char** argv) { 6 | srand(time(0)); 7 | const size_t states = (argc > 1) ? atol(argv[1]) : 2; 8 | const size_t width = (argc > 2) ? atol(argv[2]) : 128; 9 | const float d = 600.0f / (width + 1); 10 | const float r = d * 0.5; 11 | CT_CARule2D rule = {.birthRule = 0b1000, 12 | .survivalRule = 0b1100, 13 | .kernelWidth = 1, 14 | .numStates = states, 15 | .flags = CT_CA_TILING}; 16 | CT_CAMatrix mat = {.width = width, .height = width}; 17 | ct_carule2d_init(&rule); 18 | ct_camatrix_init(&mat); 19 | ct_camatrix_seed_noise(&mat, 0.5f); 20 | for (size_t gen = 0; gen < 300; gen++) { 21 | char fname[64]; 22 | snprintf(fname, 64, "assets/ca2d-%04zu.svg", gen); 23 | CT_INFO("---------- writing: %s", fname); 24 | FILE* out = fopen(fname, "w"); 25 | ct_svg_start_doc(out, ct_svg_attribs(1, 2, SVG_INT("width", 600), 26 | SVG_INT("height", 600))); 27 | ct_svg_start_group(out, ct_svg_attribs(1, 2, SVG_STR("stroke", "none"), 28 | SVG_HEX("fill", 0x0000ff))); 29 | uint8_t* cell = mat.matrix; 30 | for (size_t i = 0; i < width; i++) { 31 | for (size_t j = 0; j < width; j++) { 32 | if (*cell) { 33 | ct_svg_write_circle(out, j * d + r, i * d + r, r, NULL); 34 | } 35 | cell++; 36 | } 37 | } 38 | ct_svg_end_group(out); 39 | ct_svg_end_doc(out); 40 | fclose(out); 41 | ct_carule2d_evolve(&rule, &mat); 42 | } 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /examples/convexhull/main.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/random.h" 2 | 3 | #include "geom/hull.h" 4 | #include "io/svg.h" 5 | 6 | #define NUM 10000 7 | #define WIDTH 600 8 | #define HEIGHT 600 9 | #define RADIUS (0.48 * WIDTH) 10 | #define THETA (0.5 * CT_PI) 11 | 12 | static void export_poly(FILE *out, CT_Vector *poly, CT_SVGAttribs *attribs) { 13 | CT_VectorIter *i = ct_vector_iter_new(poly, 0); 14 | CT_Vec2f *p; 15 | ct_svg_start_group(out, attribs); 16 | fputs("x, p->y); 19 | } 20 | fputs("\"/>", out); 21 | ct_svg_end_group(out); 22 | free(i); 23 | } 24 | 25 | int main(int argc, char **argv) { 26 | CT_Vector *hull = ct_vector_new(32, sizeof(CT_Vec2f)); 27 | CT_Vec2f *points = calloc(NUM, sizeof(CT_Vec2f)); 28 | 29 | ct_svg_start_doc(stdout, ct_svg_attribs(1, 3, SVG_INT("width", WIDTH), 30 | SVG_INT("height", HEIGHT), 31 | SVG_STR("fill", "none"))); 32 | 33 | ct_svg_start_group(stdout, ct_svg_attribs(1, 1, SVG_HEX("fill", 0xff00cc))); 34 | for (size_t i = 0; i < NUM; i++) { 35 | CT_Vec2f *v = &points[i]; 36 | float r = ct_rand_normpos() * RADIUS; 37 | float t = ct_rand_normpos() * THETA; 38 | t = ct_rand_normpos() < 0.5 ? t : CT_PI + t; 39 | ct_add2fxy_imm(ct_cartesian2f_imm(ct_set2fxy(v, r, t)), WIDTH / 2, 40 | HEIGHT / 2); 41 | ct_svg_write_circle(stdout, v->x, v->y, 1.5, NULL); 42 | } 43 | ct_svg_end_group(stdout); 44 | 45 | size_t len = ct_convexhull2f(points, NUM, hull); 46 | CT_INFO("hull points: %zu", len); 47 | export_poly(stdout, hull, ct_svg_attribs(1, 1, SVG_HEX("stroke", 0xff))); 48 | 49 | ct_svg_end_doc(stdout); 50 | 51 | free(points); 52 | ct_vector_free(hull); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /examples/dla/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "ct-head/random.h" 4 | 5 | #include "data/spatialgrid.h" 6 | #include "io/svg.h" 7 | #include "math/math.h" 8 | #include "math/vec.h" 9 | 10 | #define BUF_SIZE 0x400 11 | 12 | typedef struct { 13 | CT_Vec3f *particles; 14 | CT_SpatialGrid accel; 15 | size_t length; 16 | size_t num; 17 | size_t width; 18 | size_t height; 19 | size_t seeds; 20 | float eps[2]; 21 | } DLA; 22 | 23 | // clang-format off 24 | static DLA dla = { 25 | .width = 600, 26 | .height = 600, 27 | .seeds = 16, 28 | .eps = {25, 25} 29 | }; 30 | // clang-format on 31 | 32 | ct_inline CT_Vec3f *rand_particle(DLA *dla) { 33 | return ct_set3fxyz(&dla->particles[dla->num++], 34 | ct_rand_normpos() * dla->width, 35 | ct_rand_normpos() * dla->height, 0); 36 | } 37 | 38 | static void add_particle(DLA *dla) { 39 | static CT_Vec3f *res[BUF_SIZE]; 40 | CT_Vec3f *p = rand_particle(dla); 41 | while (1) { 42 | const size_t num = ct_spgrid_select2d(&dla->accel, p->buf, dla->eps, 43 | (void **)&res, BUF_SIZE); 44 | if (num > 0) { 45 | float minD = FLT_MAX; 46 | CT_Vec3f *c = NULL; 47 | for (size_t i = 0; i < num; i++) { 48 | const float d = ct_distsq2fv(&p->xy, (CT_Vec2f *)res[i]); 49 | if (d >= 1 && d < minD) { 50 | minD = d; 51 | c = res[i]; 52 | } 53 | } 54 | if (c) { 55 | #ifdef CT_FEATURE_SSE4 56 | const __m128 cmm = c->mmval; 57 | p->mmval = (p->mmval - cmm) * _mm_rsqrt_ps(_mm_set1_ps(minD)) + cmm; 58 | #else 59 | const float t = 1.0f / sqrtf(minD); 60 | p->x = c->x + t * (p->x - c->x); 61 | p->y = c->y + t * (p->y - c->y); 62 | #endif 63 | p->z = c->z; 64 | ct_spgrid_insert(&dla->accel, p->buf, p); 65 | return; 66 | } 67 | } 68 | ct_set3fxyz(p, ct_rand_normpos() * dla->width, 69 | ct_rand_normpos() * dla->height, 0); 70 | }; 71 | } 72 | 73 | int main() { 74 | dla.length = dla.width * dla.height >> 2; 75 | dla.particles = malloc(dla.length * sizeof(CT_Vec3f)); 76 | ct_spgrid_init(&dla.accel, FVEC(0, 0), FVEC(dla.width, dla.height), 77 | IVEC(120, 120), 2, 0x8000); 78 | srand(time(0)); 79 | int cols[50]; 80 | for (int i = 0; i < dla.seeds; i++) { 81 | CT_Vec3f *p = rand_particle(&dla); 82 | p->z = i; 83 | ct_spgrid_insert(&dla.accel, p->buf, p); 84 | cols[i] = rand() & 0xffffff; 85 | } 86 | while (dla.num < dla.length) { 87 | add_particle(&dla); 88 | } 89 | ct_svg_start_doc(stdout, ct_svg_attribs(1, 2, SVG_INT("width", dla.width), 90 | SVG_INT("height", dla.height))); 91 | ct_svg_start_group(stdout, ct_svg_attribs(1, 1, SVG_STR("stroke", "none"))); 92 | for (size_t i = 0; i < dla.num; i++) { 93 | CT_Vec3f *p = &dla.particles[i]; 94 | ct_svg_write_circle(stdout, p->x, p->y, 1, 95 | ct_svg_attribs(1, 1, SVG_HEX("fill", cols[(int)p->z]))); 96 | } 97 | ct_svg_end_group(stdout); 98 | ct_svg_end_doc(stdout); 99 | fprintf(stderr, "%zu particles", dla.num); 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /examples/glfw/ex01.c: -------------------------------------------------------------------------------- 1 | #include "glfw_example.h" 2 | 3 | extern const char* phong_vs_src; 4 | extern const char* phong_fs_src; 5 | 6 | GLFWwindow* window; 7 | GLuint vbo, program; 8 | GLint model_loc, nmat_loc, view_loc, proj_loc; 9 | 10 | double mpos[] = {320, 240}; 11 | double zoom = 1; 12 | bool is_fullsceen; 13 | float* vertices; 14 | uint32_t numFaces; 15 | 16 | static void error_callback(int error, const char* description) { 17 | CT_ERROR("Error: %s", description); 18 | } 19 | 20 | static void key_callback(GLFWwindow* window, 21 | int key, 22 | int scancode, 23 | int action, 24 | int mods) { 25 | if (action == GLFW_PRESS) { 26 | if (key == GLFW_KEY_ESCAPE) { 27 | glfwSetWindowShouldClose(window, 1); 28 | } 29 | #ifndef __EMSCRIPTEN__ 30 | if (key == GLFW_KEY_F) { 31 | is_fullsceen = !is_fullsceen; 32 | if (is_fullsceen) { 33 | glfwSetWindowMonitor(window, glfwGetPrimaryMonitor(), 0, 0, 1280, 720, 34 | 60); 35 | } else { 36 | glfwSetWindowMonitor(window, NULL, 100, 100, 640, 480, 60); 37 | glfwSetWindowSize(window, 640, 480); 38 | } 39 | } 40 | #endif 41 | } 42 | } 43 | 44 | static void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) { 45 | mpos[0] = xpos; 46 | mpos[1] = ypos; 47 | } 48 | 49 | void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { 50 | zoom += yoffset * 0.01; 51 | zoom = ct_clampf(zoom, 0.1, 4); 52 | CT_DEBUG("%f", zoom); 53 | } 54 | 55 | void render() { 56 | int width, height; 57 | float aspect; 58 | CT_Mat4f model, proj, view, nmat, t; 59 | 60 | glfwGetFramebufferSize(window, &width, &height); 61 | aspect = (width / (float)height); 62 | glViewport(0, 0, width, height); 63 | glClearColor(0.1, 0.1, 0.1, 1); 64 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 65 | glEnable(GL_DEPTH_TEST); 66 | 67 | float mx = (width / 2.0 - mpos[0]) / width * 2 * aspect; 68 | float my = (height / 2.0 - mpos[1]) / height * 2; 69 | ct_mat4f_set_identity(&model); 70 | ct_mat4f_translate3fp_imm(&model, FVEC(mx, my, 0)); 71 | ct_mat4f_rotatex_imm(&model, (float)glfwGetTime() * 0.5); 72 | ct_mat4f_rotatey_imm(&model, (float)glfwGetTime()); 73 | ct_mat4f_set_identity(&t); 74 | ct_mat4f_scalen_imm(&t, zoom); 75 | ct_mat4f_mul_imm(&model, &t); 76 | CT_Vec3f eye = {0, 0, -2}; 77 | CT_Vec3f target = {0, 0, 0}; 78 | CT_Vec3f up = {0, 1, 0}; 79 | ct_mat4f_set_lookat(&view, &eye, &target, &up); 80 | ct_mat4f_set_perspective(&proj, 60, aspect, 0.1, 10); 81 | 82 | ct_mat4f_transpose_imm( 83 | ct_mat4f_invert(ct_mat4f_mul(&view, &model, &t), &nmat)); 84 | 85 | glUseProgram(program); 86 | glUniformMatrix4fv(model_loc, 1, GL_FALSE, (GLfloat*)&model); 87 | glUniformMatrix4fv(view_loc, 1, GL_FALSE, (GLfloat*)&view); 88 | glUniformMatrix4fv(proj_loc, 1, GL_FALSE, (GLfloat*)&proj); 89 | glUniformMatrix4fv(nmat_loc, 1, GL_FALSE, (GLfloat*)&nmat); 90 | glUniform3f(glGetUniformLocation(program, "lightPos"), 0, 1, 2); 91 | glUniform3f(glGetUniformLocation(program, "ambientCol"), 0.05, 0.1, 0.2); 92 | glUniform3f(glGetUniformLocation(program, "diffuseCol"), 0.05, 0.8, 1); 93 | glUniform3f(glGetUniformLocation(program, "specularCol"), 1, 1, 1); 94 | glUniform1f(glGetUniformLocation(program, "shininess"), 16); 95 | 96 | glDrawArrays(GL_TRIANGLES, 0, numFaces * 3); 97 | } 98 | 99 | int main(void) { 100 | char log[1024]; 101 | int status = 0; 102 | 103 | glfwSetErrorCallback(error_callback); 104 | if (!glfwInit()) { 105 | return 1; 106 | } 107 | //glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); 108 | //glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); 109 | //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 110 | //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 111 | glfwWindowHint(GLFW_SAMPLES, 4); 112 | glfwWindowHint(GLFW_RESIZABLE, 1); 113 | 114 | window = glfwCreateWindow(640, 480, "c.thi.ng x GLFW", NULL, NULL); 115 | if (!window) { 116 | glfwTerminate(); 117 | exit(EXIT_FAILURE); 118 | } 119 | #ifndef __EMSCRIPTEN__ 120 | glfwSetCursor(window, glfwCreateStandardCursor(GLFW_CROSSHAIR_CURSOR)); 121 | #endif 122 | glfwSetKeyCallback(window, key_callback); 123 | glfwSetCursorPosCallback(window, cursor_pos_callback); 124 | glfwSetScrollCallback(window, scroll_callback); 125 | 126 | glfwMakeContextCurrent(window); 127 | glfwSwapInterval(1); 128 | 129 | CT_TIMED(vertices = read_stl_binary(ASSET_PATH "/suzanne.stl", &numFaces)); 130 | glGenBuffers(1, &vbo); 131 | glBindBuffer(GL_ARRAY_BUFFER, vbo); 132 | glBufferData(GL_ARRAY_BUFFER, numFaces * 18 * sizeof(float), vertices, 133 | GL_STATIC_DRAW); 134 | 135 | program = init_shader_program(phong_vs_src, phong_fs_src); 136 | 137 | model_loc = glGetUniformLocation(program, "model"); 138 | view_loc = glGetUniformLocation(program, "view"); 139 | proj_loc = glGetUniformLocation(program, "proj"); 140 | nmat_loc = glGetUniformLocation(program, "normalMat"); 141 | CT_DEBUG("model: %d, view: %d, proj: %d, nmat: %d", model_loc, view_loc, 142 | proj_loc, nmat_loc); 143 | 144 | GLint pos = glGetAttribLocation(program, "position"); 145 | GLint normal = glGetAttribLocation(program, "normal"); 146 | CT_DEBUG("pos: %d, norm: %d", pos, normal); 147 | 148 | glEnableVertexAttribArray(pos); 149 | glVertexAttribPointer(pos, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), 150 | (void*)0); 151 | glEnableVertexAttribArray(normal); 152 | glVertexAttribPointer(normal, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), 153 | (void*)(sizeof(float) * 3)); 154 | #ifdef __EMSCRIPTEN__ 155 | emscripten_set_main_loop(render, 0, 1); 156 | #else 157 | while (!glfwWindowShouldClose(window)) { 158 | render(); 159 | glfwSwapBuffers(window); 160 | glfwPollEvents(); 161 | } 162 | glfwDestroyWindow(window); 163 | #endif 164 | glfwTerminate(); 165 | free(vertices); 166 | return 0; 167 | } 168 | -------------------------------------------------------------------------------- /examples/glfw/glfw_example.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __EMSCRIPTEN__ 4 | #include 5 | #define GLFW_INCLUDE_ES2 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "math/matrix.h" 14 | #include "math/vec.h" 15 | 16 | #ifndef ASSET_PATH 17 | #ifdef __EMSCRIPTEN__ 18 | #define ASSET_PATH "assets" 19 | #else 20 | #define ASSET_PATH "assets" 21 | #endif 22 | #endif 23 | 24 | char* slurp(const char* path); 25 | float* read_stl_binary(const char* path, uint32_t* numf); 26 | 27 | GLuint init_shader(GLenum type, const char* src); 28 | GLuint init_shader_program(const char* vsrc, const char* fsrc); 29 | -------------------------------------------------------------------------------- /examples/glfw/phong.c: -------------------------------------------------------------------------------- 1 | #include "glfw_example.h" 2 | 3 | const char* phong_vs_src = 4 | "uniform mat4 model;" 5 | "uniform mat4 view;" 6 | "uniform mat4 proj;" 7 | "uniform mat4 normalMat;" 8 | "uniform vec3 ambientCol;" 9 | "uniform vec3 diffuseCol;" 10 | "uniform vec3 specularCol;" 11 | "uniform vec3 lightPos;" 12 | "uniform float shininess;" 13 | "attribute vec3 position;" 14 | "attribute vec3 normal;" 15 | "varying vec3 vNormal;" 16 | "varying vec3 vEyePos;" 17 | "varying vec3 vLightPos;" 18 | "" 19 | "vec3 surfaceNormal(vec3 normal, mat4 normalMat) {" 20 | " return normalize((normalMat * vec4(normal, 0.0)).xyz);" 21 | "}" 22 | "" 23 | "void main(){" 24 | " vec4 worldPos = model * vec4(position, 1.0);" 25 | " vec4 eyePos = view * worldPos;" 26 | " vEyePos = eyePos.xyz;" 27 | " vNormal = surfaceNormal(normalize(normal), normalMat);" 28 | " vLightPos = (view * vec4(lightPos, 1.0)).xyz;" 29 | " gl_Position = proj * eyePos;" 30 | "}"; 31 | 32 | const char* phong_fs_src = 33 | #ifdef __EMSCRIPTEN__ 34 | "precision highp float;" 35 | #endif 36 | "uniform mat4 model;" 37 | "uniform mat4 view;" 38 | "uniform mat4 proj;" 39 | "uniform mat4 normalMat;" 40 | "uniform vec3 ambientCol;" 41 | "uniform vec3 diffuseCol;" 42 | "uniform vec3 specularCol;" 43 | "uniform vec3 lightPos;" 44 | "uniform float shininess;" 45 | "varying vec3 vNormal;" 46 | "varying vec3 vEyePos;" 47 | "varying vec3 vLightPos;" 48 | "" 49 | "float phong(vec3 lightDir, vec3 eyeDir, vec3 surfaceNormal) {" 50 | " return dot(reflect(-lightDir, surfaceNormal), eyeDir);" 51 | "}" 52 | "" 53 | "void main() {" 54 | " vec3 L = normalize(vLightPos - vEyePos);" 55 | " vec3 E = normalize(-vEyePos);" 56 | " vec3 N = normalize(vNormal);" 57 | "" 58 | " float NdotL = max(0.0, dot(N, L));" 59 | " vec3 color = ambientCol + NdotL * diffuseCol;" 60 | "" 61 | " float specular = phong(L, E, N);" 62 | " color += max(pow(specular, shininess), 0.0) * specularCol;" 63 | " gl_FragColor = vec4(color, 1.0);" 64 | "}"; 65 | -------------------------------------------------------------------------------- /examples/glfw/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "glfw_example.h" 4 | 5 | char *slurp(const char *path) { 6 | FILE *f = fopen(path, "r"); 7 | if (!f) 8 | return NULL; 9 | fseek(f, 0, SEEK_END); 10 | size_t len = ftell(f); 11 | char *buf = malloc(len); 12 | fseek(f, 0, SEEK_SET); 13 | fread(buf, 1, len, f); 14 | fclose(f); 15 | return buf; 16 | } 17 | 18 | float *read_stl_binary(const char *path, uint32_t *num) { 19 | CT_INFO("loading stl: %s", path); 20 | 21 | FILE *f = fopen(path, "rb"); 22 | CT_CHECK(f, "can't open file..."); 23 | 24 | fseek(f, 80, SEEK_SET); 25 | fread(num, 4, 1, f); 26 | uint32_t numf = *num; 27 | CT_INFO("%u faces", numf); 28 | 29 | // 3 verts + 3 normals 30 | float *buf = calloc(numf, sizeof(float) * 18); 31 | 32 | // skip 1st normal 33 | fseek(f, 3 * sizeof(float), SEEK_CUR); 34 | 35 | for (uint32_t i = 0; i < numf; i++) { 36 | const size_t j = i * 18; 37 | CT_Vec3f a, b, c, n; 38 | 39 | fread(&buf[j], sizeof(float), 3, f); 40 | fread(&buf[j + 6], sizeof(float), 3, f); 41 | fread(&buf[j + 12], sizeof(float), 3, f); 42 | // skip face attrib + next normal 43 | fseek(f, 2 + 3 * sizeof(float), SEEK_CUR); 44 | 45 | #ifdef CT_FEATURE_SSE 46 | // memcpy needed for SSE alignment 47 | memcpy(&a, &buf[j], 3 * sizeof(float)); 48 | memcpy(&b, &buf[j + 6], 3 * sizeof(float)); 49 | memcpy(&c, &buf[j + 12], 3 * sizeof(float)); 50 | ct_orthonormal3fv(&a, &b, &c, &n); 51 | #else 52 | ct_orthonormal3fv((CT_Vec3f *)&buf[j], (CT_Vec3f *)&buf[j + 6], 53 | (CT_Vec3f *)&buf[j + 12], &n); 54 | #endif 55 | 56 | memcpy(&buf[j + 3], &n, 3 * sizeof(float)); 57 | memcpy(&buf[j + 9], &n, 3 * sizeof(float)); 58 | memcpy(&buf[j + 15], &n, 3 * sizeof(float)); 59 | 60 | CT_DEBUG("[%f,%f,%f] [%f,%f,%f] [%f,%f,%f] n: [%f,%f,%f]", buf[j], 61 | buf[j + 1], buf[j + 2], buf[j + 6], buf[j + 7], buf[j + 8], 62 | buf[j + 12], buf[j + 13], buf[j + 14], n.x, n.y, n.z); 63 | } 64 | 65 | fclose(f); 66 | return buf; 67 | fail: 68 | exit(1); 69 | } 70 | 71 | GLuint init_shader(GLenum type, const char *src) { 72 | static char log[0x400]; 73 | int status; 74 | GLuint shader = glCreateShader(type); 75 | glShaderSource(shader, 1, &src, NULL); 76 | glCompileShader(shader); 77 | glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 78 | CT_CHECK(status == GL_TRUE, "shader compiler error: %d", status); 79 | return shader; 80 | fail: 81 | glGetShaderInfoLog(shader, 0x400, &status, log); 82 | CT_ERROR("%s", log); 83 | exit(1); 84 | } 85 | 86 | GLuint init_shader_program(const char *vsrc, const char *fsrc) { 87 | GLuint vs = init_shader(GL_VERTEX_SHADER, vsrc); 88 | GLuint fs = init_shader(GL_FRAGMENT_SHADER, fsrc); 89 | GLuint program = glCreateProgram(); 90 | glAttachShader(program, vs); 91 | glAttachShader(program, fs); 92 | glLinkProgram(program); 93 | 94 | int status; 95 | glGetProgramiv(program, GL_LINK_STATUS, &status); 96 | glDeleteShader(vs); 97 | glDeleteShader(fs); 98 | CT_CHECK(status == GL_TRUE, "link error: %d", status); 99 | return program; 100 | fail: 101 | exit(1); 102 | } 103 | -------------------------------------------------------------------------------- /examples/polyclip/main.c: -------------------------------------------------------------------------------- 1 | #include "geom/polygon.h" 2 | #include "io/svg.h" 3 | 4 | static void export_poly(FILE *out, CT_Polygon2f *poly, CT_SVGAttribs *attribs) { 5 | ct_svg_start_group(out, attribs); 6 | fputs("first; 8 | do { 9 | fprintf(out, "%1.3f,%1.3f ", v->pos.x, v->pos.y); 10 | v = v->next; 11 | } while (v != poly->first); 12 | fputs("\"/>", out); 13 | ct_svg_end_group(out); 14 | } 15 | 16 | int main() { 17 | //CT_Vec2f a[] = {{10, 10}, {590, 10}, {300, 510}}; 18 | //CT_Vec2f b[] = {{10, 300}, {250, 100}, {400, 200}, 19 | // {590, 100}, {350, 300}, {200, 200}}; 20 | CT_Vec2f a[] = {{108, 106}, {185, 58}, {172, 42}, {225, 10}, 21 | {369, 175}, {402, 232}, {418, 276}, {358, 302}, 22 | {378, 256}, {247, 188}, {186, 119}, {132, 148}}; 23 | CT_Vec2f b[] = {{78, 236}, {115, 276}, {170, 212}, {181, 207}, {215, 234}, 24 | {282, 264}, {313, 175}, {296, 169}, {285, 193}, {277, 189}, 25 | {283, 175}, {275, 172}, {284, 160}, {273, 152}, {259, 178}, 26 | {241, 148}, {275, 114}, {317, 157}, {329, 147}, {261, 71}, 27 | {180, 138}, {139, 159}, {149, 170}}; 28 | ct_svg_start_doc( 29 | stdout, ct_svg_attribs(1, 3, SVG_INT("width", 600), 30 | SVG_INT("height", 600), SVG_STR("fill", "none"))); 31 | fputs( 32 | "", 35 | stdout); 36 | for (size_t i = 0; i < 4; i++) { 37 | CT_PolyClipContext ctx; 38 | ct_polygon2f_clip_ctx_init(&ctx, 4); 39 | 40 | CT_Polygon2f s, c; 41 | ct_polygon2f_init(&s, a, sizeof(a) / sizeof(CT_Vec2f)); 42 | ct_polygon2f_init(&c, b, sizeof(b) / sizeof(CT_Vec2f)); 43 | CT_Cons *result = ct_polygon2f_clip(&ctx, &s, &c, i); 44 | char tx[64]; 45 | snprintf(tx, 64, "translate(%f,%f) scale(0.75)", (i & 1) * 300.0 - 50, 46 | ((i >> 1) & 1) * 300.0); 47 | ct_svg_start_group(stdout, ct_svg_attribs(1, 1, SVG_STR("transform", tx))); 48 | export_poly(stdout, &s, ct_svg_attribs(1, 1, SVG_HEX("stroke", 0xff0088))); 49 | export_poly(stdout, &c, ct_svg_attribs(1, 1, SVG_HEX("stroke", 0x8800ff))); 50 | while (result) { 51 | export_poly(stdout, result->value, 52 | ct_svg_attribs(1, 3, SVG_HEX("stroke", 0x0000ff), 53 | SVG_STR("fill", "url(#P1)"), 54 | SVG_FLOAT("stroke-width", 3.f))); 55 | result = result->next; 56 | } 57 | ct_svg_end_group(stdout); 58 | ct_polygon2f_free(&s); 59 | ct_polygon2f_free(&c); 60 | ct_polygon2f_clip_ctx_free(&ctx); 61 | } 62 | ct_svg_end_doc(stdout); 63 | } 64 | -------------------------------------------------------------------------------- /examples/polyoffset/main.c: -------------------------------------------------------------------------------- 1 | #include "geom/polygon.h" 2 | #include "io/svg.h" 3 | 4 | static void export_poly(FILE *out, CT_Polygon2f *poly, CT_SVGAttribs *attribs) { 5 | ct_svg_start_group(out, attribs); 6 | fputs("first; 8 | do { 9 | fprintf(out, "%1.3f,%1.3f ", v->pos.x, v->pos.y); 10 | v = v->next; 11 | } while (v != poly->first); 12 | fputs("\"/>", out); 13 | ct_svg_end_group(out); 14 | } 15 | 16 | int main() { 17 | CT_Vec2f a[] = {{-157, -53}, {-80, -101}, {-93, -117}, {-40, -149}, 18 | {104, 15}, {137, 72}, {153, 116}, {93, 142}, 19 | {113, 96}, {-18, 28}, {-79, -40}, {-133, -11}}; 20 | 21 | CT_Vec2f b[] = {{-160, 57}, {-123, 97}, {-68, 33}, {-57, 28}, {-23, 55}, 22 | {43, 85}, {74, -3}, {57, -9}, {46, 14}, {38, 10}, 23 | {44, -3}, {36, -6}, {45, -18}, {34, -26}, {20, 0}, 24 | {2, -30}, {36, -64}, {78, -21}, {90, -31}, {22, -107}, 25 | {-58, -40}, {-99, -19}, {-89, -8}}; 26 | 27 | ct_svg_start_doc( 28 | stdout, 29 | ct_svg_attribs(1, 4, SVG_INT("width", 600), SVG_INT("height", 600), 30 | SVG_STR("fill", "none"), SVG_FLOAT("stroke-width", 0.5f))); 31 | ct_svg_start_group( 32 | stdout, ct_svg_attribs( 33 | 1, 1, SVG_STR("transform", "matrix(1.8 0 0 1.8 360 300)"))); 34 | 35 | CT_Polygon2f *result; 36 | CT_PolyOffsetContext ctx; 37 | ct_polygon2f_offset_ctx_init(&ctx, 64); 38 | 39 | for (int i = 9; i > -10; i--) { 40 | result = ct_polygon2f_offset_points(&ctx, b, sizeof(b) / sizeof(CT_Vec2f), 41 | i * 2.5, 7); 42 | if (result) { 43 | uint32_t col = abs(i) * 25; 44 | uint32_t col2 = col >> 1; 45 | col = (col2 << 16) | (col2 << 8) | col; 46 | export_poly(stdout, result, 47 | ct_svg_attribs(1, 1, SVG_HEX("stroke", i ? col : 0xff00cc))); 48 | } 49 | ct_polygon2f_offset_ctx_reset(&ctx); 50 | } 51 | 52 | ct_polygon2f_offset_ctx_free(&ctx); 53 | 54 | ct_svg_end_group(stdout); 55 | ct_svg_end_doc(stdout); 56 | } 57 | -------------------------------------------------------------------------------- /examples/verlet/cpack.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/random.h" 2 | 3 | #include "io/svg.h" 4 | #include "math/math.h" 5 | #include "math/vec.h" 6 | #include "sim/verlet.h" 7 | 8 | #define NUM 276 9 | 10 | static CT_SVGAttribs *doc_attribs; 11 | static CT_SVGAttribs *group_attribs; 12 | 13 | void outputFrame(CT_Verlet *phys, size_t frame) { 14 | char fname[64]; 15 | snprintf(fname, 64, "assets/verlet-%04zu.svg", frame); 16 | CT_INFO("---------- writing: %s", fname); 17 | FILE *out = fopen(fname, "w"); 18 | ct_svg_start_doc(out, doc_attribs); 19 | ct_svg_start_group(out, group_attribs); 20 | for (size_t i = 0; i < phys->numP; i++) { 21 | float p[3]; 22 | ct_verlet_pos2f(phys, i, p); 23 | ct_svg_write_circle(out, p[0], p[1], p[2], NULL); 24 | } 25 | ct_svg_end_group(out); 26 | ct_svg_end_doc(out); 27 | fclose(out); 28 | } 29 | 30 | void spawn_particle(CT_Verlet *phys, CT_Vec2f *p, size_t id) { 31 | CT_Vec2f q; 32 | int ok; 33 | float r = 34 | ct_rand_normpos() < 1.1 ? ct_rand_minmax(4, 30) : ct_rand_minmax(2, 4); 35 | float raccept = (r * 0.5) * (r * 0.5); 36 | do { 37 | q.x = ct_rand_normpos() * r * 2 + p->x; 38 | q.y = ct_rand_normpos() * r * 2 + p->y; 39 | ok = (id == 0); 40 | for (size_t i = 0, j = id << 1; i < j && !ok; i += 2) { 41 | ok = (ct_distsq2fv(&q, (CT_Vec2f *)&phys->pos[i]) >= raccept); 42 | } 43 | } while (!ok); 44 | ct_verlet_set2f(phys, id, (float *)&q, r); 45 | } 46 | 47 | int main() { 48 | // clang-format off 49 | CT_Verlet phys = { 50 | .bounds = {20, 20, 580, 580}, 51 | .gravity = {0.0, 0.0}, 52 | .friction = 0.5, 53 | .repulsion = 1.0, 54 | .maxForce = 20, 55 | .iter = 4 56 | }; 57 | // clang-format off 58 | if (ct_verlet_init2d(&phys, NUM, 0, IVEC(120, 120, 120))) { 59 | return 1; 60 | } 61 | ct_spgrid_trace(&phys.accel); 62 | srand(time(0)); 63 | doc_attribs = ct_svg_attribs(0, 2, SVG_INT("width", 600), SVG_INT("height", 600)); 64 | group_attribs = ct_svg_attribs(0, 2, SVG_STR("fill", "none"), SVG_HEX("stroke", 0x0)); 65 | outputFrame(&phys, 0); 66 | for (size_t i = 1; i < 100; i++) { 67 | size_t num = CT_MIN(i * 64, NUM); 68 | CT_Vec2f *p = (CT_Vec2f*)&phys.pos[num - 1]; 69 | for(size_t j = phys.numP; j< num; j++) { 70 | spawn_particle(&phys, p, j); 71 | } 72 | phys.numP = num; 73 | CT_TIMED(ct_verlet_update2d(&phys)); 74 | outputFrame(&phys, i); 75 | } 76 | ct_verlet_free(&phys); 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /examples/verlet/main.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/random.h" 2 | 3 | #include "io/svg.h" 4 | #include "math/math.h" 5 | #include "math/vec.h" 6 | #include "sim/verlet.h" 7 | 8 | #define NUM 2048 9 | 10 | static CT_SVGAttribs *doc_attr; 11 | static CT_SVGAttribs *group_attr; 12 | static CT_SVGAttribs *spring_attr; 13 | 14 | void outputFrame(CT_Verlet *phys, size_t frame) { 15 | char fname[64]; 16 | snprintf(fname, 64, "assets/verlet-%04zu.svg", frame); 17 | CT_INFO("---------- writing: %s", fname); 18 | FILE *out = fopen(fname, "w"); 19 | ct_svg_start_doc(out, doc_attr); 20 | // springs 21 | ct_svg_start_group(out, spring_attr); 22 | for (size_t i = 0; i < phys->numS; i++) { 23 | CT_VPSpring *s = &phys->springs[i]; 24 | CT_Vec2f *a = (CT_Vec2f *)&phys->pos[s->a]; 25 | CT_Vec2f *b = (CT_Vec2f *)&phys->pos[s->b]; 26 | ct_svg_write_line(out, a->x, a->y, b->x, b->y, NULL); 27 | } 28 | ct_svg_end_group(out); 29 | // particles 30 | ct_svg_start_group(out, group_attr); 31 | for (size_t i = 0; i < phys->numP; i++) { 32 | float p[3]; 33 | ct_verlet_pos2f(phys, i, p); 34 | ct_svg_write_circle(out, p[0], p[1], 3, NULL); 35 | } 36 | ct_svg_end_group(out); 37 | ct_svg_end_doc(out); 38 | fclose(out); 39 | } 40 | 41 | void spawn_particle(CT_Verlet *phys, CT_Vec2f *p, size_t id) { 42 | CT_Vec2f q; 43 | int ok; 44 | float r = 5; 45 | float raccept = (r * 0.5) * (r * 0.5); 46 | do { 47 | q.x = ct_clampf(ct_rand_normpos() * r * 2 + p->x, 0, 600); 48 | q.y = ct_clampf(ct_rand_normpos() * r * 2 + p->y, 0, 600); 49 | ok = (id == 0); 50 | for (size_t i = 0, j = id << 1; i < j && !ok; i += 2) { 51 | ok = (ct_distsq2fv(&q, (CT_Vec2f *)&phys->pos[i]) >= raccept); 52 | } 53 | } while (!ok); 54 | ct_verlet_set2f(phys, id, q.buf, r); 55 | if (id > 0) { 56 | ct_verlet_set_spring2d(phys, phys->numS, id - 1, id, 16, 0.5); 57 | phys->numS++; 58 | } 59 | } 60 | 61 | int main() { 62 | // clang-format off 63 | CT_Verlet phys = { 64 | .bounds = {20, 20, 580, 580}, 65 | .gravity = {0.05, 0.1}, 66 | .friction = 0.5, 67 | .repulsion = 1.0, 68 | .maxForce = 20, 69 | .iter = 2 70 | }; 71 | // clang-format off 72 | if (ct_verlet_init2d(&phys, NUM, NUM, IVEC(120, 120, 120))) { 73 | return 1; 74 | } 75 | ct_spgrid_trace(&phys.accel); 76 | srand(time(0)); 77 | doc_attr = ct_svg_attribs(0, 2, SVG_INT("width", 600), SVG_INT("height", 600)); 78 | group_attr = ct_svg_attribs(0, 2, SVG_STR("stroke", "none"), SVG_HEX("fill", 0x0000ff)); 79 | spring_attr = ct_svg_attribs(0, 1, SVG_HEX("stroke", 0xff0000)); 80 | outputFrame(&phys, 0); 81 | for (size_t i = 1; i < 300; i++) { 82 | size_t num = CT_MIN(i * 8, NUM); 83 | CT_Vec2f *p = i > 1 ? (CT_Vec2f*)&phys.pos[num - 1] : (CT_Vec2f*)FVEC(300,300); 84 | for(size_t j = phys.numP; j< num; j++) { 85 | spawn_particle(&phys, p, j); 86 | } 87 | phys.numP = num; 88 | CT_TIMED(ct_verlet_update2d(&phys)); 89 | outputFrame(&phys, i); 90 | } 91 | ct_verlet_free(&phys); 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /examples/voronoi/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "geom/voronoi.h" 4 | #include "io/svg.h" 5 | #include "math/math.h" 6 | #include "math/poisson.h" 7 | 8 | #define NUM_SITES 20000 9 | #define LIMIT 1e4 10 | #define WIDTH 600 11 | #define DIST 10 12 | #define QUALITY 100 13 | 14 | typedef struct { 15 | CT_Vec2f *sites; 16 | int width; 17 | int height; 18 | int num; 19 | int quality; 20 | int showSites; 21 | int pipe; 22 | float dist; 23 | float limit; 24 | } AppState; 25 | 26 | // clang-format off 27 | static AppState state = { 28 | .width = WIDTH, 29 | .height = WIDTH, 30 | .num = NUM_SITES, 31 | .dist = DIST, 32 | .quality = QUALITY, 33 | .limit = LIMIT, 34 | .pipe = 0, 35 | .showSites = 0 36 | }; 37 | // clang-format on 38 | 39 | static void write_edge(CT_VOEdge *e, void *_) { 40 | CT_VOVertex *a = e->ep[0], *b = e->ep[1]; 41 | if (a && b) { 42 | ct_svg_write_line2fv(stdout, &a->pos, &b->pos, NULL); 43 | } 44 | } 45 | 46 | static void voronoi_poisson(AppState *state) { 47 | srand(time(0)); 48 | CT_Quadtree qt; 49 | CT_Voronoi vor; 50 | size_t num = 3; 51 | ct_qtree_init(&qt, 0, 0, state->width, state->height, 0x1000); 52 | while (num < state->num) { 53 | if (ct_poisson_sample2f(&qt, state->dist, state->quality, 54 | &state->sites[num])) 55 | break; 56 | if (state->showSites) { 57 | ct_svg_write_circle(stdout, state->sites[num].x, state->sites[num].y, 2, 58 | NULL); 59 | } 60 | num++; 61 | } 62 | ct_svg_start_group(stdout, ct_svg_attribs(1, 1, SVG_HEX("stroke", 0xff))); 63 | ct_voronoi_init(&vor, num); 64 | clock_t t0 = clock(); 65 | ct_voronoi_compute(&vor, state->sites, num, write_edge, stdout); 66 | double taken = (double)(clock() - t0) / CLOCKS_PER_SEC * 1000.0; 67 | fprintf(stderr, "voronoi: %1.3fms (%zu sites)\n", taken, num); 68 | ct_voronoi_free(&vor); 69 | ct_qtree_free(&qt); 70 | } 71 | 72 | static void voronoi_pipe(AppState *state) { 73 | size_t num = 3; 74 | while (num < state->num && 75 | fscanf(stdin, "%f,%f", &state->sites[num].x, &state->sites[num].y) != 76 | EOF) { 77 | if (state->showSites) { 78 | ct_svg_write_circle(stdout, state->sites[num].x, state->sites[num].y, 2, 79 | NULL); 80 | } 81 | num++; 82 | } 83 | ct_svg_start_group(stdout, ct_svg_attribs(1, 1, SVG_HEX("stroke", 0xff))); 84 | CT_Voronoi vor; 85 | ct_voronoi_init(&vor, num); 86 | clock_t t0 = clock(); 87 | ct_voronoi_compute(&vor, state->sites, num, write_edge, stdout); 88 | double taken = (double)(clock() - t0) / CLOCKS_PER_SEC * 1000.0; 89 | fprintf(stderr, "voronoi: %1.3fms (%zu sites)\n", taken, num); 90 | ct_voronoi_free(&vor); 91 | } 92 | 93 | void usage(AppState *state) { 94 | fprintf(stderr, "TODO usage:\n"); 95 | } 96 | 97 | int main(int argc, char **argv) { 98 | char c; 99 | uint8_t err = 0; 100 | while (!err && (c = getopt(argc, argv, "d:h:l:n:pq:sw:")) != -1) { 101 | switch (c) { 102 | case 'd': 103 | state.dist = ct_parse_float(optarg, state.dist); 104 | break; 105 | case 'l': 106 | state.limit = ct_parse_float(optarg, state.limit); 107 | break; 108 | case 'q': 109 | state.quality = ct_parse_int(optarg, state.quality); 110 | break; 111 | case 's': 112 | state.showSites = 1; 113 | break; 114 | case 'w': 115 | state.width = ct_parse_int(optarg, state.width); 116 | break; 117 | case 'h': 118 | state.height = ct_parse_int(optarg, state.height); 119 | break; 120 | case 'n': 121 | state.num = ct_parse_int(optarg, state.num); 122 | break; 123 | case 'p': 124 | state.pipe = 1; 125 | break; 126 | case '?': 127 | fprintf(stderr, "Option -%c requires an argument\n", optopt); 128 | err = 1; 129 | break; 130 | default: 131 | err = 1; 132 | } 133 | } 134 | if (err) { 135 | usage(&state); 136 | return 1; 137 | } 138 | state.sites = malloc(state.num * sizeof(CT_Vec2f)); 139 | // define surrounding triangle 140 | ct_set2fxy(&state.sites[0], -state.limit, -state.limit); 141 | ct_set2fxy(&state.sites[1], state.limit, -state.limit); 142 | ct_set2fxy(&state.sites[2], state.width / 2, state.limit); 143 | 144 | ct_svg_start_doc(stdout, ct_svg_attribs(1, 3, SVG_INT("width", state.width), 145 | SVG_INT("height", state.height), 146 | SVG_HEX("fill", 0xff00cc))); 147 | if (state.pipe) { 148 | voronoi_pipe(&state); 149 | } else { 150 | voronoi_poisson(&state); 151 | } 152 | ct_svg_end_group(stdout); 153 | ct_svg_end_doc(stdout); 154 | return 0; 155 | } 156 | -------------------------------------------------------------------------------- /geom-cljs/externs.js: -------------------------------------------------------------------------------- 1 | var geom = {}; 2 | 3 | geom.ccall = function() {}; 4 | geom.cwrap = function() {}; 5 | geom._malloc = function() {}; 6 | geom._free = function() {}; 7 | 8 | geom._ct_mpool_init = function() {}; 9 | geom._ct_mpool_alloc = function() {}; 10 | geom._ct_mpool_free = function() {}; 11 | geom._ct_mpool_free_all = function() {}; 12 | 13 | geom._ct_vec2f = function() {}; 14 | geom._ct_mag2f = function() {}; 15 | geom._ct_add2fv_imm = function() {}; 16 | geom._ct_add2fn_imm = function() {}; 17 | geom._ct_add2fxy_imm = function() {}; 18 | geom._ct_sub2fv_imm = function() {}; 19 | geom._ct_sub2fn_imm = function() {}; 20 | geom._ct_sub2fxy_imm = function() {}; 21 | geom._ct_mul2fv_imm = function() {}; 22 | geom._ct_mul2fn_imm = function() {}; 23 | geom._ct_mul2fxy_imm = function() {}; 24 | geom._ct_div2fv_imm = function() {}; 25 | geom._ct_div2fn_imm = function() {}; 26 | geom._ct_div2fxy_imm = function() {}; 27 | 28 | geom._ct_vec3f = function() {}; 29 | geom._ct_mag3f = function() {}; 30 | geom._ct_add3fv_imm = function() {}; 31 | geom._ct_add3fn_imm = function() {}; 32 | geom._ct_add3fxy_imm = function() {}; 33 | geom._ct_sub3fv_imm = function() {}; 34 | geom._ct_sub3fn_imm = function() {}; 35 | geom._ct_sub3fxy_imm = function() {}; 36 | geom._ct_mul3fv_imm = function() {}; 37 | geom._ct_mul3fn_imm = function() {}; 38 | geom._ct_mul3fxy_imm = function() {}; 39 | geom._ct_div3fv_imm = function() {}; 40 | geom._ct_div3fn_imm = function() {}; 41 | geom._ct_div3fxy_imm = function() {}; 42 | 43 | geom._ct_cross3fv_imm = function() {}; 44 | geom._ct_mix3fv_imm = function() {}; 45 | geom._ct_mix3fv = function() {}; 46 | 47 | geom._ct_circle2f_init = function() {}; 48 | geom._ct_circle2f_area = function() {}; 49 | geom._ct_circle2f_vertices = function() {}; 50 | geom._ct_circle2f_tessellate = function() {}; 51 | 52 | geom._ct_triangle2f_init = function() {}; 53 | geom._ct_triangle2f_area = function() {}; 54 | 55 | geom._ct_triangle3f_init = function() {}; 56 | geom._ct_triangle3f_area = function() {}; 57 | 58 | geom.HEAPF32 = []; 59 | geom.HEAPU8 = []; 60 | -------------------------------------------------------------------------------- /geom-cljs/project.clj: -------------------------------------------------------------------------------- 1 | (defproject thi.ng/geom-cljs "0.1.0-SNAPSHOT" 2 | :description "thi.ng/geom asm.js" 3 | :url "http://thi.ng/geom" 4 | 5 | :min-lein-version "2.5.3" 6 | 7 | :dependencies [[org.clojure/clojure "1.8.0"] 8 | [org.clojure/clojurescript "1.8.51"] 9 | [thi.ng/geom "0.0.1158-SNAPSHOT"] 10 | [thi.ng/domus "0.3.0-SNAPSHOT"] 11 | [reagent "0.5.1"]] 12 | 13 | :plugins [[lein-figwheel "0.5.0-6"] 14 | [lein-cljsbuild "1.1.3" :exclusions [[org.clojure/clojure]]]] 15 | 16 | :source-paths ["src"] 17 | 18 | :clean-targets ^{:protect false} ["resources/public/js/compiled" "target"] 19 | 20 | :cljsbuild {:builds 21 | [{:id "dev" 22 | :source-paths ["src"] 23 | :figwheel true 24 | :compiler {:main thi.ng.geomc.core 25 | :asset-path "js/compiled/out" 26 | :output-to "resources/public/js/compiled/app.js" 27 | :output-dir "resources/public/js/compiled/out" 28 | :source-map-timestamp true}} 29 | {:id "min" 30 | :source-paths ["src"] 31 | :compiler {:output-to "resources/public/js/compiled/app.js" 32 | :optimizations :advanced 33 | :externs ["externs.js"]}}]} 34 | 35 | :figwheel {:css-dirs ["resource/public/css"] 36 | ;; :ring-handler hello_world.server/handler 37 | }) 38 | -------------------------------------------------------------------------------- /geom-cljs/protocol.org: -------------------------------------------------------------------------------- 1 | ** CLJS 2 | 3 | #+BEGIN_SRC clojure 4 | (defprotocol IFoo 5 | (foo [_]) 6 | (foo1 [_ x]) 7 | (foo2 [_ x y])) 8 | 9 | (deftype Bar [ptr] 10 | IFoo 11 | (foo [_] _) 12 | (foo1 [_ x] x) 13 | (foo2 [_ x y] [x y])) 14 | #+END_SRC 15 | 16 | ** Default impl 17 | #+BEGIN_SRC javascript 18 | /** 19 | ,* @interface 20 | ,*/ 21 | cljs.user.IFoo = function(){ 22 | }; 23 | cljs.user.foo = (function cljs$user$foo(_){ 24 | if((!((_ == null))) && (!((_.cljs$user$IFoo$foo$arity$1 == null)))){ 25 | return _.cljs$user$IFoo$foo$arity$1(_); 26 | } 27 | else { 28 | var x__32269__auto__ = (((_ == null))?null:_); 29 | var m__32270__auto__ = (cljs.user.foo[goog.typeOf(x__32269__auto__)]); 30 | if(!((m__32270__auto__ == null))){ 31 | return m__32270__auto__.call(null,_); 32 | } 33 | else { 34 | var m__32270__auto____$1 = (cljs.user.foo["_"]); 35 | if(!((m__32270__auto____$1 == null))){ 36 | return m__32270__auto____$1.call(null,_); 37 | } 38 | else { 39 | throw cljs.core.missing_protocol.call(null,"IFoo.foo",_); 40 | } 41 | } 42 | } 43 | } 44 | ); 45 | cljs.user.foo1 = (function cljs$user$foo1(_,x){ 46 | if((!((_ == null))) && (!((_.cljs$user$IFoo$foo1$arity$2 == null)))){ 47 | return _.cljs$user$IFoo$foo1$arity$2(_,x); 48 | } 49 | else { 50 | var x__32269__auto__ = (((_ == null))?null:_); 51 | var m__32270__auto__ = (cljs.user.foo1[goog.typeOf(x__32269__auto__)]); 52 | if(!((m__32270__auto__ == null))){ 53 | return m__32270__auto__.call(null,_,x); 54 | } 55 | else { 56 | var m__32270__auto____$1 = (cljs.user.foo1["_"]); 57 | if(!((m__32270__auto____$1 == null))){ 58 | return m__32270__auto____$1.call(null,_,x); 59 | } 60 | else { 61 | throw cljs.core.missing_protocol.call(null,"IFoo.foo1",_); 62 | } 63 | } 64 | } 65 | } 66 | ); 67 | cljs.user.foo2 = (function cljs$user$foo2(_,x,y){ 68 | if((!((_ == null))) && (!((_.cljs$user$IFoo$foo2$arity$3 == null)))){ 69 | return _.cljs$user$IFoo$foo2$arity$3(_,x,y); 70 | } 71 | else { 72 | var x__32269__auto__ = (((_ == null))?null:_); 73 | var m__32270__auto__ = (cljs.user.foo2[goog.typeOf(x__32269__auto__)]); 74 | if(!((m__32270__auto__ == null))){ 75 | return m__32270__auto__.call(null,_,x,y); 76 | } 77 | else { 78 | var m__32270__auto____$1 = (cljs.user.foo2["_"]); 79 | if(!((m__32270__auto____$1 == null))){ 80 | return m__32270__auto____$1.call(null,_,x,y); 81 | } 82 | else { 83 | throw cljs.core.missing_protocol.call(null,"IFoo.foo2",_); 84 | } 85 | } 86 | } 87 | } 88 | ); 89 | /** 90 | ,* @constructor 91 | ,* @implements {cljs.user.IFoo} 92 | ,*/ 93 | cljs.user.Bar = (function (ptr){ 94 | this.ptr = ptr; 95 | } 96 | ) 97 | cljs.user.Bar.prototype.cljs$user$IFoo$ = true; 98 | cljs.user.Bar.prototype.cljs$user$IFoo$foo$arity$1 = (function (_){ 99 | var self__ = this; 100 | var ___$1 = this; 101 | return ___$1; 102 | } 103 | ); 104 | cljs.user.Bar.prototype.cljs$user$IFoo$foo1$arity$2 = (function (_,x){ 105 | var self__ = this; 106 | var ___$1 = this; 107 | return x; 108 | } 109 | ); 110 | cljs.user.Bar.prototype.cljs$user$IFoo$foo2$arity$3 = (function (_,x,y){ 111 | var self__ = this; 112 | var ___$1 = this; 113 | return new cljs.core.PersistentVector(null, 2, 5, cljs.core.PersistentVector.EMPTY_NODE, [x,y], null); 114 | } 115 | ); 116 | cljs.user.Bar.getBasis = (function (){ 117 | return new cljs.core.PersistentVector(null, 1, 5, cljs.core.PersistentVector.EMPTY_NODE, [new cljs.core.Symbol(null,"ptr","ptr",(1213150338),null)], null); 118 | } 119 | ); 120 | cljs.user.Bar.cljs$lang$type = true; 121 | cljs.user.Bar.cljs$lang$ctorStr = "cljs.user/Bar"; 122 | cljs.user.Bar.cljs$lang$ctorPrWriter = (function (this__32219__auto__,writer__32220__auto__,opt__32221__auto__){ 123 | return cljs.core._write.call(null,writer__32220__auto__,"cljs.user/Bar"); 124 | } 125 | ); 126 | cljs.user.__GT_Bar = (function cljs$user$__GT_Bar(ptr){ 127 | return (new cljs.user.Bar(ptr)); 128 | } 129 | ); 130 | #+END_SRC 131 | -------------------------------------------------------------------------------- /geom-cljs/resources/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 |
11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /geom-cljs/src/thi/ng/geomc/core.cljs: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geomc.core 2 | (:require-macros 3 | [thi.ng.geomc.macros :refer [defproto]]) 4 | (:require 5 | [thi.ng.math.core :as m] 6 | [thi.ng.geom.core :as g] 7 | [thi.ng.geom.circle :as c] 8 | [thi.ng.geom.vector :as v] 9 | [thi.ng.strf.core :as f])) 10 | 11 | (defonce cthing (js/cthing)) 12 | 13 | (enable-console-print!) 14 | 15 | (defproto IMag 16 | (mag [_])) 17 | 18 | (defproto IMathOps 19 | (+! [_ v]) 20 | (-! [_ v]) 21 | (*! [_ v]) 22 | (div! [_ v])) 23 | 24 | (defproto ICross 25 | (cross! [_ v])) 26 | 27 | (defproto IMix 28 | (mix! [_ v t])) 29 | 30 | (defproto IArea 31 | (area [_])) 32 | 33 | (defproto ITessellate 34 | (tessellate [_ opts])) 35 | 36 | (deftype Vec2f [ptr] 37 | IMag 38 | (mag [_] (._ct_mag2f js/cthing ptr)) 39 | IMathOps 40 | (+! [_ v] (._ct_add2fv_imm js/cthing ptr (.-ptr ^Vec2f v)) _) 41 | (-! [_ v] (._ct_sub2fv_imm js/cthing ptr (.-ptr ^Vec2f v)) _) 42 | IPrintWithWriter 43 | (-pr-writer [_ writer opts] 44 | (pr-sequential-writer 45 | writer pr-writer "#vec2f [" " " "]" opts 46 | [(aget (.-HEAPF32 js/cthing) (unsigned-bit-shift-right ptr 2)) 47 | (aget (.-HEAPF32 js/cthing) (unsigned-bit-shift-right (+ ptr 4) 2))]))) 48 | 49 | (deftype Vec3f [ptr] 50 | IMag 51 | (mag [_] (._ct_mag3f js/cthing ptr)) 52 | IMathOps 53 | (+! [_ v] (._ct_add3fv_imm js/cthing ptr (.-ptr ^Vec3f v)) _) 54 | ICross 55 | (cross! [_ v] (._ct_cross3fv_imm js/cthing ptr (.-ptr ^Vec3f v)) _) 56 | IMix 57 | (mix! [_ b t] (._ct_mix3fv_imm js/cthing ptr (.-ptr ^Vec3f b) t) _) 58 | IPrintWithWriter 59 | (-pr-writer [_ writer opts] 60 | (pr-sequential-writer 61 | writer pr-writer "#vec3f [" " " "]" opts 62 | [(aget (.-HEAPF32 js/cthing) (unsigned-bit-shift-right ptr 2)) 63 | (aget (.-HEAPF32 js/cthing) (unsigned-bit-shift-right (+ ptr 4) 2)) 64 | (aget (.-HEAPF32 js/cthing) (unsigned-bit-shift-right (+ ptr 8) 2))]))) 65 | 66 | (deftype Circle2f [ptr] 67 | IArea 68 | (area [_] (._ct_circle2f_area js/cthing ptr)) 69 | ITessellate 70 | (tessellate [_ {:keys [res target]}] 71 | (let [target (or target (._malloc js/cthing (* (inc res) 36)))] 72 | (._ct_circle2f_tessellate js/cthing ptr target res))) 73 | IPrintWithWriter 74 | (-pr-writer [_ writer opts] 75 | (pr-sequential-writer 76 | writer pr-writer "#circle2f [" " " "]" opts 77 | [(aget (.-HEAPF32 js/cthing) (unsigned-bit-shift-right ptr 2)) 78 | (aget (.-HEAPF32 js/cthing) (unsigned-bit-shift-right (+ ptr 4) 2)) 79 | (aget (.-HEAPF32 js/cthing) (unsigned-bit-shift-right (+ ptr 8) 2))]))) 80 | 81 | (defn ^:export vec2f 82 | [x y] (Vec2f. (._ct_vec2f js/cthing x y nil))) 83 | 84 | (defn ^:export vec3f 85 | [x y z] (Vec3f. (._ct_vec3f js/cthing x y z nil))) 86 | 87 | (defn ^:export circle2f 88 | [x y r] 89 | (let [ptr (._malloc js/cthing 12)] 90 | (Circle2f. (._ct_circle2f_init js/cthing ptr x y r)))) 91 | 92 | (defn ^:export main 93 | [] 94 | (let [a2 (+! (vec2f 10 10) (vec2f 90 90)) 95 | b2 (+! (vec2f 100 100) (vec2f 100 100)) 96 | a3 (+! (vec3f 10 10 10) (vec3f 90 90 90)) 97 | b3 (+! (vec3f 100 100 100) (vec3f 100 100 100))] 98 | (clj->js [(mag a2) (mag b2) (mag a3) (mag b3)]))) 99 | 100 | (defn ^:export bench-cross 101 | [] 102 | (let [a (vec3f 1 0 0) 103 | b (vec3f 0 1 0) 104 | t0 (.getTime (js/Date.))] 105 | (loop [i 1e6] 106 | (when (pos? i) 107 | (cross! a b) 108 | (recur (dec i)))) 109 | (prn (- (.getTime (js/Date.)) t0) (.-ptr a)))) 110 | 111 | (defn ^:export bench-cross2 112 | [] 113 | (let [a (v/vec3 1 0 0) 114 | b (v/vec3 0 1 0) 115 | t0 (.getTime (js/Date.))] 116 | (loop [i 1e6] 117 | (when (pos? i) 118 | (m/cross a b) 119 | (recur (dec i)))) 120 | (prn (- (.getTime (js/Date.)) t0) (.-ptr a)))) 121 | 122 | (defn ^:export bench-mix 123 | [] 124 | (let [a (vec3f 1 0 0) 125 | b (vec3f 0 1 0) 126 | t0 (.getTime (js/Date.))] 127 | (loop [i 1e6] 128 | (when (pos? i) 129 | (mix! a b 0.5) 130 | (recur (dec i)))) 131 | (prn (- (.getTime (js/Date.)) t0) (.-ptr a)))) 132 | 133 | (defn ^:export bench-mix2 134 | [] 135 | (let [a (v/vec3 1 0 0) 136 | b (v/vec3 0 1 0) 137 | t0 (.getTime (js/Date.))] 138 | (loop [i 1e6] 139 | (when (pos? i) 140 | (m/mix a b 0.5) 141 | (recur (dec i)))) 142 | (prn (- (.getTime (js/Date.)) t0) (.-ptr a)))) 143 | 144 | (defn ^:export bench-tessel 145 | [] 146 | (let [c (circle2f 0 0 1) 147 | tptr (._malloc js/cthing (* 81 3 2 4)) 148 | t0 (.getTime (js/Date.))] 149 | (loop [i 1e5] 150 | (when (pos? i) 151 | (tessellate c {:res 80 :target tptr}) 152 | (recur (dec i)))) 153 | (._free js/cthing tptr) 154 | (prn (- (.getTime (js/Date.)) t0)))) 155 | 156 | (defn ^:export bench-tessel2 157 | [] 158 | (let [c (c/circle 0 0 1) 159 | t0 (.getTime (js/Date.))] 160 | (loop [i 1e5] 161 | (when (pos? i) 162 | (g/tessellate c {:res 80}) 163 | (recur (dec i)))) 164 | (prn (- (.getTime (js/Date.)) t0)))) 165 | -------------------------------------------------------------------------------- /geom-cljs/src/thi/ng/geomc/macros.clj: -------------------------------------------------------------------------------- 1 | (ns thi.ng.geomc.macros 2 | (:require 3 | [cljs.analyzer :as ana] 4 | [clojure.string :as str])) 5 | 6 | (def js-replacements 7 | {\. \$ 8 | \/ \$ 9 | \- \_ 10 | \* "_STAR_" 11 | \+ "_PLUS_" 12 | \? "_QMARK_" 13 | \! "_BANG_" 14 | \' "_QUOTE_"}) 15 | 16 | (defn jsify-symbol 17 | [sym] 18 | (->> (str sym) 19 | (replace js-replacements) 20 | (apply str))) 21 | 22 | (defmacro defproto 23 | [proto & specs] 24 | (let [js 'js* 25 | methods (into {} (map (fn [[f & sigs]] [f (vec sigs)]) specs)) 26 | pname (-> &env 27 | (dissoc :locals) 28 | (cljs.analyzer/resolve-var proto) 29 | :name 30 | jsify-symbol 31 | (str "$")) 32 | proto (-> proto 33 | (vary-meta assoc :protocol-symbol true) 34 | (vary-meta assoc-in [:protocol-info :methods] methods) 35 | (vary-meta update :jsdoc conj "@interface"))] 36 | `(do 37 | (def ~proto (~js "function(){}")) 38 | ~@(map 39 | (fn [[f [_ & more :as args]]] 40 | (let [f (vary-meta f assoc :protocol proto) 41 | fn$ (str pname (jsify-symbol f) "$arity$" (count args)) 42 | args$ (str/join "," args)] 43 | `(defn ~f ~args (~js ~(str _ "." fn$ "(" args$ ")"))))) 44 | specs)))) 45 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 |
11 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /makevideo: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | for i in `ls assets/$1*.svg`; do 3 | echo "converting $i" 4 | rsvg-convert -b "#fff" -f png -o $i.png $i 5 | done 6 | ffmpeg \ 7 | -framerate 30 \ 8 | -i assets/$1-%04d.svg.png \ 9 | -s:v 600x600 \ 10 | -c:v libx264 \ 11 | -profile:v high \ 12 | -crf 23 \ 13 | -pix_fmt yuv420p \ 14 | -y \ 15 | out.mp4 16 | -------------------------------------------------------------------------------- /postprocess.js: -------------------------------------------------------------------------------- 1 | fs=require('fs'); 2 | src=fs.readFileSync(process.argv[2],'utf8'); 3 | src=src.replace(/_ct_\w+_\d+:[\w\$]+,?/g, ''); 4 | src=src.replace(/\w+\._ct_\w+_\d+\=\w+._ct_\w+_\d+;/g, ''); 5 | src=src.replace(/;\s{2,}/g,'\n'); 6 | fs.writeFileSync(process.argv[3], src, 'utf8'); 7 | -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | workspace "cthing" 2 | configurations { "debug", "release" } 3 | platforms { "sse", "no_sse" } 4 | language "C" 5 | includedirs { "ext", "src" } 6 | targetdir "bin/%{cfg.buildcfg}" 7 | flags { "Symbols", "C++11" } 8 | linkoptions "-lm" 9 | 10 | filter "platforms:sse" 11 | defines { "CT_FEATURE_SSE" } 12 | buildoptions { "-msse", "-msse2", "-msse3", "-msse4.1" } 13 | 14 | filter "configurations:debug" 15 | defines { "DEBUG", "CT_FEATURE_CHECKS", "CT_FEATURE_CHECK_MEM" } 16 | 17 | filter "configurations:release" 18 | defines { "NDEBUG", "CT_FEATURE_LOG" } 19 | optimize "Size" 20 | 21 | ----- test 22 | 23 | project "test" 24 | kind "ConsoleApp" 25 | files { "ext/**.c", "test/**.c" } 26 | defines { "CT_FEATURE_ANSI" } 27 | links "lib" 28 | dependson "lib" 29 | flags { "FatalWarnings", "LinkTimeOptimization" } 30 | 31 | ----- test w/ addr sanitizer 32 | 33 | project "test_asan" 34 | kind "ConsoleApp" 35 | files { "ext/**.c", "test/**.c" } 36 | defines { "CT_FEATURE_ANSI", "CT_FEATURE_CHECKS", "CT_FEATURE_CHECK_MEM" } 37 | links "lib" 38 | dependson "lib" 39 | flags { "FatalWarnings" } 40 | buildoptions { "-fsanitize=address", "-fno-omit-frame-pointer" } 41 | linkoptions { "-fsanitize=address" } 42 | 43 | ----- test w/ mem sanitizer (currently Linux x86_64 only & clang) 44 | --[[-- 45 | project "test_msan" 46 | kind "ConsoleApp" 47 | files { "src/**.h", "src/**.c", "test/**.c" } 48 | removefiles {"src/geom/mesh.c" } 49 | defines { "CT_FEATURE_ANSI" } 50 | flags { "FatalWarnings" } 51 | buildoptions { "-fsanitize=mem", "-fno-omit-frame-pointer", "-fsanitize-memory-track-origins" } 52 | linkoptions { "-fsanitize=mem", "-fsanitize-memory-track-origins" } 53 | --]]-- 54 | 55 | ----- lib 56 | 57 | project "lib" 58 | files { "src/**.h", "src/**.c" } 59 | removefiles {"src/geom/mesh.c", "src/common/test.c" } 60 | kind "StaticLib" 61 | targetname "cthing" 62 | 63 | ----- ca1d ----- 64 | 65 | project "ex-ca1d" 66 | kind "ConsoleApp" 67 | files { "examples/ca/ca1d.c" } 68 | includedirs { "examples/common", "examples/ca" } 69 | links "lib" 70 | dependson "lib" 71 | flags { "LinkTimeOptimization" } 72 | 73 | ----- ca2d ----- 74 | 75 | project "ex-ca2d" 76 | kind "ConsoleApp" 77 | files { "examples/ca/ca2d.c" } 78 | includedirs { "examples/common", "examples/ca" } 79 | links "lib" 80 | dependson "lib" 81 | flags { "LinkTimeOptimization" } 82 | 83 | ----- chull ----- 84 | 85 | project "ex-chull" 86 | kind "ConsoleApp" 87 | files { "examples/convexhull/main.c" } 88 | includedirs { "examples/common", "examples/convexhull" } 89 | links "lib" 90 | dependson "lib" 91 | flags { "LinkTimeOptimization" } 92 | 93 | ----- dla ----- 94 | 95 | project "ex-dla" 96 | kind "ConsoleApp" 97 | files { "examples/dla/*.c" } 98 | includedirs { "examples/common", "examples/dla" } 99 | links "lib" 100 | dependson "lib" 101 | flags { "LinkTimeOptimization" } 102 | 103 | ----- poisson ----- 104 | 105 | project "ex-poisson" 106 | kind "ConsoleApp" 107 | files { "examples/poisson/*.c" } 108 | includedirs { "examples/common", "examples/poisson" } 109 | links "lib" 110 | dependson "lib" 111 | flags { "LinkTimeOptimization" } 112 | 113 | ----- verlet ----- 114 | 115 | project "ex-verlet" 116 | kind "ConsoleApp" 117 | files { "examples/verlet/main.c" } 118 | includedirs { "examples/common", "examples/verlet" } 119 | links "lib" 120 | dependson "lib" 121 | flags { "LinkTimeOptimization" } 122 | 123 | project "ex-verlet-pack" 124 | kind "ConsoleApp" 125 | files { "examples/verlet/cpack.c" } 126 | includedirs { "examples/common", "examples/verlet" } 127 | links "lib" 128 | dependson "lib" 129 | flags { "LinkTimeOptimization" } 130 | 131 | ----- clipping ----- 132 | 133 | project "ex-polyclip" 134 | kind "ConsoleApp" 135 | files { "examples/polyclip/*.c" } 136 | includedirs { "examples/common", "examples/polyclip" } 137 | links "lib" 138 | dependson "lib" 139 | flags { "LinkTimeOptimization" } 140 | 141 | ----- offset ----- 142 | 143 | project "ex-polyoffset" 144 | kind "ConsoleApp" 145 | files { "examples/polyoffset/*.c" } 146 | includedirs { "examples/common", "examples/polyoffset" } 147 | links "lib" 148 | dependson "lib" 149 | flags { "LinkTimeOptimization" } 150 | 151 | ----- voronoi ----- 152 | 153 | project "ex-voronoi" 154 | kind "ConsoleApp" 155 | files { "examples/voronoi/*.c" } 156 | includedirs { "examples/common", "examples/voronoi" } 157 | links "lib" 158 | dependson "lib" 159 | flags { "LinkTimeOptimization" } 160 | 161 | ----- glfw ----- 162 | 163 | project "ex-glfw01" 164 | kind "ConsoleApp" 165 | files { "examples/glfw/*.c" } 166 | includedirs { "examples/common", "examples/glfw" } 167 | links "lib" 168 | dependson "lib" 169 | flags { "LinkTimeOptimization" } 170 | linkoptions { "-lglfw3", "-framework Cocoa", "-framework OpenGL" } 171 | -------------------------------------------------------------------------------- /src/cthing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define CT_VERSION_MAJOR 0 4 | #define CT_VERSION_MINOR 1 5 | 6 | #include "ct-head/features.h" 7 | #include "ct-head/log.h" 8 | 9 | #ifndef CT_MAX_TYPES 10 | #define CT_MAX_TYPES 16 11 | #endif 12 | 13 | #ifndef CT_POOLSIZE_OBJECT 14 | #define CT_POOLSIZE_OBJECT 0x1000 15 | #endif 16 | 17 | #ifndef CT_POOLSIZE_CONSRC 18 | #define CT_POOLSIZE_CONSRC 0x1000 19 | #endif 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | -------------------------------------------------------------------------------- /src/data/adjacency.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "data/adjacency.h" 4 | #include "math/math.h" 5 | 6 | ct_inline size_t cell_index(const CT_AdjMatrix *mat, 7 | const size_t x, 8 | const size_t y) { 9 | return x * mat->stride + (y >> 3); 10 | } 11 | 12 | ct_export int ct_adjmat_init(CT_AdjMatrix *mat, size_t width) { 13 | width = ct_ceil_multiple_pow2(width, 8); 14 | mat->stride = width >> 3; 15 | mat->numBytes = width * mat->stride; 16 | mat->bits = calloc(mat->numBytes, 1); 17 | return mat->bits == NULL; 18 | } 19 | 20 | ct_export void ct_adjmat_free(CT_AdjMatrix *mat) { 21 | free(mat->bits); 22 | } 23 | 24 | ct_export int ct_adjmat_join(CT_AdjMatrix *mat, 25 | const size_t x, 26 | const size_t y) { 27 | CT_CHECK(x < mat->stride << 3, "x out of bounds"); 28 | CT_CHECK(y < mat->stride << 3, "y out of bounds"); 29 | const size_t id1 = cell_index(mat, x, y); 30 | const size_t id2 = cell_index(mat, y, x); 31 | CT_DEBUG("connect: %zu -> %zu, idx: %zu,%zu, bits: %zu,%zu", x, y, id1, id2, 32 | y & 7, x & 7); 33 | mat->bits[id1] |= (1 << (y & 7)); 34 | mat->bits[id2] |= (1 << (x & 7)); 35 | return 0; 36 | fail: 37 | return 1; 38 | } 39 | 40 | ct_export int ct_adjmat_disjoin(CT_AdjMatrix *mat, 41 | const size_t x, 42 | const size_t y) { 43 | CT_CHECK(x < mat->stride << 3, "x out of bounds"); 44 | CT_CHECK(y < mat->stride << 3, "y out of bounds"); 45 | const size_t id1 = cell_index(mat, x, y); 46 | const size_t id2 = cell_index(mat, y, x); 47 | CT_DEBUG("disconnect: %zu -> %zu, idx: %zu,%zu, bits: %zu,%zu", x, y, id1, 48 | id2, y & 7, x & 7); 49 | mat->bits[id1] &= ~(1 << (y & 7)); 50 | mat->bits[id2] &= ~(1 << (x & 7)); 51 | return 0; 52 | fail: 53 | return 1; 54 | } 55 | 56 | ct_export int ct_adjmat_is_join(CT_AdjMatrix *mat, 57 | const size_t x, 58 | const size_t y) { 59 | CT_CHECK(x < mat->stride << 3, "x out of bounds"); 60 | CT_CHECK(y < mat->stride << 3, "y out of bounds"); 61 | const size_t id1 = cell_index(mat, x, y); 62 | const size_t id2 = cell_index(mat, y, x); 63 | return mat->bits[id1] & (1 << (y & 7)) || mat->bits[id2] & (1 << (x & 7)); 64 | fail: 65 | return -1; 66 | } 67 | 68 | ct_export void ct_adjmat_trace(const CT_AdjMatrix *mat) { 69 | uint8_t *ptr = mat->bits; 70 | for (size_t y = 0, w = mat->stride << 3; y < w; y++) { 71 | fprintf(stderr, "%04zx: ", y); 72 | for (size_t x = 0; x < mat->stride; x++) { 73 | if (*ptr) { 74 | fprintf(stderr, "%02x ", *ptr); 75 | } else { 76 | fputs(".. ", stderr); 77 | } 78 | ptr++; 79 | } 80 | fputs("\n", stderr); 81 | } 82 | } 83 | 84 | ct_export int ct_adjmat_iterate(const CT_AdjMatrix *mat, 85 | CT_AdjMatIterator iter, 86 | void *state) { 87 | uint8_t *ptr = mat->bits; 88 | for (size_t y = 0, w = mat->stride << 3; y < w; y++) { 89 | for (size_t x = 0; x <= y >> 3; x++) { 90 | uint8_t cell = ptr[x]; 91 | if (cell) { 92 | size_t bmax = 8 - ct_clz8(cell); 93 | for (size_t b = 0, bv = 1, xx = x << 3; b < bmax && xx <= y; 94 | b++, bv <<= 1, xx++) { 95 | if (cell & bv) { 96 | int res = iter(xx, y, state); 97 | if (res) { 98 | return res; 99 | } 100 | } 101 | } 102 | } 103 | } 104 | ptr += mat->stride; 105 | } 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /src/data/adjacency.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | CT_BEGIN_DECLS 6 | 7 | typedef struct { 8 | uint8_t *bits; 9 | size_t stride; 10 | size_t numBytes; 11 | } CT_AdjMatrix; 12 | 13 | typedef int (*CT_AdjMatIterator)(size_t, size_t, void *state); 14 | 15 | int ct_adjmat_init(CT_AdjMatrix *mat, size_t width); 16 | void ct_adjmat_free(CT_AdjMatrix *mat); 17 | int ct_adjmat_join(CT_AdjMatrix *mat, size_t x, size_t y); 18 | int ct_adjmat_disjoin(CT_AdjMatrix *mat, size_t x, size_t y); 19 | int ct_adjmat_is_join(CT_AdjMatrix *mat, size_t x, size_t y); 20 | void ct_adjmat_trace(const CT_AdjMatrix *mat); 21 | int ct_adjmat_iterate(const CT_AdjMatrix *mat, 22 | CT_AdjMatIterator iter, 23 | void *state); 24 | 25 | CT_END_DECLS 26 | -------------------------------------------------------------------------------- /src/data/array.h: -------------------------------------------------------------------------------- 1 | #include "cthing.h" 2 | 3 | float *ct_array_add2_f32(const float *a, 4 | const float *b, 5 | float *out, 6 | size_t num, 7 | size_t fstridea, 8 | size_t fstrideb, 9 | size_t fstrideo); 10 | float *ct_array_mul2_f32(const float *a, 11 | const float *b, 12 | float *out, 13 | size_t num, 14 | size_t fstridea, 15 | size_t fstrideb, 16 | size_t fstrideo); 17 | 18 | float ct_array_reduce_sum_f32(const float *p, size_t num, size_t fstride); 19 | intptr_t ct_array_reduce_sum_i32(const int32_t *p, size_t num, size_t istride); 20 | uintptr_t ct_array_reduce_sum_u32(const uint32_t *p, 21 | size_t num, 22 | size_t istride); 23 | 24 | float *ct_array_reverse_f32_imm(float *ptr, size_t num, size_t fstride); 25 | void *ct_array_reverse_imm(void *ptr, size_t num, size_t stride); 26 | void *ct_array_reverse8_imm(void *ptr, size_t num); 27 | void *ct_array_reverse(const void *src, size_t num, size_t stride, void *out); 28 | 29 | int ct_array_deltaeq_f32(const float *a, const float *b, float eps, size_t num); 30 | int ct_array_compare_f32(const float *a, const float *b, float eps, size_t num); 31 | int ct_array_tostring_f32(char *buf, 32 | int bufsz, 33 | const float *p, 34 | size_t num, 35 | size_t fstride); 36 | -------------------------------------------------------------------------------- /src/data/cons.c: -------------------------------------------------------------------------------- 1 | #include "data/cons.h" 2 | 3 | typedef struct { 4 | CT_Cons* head; 5 | CT_Cons* prev; 6 | CT_MPool* pool; 7 | } CT_ConsCloneState; 8 | 9 | ct_export CT_Cons* ct_cons(void* val, CT_Cons* head, CT_MPool* pool) { 10 | CT_Cons* cell; 11 | CT_CHECK_MEM(cell = CT_MP_ALLOC(pool, CT_Cons)); 12 | CT_DEBUG("cons: %p (val: %p) -> %p", cell, val, head); 13 | cell->value = val; 14 | cell->next = head; 15 | fail: 16 | return cell; 17 | } 18 | 19 | ct_export CT_Cons* ct_cons_append(void* val, CT_Cons* tail, CT_MPool* pool) { 20 | CT_Cons* cell; 21 | CT_CHECK_MEM(cell = CT_MP_ALLOC(pool, CT_Cons)); 22 | CT_DEBUG("cons append: %p -> %p (val: %p)", tail, cell, val); 23 | cell->value = val; 24 | cell->next = NULL; 25 | if (tail) { 26 | tail->next = cell; 27 | } 28 | fail: 29 | return cell; 30 | } 31 | 32 | ct_export CT_Cons* ct_cons_get_tail(CT_Cons* cell) { 33 | while (cell->next) { 34 | cell = cell->next; 35 | } 36 | return cell; 37 | } 38 | 39 | static void ct_cons_iterate_clone(CT_Cons* c, void* cstate) { 40 | CT_ConsCloneState* state = (CT_ConsCloneState*)cstate; 41 | c = ct_cons(c->value, NULL, state->pool); 42 | if (!state->head) { 43 | state->head = c; 44 | state->prev = c; 45 | } else { 46 | state->prev->next = c; 47 | state->prev = c; 48 | } 49 | } 50 | 51 | ct_export void ct_cons_free(CT_Cons* cell, 52 | CT_MPool* pool, 53 | void (*freeVal)(void*, void*), 54 | void* state) { 55 | if (cell) { 56 | if (freeVal) { 57 | freeVal(cell->value, state); 58 | } 59 | CT_MP_FREE(pool, cell); 60 | } 61 | } 62 | 63 | ct_export void ct_cons_free_all(CT_Cons* cell, 64 | CT_MPool* pool, 65 | void (*freeVal)(void*, void*), 66 | void* state) { 67 | CT_Cons* next = NULL; 68 | while (cell) { 69 | next = cell->next; 70 | ct_cons_free(cell, pool, freeVal, state); 71 | cell = next; 72 | } 73 | } 74 | 75 | ct_export void* ct_cons_iterate(CT_Cons* cell, 76 | CT_ConsVisitor visit, 77 | void* state) { 78 | while (cell) { 79 | visit(cell, state); 80 | cell = cell->next; 81 | } 82 | return state; 83 | } 84 | 85 | ct_export void* ct_cons_iterate_n(CT_Cons* cell, 86 | CT_ConsVisitor visit, 87 | void* state, 88 | size_t num) { 89 | while (cell && num--) { 90 | visit(cell, state); 91 | cell = cell->next; 92 | } 93 | return state; 94 | } 95 | 96 | ct_export CT_Cons* ct_cons_find(CT_Cons* cell, void* value) { 97 | while (cell) { 98 | if (cell->value == value) { 99 | return cell; 100 | } 101 | cell = cell->next; 102 | } 103 | return NULL; 104 | } 105 | 106 | ct_export CT_Cons* ct_cons_from_array(void* values, 107 | size_t num, 108 | size_t stride, 109 | CT_Cons* head, 110 | CT_MPool* pool) { 111 | if (num > 0) { 112 | values += (num - 1) * stride; 113 | while (num--) { 114 | head = ct_cons(values, head, pool); 115 | values -= stride; 116 | } 117 | } 118 | return head; 119 | } 120 | 121 | ct_export CT_Cons* ct_cons_from_parray(void** values, 122 | size_t num, 123 | CT_Cons* head, 124 | CT_MPool* pool) { 125 | if (num > 0) { 126 | values += num - 1; 127 | while (num--) { 128 | head = ct_cons(*values--, head, pool); 129 | } 130 | } 131 | return head; 132 | } 133 | 134 | ct_export CT_Cons* ct_cons_concat_imm(CT_Cons* head, CT_Cons* rest) { 135 | CT_Cons* hd = ct_cons_get_tail(head); 136 | if (hd) { 137 | hd->next = rest; 138 | return head; 139 | } else { 140 | return rest; 141 | } 142 | } 143 | 144 | ct_export CT_Cons* ct_cons_concat(CT_Cons* head, 145 | CT_Cons* rest, 146 | CT_MPool* pool) { 147 | CT_ConsCloneState state = {.head = NULL, .pool = pool}; 148 | ct_cons_iterate(head, ct_cons_iterate_clone, 149 | ct_cons_iterate(rest, ct_cons_iterate_clone, &state)); 150 | return state.head; 151 | } 152 | 153 | ct_export CT_Cons* ct_cons_take(CT_Cons* head, size_t num, CT_MPool* pool) { 154 | CT_ConsCloneState state = {.head = NULL, .pool = pool}; 155 | ct_cons_iterate_n(head, ct_cons_iterate_clone, &state, num); 156 | return state.head; 157 | } 158 | 159 | //// double-linked list 160 | 161 | ct_export CT_ConsD* ct_consd(void* val, CT_ConsD* head, CT_MPool* pool) { 162 | CT_ConsD* cell; 163 | CT_CHECK_MEM(cell = CT_MP_ALLOC(pool, CT_ConsD)); 164 | cell->value = val; 165 | cell->next = head; 166 | if (head) { 167 | head->prev = cell; 168 | } 169 | fail: 170 | return cell; 171 | } 172 | -------------------------------------------------------------------------------- /src/data/cons.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | #include "mem/mpool.h" 5 | 6 | CT_BEGIN_DECLS 7 | 8 | typedef struct CT_Cons CT_Cons; 9 | typedef struct CT_ConsD CT_ConsD; 10 | 11 | struct CT_Cons { 12 | void* value; 13 | CT_Cons* next; 14 | }; 15 | 16 | struct CT_ConsD { 17 | void* value; 18 | CT_ConsD* next; 19 | CT_ConsD* prev; 20 | }; 21 | 22 | typedef void (*CT_ConsVisitor)(CT_Cons*, void*); 23 | 24 | CT_Cons* ct_cons(void* val, CT_Cons* head, CT_MPool* mpool); 25 | CT_Cons* ct_cons_append(void* val, CT_Cons* tail, CT_MPool* pool); 26 | CT_Cons* ct_cons_get_tail(CT_Cons* cell); 27 | void ct_cons_free(CT_Cons* cell, 28 | CT_MPool* pool, 29 | void (*freeVal)(void*, void*), 30 | void* state); 31 | void ct_cons_free_all(CT_Cons* cell, 32 | CT_MPool* pool, 33 | void (*freeVal)(void*, void*), 34 | void* state); 35 | void* ct_cons_iterate(CT_Cons* cell, CT_ConsVisitor visit, void* state); 36 | void* ct_cons_iterate_n(CT_Cons* cell, 37 | CT_ConsVisitor visit, 38 | void* state, 39 | size_t num); 40 | CT_Cons* ct_cons_from_array(void* values, 41 | size_t num, 42 | size_t stride, 43 | CT_Cons* head, 44 | CT_MPool* mpool); 45 | CT_Cons* ct_cons_from_parray(void** values, 46 | size_t num, 47 | CT_Cons* head, 48 | CT_MPool* mpool); 49 | CT_Cons* ct_cons_concat_imm(CT_Cons* head, CT_Cons* rest); 50 | CT_Cons* ct_cons_concat(CT_Cons* head, CT_Cons* rest, CT_MPool* mpool); 51 | CT_Cons* ct_cons_take(CT_Cons* head, size_t num, CT_MPool* pool); 52 | 53 | CT_ConsD* ct_consd(void* x, CT_ConsD* head, CT_MPool* mpool); 54 | 55 | CT_END_DECLS 56 | -------------------------------------------------------------------------------- /src/data/consrc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "data/consrc.h" 5 | #include "data/object.h" 6 | #include "mem/mpool.h" 7 | 8 | typedef struct { 9 | CT_MPool pool; 10 | size_t inited; 11 | } CT_ConsRC_private; 12 | 13 | static CT_ConsRC_private __ct_consrc = {.inited = 0}; 14 | 15 | static int ct_obj_print_cons(CT_Object *o, FILE *out) { 16 | int res = fprintf(out, "("); 17 | while (o && res >= 0) { 18 | res = ct_object_print(ct_object_cons_ptr(o)->value, out); 19 | if (res >= 0) { 20 | o = ct_object_cons_ptr(o)->next; 21 | if (o) { 22 | res = fprintf(out, " "); 23 | } else { 24 | return fprintf(out, ")"); 25 | } 26 | } 27 | } 28 | return res; 29 | } 30 | 31 | static int ct_obj_tostring_cons(CT_Object *o, char *buf, int bsize) { 32 | int w = snprintf(buf, bsize, "("); 33 | while (o) { 34 | int res = 35 | ct_object_tostring(ct_object_cons_ptr(o)->value, &buf[w], bsize - w); 36 | if (res <= 0) { 37 | return res; 38 | } 39 | w += res; 40 | o = ct_object_cons_ptr(o)->next; 41 | if (o && bsize - w > 1) { 42 | buf[w] = ' '; 43 | w++; 44 | } 45 | } 46 | w += snprintf(buf + w, bsize - w, ")"); 47 | return w; 48 | } 49 | 50 | static void ct_consrc_free(const CT_Ref *ref) { 51 | CT_Object *o = container_of(ref, CT_Object, rc); 52 | CT_ConsRC *c = ct_object_cons_ptr(o); 53 | CT_Object *next = c->next; 54 | CT_DEBUG("free cons: %p->%p val: %p", o, next, c->value); 55 | if (c->value) { 56 | ct_ref_dec(&c->value->rc); 57 | } 58 | if (next) { 59 | ct_ref_dec(&next->rc); 60 | } 61 | ct_mpool_free_block(&__ct_consrc.pool, c); 62 | ct_object_free_box(o); 63 | } 64 | 65 | CT_Object *ct_object_cons(CT_Object *value) { 66 | CT_Object *o = ct_object_raw(CT_TYPE_CONS); 67 | CT_ConsRC *node = ct_mpool_alloc(&__ct_consrc.pool); 68 | ct_object_assign(&node->value, value); 69 | node->next = NULL; 70 | o->atom.p = node; 71 | o->rc = (CT_Ref){ct_consrc_free, 0}; 72 | CT_DEBUG("new cons obj: %p %d %d", o, node == o->atom.p, 73 | node->value == value); 74 | return o; 75 | } 76 | 77 | void ct_consrc_push_imm(CT_Object **list, CT_Object *v) { 78 | CT_CHECK(ct_object_is(*list, CT_TYPE_CONS), "%p is not a cons", *list); 79 | CT_DEBUG("push_imm %p", v); 80 | CT_Object *node = ct_object_cons(v); 81 | CT_ConsRC *c = (CT_ConsRC *)node->atom.p; 82 | c->next = *list; 83 | node->rc.count = 1; 84 | *list = node; 85 | fail: 86 | return; 87 | } 88 | 89 | CT_Object *ct_consrc_pop_imm(CT_Object **list) { 90 | CT_CHECK(ct_object_is(*list, CT_TYPE_CONS), "%p is not a cons", *list); 91 | CT_Object *node = *list; 92 | *list = ct_object_cons_ptr(node)->next; 93 | if (*list) { 94 | ct_ref_inc(&(*list)->rc); 95 | } 96 | return node; 97 | fail: 98 | return NULL; 99 | } 100 | 101 | CT_Object *ct_consrc_cons(CT_Object *v, CT_Object *list) { 102 | CT_CHECK(ct_object_is(list, CT_TYPE_CONS), "%p is not a cons", list); 103 | CT_DEBUG("push %p", v); 104 | CT_Object *node = ct_object_cons(v); 105 | CT_ConsRC *c = (CT_ConsRC *)node->atom.p; 106 | ct_object_assign(&c->next, list); 107 | return node; 108 | fail: 109 | return NULL; 110 | } 111 | 112 | CT_Object *ct_consrc_rest(CT_Object *list) { 113 | CT_CHECK(ct_object_is(list, CT_TYPE_CONS), "%p is not a cons", list); 114 | return ct_object_cons_ptr(list)->next; 115 | fail: 116 | return NULL; 117 | } 118 | 119 | static void ct_consrc_deinit() { 120 | CT_DEBUG("free consrc pool"); 121 | ct_mpool_free(&__ct_consrc.pool); 122 | } 123 | 124 | int ct_consrc_init() { 125 | if (!__ct_consrc.inited) { 126 | if (ct_object_init() || ct_mpool_init(&__ct_consrc.pool, CT_POOLSIZE_CONSRC, 127 | sizeof(CT_ConsRC))) { 128 | return 1; 129 | } 130 | ct_register_print(CT_TYPE_CONS, ct_obj_print_cons); 131 | ct_register_tostring(CT_TYPE_CONS, ct_obj_tostring_cons); 132 | __ct_consrc.inited = 1; 133 | atexit(ct_consrc_deinit); 134 | } 135 | return 0; 136 | } 137 | -------------------------------------------------------------------------------- /src/data/consrc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | #include "data/object.h" 5 | 6 | CT_BEGIN_DECLS 7 | 8 | CT_Object *ct_object_cons(CT_Object *v); 9 | void ct_consrc_push_imm(CT_Object **list, CT_Object *v); 10 | CT_Object *ct_consrc_pop_imm(CT_Object **list); 11 | CT_Object *ct_consrc_cons(CT_Object *v, CT_Object *list); 12 | CT_Object *ct_consrc_rest(CT_Object *list); 13 | 14 | int ct_consrc_init(); 15 | 16 | ct_inline CT_ConsRC *ct_object_cons_ptr(CT_Object *o) { 17 | return (CT_ConsRC *)(o->atom.p); 18 | } 19 | 20 | CT_END_DECLS 21 | -------------------------------------------------------------------------------- /src/data/hashset.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | #include "math/hashfn.h" 6 | #include "mem/mpool.h" 7 | 8 | CT_BEGIN_DECLS 9 | 10 | // clang-format off 11 | typedef enum { 12 | CT_HS_NONE = 0, 13 | CT_HS_CONST_KEYS = 1 14 | } CT_HSFlags; 15 | // clang-format on 16 | 17 | typedef struct CT_HSEntry CT_HSEntry; 18 | 19 | typedef int (*CT_HSIterator)(const CT_HSEntry*, void*); 20 | 21 | typedef struct { 22 | CT_HashFn32 hash; 23 | int (*equiv_keys)(const void* a, const void* b, uint32_t sa, uint32_t sb); 24 | void* (*alloc_key)(const uint32_t size, void* state); 25 | void (*free_key)(const void* key, void* state); 26 | void* state; 27 | } CT_HSOps; 28 | 29 | struct CT_HSEntry { 30 | CT_HSEntry* next; 31 | void* key; 32 | uint32_t keySize; 33 | }; 34 | 35 | typedef struct CT_Hashset { 36 | CT_HSEntry** bins; 37 | uint32_t binMask; 38 | uint32_t flags; 39 | CT_MPool pool; 40 | CT_HSOps ops; 41 | uint32_t size; 42 | uint32_t collisions; 43 | } CT_Hashset; 44 | 45 | int ct_hs_init(CT_Hashset* s, 46 | const CT_HSOps* ops, 47 | size_t num, 48 | size_t poolSize, 49 | CT_HSFlags flags); 50 | void ct_hs_free(CT_Hashset* s); 51 | void* ct_hs_get(const CT_Hashset* s, const void* key, uint32_t ks); 52 | int ct_hs_contains(const CT_Hashset* s, const void* key, uint32_t ks); 53 | int ct_hs_assoc(CT_Hashset* s, const void* key, uint32_t ks); 54 | int ct_hs_dissoc(CT_Hashset* s, const void* key, uint32_t ks); 55 | int ct_hs_iterate(const CT_Hashset* s, CT_HSIterator visit, void* state); 56 | int ct_hs_into(CT_Hashset* dest, const CT_Hashset* src); 57 | 58 | CT_END_DECLS 59 | -------------------------------------------------------------------------------- /src/data/hashtable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | #include "math/hashfn.h" 6 | #include "mem/mpool.h" 7 | 8 | CT_BEGIN_DECLS 9 | 10 | // clang-format off 11 | typedef enum { 12 | CT_HT_NONE = 0, 13 | CT_HT_CONST_KEYS = 1, 14 | CT_HT_CONST_VALS = 2, 15 | CT_HT_CONST_ALL = 3 16 | } CT_HTFlags; 17 | // clang-format on 18 | 19 | typedef struct CT_HTEntry CT_HTEntry; 20 | 21 | typedef int (*CT_HTIterator)(const CT_HTEntry* e, void* state); 22 | typedef void (*CT_HTUpdater)(void** val, uint32_t* vs, void* state); 23 | 24 | typedef struct { 25 | CT_HashFn32 hash; 26 | int (*equiv_keys)(const void* a, const void* b, uint32_t sa, uint32_t sb); 27 | void* (*alloc_key)(const uint32_t size, void* state); 28 | void* (*alloc_val)(const uint32_t size, void* state); 29 | void (*free_key)(const void* key, void* state); 30 | void (*free_val)(const void* val, void* state); 31 | void* state; 32 | } CT_HTOps; 33 | 34 | struct CT_HTEntry { 35 | CT_HTEntry* next; 36 | void* key; 37 | void* val; 38 | uint32_t keySize; 39 | uint32_t valSize; 40 | }; 41 | 42 | typedef struct CT_Hashtable { 43 | CT_HTEntry** bins; 44 | uint32_t binMask; 45 | uint32_t flags; 46 | uint32_t size; 47 | uint32_t collisions; 48 | CT_HTOps ops; 49 | CT_MPool pool; 50 | } CT_Hashtable; 51 | 52 | int ct_ht_init(CT_Hashtable* t, 53 | const CT_HTOps* ops, 54 | size_t num, 55 | const size_t poolSize, 56 | const CT_HTFlags flags); 57 | void ct_ht_free(CT_Hashtable* t); 58 | void* ct_ht_get(const CT_Hashtable* t, 59 | const void* key, 60 | uint32_t ks, 61 | uint32_t* vs); 62 | int ct_ht_contains(const CT_Hashtable* t, const void* key, uint32_t ks); 63 | int ct_ht_assoc(CT_Hashtable* t, 64 | const void* key, 65 | const void* value, 66 | uint32_t ks, 67 | uint32_t vs); 68 | int ct_ht_dissoc(CT_Hashtable* t, const void* key, uint32_t ks); 69 | void* ct_ht_update(CT_Hashtable* t, 70 | const void* key, 71 | uint32_t ks, 72 | CT_HTUpdater update, 73 | void* state); 74 | int ct_ht_iterate(const CT_Hashtable* t, CT_HTIterator iter, void* state); 75 | int ct_ht_into(CT_Hashtable* dest, const CT_Hashtable* src); 76 | 77 | CT_END_DECLS 78 | -------------------------------------------------------------------------------- /src/data/object.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "cthing.h" 6 | 7 | #include "mem/ref.h" 8 | 9 | #ifdef CT_FEATURE_SSE 10 | #include 11 | #endif 12 | 13 | CT_BEGIN_DECLS 14 | 15 | typedef enum { 16 | CT_TYPE_NIL = 0, 17 | CT_TYPE_I32, 18 | CT_TYPE_U32, 19 | CT_TYPE_F32, 20 | CT_TYPE_VEC4, 21 | CT_TYPE_PTR, 22 | CT_TYPE_STR, 23 | CT_TYPE_CONS 24 | } CT_PrimType; 25 | 26 | typedef union { 27 | uintptr_t u; 28 | intptr_t i; 29 | float f; 30 | void *p; 31 | struct { 32 | float x, y, z, w; 33 | }; 34 | struct { 35 | float r, g, b, a; 36 | }; 37 | #ifdef CT_FEATURE_SSE 38 | __m128 vec; 39 | #endif 40 | } CT_Atom; 41 | 42 | typedef union { 43 | size_t tag; 44 | struct { 45 | size_t type : 24; 46 | size_t free : 1; 47 | }; 48 | } CT_Tag; 49 | 50 | typedef struct { 51 | CT_Atom atom; 52 | CT_Ref rc; 53 | CT_Tag tag; 54 | } CT_Object; 55 | 56 | typedef struct { 57 | CT_Object *value; 58 | CT_Object *next; 59 | } CT_ConsRC; 60 | 61 | typedef struct { int (*print)(CT_Object *, FILE *); } CT_IPrint; 62 | 63 | typedef struct { int (*tostring)(CT_Object *, char *, int); } CT_IToString; 64 | 65 | int ct_object_print(CT_Object *o, FILE *out); 66 | int ct_register_print(size_t type, int impl(CT_Object *, FILE *)); 67 | 68 | int ct_object_tostring(CT_Object *o, char *buf, int bsize); 69 | int ct_register_tostring(size_t type, int impl(CT_Object *, char *, int)); 70 | 71 | int ct_object_init(); 72 | CT_Object *ct_object_raw(size_t type); 73 | CT_Object *ct_object_str(char *x, size_t free); 74 | CT_Object *ct_object_i32(int32_t x); 75 | CT_Object *ct_object_u32(uint32_t x); 76 | CT_Object *ct_object_f32(float x); 77 | CT_Object *ct_object_vec4(float x, float y, float z, float w); 78 | 79 | void ct_object_free_nop(const CT_Ref *ref); 80 | void ct_object_free_box(const CT_Object *o); 81 | void ct_object_trace(const CT_Object *o); 82 | 83 | ct_inline int ct_object_is(const CT_Object *o, size_t type) { 84 | return o->tag.type == type; 85 | } 86 | 87 | ct_inline CT_Object *ct_object_assign(CT_Object **dest, CT_Object *src) { 88 | ct_ref_inc(&src->rc); 89 | *dest = src; 90 | return *dest; 91 | } 92 | 93 | ct_inline void ct_object_unassign(CT_Object **o) { 94 | ct_ref_dec(&(*o)->rc); 95 | *o = NULL; 96 | } 97 | 98 | CT_END_DECLS 99 | -------------------------------------------------------------------------------- /src/data/octree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | #include "data/tree.h" 6 | #include "math/vec.h" 7 | #include "mem/mpool.h" 8 | 9 | CT_BEGIN_DECLS 10 | 11 | typedef struct CT_OTNode CT_OTNode; 12 | 13 | struct CT_OTNode { 14 | CT_OTNode *children[8]; 15 | CT_Vec3f *point; 16 | void *data; 17 | union { 18 | struct { 19 | float x, cx, y, cy, z, cz, w, h, d; 20 | }; 21 | float coords[9]; 22 | }; 23 | size_t type; 24 | }; 25 | 26 | typedef struct { 27 | CT_OTNode root; 28 | CT_MPool pool; 29 | size_t size; 30 | } CT_Octree; 31 | 32 | typedef int (*CT_OTVisitor)(const CT_OTNode *, void *); 33 | 34 | int ct_octree_init(CT_Octree *t, 35 | float x, 36 | float y, 37 | float z, 38 | float w, 39 | float h, 40 | float d, 41 | size_t poolSize); 42 | void ct_octree_free(CT_Octree *t); 43 | int ct_octree_insert(CT_Octree *t, const CT_Vec3f *p, const void *data); 44 | int ct_octree_remove(CT_Octree *t, const CT_Vec3f *p); 45 | CT_OTNode *ct_octree_find_leaf(const CT_Octree *t, const CT_Vec3f *p); 46 | void ct_octree_trace_node(const CT_OTNode *t, size_t depth); 47 | void ct_octree_trace(const CT_Octree *t); 48 | int ct_octree_visit_leaves(const CT_Octree *t, CT_OTVisitor visit, void *state); 49 | void ct_octree_visit(const CT_Octree *t, CT_OTVisitor visit, void *state); 50 | 51 | CT_END_DECLS 52 | -------------------------------------------------------------------------------- /src/data/quadtree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | #include "data/tree.h" 6 | #include "geom/rect.h" 7 | #include "math/vec.h" 8 | #include "mem/mpool.h" 9 | 10 | CT_BEGIN_DECLS 11 | 12 | typedef struct CT_QTNode CT_QTNode; 13 | 14 | struct CT_QTNode { 15 | CT_QTNode *children[4]; 16 | CT_Vec2f *point; 17 | void *data; 18 | union { 19 | struct { 20 | float x, y, w, h, cx, cy; 21 | }; 22 | struct { 23 | CT_Vec2f pos, size, centroid; 24 | }; 25 | CT_Rect2f bounds; 26 | float coords[6]; 27 | }; 28 | size_t type; 29 | }; 30 | 31 | typedef struct { 32 | CT_MPool pool; 33 | CT_QTNode root; 34 | size_t size; 35 | } CT_Quadtree; 36 | 37 | typedef int (*CT_QTVisitor)(const CT_QTNode *, void *); 38 | 39 | int ct_qtree_init(CT_Quadtree *t, 40 | float x, 41 | float y, 42 | float w, 43 | float h, 44 | size_t poolSize); 45 | void ct_qtree_free(CT_Quadtree *t); 46 | int ct_qtree_insert(CT_Quadtree *t, const CT_Vec2f *p, const void *data); 47 | int ct_qtree_remove(CT_Quadtree *t, const CT_Vec2f *p); 48 | CT_QTNode *ct_qtree_find_leaf(const CT_Quadtree *t, const CT_Vec2f *p); 49 | void ct_qtree_trace_node(const CT_QTNode *node, size_t depth); 50 | void ct_qtree_trace(const CT_Quadtree *t); 51 | int ct_qtree_visit_leaves(const CT_Quadtree *t, 52 | CT_QTVisitor visit, 53 | void *state); 54 | void ct_qtree_visit(const CT_Quadtree *t, CT_QTVisitor visit, void *state); 55 | 56 | CT_END_DECLS 57 | -------------------------------------------------------------------------------- /src/data/soa.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "data/soa.h" 4 | 5 | CT_SOA *ct_soa_new(size_t width, size_t num, size_t stride) { 6 | void *buf = NULL; 7 | CT_SOA *s = NULL; 8 | CT_CHECK(0 == num % (1 << CT_SOA_WORD_SHIFT), "num must be multiple of %d", 9 | (1 << CT_SOA_WORD_SHIFT)); 10 | CT_CHECK_MEM(s = calloc(1, sizeof(CT_SOA))); 11 | CT_CHECK_MEM(buf = calloc(width * num, stride)); 12 | CT_CHECK_MEM(s->comps = calloc(width, sizeof(void *))); 13 | for (size_t i = 0; i < width; i++) { 14 | s->comps[i] = (void *)((uintptr_t)buf + i * num * stride); 15 | } 16 | s->num = num; 17 | s->width = width; 18 | s->stride = stride; 19 | //CT_INFO("soa: %p, comps: %p, comps[0]: %p", s, s->comps, s->comps[0]); 20 | return s; 21 | fail: 22 | if (s) { 23 | if (buf) { 24 | free(buf); 25 | } 26 | free(s); 27 | } 28 | return NULL; 29 | } 30 | 31 | int ct_soa_init(CT_SOA *s, 32 | void **comps, 33 | size_t width, 34 | size_t num, 35 | size_t stride) { 36 | CT_CHECK(comps, "comps is NULL"); 37 | CT_CHECK(0 == num % (1 << CT_SOA_WORD_SHIFT), "num must be multiple of %d", 38 | (1 << CT_SOA_WORD_SHIFT)); 39 | s->comps = comps; 40 | s->width = width; 41 | s->num = num; 42 | s->stride = stride; 43 | return 0; 44 | fail: 45 | return 1; 46 | } 47 | 48 | void ct_soa_free(CT_SOA *s) { 49 | free(s->comps[0]); 50 | free(s->comps); 51 | free(s); 52 | } 53 | 54 | void *ct_soa_flatten(const CT_SOA *s, void *out) { 55 | size_t len = s->num * s->stride; 56 | uint8_t *buf; 57 | CT_CHECK_MEM(buf = out ? out : malloc(s->width * len)); 58 | for (size_t i = 0; i < s->width; i++) { 59 | memcpy(&buf[i * len], s->comps[i], len); 60 | } 61 | fail: 62 | return buf; 63 | } 64 | 65 | #ifdef CT_FEATURE_SSE 66 | 67 | #else 68 | 69 | #endif 70 | 71 | CT_SOA_PROLOGUE2_SCALAR_IMM(add1f) { 72 | aa[j] += bb; 73 | } 74 | CT_SOA_EPILOGUE_IMM; 75 | 76 | CT_SOA_PROLOGUE2_SCALAR_IMM(sub1f) { 77 | aa[j] -= bb; 78 | } 79 | CT_SOA_EPILOGUE_IMM; 80 | 81 | CT_SOA_PROLOGUE2_SCALAR_IMM(mul1f) { 82 | aa[j] *= bb; 83 | } 84 | CT_SOA_EPILOGUE_IMM; 85 | 86 | CT_SOA_PROLOGUE2_SCALAR_IMM(div1f) { 87 | aa[j] /= bb; 88 | } 89 | CT_SOA_EPILOGUE_IMM; 90 | 91 | CT_SOA_PROLOGUE2_FPTR_IMM(add1fp) { 92 | aa[j] += bb; 93 | } 94 | CT_SOA_EPILOGUE_IMM; 95 | 96 | CT_SOA_PROLOGUE2_FPTR_IMM(sub1fp) { 97 | aa[j] -= bb; 98 | } 99 | CT_SOA_EPILOGUE_IMM; 100 | 101 | CT_SOA_PROLOGUE2_FPTR_IMM(mul1fp) { 102 | aa[j] *= bb; 103 | } 104 | CT_SOA_EPILOGUE_IMM; 105 | 106 | CT_SOA_PROLOGUE2_FPTR_IMM(div1fp) { 107 | aa[j] /= bb; 108 | } 109 | CT_SOA_EPILOGUE_IMM; 110 | 111 | CT_SOA_PROLOGUE2_IMM(add) { 112 | aa[j] += bb[j]; 113 | } 114 | CT_SOA_EPILOGUE_IMM; 115 | 116 | CT_SOA_PROLOGUE2_IMM(sub) { 117 | aa[j] -= bb[j]; 118 | } 119 | CT_SOA_EPILOGUE_IMM; 120 | 121 | CT_SOA_PROLOGUE2_IMM(mul) { 122 | aa[j] *= bb[j]; 123 | } 124 | CT_SOA_EPILOGUE_IMM; 125 | 126 | CT_SOA_PROLOGUE2_IMM(div) { 127 | aa[j] /= bb[j]; 128 | } 129 | CT_SOA_EPILOGUE_IMM; 130 | 131 | CT_SOA_PROLOGUE2_IMM(min) { 132 | aa[j] = CT_SOA_MIN(aa[j], bb[j]); 133 | } 134 | CT_SOA_EPILOGUE_IMM; 135 | 136 | CT_SOA_PROLOGUE2_IMM(max) { 137 | aa[j] = CT_SOA_MAX(aa[j], bb[j]); 138 | } 139 | CT_SOA_EPILOGUE_IMM; 140 | 141 | /// immutable SOA ops 142 | 143 | CT_SOA_PROLOGUE3(add) { 144 | oo[j] = aa[j] + bb[j]; 145 | } 146 | CT_SOA_EPILOGUE3; 147 | 148 | CT_SOA_PROLOGUE3(sub) { 149 | oo[j] = aa[j] - bb[j]; 150 | } 151 | CT_SOA_EPILOGUE3; 152 | 153 | CT_SOA_PROLOGUE3(mul) { 154 | oo[j] = aa[j] * bb[j]; 155 | } 156 | CT_SOA_EPILOGUE3; 157 | 158 | CT_SOA_PROLOGUE3(div) { 159 | oo[j] = aa[j] / bb[j]; 160 | } 161 | CT_SOA_EPILOGUE3; 162 | 163 | //// 2D SOA ops 164 | 165 | CT_SOA2_PROLOGUE3(dot2) { 166 | oo[i] = ax[i] * bx[i] + ay[i] * by[i]; 167 | } 168 | CT_SOA_EPILOGUE3_ALT; 169 | 170 | CT_SOA2_PROLOGUE3(dist2) { 171 | ct_soa_vec dx = ax[i] - bx[i]; 172 | ct_soa_vec dy = ay[i] - by[i]; 173 | oo[i] = CT_SOA_SQRT(dx * dx + dy * dy); 174 | } 175 | CT_SOA_EPILOGUE3_ALT; 176 | 177 | CT_SOA *ct_soa_normalize2f_imm(CT_SOA *a, float len) { 178 | size_t n = a->num >> CT_SOA_WORD_SHIFT; 179 | ct_soa_vec *ax = (ct_soa_vec *)a->comps[0]; 180 | ct_soa_vec *ay = (ct_soa_vec *)a->comps[1]; 181 | ct_soa_vec ll = CT_SOA_SET1(len); 182 | for (size_t i = 0; i < n; i++) { 183 | ct_soa_vec x = ax[i]; 184 | ct_soa_vec y = ay[i]; 185 | ct_soa_vec l = ll * CT_SOA_RSQRT(x * x + y * y); 186 | ax[i] = x * l; 187 | ay[i] = y * l; 188 | } 189 | return a; 190 | fail: 191 | return NULL; 192 | } 193 | 194 | //// 3D SOA ops 195 | 196 | CT_SOA3_PROLOGUE3(dot3) { 197 | oo[i] = ax[i] * bx[i] + ay[i] * by[i] + az[i] * bz[i]; 198 | } 199 | CT_SOA_EPILOGUE3_ALT; 200 | -------------------------------------------------------------------------------- /src/data/spatialgrid.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | #include "math/math.h" 5 | #include "mem/mpool.h" 6 | 7 | CT_BEGIN_DECLS 8 | 9 | typedef struct CT_SPCell CT_SPCell; 10 | 11 | typedef struct CT_SpatialGrid CT_SpatialGrid; 12 | 13 | struct CT_SpatialGrid { 14 | CT_MPool pool; 15 | CT_SPCell **cells; 16 | size_t numCells; 17 | size_t dims; 18 | size_t stride[3]; 19 | size_t size[3]; 20 | float offset[3]; 21 | float limit[3]; 22 | float invWidth[3]; 23 | int (*find_cell)(const CT_SpatialGrid *, const float *); 24 | }; 25 | 26 | int ct_spgrid_init(CT_SpatialGrid *grid, 27 | const float *start, 28 | const float *end, 29 | const size_t *strides, 30 | size_t dims, 31 | size_t poolSize); 32 | void ct_spgrid_free(CT_SpatialGrid *grid); 33 | int ct_spgrid_insert(CT_SpatialGrid *grid, const float *p, const void *item); 34 | int ct_spgrid_remove(CT_SpatialGrid *grid, const float *p, const void *item); 35 | int ct_spgrid_update(CT_SpatialGrid *grid, 36 | const float *p1, 37 | const float *p2, 38 | const void *item); 39 | size_t ct_spgrid_select1d(const CT_SpatialGrid *grid, 40 | float p, 41 | float eps, 42 | void **results, 43 | size_t len); 44 | size_t ct_spgrid_select2d(const CT_SpatialGrid *grid, 45 | const float *p, 46 | const float *eps, 47 | void **results, 48 | size_t len); 49 | size_t ct_spgrid_select3d(const CT_SpatialGrid *grid, 50 | const float *p, 51 | const float *eps, 52 | void **results, 53 | size_t len); 54 | 55 | void ct_spgrid_trace(const CT_SpatialGrid *grid); 56 | 57 | CT_END_DECLS 58 | -------------------------------------------------------------------------------- /src/data/tree.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | CT_BEGIN_DECLS 4 | 5 | enum { CT_TREE_EMPTY = 0, CT_TREE_BRANCH, CT_TREE_LEAF }; 6 | 7 | CT_END_DECLS 8 | -------------------------------------------------------------------------------- /src/data/vector.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "data/vector.h" 4 | #include "math/math.h" 5 | 6 | enum { CT_VECTOR_FREE = 1 }; 7 | 8 | CT_Vector *ct_vector_new(size_t limit, uint32_t stride) { 9 | CT_Vector *v; 10 | CT_CHECK_MEM(v = calloc(1, sizeof(CT_Vector))); 11 | if (!ct_vector_init(v, limit, stride)) { 12 | v->flags = CT_VECTOR_FREE; 13 | return v; 14 | } 15 | free(v); 16 | fail: 17 | return NULL; 18 | } 19 | 20 | int ct_vector_init(CT_Vector *v, size_t limit, uint32_t stride) { 21 | CT_CHECK(stride > 0, "stride must be > 0"); 22 | CT_CHECK_MEM(v->buffer = calloc(limit, stride)); 23 | v->num = 0; 24 | v->limit = limit; 25 | v->stride = stride; 26 | return 0; 27 | fail: 28 | return 1; 29 | } 30 | 31 | int ct_vector_init_ptr(CT_Vector *v, void *ptr, size_t limit, uint32_t stride) { 32 | CT_CHECK(stride > 0, "stride must be > 0"); 33 | v->buffer = ptr; 34 | v->num = limit; 35 | v->limit = limit; 36 | v->stride = stride; 37 | return 0; 38 | fail: 39 | return 1; 40 | } 41 | 42 | void ct_vector_free(CT_Vector *v) { 43 | free(v->buffer); 44 | if (v->flags & CT_VECTOR_FREE) { 45 | free(v); 46 | } 47 | } 48 | 49 | int ct_vector_push(CT_Vector *v, const void *x) { 50 | if (v->num == v->limit) { 51 | size_t new_limit = ct_ceil_multiple_pow2(v->limit * CT_VECTOR_GROWTH_FACTOR, 52 | CT_VECTOR_GROWTH_MIN); 53 | void *new_buf; 54 | CT_CHECK_MEM(new_buf = realloc(v->buffer, new_limit * v->stride)); 55 | CT_DEBUG("realloc vector: %p -> %p (%zu)", v->buffer, new_buf, new_limit); 56 | v->buffer = new_buf; 57 | v->limit = new_limit; 58 | } 59 | memcpy(&v->buffer[v->num * v->stride], x, v->stride); 60 | v->num++; 61 | return 0; 62 | fail: 63 | return 1; 64 | } 65 | 66 | int ct_vector_pop(CT_Vector *v, void *out) { 67 | if (!v->num) { 68 | return 1; 69 | } 70 | v->num--; 71 | if (out) { 72 | memcpy(out, &v->buffer[v->num * v->stride], v->stride); 73 | } 74 | // TODO downsize? 75 | return 0; 76 | } 77 | 78 | CT_VectorIter *ct_vector_iter_new(const CT_Vector *v, int reverse) { 79 | CT_CHECK(v, "vector is NULL"); 80 | CT_VectorIter *i; 81 | CT_CHECK_MEM(i = malloc(sizeof(CT_VectorIter))); 82 | if (!ct_vector_iter_init(i, v, reverse)) { 83 | return i; 84 | } 85 | free(i); 86 | fail: 87 | return NULL; 88 | } 89 | 90 | int ct_vector_iter_init(CT_VectorIter *i, const CT_Vector *v, int reverse) { 91 | CT_CHECK(v, "vector is NULL"); 92 | uint8_t *end = &v->buffer[v->num * v->stride]; 93 | if (reverse) { 94 | i->curr = end - v->stride; 95 | i->start = i->curr; 96 | i->end = v->buffer; 97 | i->stride = -v->stride; 98 | } else { 99 | i->curr = v->buffer; 100 | i->start = v->buffer; 101 | i->end = end; 102 | i->stride = v->stride; 103 | } 104 | return 0; 105 | fail: 106 | return 1; 107 | } 108 | 109 | void *ct_vector_iter_get(CT_VectorIter *i) { 110 | if (i->stride > 0) { 111 | if (i->curr < i->start || i->curr >= i->end) { 112 | return NULL; 113 | } 114 | } else { 115 | if (i->curr > i->start || i->curr < i->end) { 116 | return NULL; 117 | } 118 | } 119 | return i->curr; 120 | } 121 | 122 | void *ct_vector_iter_next(CT_VectorIter *i) { 123 | if (i->stride > 0) { 124 | if (i->curr >= i->end) { // fwd 125 | return NULL; 126 | } 127 | } else { 128 | if (i->curr < i->end) { // rev 129 | return NULL; 130 | } 131 | } 132 | void *p = i->curr; 133 | i->curr += i->stride; 134 | return p; 135 | } 136 | 137 | void *ct_vector_iter_prev(CT_VectorIter *i) { 138 | if (i->stride > 0) { 139 | if (i->curr <= i->start) { // fwd 140 | return NULL; 141 | } 142 | } else { 143 | if (i->curr >= i->start) { // rev 144 | return NULL; 145 | } 146 | } 147 | i->curr -= i->stride; 148 | void *p = i->curr; 149 | return p; 150 | } 151 | -------------------------------------------------------------------------------- /src/data/vector.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | #ifndef CT_VECTOR_GROWTH_MIN 6 | #define CT_VECTOR_GROWTH_MIN 4 7 | #endif 8 | 9 | #ifndef CT_VECTOR_GROWTH_FACTOR 10 | #define CT_VECTOR_GROWTH_FACTOR 1.25 11 | #endif 12 | 13 | typedef struct CT_Vector { 14 | uint8_t *buffer; 15 | size_t num; 16 | size_t limit; 17 | int32_t stride; 18 | uint8_t flags; 19 | } CT_Vector; 20 | 21 | typedef struct { 22 | uint8_t *curr; 23 | uint8_t *end; 24 | uint8_t *start; 25 | int32_t stride; 26 | } CT_VectorIter; 27 | 28 | CT_Vector *ct_vector_new(size_t limit, uint32_t stride); 29 | int ct_vector_init(CT_Vector *v, size_t limit, uint32_t stride); 30 | int ct_vector_init_ptr(CT_Vector *v, void *ptr, size_t limit, uint32_t stride); 31 | void ct_vector_free(CT_Vector *v); 32 | 33 | int ct_vector_push(CT_Vector *v, const void *x); 34 | int ct_vector_pop(CT_Vector *v, void *out); 35 | 36 | CT_VectorIter *ct_vector_iter_new(const CT_Vector *v, int reverse); 37 | int ct_vector_iter_init(CT_VectorIter *i, const CT_Vector *v, int reverse); 38 | void *ct_vector_iter_next(CT_VectorIter *i); 39 | void *ct_vector_iter_prev(CT_VectorIter *i); 40 | void *ct_vector_iter_get(CT_VectorIter *i); 41 | 42 | ct_inline void ct_vector_clear(CT_Vector *v) { 43 | v->num = 0; 44 | } 45 | 46 | ct_inline size_t ct_vector_size(const CT_Vector *v) { 47 | return v->num; 48 | } 49 | 50 | ct_inline void *ct_vector_get(const CT_Vector *v, size_t idx) { 51 | CT_CHECK(idx < v->limit, "idx out of bounds: %zu", idx); 52 | return &v->buffer[idx * v->stride]; 53 | fail: 54 | return NULL; 55 | } 56 | 57 | ct_inline void *ct_vector_get_unsafe(const CT_Vector *v, size_t idx) { 58 | return &v->buffer[idx * v->stride]; 59 | } 60 | 61 | ct_inline void *ct_vector_peek(const CT_Vector *v) { 62 | return v->num ? ct_vector_get(v, v->num - 1) : NULL; 63 | } 64 | -------------------------------------------------------------------------------- /src/geom/aabb.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | #include "math/vec.h" 6 | #include "mem/mpool.h" 7 | 8 | CT_BEGIN_DECLS 9 | 10 | typedef struct { 11 | CT_Vec3f p; 12 | CT_Vec3f size; 13 | } CT_AABB; 14 | 15 | CT_AABB *ct_aabbv(CT_Vec3f *p, CT_Vec3f *size, CT_MPool *mpool); 16 | CT_AABB *ct_aabbn(CT_Vec3f *p, float size, CT_MPool *mpool); 17 | 18 | float ct_aabb_area(void *a); 19 | int ct_aabb_classify_point(void *a, const CT_Vec3f *p); 20 | 21 | CT_END_DECLS 22 | -------------------------------------------------------------------------------- /src/geom/circle.c: -------------------------------------------------------------------------------- 1 | #include "geom/circle.h" 2 | #include "geom/protocols.h" 3 | 4 | // clang-format off 5 | /* 6 | CT_IArea __ct_iarea_circle2 = { 7 | .area = ct_circle2f_area 8 | }; 9 | 10 | CT_ICircumference __ct_icircumference_circle2 = { 11 | .circumference = ct_circle2f_circumference 12 | }; 13 | 14 | CT_IClassify __ct_iclassify_circle2 = { 15 | .classify_point2f = ct_circle2f_classify_point, 16 | .classify_point3f = NULL 17 | }; 18 | */ 19 | // clang-format off 20 | 21 | ct_export CT_Circle2f *ct_circle2f_init(CT_Circle2f *c, float x, float y, 22 | float r) { 23 | c->pos.x = x; 24 | c->pos.y = y; 25 | c->r = r; 26 | return c; 27 | } 28 | 29 | ct_export CT_Circle2f *ct_circle2f_initvr(CT_Circle2f *c, CT_Vec2f *p, 30 | float r) { 31 | return ct_circle2f_init(c, p->x, p->y, r); 32 | } 33 | 34 | ct_export CT_Circle2f *ct_circle2f_initr(CT_Circle2f *c, float r) { 35 | return ct_circle2f_init(c, 0, 0, r); 36 | } 37 | 38 | ct_export float ct_circle2f_area(CT_Circle2f *c) { 39 | return CT_PI * c->r * c->r; 40 | } 41 | 42 | ct_export float ct_circle2f_circumference(CT_Circle2f *c) { 43 | return CT_TAU * c->r; 44 | } 45 | 46 | ct_export int ct_circle2f_classify_point(CT_Circle2f *c, CT_Vec2f *p) { 47 | return ct_signumf(c->r - ct_dist2fv(&c->pos, p), CT_EPS); 48 | } 49 | 50 | ct_export CT_Vec2f *ct_circle2f_vertices(CT_Circle2f *c, CT_Vec2f *verts, 51 | size_t n) { 52 | CT_Vec2f *ptr = verts; 53 | float t = CT_TAU / n; 54 | for (size_t i = 0; i < n; i++) { 55 | ct_add2fv_imm(ct_cartesian2f_imm(ct_set2fxy(ptr, c->r, t * i)), &c->pos); 56 | ptr++; 57 | } 58 | return verts; 59 | } 60 | 61 | ct_export CT_Triangle2f *ct_circle2f_tessellate(CT_Circle2f *c, 62 | CT_Triangle2f *tris, size_t n) { 63 | CT_Vec2f *verts = 64 | ct_circle2f_vertices(c, malloc(sizeof(CT_Vec2f) * n), n); 65 | CT_Triangle2f *ptr = tris; 66 | for (size_t i = 0; i < n; i++) { 67 | ct_triangle2f_init(ptr, &c->pos, &verts[i], &verts[(i + 1) % n]); 68 | ptr++; 69 | } 70 | free(verts); 71 | return tris; 72 | } 73 | -------------------------------------------------------------------------------- /src/geom/circle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | //#include "geom/protocols.h" 5 | #include "geom/triangle.h" 6 | #include "math/vec.h" 7 | 8 | CT_BEGIN_DECLS 9 | 10 | typedef union { 11 | struct { 12 | CT_Vec2f pos; 13 | float r; 14 | }; 15 | float buf[3]; 16 | } CT_Circle2f; 17 | 18 | CT_Circle2f *ct_circle2f_init(CT_Circle2f *c, float x, float y, float r); 19 | CT_Circle2f *ct_circle2f_initvr(CT_Circle2f *c, CT_Vec2f *p, float r); 20 | CT_Circle2f *ct_circle2f_initr(CT_Circle2f *c, float r); 21 | 22 | float ct_circle2f_area(CT_Circle2f *c); 23 | float ct_circle2f_circumference(CT_Circle2f *c); 24 | int ct_circle2f_classify_point(CT_Circle2f *c, CT_Vec2f *p); 25 | 26 | CT_Vec2f *ct_circle2f_vertices(CT_Circle2f *c, CT_Vec2f *verts, size_t n); 27 | CT_Triangle2f *ct_circle2f_tessellate(CT_Circle2f *c, 28 | CT_Triangle2f *tris, 29 | size_t n); 30 | 31 | CT_END_DECLS 32 | -------------------------------------------------------------------------------- /src/geom/clip/liangbarsky.c: -------------------------------------------------------------------------------- 1 | #include "geom/clip/liangbarsky.h" 2 | 3 | #define CLIP_LB(pp, qq) \ 4 | p = (pp); \ 5 | q = (qq); \ 6 | if (q < 0 && fabs(p) < CT_EPS) { \ 7 | return 0; \ 8 | } \ 9 | r = q / p; \ 10 | if (p < 0) { \ 11 | if (r > b) { \ 12 | return 0; \ 13 | } else if (r > a) { \ 14 | a = r; \ 15 | } \ 16 | } else if (p > 0) { \ 17 | if (r < a) { \ 18 | return 0; \ 19 | } else if (r < b) { \ 20 | b = r; \ 21 | } \ 22 | } 23 | 24 | // https://en.wikipedia.org/wiki/Liang%E2%80%93Barsky_algorithm 25 | 26 | ct_export int ct_clip2f_liangbarsky(const CT_Vec2f *tl, 27 | const CT_Vec2f *br, 28 | const CT_Vec2f *la, 29 | const CT_Vec2f *lb, 30 | CT_Vec2f *ca, 31 | CT_Vec2f *cb) { 32 | const float dx = lb->x - la->x; 33 | const float dy = lb->y - la->y; 34 | float a = 0.0; 35 | float b = 1.0; 36 | float p, q, r; 37 | 38 | CLIP_LB(-dx, -(tl->x - la->x)); 39 | CLIP_LB(dx, br->x - la->x); 40 | CLIP_LB(-dy, -(tl->y - la->y)); 41 | CLIP_LB(dy, br->y - la->y); 42 | 43 | ca->x = a * dx + la->x; 44 | ca->y = a * dy + la->y; 45 | cb->x = b * dx + la->x; 46 | cb->y = b * dy + la->y; 47 | 48 | CT_DEBUG("ca: [%f,%f] cb: [%f,%f]", ca->x, ca->y, cb->x, cb->y); 49 | return 1; 50 | } 51 | -------------------------------------------------------------------------------- /src/geom/clip/liangbarsky.h: -------------------------------------------------------------------------------- 1 | #include "math/vec.h" 2 | 3 | int ct_clip2f_liangbarsky(const CT_Vec2f *tl, 4 | const CT_Vec2f *br, 5 | const CT_Vec2f *la, 6 | const CT_Vec2f *lb, 7 | CT_Vec2f *ca, 8 | CT_Vec2f *cb); 9 | -------------------------------------------------------------------------------- /src/geom/halfedge.c: -------------------------------------------------------------------------------- 1 | // #pragma once 2 | 3 | #include "cthing.h" 4 | #include "math/vec.h" 5 | #include "mem/mpool.h" 6 | 7 | typedef struct CT_HalfEdge CT_HalfEdge; 8 | typedef struct CT_HEVertex CT_HEVertex; 9 | typedef struct CT_HEFace CT_HEFace; 10 | 11 | struct CT_HalfEdge { 12 | CT_HEVertex *vertex; 13 | CT_HEFace *face; 14 | CT_HalfEdge *pair; 15 | CT_HalfEdge *next; 16 | }; 17 | 18 | struct CT_HEVertex { 19 | CT_Vec3f pos; 20 | CT_HalfEdge *edge; 21 | }; 22 | 23 | struct CT_HEFace { 24 | CT_HalfEdge *edge; 25 | CT_Vec3f normal; 26 | }; 27 | 28 | typedef struct { 29 | CT_HEVertex **vertices; 30 | CT_HEFace **faces; 31 | CT_MPool mpoolV, mpoolF, mpoolE; 32 | size_t numV; 33 | size_t numF; 34 | } CT_HEMesh; 35 | 36 | static size_t _vertex_idx = 0; 37 | 38 | CT_HEVertex *ct_hevertex(float *pos, CT_HalfEdge *e, CT_MPool *pool) { 39 | CT_HEVertex *v; 40 | CT_CHECK_MEM(v = CT_MP_ALLOC(pool, CT_HEVertex)); 41 | ct_set3fxyz(&v->pos, pos[0], pos[1], pos[2]); 42 | v->edge = e; 43 | fail: 44 | return v; 45 | } 46 | 47 | ct_export int ct_hemesh_init(CT_HEMesh *mesh, size_t numV, size_t numF) { 48 | ct_mpool_init(&mesh->mpoolV, numV, sizeof(CT_HEVertex)); 49 | ct_mpool_init(&mesh->mpoolF, numF, sizeof(CT_HEFace)); 50 | ct_mpool_init(&mesh->mpoolE, numF * 2, sizeof(CT_HalfEdge)); 51 | mesh->vertices = calloc(numV, sizeof(CT_HEVertex *)); 52 | mesh->faces = calloc(numF, sizeof(CT_HEFace *)); 53 | mesh->numV = mesh->numF = 0; 54 | return 0; 55 | } 56 | 57 | ct_export void ct_hemesh_free(CT_HEMesh *mesh) { 58 | ct_mpool_free(&mesh->mpoolV); 59 | ct_mpool_free(&mesh->mpoolF); 60 | ct_mpool_free(&mesh->mpoolE); 61 | } 62 | -------------------------------------------------------------------------------- /src/geom/hull.c: -------------------------------------------------------------------------------- 1 | #include "geom/hull.h" 2 | 3 | static size_t hull2f(CT_Vec2f *points, size_t num, CT_Vector *h) { 4 | size_t len = 0; 5 | for (size_t i = 0; i < num; i++) { 6 | while (CT_LIKELY(len >= 2) && 7 | ct_cross2fv3(&((CT_Vec2f *)h->buffer)[h->num - 2], 8 | &((CT_Vec2f *)h->buffer)[h->num - 1], 9 | &points[i]) >= 0) { 10 | h->num--; 11 | len--; 12 | } 13 | ct_vector_push(h, &points[i]); 14 | //CT_DEBUG("add h: %f,%f (%zu)", points[i].x, points[i].y, len); 15 | len++; 16 | } 17 | return len - 1; 18 | } 19 | 20 | size_t ct_convexhull2f(CT_Vec2f *points, size_t num, CT_Vector *hull) { 21 | if (num < 1) { 22 | return 0; 23 | } 24 | qsort(points, num, sizeof(CT_Vec2f), ct_compare2fv_xy); 25 | size_t len = hull2f(points, num, hull); 26 | ct_array_reverse8_imm(points, num); 27 | len += hull2f(points, num, hull); 28 | return len - (ct_compare2fv_xy((CT_Vec2f *)ct_vector_get(hull, 0), 29 | (CT_Vec2f *)ct_vector_get(hull, 1)) == 0); 30 | } 31 | -------------------------------------------------------------------------------- /src/geom/hull.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | #include "data/array.h" 6 | #include "data/vector.h" 7 | #include "math/vec.h" 8 | 9 | size_t ct_convexhull2f(CT_Vec2f* ptr, size_t num, CT_Vector* hull); 10 | -------------------------------------------------------------------------------- /src/geom/isec.c: -------------------------------------------------------------------------------- 1 | #include "geom/isec.h" 2 | 3 | #define DELTA(a, b, c) ((a) < (b) ? ((a) - (b)) : ((a) > (c) ? ((a) - (c)) : 0)) 4 | 5 | // returns: -1 = parallel, 0 = isec outside, 1 = isec inside 6 | ct_export int ct_intersect_lines(const CT_Vec2f *a, 7 | const CT_Vec2f *b, 8 | const CT_Vec2f *c, 9 | const CT_Vec2f *d, 10 | CT_Vec2f *isec, 11 | float *alpha, 12 | float *beta) { 13 | float bax = b->x - a->x; 14 | float bay = b->y - a->y; 15 | float dcx = d->x - c->x; 16 | float dcy = d->y - c->y; 17 | float det = (dcy * bax - dcx * bay); 18 | if (det == 0) { 19 | return -1; 20 | } 21 | det = 1 / det; 22 | float acx = a->x - c->x; 23 | float acy = a->y - c->y; 24 | *alpha = (dcx * acy - dcy * acx) * det; 25 | *beta = (bax * acy - bay * acx) * det; 26 | ct_mix2fv(a, b, *alpha, isec); 27 | return (0 < *alpha && *alpha < 1) && (0 < *beta && *beta < 1); 28 | } 29 | 30 | ct_export int ct_intersect_rect_circle(const CT_Vec2f *p, 31 | const CT_Vec2f *q, 32 | const CT_Vec2f *c, 33 | float r) { 34 | const float dx = DELTA(c->x, p->x, q->x); 35 | const float dy = DELTA(c->y, p->y, q->y); 36 | return (dx * dx + dy * dy) <= (r * r); 37 | } 38 | 39 | ct_export int ct_intersect_aabb_sphere(const CT_Vec3f *p, 40 | const CT_Vec3f *q, 41 | const CT_Vec3f *c, 42 | float r) { 43 | const float dx = DELTA(c->x, p->x, q->x); 44 | const float dy = DELTA(c->y, p->y, q->y); 45 | const float dz = DELTA(c->z, p->z, q->z); 46 | return (dx * dx + dy * dy + dz * dz) <= (r * r); 47 | } 48 | -------------------------------------------------------------------------------- /src/geom/isec.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "math/vec.h" 4 | 5 | CT_BEGIN_DECLS 6 | 7 | int ct_intersect_lines(const CT_Vec2f *a, 8 | const CT_Vec2f *b, 9 | const CT_Vec2f *c, 10 | const CT_Vec2f *d, 11 | CT_Vec2f *isec, 12 | float *alpha, 13 | float *beta); 14 | 15 | // p/q = rect min/max, c = circle origin, r = radius 16 | int ct_intersect_rect_circle(const CT_Vec2f *p, 17 | const CT_Vec2f *q, 18 | const CT_Vec2f *c, 19 | float r); 20 | 21 | int ct_intersect_aabb_sphere(const CT_Vec3f *p, 22 | const CT_Vec3f *q, 23 | const CT_Vec3f *c, 24 | float r); 25 | 26 | CT_END_DECLS 27 | -------------------------------------------------------------------------------- /src/geom/mesh.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "data/hashtable.h" 4 | #include "math/vec.h" 5 | 6 | typedef struct { CT_Vec3f *a, *b; } CT_MeshEdge; 7 | 8 | typedef struct { 9 | uint32_t *vertices; 10 | uint32_t numV; 11 | } CT_MeshFace; 12 | 13 | typedef struct { 14 | CT_Hashtable vertices; 15 | CT_Hashtable edges; 16 | CT_MPool vpool; 17 | uint32_t vid; 18 | } CT_Mesh; 19 | 20 | static uint32_t hash_vec3f(const void *v, size_t _) { 21 | return ct_murmur3_32(v, 12); 22 | } 23 | 24 | static int equiv_vec3f(const void *a, const void *b, size_t as, size_t bs) { 25 | return !memcmp(a, b, 12); 26 | } 27 | 28 | static uint32_t hash_edge_vec3f(const void *a, size_t _) { 29 | const CT_MeshEdge *e = (CT_MeshEdge *)a; 30 | return ct_murmur3_32(e->a, 12) + ct_murmur3_32(e->b, 12); 31 | } 32 | 33 | static int equiv_edge_vec3f(const void *a, 34 | const void *b, 35 | size_t as, 36 | size_t bs) { 37 | CT_MeshEdge *ea = (CT_MeshEdge *)a; 38 | CT_MeshEdge *eb = (CT_MeshEdge *)b; 39 | if (!memcmp(ea->a, eb->a, 12)) { 40 | if (!memcmp(ea->b, eb->b, 12)) { 41 | return 1; 42 | } 43 | } 44 | if (!memcmp(ea->a, eb->b, 12)) { 45 | if (!memcmp(ea->b, eb->a, 12)) { 46 | return 1; 47 | } 48 | } 49 | return 0; 50 | } 51 | 52 | static CT_HTOps _ht_vertex_ops_vec3f = {.hash = hash_vec3f, 53 | .equiv_keys = equiv_vec3f}; 54 | 55 | static CT_HTOps _ht_edge_ops_vec3f = {.hash = hash_edge_vec3f, 56 | .equiv_keys = equiv_edge_vec3f}; 57 | 58 | int ct_mesh_init(CT_Mesh *m, size_t numF, size_t numV) { 59 | ct_ht_init(&m->vertices, &_ht_vertex_ops_vec3f, numV, numV >> 2, CT_HT_NONE); 60 | ct_ht_init(&m->edges, &_ht_edge_ops_vec3f, numF * 2, numF >> 1, 61 | CT_HT_CONST_KEYS | CT_HT_CONST_VALS); 62 | ct_mpool_init(&m->vpool, numV, sizeof(CT_Vec3f)); 63 | m->vid = 0; 64 | return 0; 65 | } 66 | 67 | void ct_mesh_free(CT_Mesh *m) { 68 | ct_ht_free(&m->vertices); 69 | ct_ht_free(&m->edges); 70 | } 71 | 72 | int ct_mesh_add_face(CT_Mesh *m, CT_Vec3f **verts, size_t num) { 73 | uint32_t ids[4]; 74 | uint32_t prev_id, id; 75 | for (size_t i = 0; i <= num; i++) { 76 | if (id < num) { 77 | uint32_t *vid = (uint32_t *)ct_ht_get(&m->vertices, verts[i], 12, NULL); 78 | if (!vid) { 79 | ct_ht_assoc(&m->vertices, verts[i], &m->vid, sizeof(CT_Vec3f), 4); 80 | id = m->vid; 81 | m->vid++; 82 | } else { 83 | id = *vid; 84 | } 85 | ids[i] = id; 86 | } else { 87 | id = ids[0]; 88 | } 89 | } 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /src/geom/polygon.h: -------------------------------------------------------------------------------- 1 | #include "cthing.h" 2 | 3 | #include "data/cons.h" 4 | #include "math/vec.h" 5 | #include "mem/mpool.h" 6 | 7 | enum { CT_CLIP_UNION = 0, CT_CLIP_INTERSECTION = 1, CT_CLIP_DIFF = 2 }; 8 | 9 | typedef struct CT_PolyVertex CT_PolyVertex; 10 | 11 | struct CT_PolyVertex { 12 | CT_Vec2f pos; 13 | CT_PolyVertex *next; 14 | CT_PolyVertex *prev; 15 | CT_PolyVertex *pair; 16 | float dist; 17 | uint8_t isec : 1; 18 | uint8_t entry : 1; 19 | uint8_t visited : 1; 20 | }; 21 | 22 | typedef struct { 23 | CT_PolyVertex *first; 24 | CT_PolyVertex *firstIsec; 25 | CT_PolyVertex *lastProc; 26 | size_t num; 27 | CT_MPool pool; 28 | } CT_Polygon2f; 29 | 30 | typedef struct { 31 | CT_Vec2f curr; 32 | CT_Vec2f next; 33 | CT_Vec2f normal; 34 | } CT_PolyEdge; 35 | 36 | typedef struct { 37 | CT_MPool ppool; 38 | CT_MPool cpool; 39 | CT_Cons *result; 40 | } CT_PolyClipContext; 41 | 42 | typedef struct { 43 | CT_PolyEdge *edges; 44 | size_t num; 45 | int8_t res; 46 | CT_MPool vpool; 47 | CT_MPool cpool; 48 | CT_PolyClipContext clip; 49 | } CT_PolyOffsetContext; 50 | 51 | int ct_polygon2f_init(CT_Polygon2f *poly, CT_Vec2f *points, size_t num); 52 | void ct_polygon2f_free(CT_Polygon2f *poly); 53 | CT_Polygon2f *ct_polygon2f_add_vertex(CT_Polygon2f *poly, const CT_Vec2f *pos); 54 | int ct_polygon2f_point_inside(const CT_Polygon2f *poly, const CT_Vec2f *v); 55 | CT_Cons *ct_polygon2f_clip(CT_PolyClipContext *ctx, 56 | CT_Polygon2f *src, 57 | CT_Polygon2f *clip, 58 | size_t mode); 59 | 60 | int ct_polygon2f_clip_ctx_init(CT_PolyClipContext *ctx, size_t poolSize); 61 | void ct_polygon2f_clip_ctx_free(CT_PolyClipContext *ctx); 62 | void ct_polygon2f_clip_ctx_reset(CT_PolyClipContext *ctx); 63 | 64 | int ct_polygon2f_offset_ctx_init(CT_PolyOffsetContext *ctx, size_t poolSize); 65 | void ct_polygon2f_offset_ctx_free(CT_PolyOffsetContext *ctx); 66 | void ct_polygon2f_offset_ctx_reset(CT_PolyOffsetContext *ctx); 67 | 68 | CT_Polygon2f *ct_polygon2f_offset_points(CT_PolyOffsetContext *ctx, 69 | const CT_Vec2f *points, 70 | size_t num, 71 | float dist, 72 | int8_t res); 73 | -------------------------------------------------------------------------------- /src/geom/protocols.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | #include "geom/aabb.h" 5 | #include "geom/circle.h" 6 | #include "geom/rect.h" 7 | 8 | #define PROTO_FN1(proto, rtype, name) \ 9 | ct_export ct_inline rtype ct_##name(const proto *p, void *i) { \ 10 | return p->name(i); \ 11 | } 12 | 13 | #define PROTO_FN2(proto, rtype, name, atype) \ 14 | ct_export ct_inline rtype ct_##name(const proto *p, void *i, atype *a) { \ 15 | return p->name(i, a); \ 16 | } 17 | 18 | CT_BEGIN_DECLS 19 | 20 | typedef struct { float (*area)(void *); } CT_IArea; 21 | 22 | typedef struct { 23 | CT_Rect2f (*bounds2f)(void *); 24 | CT_AABB (*bounds3f)(void *); 25 | } CT_IBounds; 26 | 27 | typedef struct { float (*circumference)(void *); } CT_ICircumference; 28 | 29 | typedef struct { 30 | int (*classify_point2f)(void *, CT_Vec2f *); 31 | int (*classify_point3f)(void *, CT_Vec3f *); 32 | } CT_IClassify; 33 | 34 | PROTO_FN1(CT_IArea, float, area) 35 | 36 | PROTO_FN1(CT_IBounds, CT_Rect2f, bounds2f) 37 | PROTO_FN1(CT_IBounds, CT_AABB, bounds3f) 38 | 39 | PROTO_FN1(CT_ICircumference, float, circumference) 40 | 41 | PROTO_FN2(CT_IClassify, int, classify_point2f, CT_Vec2f) 42 | PROTO_FN2(CT_IClassify, int, classify_point3f, CT_Vec3f) 43 | 44 | CT_END_DECLS 45 | -------------------------------------------------------------------------------- /src/geom/quadedge.c: -------------------------------------------------------------------------------- 1 | #include "geom/quadedge.h" 2 | 3 | ct_export CT_QuadEdgeRef ct_qedge() { 4 | CT_QuadEdgeRef e = (CT_QuadEdgeRef)malloc(sizeof(CT_QuadEdge)); 5 | ONEXT(e) = e; 6 | SYMDNEXT(e) = SYM(e); 7 | ROTRNEXT(e) = TOR(e); 8 | TORLNEXT(e) = ROT(e); 9 | MARK(e) = 0; 10 | return e; 11 | } 12 | 13 | /* Delete an edge: */ 14 | 15 | ct_export void ct_qedge_destroy(CT_QuadEdgeRef e) { 16 | CT_QuadEdgeRef f = SYM(e); 17 | if (ONEXT(e) != e) { 18 | ct_qedge_splice(e, OPREV(e)); 19 | } 20 | if (ONEXT(f) != f) { 21 | ct_qedge_splice(f, OPREV(f)); 22 | } 23 | free((uint8_t *)QE_MASK(e)); 24 | } 25 | 26 | /* Splice primitive: */ 27 | 28 | ct_export void ct_qedge_splice(CT_QuadEdgeRef a, CT_QuadEdgeRef b) { 29 | CT_QuadEdgeRef ta, tb; 30 | CT_QuadEdgeRef alpha = ROT(ONEXT(a)); 31 | CT_QuadEdgeRef beta = ROT(ONEXT(b)); 32 | 33 | ta = ONEXT(a); 34 | tb = ONEXT(b); 35 | ONEXT(a) = tb; 36 | ONEXT(b) = ta; 37 | ta = ONEXT(alpha); 38 | tb = ONEXT(beta); 39 | ONEXT(alpha) = tb; 40 | ONEXT(beta) = ta; 41 | } 42 | 43 | /* Enumerate edge quads */ 44 | 45 | static void ct_qedge_do_iter(CT_QuadEdgeRef e, 46 | CT_QuadEdgeVisitor visit, 47 | void *state, 48 | size_t mark) { 49 | while (MARK(e) != mark) { 50 | visit(e, state); 51 | MARK(e) = mark; 52 | ct_qedge_do_iter(ONEXT(SYM(e)), visit, state, mark); 53 | e = ONEXT(e); 54 | } 55 | } 56 | 57 | static size_t next_mark = 1; 58 | 59 | ct_export void ct_qedge_iterate(CT_QuadEdgeRef a, 60 | CT_QuadEdgeVisitor visit, 61 | void *state) { 62 | size_t mark = next_mark; 63 | next_mark++; 64 | if (next_mark == 0) { 65 | next_mark = 1; 66 | } 67 | ct_qedge_do_iter(a, visit, state, mark); 68 | } 69 | -------------------------------------------------------------------------------- /src/geom/quadedge.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | #include "math/vec.h" 6 | 7 | CT_BEGIN_DECLS 8 | 9 | typedef size_t CT_QuadEdgeRef; 10 | 11 | typedef struct { 12 | CT_QuadEdgeRef next[4]; 13 | void *data[4]; 14 | size_t mark; 15 | } CT_QuadEdge; 16 | 17 | typedef void (*CT_QuadEdgeVisitor)(CT_QuadEdgeRef, void *); 18 | 19 | // Edge orientation operators 20 | 21 | #define QE_MASK(e) ((e) & (size_t)-4) 22 | 23 | #define ROT(e) (QE_MASK(e) + (((e) + 1) & 3)) 24 | #define SYM(e) (QE_MASK(e) + (((e) + 2) & 3)) 25 | #define TOR(e) (QE_MASK(e) + (((e) + 3) & 3)) 26 | 27 | // Vertex/face walking operators 28 | 29 | #define ONEXT(e) ((CT_QuadEdge *)QE_MASK(e))->next[(e)&3] 30 | #define ROTRNEXT(e) ((CT_QuadEdge *)QE_MASK(e))->next[((e) + 1) & 3] 31 | #define SYMDNEXT(e) ((CT_QuadEdge *)QE_MASK(e))->next[((e) + 2) & 3] 32 | #define TORLNEXT(e) ((CT_QuadEdge *)QE_MASK(e))->next[((e) + 3) & 3] 33 | 34 | #define RNEXT(e) (TOR(ROTRNEXT(e))) 35 | #define DNEXT(e) (SYM(SYMDNEXT(e))) 36 | #define LNEXT(e) (ROT(TORLNEXT(e))) 37 | 38 | #define OPREV(e) (ROT(ROTRNEXT(e))) 39 | #define DPREV(e) (TOR(TORLNEXT(e))) 40 | #define RPREV(e) (SYMDNEXT(e)) 41 | #define LPREV(e) (SYM(ONEXT(e))) 42 | 43 | // Data pointers 44 | 45 | #define ODATA(e) ((CT_QuadEdge *)QE_MASK(e))->data[(e)&3] 46 | #define RDATA(e) ((CT_QuadEdge *)QE_MASK(e))->data[((e) + 1) & 3] 47 | #define DDATA(e) ((CT_QuadEdge *)QE_MASK(e))->data[((e) + 2) & 3] 48 | #define LDATA(e) ((CT_QuadEdge *)QE_MASK(e))->data[((e) + 3) & 3] 49 | 50 | #define MARK(e) ((CT_QuadEdge *)QE_MASK(e))->mark 51 | 52 | CT_QuadEdgeRef ct_qedge(void); 53 | 54 | void ct_qedge_destroy(CT_QuadEdgeRef e); 55 | 56 | void ct_qedge_splice(CT_QuadEdgeRef a, CT_QuadEdgeRef b); 57 | 58 | void ct_qedge_iterate(CT_QuadEdgeRef a, CT_QuadEdgeVisitor visit, void *state); 59 | 60 | CT_END_DECLS 61 | -------------------------------------------------------------------------------- /src/geom/rect.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/random.h" 2 | 3 | #include "geom/rect.h" 4 | 5 | ct_export float ct_rect2f_area(const CT_Rect2f *r) { 6 | return (r->q.x - r->p.x) * (r->q.y - r->p.y); 7 | } 8 | 9 | ct_export int ct_rect2f_classify_point(const CT_Rect2f *r, const CT_Vec2f *p) { 10 | if (p->x > r->p.x && p->x < r->q.x && p->y > r->p.y && p->y < r->q.y) { 11 | return 1; 12 | } else if (p->x < r->p.x || p->x > r->q.x || p->y < r->p.y || p->y > r->q.y) { 13 | return -1; 14 | } 15 | return 0; // FIXME 16 | } 17 | 18 | ct_export CT_Vec2f *ct_rect2f_sample_inside(const CT_Rect2f *r, CT_Vec2f *out) { 19 | out->x = ct_rand_normpos() * (r->q.x - r->p.x) + r->p.x; 20 | out->y = ct_rand_normpos() * (r->q.y - r->p.y) + r->p.y; 21 | return out; 22 | } 23 | -------------------------------------------------------------------------------- /src/geom/rect.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | #include "math/vec.h" 5 | #include "mem/mpool.h" 6 | 7 | CT_BEGIN_DECLS 8 | 9 | typedef union { 10 | struct { 11 | CT_Vec2f p; 12 | CT_Vec2f q; 13 | }; 14 | float buf[4]; 15 | } CT_Rect2f; 16 | 17 | CT_Rect2f *ct_rect2fv(CT_Vec2f *p, CT_Vec2f *size, CT_MPool *mpool); 18 | CT_Rect2f *ct_rect2fn(CT_Vec2f *p, float size, CT_MPool *mpool); 19 | 20 | float ct_rect2f_area(const CT_Rect2f *a); 21 | int ct_rect2f_classify_point(const CT_Rect2f *a, const CT_Vec2f *p); 22 | CT_Vec2f *ct_rect2f_sample_inside(const CT_Rect2f *r, CT_Vec2f *out); 23 | 24 | CT_END_DECLS 25 | -------------------------------------------------------------------------------- /src/geom/triangle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | #include "math/vec.h" 5 | 6 | CT_BEGIN_DECLS 7 | 8 | typedef union { 9 | struct { 10 | CT_Vec2f a, b, c; 11 | }; 12 | float buf[3 * sizeof(CT_Vec2f) / sizeof(float)]; 13 | } CT_Triangle2f; 14 | 15 | typedef union { 16 | struct { 17 | CT_Vec3f a, b, c; 18 | }; 19 | float buf[3 * sizeof(CT_Vec3f) / sizeof(float)]; 20 | } CT_Triangle3f; 21 | 22 | CT_Triangle2f *ct_triangle2f_init(CT_Triangle2f *t, 23 | const CT_Vec2f *a, 24 | const CT_Vec2f *b, 25 | const CT_Vec2f *c); 26 | CT_Triangle2f *ct_triangle2f_initpv(CT_Triangle2f *t, const CT_Vec2f *points); 27 | CT_Triangle2f *ct_triangle2f_initpf(CT_Triangle2f *t, const float *coords); 28 | 29 | float ct_triangle2f_area(const CT_Triangle2f *t); 30 | float ct_triangle2f_circumference(const CT_Triangle2f *t); 31 | float ct_triangle2f_normsign(const CT_Triangle2f *t); 32 | size_t ct_triangle2f_is_clockwise(const CT_Triangle2f *t); 33 | CT_Vec2f *ct_triangle2f_point_opposite_ptr(CT_Triangle2f *t, 34 | const CT_Vec2f *a, 35 | const CT_Vec2f *b); 36 | CT_Vec2f *ct_triangle2f_point_opposite(CT_Triangle2f *t, 37 | const CT_Vec2f *a, 38 | const CT_Vec2f *b); 39 | 40 | ///// CT_Triangle3f 41 | 42 | CT_Triangle3f *ct_triangle3f_init(CT_Triangle3f *t, 43 | const CT_Vec3f *a, 44 | const CT_Vec3f *b, 45 | const CT_Vec3f *c); 46 | CT_Triangle3f *ct_triangle3f_initpv(CT_Triangle3f *t, const CT_Vec3f *points); 47 | CT_Triangle3f *ct_triangle3f_initpf(CT_Triangle3f *t, const float *coords); 48 | 49 | float ct_triangle3f_area(CT_Triangle3f *t); 50 | float ct_triangle3f_circumference(CT_Triangle3f *t); 51 | CT_Vec3f *ct_triangle3f_normal(const CT_Triangle3f *t, 52 | CT_Vec3f *out, 53 | size_t normalize); 54 | float ct_triangle3f_normsign(const CT_Triangle3f *t); 55 | size_t ct_triangle3f_is_clockwise(const CT_Triangle3f *t, const CT_Vec3f *n); 56 | CT_Vec3f *ct_triangle3f_point_opposite_ptr(CT_Triangle3f *t, 57 | const CT_Vec3f *a, 58 | const CT_Vec3f *b); 59 | CT_Vec3f *ct_triangle3f_point_opposite(CT_Triangle3f *t, 60 | const CT_Vec3f *a, 61 | const CT_Vec3f *b); 62 | 63 | CT_END_DECLS 64 | -------------------------------------------------------------------------------- /src/geom/voronoi.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | #include "math/vec.h" 5 | #include "mem/mpool.h" 6 | 7 | #define VORONOI_DELETED -2 8 | 9 | typedef struct { 10 | CT_Vec2f pos; 11 | uint32_t id; 12 | uint32_t refs; 13 | } CT_VOVertex; 14 | 15 | typedef struct { 16 | CT_VOVertex *ep[2]; 17 | CT_VOVertex *reg[2]; 18 | uint32_t id; 19 | float a, b, c; 20 | } CT_VOEdge; 21 | 22 | typedef struct CT_VOHalfEdge CT_VOHalfEdge; 23 | 24 | struct CT_VOHalfEdge { 25 | CT_VOHalfEdge *next; 26 | CT_VOHalfEdge *left; 27 | CT_VOHalfEdge *right; 28 | CT_VOEdge *parent; 29 | CT_VOVertex *vertex; 30 | uint32_t refs; 31 | float key; 32 | uint8_t side; 33 | }; 34 | 35 | typedef struct { 36 | CT_VOHalfEdge **hash; 37 | CT_VOHalfEdge *leftend; 38 | CT_VOHalfEdge *rightend; 39 | uint32_t hashSize; 40 | float minx; 41 | float deltax; 42 | CT_MPool pool; 43 | } CT_VOEdgeList; 44 | 45 | typedef struct { 46 | CT_VOHalfEdge *hash; 47 | uint32_t hashSize; 48 | uint32_t count; 49 | uint32_t min; 50 | float miny; 51 | float deltay; 52 | } CT_VOHeap; 53 | 54 | typedef struct { 55 | CT_MPool vpool; 56 | CT_MPool epool; 57 | uint32_t numVertices; 58 | uint32_t numSites; 59 | uint32_t numEdges; 60 | CT_VOVertex *first; 61 | CT_VOEdgeList halfEdges; 62 | CT_VOHeap heap; 63 | } CT_Voronoi; 64 | 65 | typedef void (*CT_VOEdgeHandler)(CT_VOEdge *, void *); 66 | 67 | int ct_voronoi_init(CT_Voronoi *vor, size_t num); 68 | void ct_voronoi_free(CT_Voronoi *vor); 69 | void ct_voronoi_compute(CT_Voronoi *vor, 70 | CT_Vec2f *sites, 71 | size_t num, 72 | CT_VOEdgeHandler handler, 73 | void *state); 74 | void ct_vovertex_trace(const CT_VOVertex *v); 75 | void ct_vohedge_trace(const CT_VOHalfEdge *e); 76 | -------------------------------------------------------------------------------- /src/io/svg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "io/svg.h" 5 | #include "math/hashfn.h" 6 | 7 | CT_SVGAttribs *ct_svg_attribs(size_t flags, size_t num, ...) { 8 | CT_SVGAttribs *a = malloc(sizeof(CT_SVGAttribs)); 9 | CT_HTOps ops = {.hash = ct_murmur3_32}; 10 | size_t inited = 0; 11 | if (!ct_ht_init(&a->attribs, &ops, 4, 4, CT_HT_NONE)) { 12 | inited = 1; 13 | a->flags = flags; 14 | va_list args; 15 | va_start(args, num); 16 | for (size_t i = 0; i < num; i++) { 17 | char *key; 18 | CT_CHECK_MEM(key = va_arg(args, char *)); 19 | char type = (char)va_arg(args, int); 20 | size_t ks = strlen(key) + 1; 21 | CT_DEBUG("attrib: %s (%p, len=%zu)", key, key, ks); 22 | switch (type) { 23 | case 's': { 24 | char *val = va_arg(args, char *); 25 | CT_DEBUG("val: %s (%p)", val, val); 26 | ct_ht_assoc(&a->attribs, key, val, ks, strlen(val) + 1); 27 | break; 28 | } 29 | case 'f': { 30 | float val = (float)va_arg(args, double); 31 | CT_DEBUG("val: %f (%p)", val, &val); 32 | ct_ht_assoc(&a->attribs, key, &val, ks, sizeof(float)); 33 | break; 34 | } 35 | case 'd': { 36 | int val = va_arg(args, int); 37 | CT_DEBUG("val: %d (%p)", val, &val); 38 | ct_ht_assoc(&a->attribs, key, &val, ks, sizeof(int)); 39 | break; 40 | } 41 | case 'x': { 42 | uint32_t val = va_arg(args, uint32_t); 43 | char buf[8]; 44 | snprintf(buf, 8, "#%06x", val); 45 | CT_DEBUG("val: %s (%p)", buf, buf); 46 | ct_ht_assoc(&a->attribs, key, buf, ks, 8); 47 | break; 48 | } 49 | default: 50 | CT_SENTINEL("unsupported attrib type: %c", type); 51 | } 52 | } 53 | va_end(args); 54 | return a; 55 | } 56 | fail: 57 | CT_ERROR("can't create SVG attribs"); 58 | if (a != NULL) { 59 | if (inited) { 60 | ct_ht_free(&a->attribs); 61 | } 62 | free(a); 63 | } 64 | return NULL; 65 | } 66 | 67 | static int write_attrib(const CT_HTEntry *e, void *state) { 68 | FILE *out = (FILE *)state; 69 | if (!strcmp(e->key, "width")) { 70 | fprintf(out, "width=\"%d\" ", *((int *)e->val)); 71 | } else if (!strcmp(e->key, "height")) { 72 | fprintf(out, "height=\"%d\" ", *((int *)e->val)); 73 | } else if (!strcmp(e->key, "fill")) { 74 | fprintf(out, "fill=\"%s\" ", (char *)e->val); 75 | } else if (!strcmp(e->key, "stroke")) { 76 | fprintf(out, "stroke=\"%s\" ", (char *)e->val); 77 | } else if (!strcmp(e->key, "stroke-width")) { 78 | fprintf(out, "stroke-width=\"%f\" ", *((float *)e->val)); 79 | } else { 80 | fprintf(out, "%s=\"%s\" ", (char *)e->key, (char *)e->val); 81 | } 82 | return 0; 83 | } 84 | 85 | static void write_attribs(FILE *out, CT_SVGAttribs *a, char *suffix) { 86 | if (a) { 87 | ct_ht_iterate(&a->attribs, write_attrib, out); 88 | if (a->flags) { 89 | CT_DEBUG("free attribs: %p", a); 90 | ct_ht_free(&a->attribs); 91 | free(a); 92 | } 93 | } 94 | fputs(suffix, out); 95 | } 96 | 97 | int ct_svg_start_doc(FILE *out, CT_SVGAttribs *attribs) { 98 | fputs( 99 | "\n"); 104 | return 0; 105 | } 106 | 107 | int ct_svg_end_doc(FILE *out) { 108 | fputs("", out); 109 | return 0; 110 | } 111 | 112 | int ct_svg_start_group(FILE *out, CT_SVGAttribs *attribs) { 113 | fputs(""); 115 | return 0; 116 | } 117 | 118 | int ct_svg_end_group(FILE *out) { 119 | fputs("", out); 120 | return 0; 121 | } 122 | 123 | int ct_svg_write_circle(FILE *out, 124 | float x, 125 | float y, 126 | float r, 127 | CT_SVGAttribs *attribs) { 128 | fprintf(out, ""); 130 | return 0; 131 | } 132 | 133 | int ct_svg_write_rect(FILE *out, 134 | float x, 135 | float y, 136 | float w, 137 | float h, 138 | CT_SVGAttribs *attribs) { 139 | fprintf(out, ""); 142 | return 0; 143 | } 144 | 145 | int ct_svg_write_line(FILE *out, 146 | float x1, 147 | float y1, 148 | float x2, 149 | float y2, 150 | CT_SVGAttribs *attribs) { 151 | fprintf(out, ""); 154 | return 0; 155 | } 156 | 157 | int ct_svg_write_line2fv(FILE *out, 158 | const CT_Vec2f *a, 159 | const CT_Vec2f *b, 160 | CT_SVGAttribs *attribs) { 161 | return ct_svg_write_line(out, a->x, a->y, b->x, b->y, attribs); 162 | } 163 | -------------------------------------------------------------------------------- /src/io/svg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "cthing.h" 6 | 7 | #include "data/hashtable.h" 8 | #include "math/vec.h" 9 | 10 | #define SVG_STR(k, v) (k), 's', (v) 11 | #define SVG_FLOAT(k, v) (k), 'f', (v) 12 | #define SVG_INT(k, v) (k), 'd', (v) 13 | #define SVG_HEX(k, v) (k), 'x', (v) 14 | 15 | CT_BEGIN_DECLS 16 | 17 | typedef struct { 18 | CT_Hashtable attribs; 19 | size_t flags; 20 | } CT_SVGAttribs; 21 | 22 | CT_SVGAttribs *ct_svg_attribs(size_t flags, size_t num, ...); 23 | 24 | int ct_svg_start_doc(FILE *out, CT_SVGAttribs *attribs); 25 | int ct_svg_end_doc(FILE *out); 26 | 27 | int ct_svg_start_group(FILE *out, CT_SVGAttribs *attribs); 28 | int ct_svg_end_group(FILE *out); 29 | 30 | int ct_svg_write_circle(FILE *out, 31 | float x, 32 | float y, 33 | float r, 34 | CT_SVGAttribs *attribs); 35 | 36 | int ct_svg_write_rect(FILE *out, 37 | float x, 38 | float y, 39 | float w, 40 | float h, 41 | CT_SVGAttribs *attribs); 42 | 43 | int ct_svg_write_line(FILE *out, 44 | float x1, 45 | float y1, 46 | float x2, 47 | float y2, 48 | CT_SVGAttribs *attribs); 49 | int ct_svg_write_line2fv(FILE *out, 50 | const CT_Vec2f *a, 51 | const CT_Vec2f *b, 52 | CT_SVGAttribs *attribs); 53 | CT_END_DECLS 54 | -------------------------------------------------------------------------------- /src/math/hashfn.c: -------------------------------------------------------------------------------- 1 | #include "math/hashfn.h" 2 | #include "math/math.h" 3 | 4 | #define MURMUR_C1 ((uint32_t)0xcc9e2d51) 5 | #define MURMUR_C2 ((uint32_t)0x1b873593) 6 | #define MURMUR_H1 ((uint32_t)0xe6546b64) 7 | #define MURMUR_H2 ((uint32_t)0x85ebca6b) 8 | #define MURMUR_H3 ((uint32_t)0xc2b2ae35) 9 | 10 | ct_inline uint32_t mixK(uint32_t k) { 11 | return ct_rotl32(k * MURMUR_C1, 15) * MURMUR_C2; 12 | } 13 | 14 | ct_inline uint32_t mixH(uint32_t h, uint32_t k) { 15 | return ct_rotl32(h ^ k, 13) * 5 + MURMUR_H1; 16 | } 17 | 18 | ct_inline uint32_t fmix(uint32_t h, size_t len) { 19 | h ^= len; 20 | h ^= h >> 16; 21 | h *= MURMUR_H2; 22 | h ^= h >> 13; 23 | h *= MURMUR_H3; 24 | h ^= h >> 16; 25 | return h; 26 | } 27 | 28 | ct_export uint32_t ct_murmur3_32(const void *data, size_t numBytes) { 29 | if (data == NULL || numBytes == 0) { 30 | return 0; 31 | } 32 | 33 | const size_t numBlocks = numBytes >> 2; 34 | const uint32_t *blocks = (const uint32_t *)data; 35 | const uint8_t *tail = (const uint8_t *)&blocks[numBlocks]; 36 | 37 | uint32_t h = 0, k = 0; 38 | for (size_t i = 0; i < numBlocks; i++) { 39 | h = mixH(h, mixK(blocks[i])); 40 | } 41 | 42 | switch (numBytes & 3) { 43 | case 3: 44 | k ^= tail[2] << 16; 45 | case 2: 46 | k ^= tail[1] << 8; 47 | case 1: 48 | h ^= mixK(k ^ tail[0]); 49 | } 50 | 51 | return fmix(h, numBytes); 52 | } 53 | -------------------------------------------------------------------------------- /src/math/hashfn.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | CT_BEGIN_DECLS 6 | 7 | typedef uint32_t (*CT_HashFn32)(const void *, size_t); 8 | 9 | uint32_t ct_murmur3_32(const void *data, size_t numBytes); 10 | 11 | CT_END_DECLS 12 | -------------------------------------------------------------------------------- /src/math/math.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "math/math.h" 4 | 5 | ct_export float ct_parse_float(char *src, float err) { 6 | float x; 7 | return sscanf(src, "%f", &x) ? x : err; 8 | } 9 | 10 | ct_export int ct_parse_int(char *src, int err) { 11 | int x; 12 | return sscanf(src, "%d", &x) ? x : err; 13 | } 14 | 15 | ct_export uint32_t ct_parse_hex32(char *src, uint32_t err) { 16 | uint32_t x; 17 | return sscanf(src, "%x", &x) ? x : err; 18 | } 19 | -------------------------------------------------------------------------------- /src/math/math.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "ct-head/math.h" 6 | 7 | CT_BEGIN_DECLS 8 | 9 | float ct_parse_float(char *src, float err); 10 | int ct_parse_int(char *src, int err); 11 | uint32_t ct_parse_hex32(char *src, uint32_t err); 12 | 13 | CT_END_DECLS 14 | -------------------------------------------------------------------------------- /src/math/matrix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | #include "math/vec.h" 6 | #include "mem/mem.h" 7 | 8 | typedef union { 9 | struct { 10 | float m00, m01, m02, m03; 11 | float m10, m11, m12, m13; 12 | float m20, m21, m22, m23; 13 | float m30, m31, m32, m33; 14 | }; 15 | float mat[16]; 16 | } CT_Mat4f CT_ALIGN(16); 17 | 18 | CT_Mat4f *ct_mat4f_set_identity(CT_Mat4f *m); 19 | CT_Mat4f *ct_mat4f_transpose_imm(CT_Mat4f *m); 20 | CT_Mat4f *ct_mat4f_transpose(const CT_Mat4f *m, CT_Mat4f *out); 21 | CT_Mat4f *ct_mat4f_mul_imm(CT_Mat4f *a, const CT_Mat4f *b); 22 | CT_Mat4f *ct_mat4f_mul(const CT_Mat4f *a, const CT_Mat4f *b, CT_Mat4f *out); 23 | CT_Mat4f *ct_mat4f_scalen_imm(CT_Mat4f *m, float n); 24 | CT_Mat4f *ct_mat4f_scalen(const CT_Mat4f *m, float n, CT_Mat4f *out); 25 | CT_Mat4f *ct_mat4f_translate3fp_imm(CT_Mat4f *m, const float *t); 26 | CT_Mat4f *ct_mat4f_translate3fp(const CT_Mat4f *m, 27 | const float *t, 28 | CT_Mat4f *out); 29 | CT_Mat4f *ct_mat4f_rotatex_imm(CT_Mat4f *m, float theta); 30 | CT_Mat4f *ct_mat4f_rotatex(const CT_Mat4f *m, float theta, CT_Mat4f *out); 31 | CT_Mat4f *ct_mat4f_rotatey_imm(CT_Mat4f *m, float theta); 32 | CT_Mat4f *ct_mat4f_rotatey(const CT_Mat4f *m, float theta, CT_Mat4f *out); 33 | CT_Mat4f *ct_mat4f_rotatez_imm(CT_Mat4f *m, float theta); 34 | CT_Mat4f *ct_mat4f_rotatez(const CT_Mat4f *m, float theta, CT_Mat4f *out); 35 | CT_Mat4f *ct_mat4f_rotate_axis_imm(CT_Mat4f *m, 36 | const CT_Vec3f *axis, 37 | float theta); 38 | CT_Mat4f *ct_mat4f_rotate_axis(const CT_Mat4f *m, 39 | const CT_Vec3f *axis, 40 | float theta, 41 | CT_Mat4f *out); 42 | 43 | CT_Vec4f *ct_mat4f_transform4fv_imm(const CT_Mat4f *m, CT_Vec4f *v); 44 | 45 | float ct_mat4f_determinant(const CT_Mat4f *m); 46 | CT_Mat4f *ct_mat4f_invert(const CT_Mat4f *m, CT_Mat4f *out); 47 | 48 | CT_Mat4f *ct_mat4f_set_ortho(CT_Mat4f *m, 49 | float l, 50 | float t, 51 | float r, 52 | float b, 53 | float n, 54 | float f); 55 | CT_Mat4f *ct_mat4f_set_perspective(CT_Mat4f *m, 56 | float fovy, 57 | float aspect, 58 | float near, 59 | float far); 60 | int ct_mat4f_set_lookat(CT_Mat4f *m, 61 | const CT_Vec3f *eye, 62 | const CT_Vec3f *target, 63 | const CT_Vec3f *up); 64 | 65 | void ct_mat4f_trace(const CT_Mat4f *m); 66 | -------------------------------------------------------------------------------- /src/math/poisson.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "ct-head/random.h" 4 | 5 | #include "geom/isec.h" 6 | #include "math/poisson.h" 7 | 8 | static int find_candidate(const CT_QTNode *node, void *s) { 9 | CT_Circle2f *disc = (CT_Circle2f *)s; 10 | CT_Vec2f p = {node->x + node->w, node->y + node->h}; 11 | if (ct_intersect_rect_circle(&node->pos, &p, &disc->pos, disc->r)) { 12 | if (node->type == CT_TREE_LEAF) { 13 | float d = ct_dist2fv(&disc->pos, node->point); 14 | if (d < disc->r) { 15 | disc->r = d; 16 | } 17 | } 18 | return 0; 19 | } 20 | return 1; 21 | } 22 | 23 | ct_export int ct_poisson_sample2f(CT_Quadtree *t, 24 | float radius, 25 | size_t num, 26 | CT_Vec2f *out) { 27 | float maxD = 0; 28 | float w = t->root.w; 29 | float h = t->root.h; 30 | CT_Circle2f disc; 31 | for (size_t i = 0; i < num; i++) { 32 | ct_set2fxy(&disc.pos, ct_rand_normpos() * w, ct_rand_normpos() * h); 33 | disc.r = radius; 34 | ct_qtree_visit(t, find_candidate, &disc); 35 | if (disc.r > maxD) { 36 | maxD = disc.r; 37 | *out = disc.pos; 38 | } 39 | } 40 | if (maxD >= radius) { 41 | ct_qtree_insert(t, out, NULL); 42 | return 0; 43 | } 44 | return 1; 45 | } 46 | 47 | ct_export int ct_poisson_sample2f_with(CT_Quadtree *t, 48 | CT_PoissonDiskGen gen, 49 | void *state, 50 | size_t num, 51 | CT_Vec2f *out) { 52 | float maxD = 0; 53 | float radius; 54 | CT_Vec2f *min = &t->root.pos; 55 | CT_Vec2f max; 56 | ct_add2fxy(min, t->root.w - 1e-3, t->root.h - 1e-3, &max); 57 | CT_Circle2f disc; 58 | radius = gen(t, &disc, state); 59 | for (size_t i = 0; i < num; i++) { 60 | ct_add2fxy_imm(&disc.pos, ct_rand_norm(), ct_rand_norm()); 61 | ct_clamp2fv_imm(&disc.pos, min, &max); 62 | disc.r = radius; 63 | ct_qtree_visit(t, find_candidate, &disc); 64 | if (disc.r > maxD) { 65 | maxD = disc.r; 66 | *out = disc.pos; 67 | } 68 | } 69 | if (maxD >= radius) { 70 | ct_qtree_insert(t, out, NULL); 71 | return 0; 72 | } 73 | return 1; 74 | } 75 | -------------------------------------------------------------------------------- /src/math/poisson.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | #include "data/quadtree.h" 6 | #include "geom/circle.h" 7 | #include "math/vec.h" 8 | 9 | CT_BEGIN_DECLS 10 | 11 | typedef float (*CT_PoissonDiskGen)(CT_Quadtree *t, 12 | CT_Circle2f *disc, 13 | void *state); 14 | 15 | int ct_poisson_sample2f(CT_Quadtree *t, 16 | float radius, 17 | size_t num, 18 | CT_Vec2f *out); 19 | 20 | int ct_poisson_sample2f_with(CT_Quadtree *t, 21 | CT_PoissonDiskGen gen, 22 | void *state, 23 | size_t num, 24 | CT_Vec2f *out); 25 | 26 | CT_END_DECLS 27 | -------------------------------------------------------------------------------- /src/math/vec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "math/vec.h" 5 | 6 | ct_export CT_Vec2f *ct_vec2f(float x, float y, CT_MPool *mpool) { 7 | CT_Vec2f *v = CT_MP_ALLOC(mpool, CT_Vec2f); 8 | if (v != NULL) { 9 | v->x = x; 10 | v->y = y; 11 | } 12 | return v; 13 | } 14 | 15 | ct_export CT_Vec2f *ct_vec2fn(float n, CT_MPool *mpool) { 16 | return ct_vec2f(n, n, mpool); 17 | } 18 | 19 | ct_export CT_Vec3f *ct_vec3f(float x, float y, float z, CT_MPool *mpool) { 20 | CT_Vec3f *v = CT_MP_ALLOC(mpool, CT_Vec3f); 21 | if (v != NULL) { 22 | #ifdef CT_FEATURE_SSE 23 | v->mmval = _mm_set_ps(0, z, y, x); 24 | #else 25 | v->x = x; 26 | v->y = y; 27 | v->z = z; 28 | #endif 29 | } 30 | return v; 31 | } 32 | 33 | ct_export CT_Vec3f *ct_vec3fn(float n, CT_MPool *mpool) { 34 | CT_Vec3f *v = CT_MP_ALLOC(mpool, CT_Vec3f); 35 | if (v != NULL) { 36 | #ifdef CT_FEATURE_SSE 37 | v->mmval = _mm_set1_ps(n); 38 | #else 39 | v->x = v->y = v->z = n; 40 | #endif 41 | } 42 | return v; 43 | } 44 | 45 | ct_export CT_Vec4f *ct_vec4f(float x, 46 | float y, 47 | float z, 48 | float w, 49 | CT_MPool *mpool) { 50 | CT_Vec4f *v = CT_MP_ALLOC(mpool, CT_Vec4f); 51 | if (v != NULL) { 52 | #ifdef CT_FEATURE_SSE 53 | v->mmval = _mm_set_ps(w, z, y, x); 54 | #else 55 | v->x = x; 56 | v->y = y; 57 | v->z = z; 58 | v->w = w; 59 | #endif 60 | } 61 | return v; 62 | } 63 | 64 | ct_export CT_Vec4f *ct_vec4fn(float n, CT_MPool *mpool) { 65 | CT_Vec4f *v = CT_MP_ALLOC(mpool, CT_Vec4f); 66 | if (v != NULL) { 67 | #ifdef CT_FEATURE_SSE 68 | v->mmval = _mm_set1_ps(n); 69 | #else 70 | v->x = v->y = v->z = v->w = n; 71 | #endif 72 | } 73 | return v; 74 | } 75 | 76 | // ---------- array ops 77 | 78 | VEC_ARRAYOP(translate2f, CT_Vec2f, float, ct_add2fv_imm) 79 | VEC_ARRAYOP(scale2f, CT_Vec2f, float, ct_mul2fv_imm) 80 | VEC_ARRAYOP(translate3f, CT_Vec3f, float, ct_add3fv_imm) 81 | VEC_ARRAYOP(scale3f, CT_Vec3f, float, ct_mul3fv_imm) 82 | VEC_ARRAYOP(translate4f, CT_Vec4f, float, ct_add4fv_imm) 83 | VEC_ARRAYOP(scale4f, CT_Vec4f, float, ct_mul4fv_imm) 84 | 85 | ct_export CT_Vec2f *ct_centroid2f(float *ptr, 86 | size_t num, 87 | size_t fstride, 88 | CT_Vec2f *out) { 89 | float x = 0; 90 | float y = 0; 91 | size_t n = num; 92 | while (n--) { 93 | x += ptr[0]; 94 | y += ptr[1]; 95 | ptr += fstride; 96 | } 97 | ct_set2fxy(out, x / num, y / num); 98 | return out; 99 | } 100 | 101 | ct_export CT_Vec3f *ct_centroid3f(float *ptr, 102 | size_t num, 103 | size_t fstride, 104 | CT_Vec3f *out) { 105 | float x = 0; 106 | float y = 0; 107 | float z = 0; 108 | size_t n = num; 109 | while (n--) { 110 | x += ptr[0]; 111 | y += ptr[1]; 112 | z += ptr[2]; 113 | ptr += fstride; 114 | } 115 | ct_set3fxyz(out, x / num, y / num, z / num); 116 | return out; 117 | } 118 | 119 | ct_export CT_Vec2f *ct_closest_point2f(float *ptr, 120 | CT_Vec2f *p, 121 | size_t num, 122 | size_t fstride) { 123 | float minD = FLT_MAX; 124 | CT_Vec2f *closest = NULL; 125 | if (num > 0) { 126 | while (num--) { 127 | float d = ct_distsq2fv((CT_Vec2f *)ptr, p); 128 | if (d < minD) { 129 | closest = (CT_Vec2f *)ptr; 130 | minD = d; 131 | } 132 | ptr += fstride; 133 | } 134 | } 135 | return closest; 136 | } 137 | 138 | ct_export CT_Vec3f *ct_closest_point3f(float *ptr, 139 | CT_Vec3f *p, 140 | size_t num, 141 | size_t fstride) { 142 | float minD = FLT_MAX; 143 | CT_Vec3f *closest = NULL; 144 | if (num > 0) { 145 | while (num--) { 146 | const float d = ct_distsq3fv((CT_Vec3f *)ptr, p); 147 | if (d < minD) { 148 | closest = (CT_Vec3f *)ptr; 149 | minD = d; 150 | } 151 | ptr += fstride; 152 | } 153 | } 154 | return closest; 155 | } 156 | 157 | ct_export int ct_bounds2fp(float *ptr, 158 | size_t num, 159 | size_t fstride, 160 | CT_Vec2f *min, 161 | CT_Vec2f *max) { 162 | if (num > 0) { 163 | ct_set2fn(min, FLT_MAX); 164 | ct_set2fn(max, -FLT_MAX); 165 | while (num--) { 166 | ct_min2fv_imm(min, (CT_Vec2f *)ptr); 167 | ct_max2fv_imm(max, (CT_Vec2f *)ptr); 168 | ptr += fstride; 169 | } 170 | return 0; 171 | } 172 | return 1; 173 | } 174 | 175 | ct_export int ct_bounds3fp(float *ptr, 176 | size_t num, 177 | size_t fstride, 178 | CT_Vec3f *min, 179 | CT_Vec3f *max) { 180 | if (num > 0) { 181 | ct_set3fn(min, FLT_MAX); 182 | ct_set3fn(max, -FLT_MAX); 183 | while (num--) { 184 | ct_min3fv_imm(min, (CT_Vec3f *)ptr); 185 | ct_max3fv_imm(max, (CT_Vec3f *)ptr); 186 | ptr += fstride; 187 | } 188 | return 0; 189 | } 190 | return 1; 191 | } 192 | -------------------------------------------------------------------------------- /src/math/vec.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define IVEC(...) \ 4 | (size_t[]) { \ 5 | __VA_ARGS__ \ 6 | } 7 | #define FVEC(...) \ 8 | (float[]) { \ 9 | __VA_ARGS__ \ 10 | } 11 | 12 | #include 13 | 14 | #include "cthing.h" 15 | 16 | #include "math/hashfn.h" 17 | #include "math/math.h" 18 | #include "mem/mpool.h" 19 | 20 | #include "math/vec2.h" 21 | 22 | #ifdef CT_FEATURE_SSE 23 | #include "math/vec3_sse.h" 24 | #include "math/vec4_sse.h" 25 | #else 26 | #include "math/vec3.h" 27 | #include "math/vec4.h" 28 | #endif // CT_FEATURE_SSE 29 | 30 | #include "math/vec3_common.h" 31 | #include "math/vec4_common.h" 32 | 33 | #include "math/swizzle.h" 34 | 35 | #include "math/vec_arrayops.h" 36 | -------------------------------------------------------------------------------- /src/math/vec4_common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef CT_FEATURE_SSE4 4 | #include 5 | #endif 6 | 7 | #include "math/vec.h" 8 | 9 | CT_BEGIN_DECLS 10 | 11 | CT_Vec4f *ct_vec4f(float x, float y, float z, float w, CT_MPool *mpool); 12 | CT_Vec4f *ct_vec4fn(float n, CT_MPool *mpool); 13 | 14 | ct_export ct_inline int ct_compare4fv_xyzw(const void *a, const void *b) { 15 | CT_Vec4f *va = (CT_Vec4f *)a; 16 | CT_Vec4f *vb = (CT_Vec4f *)b; 17 | if (va->x < vb->x) 18 | return -1; 19 | if (va->x > vb->x) 20 | return 1; 21 | if (va->y < vb->y) 22 | return -1; 23 | if (va->y > vb->y) 24 | return 1; 25 | if (va->z < vb->z) 26 | return -1; 27 | if (va->z > vb->z) 28 | return 1; 29 | if (va->w < vb->w) 30 | return -1; 31 | if (va->w > vb->w) 32 | return 1; 33 | return 0; 34 | } 35 | 36 | ct_export ct_inline int ct_compare4fv_wzyx(const void *a, const void *b) { 37 | CT_Vec4f *va = (CT_Vec4f *)a; 38 | CT_Vec4f *vb = (CT_Vec4f *)b; 39 | if (va->w < vb->w) 40 | return -1; 41 | if (va->w > vb->w) 42 | return 1; 43 | if (va->z < vb->z) 44 | return -1; 45 | if (va->z > vb->z) 46 | return 1; 47 | if (va->y < vb->y) 48 | return -1; 49 | if (va->y > vb->y) 50 | return 1; 51 | if (va->x < vb->x) 52 | return -1; 53 | if (va->x > vb->x) 54 | return 1; 55 | return 0; 56 | } 57 | 58 | ct_export ct_inline size_t ct_deltaeq4fv(const CT_Vec4f *a, 59 | const CT_Vec4f *b, 60 | float eps) { 61 | return (ct_deltaeqf(a->x, b->x, eps) && ct_deltaeqf(a->y, b->y, eps) && 62 | ct_deltaeqf(a->z, b->z, eps) && ct_deltaeqf(a->w, b->w, eps)); 63 | } 64 | 65 | ct_export ct_inline float ct_dist4fv(const CT_Vec4f *a, const CT_Vec4f *b) { 66 | return sqrtf(ct_distsq4fv(a, b)); 67 | } 68 | 69 | ct_export ct_inline float ct_dist4fv_manhatten(const CT_Vec4f *a, 70 | const CT_Vec4f *b) { 71 | return fabs(a->x - b->x) + fabs(a->y - b->y) + fabs(a->z - b->z) + 72 | fabs(a->w - b->w); 73 | } 74 | 75 | ct_export ct_inline float ct_dist4fv_minkowski(const CT_Vec4f *a, 76 | const CT_Vec4f *b, 77 | float p) { 78 | return powf(powf(fabs(a->x - b->x), p) + powf(fabs(a->y - b->y), p) + 79 | powf(fabs(a->z - b->z), p) + powf(fabs(a->w - b->w), p), 80 | 1 / p); 81 | } 82 | 83 | ct_export ct_inline CT_Vec4f *ct_ceil4f_imm(CT_Vec4f *v) { 84 | #ifdef CT_FEATURE_SSE4 85 | v->mmval = _mm_ceil_ps(v->mmval); 86 | #else 87 | v->x = ceilf(v->x); 88 | v->y = ceilf(v->y); 89 | v->z = ceilf(v->z); 90 | v->w = ceilf(v->w); 91 | #endif 92 | return v; 93 | } 94 | 95 | ct_export ct_inline CT_Vec4f *ct_floor4f_imm(CT_Vec4f *v) { 96 | #ifdef CT_FEATURE_SSE4 97 | v->mmval = _mm_floor_ps(v->mmval); 98 | #else 99 | v->x = floorf(v->x); 100 | v->y = floorf(v->y); 101 | v->z = floorf(v->z); 102 | v->w = floorf(v->w); 103 | #endif 104 | return v; 105 | } 106 | 107 | ct_export ct_inline uint32_t ct_hash4f(const CT_Vec4f *v) { 108 | return ct_murmur3_32(v, 4 * sizeof(float)); 109 | } 110 | 111 | ct_export ct_inline CT_Vec4f *ct_madd4fv(const CT_Vec4f *a, 112 | const CT_Vec4f *b, 113 | const CT_Vec4f *c, 114 | CT_Vec4f *out) { 115 | return ct_madd4fv_imm(ct_set4fv(out, a), b, c); 116 | } 117 | 118 | ct_export ct_inline float ct_mag4f(const CT_Vec4f *v) { 119 | return sqrtf(ct_magsq4f(v)); 120 | } 121 | 122 | ct_export ct_inline CT_Vec4f *ct_mix4fv(const CT_Vec4f *a, 123 | const CT_Vec4f *b, 124 | float t, 125 | CT_Vec4f *out) { 126 | return ct_mix4fv_imm(ct_set4fv(out, a), b, t); 127 | } 128 | 129 | ct_export ct_inline CT_Vec4f *ct_negate4f(const CT_Vec4f *v, CT_Vec4f *out) { 130 | return ct_negate4f_imm(ct_set4fv(out, v)); 131 | } 132 | 133 | ct_export ct_inline CT_Vec4f *ct_normalize4f(const CT_Vec4f *v, 134 | float len, 135 | CT_Vec4f *out) { 136 | return ct_normalize4f_imm(ct_set4fv(out, v), len); 137 | } 138 | 139 | ct_export ct_inline size_t ct_is_normalized4f(const CT_Vec4f *v) { 140 | return ct_deltaeqf(ct_mag4f(v), 1.f, CT_EPS); 141 | } 142 | 143 | ct_export ct_inline CT_Vec4f *ct_limit4f_imm(CT_Vec4f *v, float len) { 144 | float m = ct_mag4f(v); 145 | if (m > len) { 146 | len /= m; 147 | v->x *= len; 148 | v->y *= len; 149 | } 150 | return v; 151 | } 152 | 153 | CT_END_DECLS 154 | -------------------------------------------------------------------------------- /src/math/vec4_sse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #ifdef CT_FEATURE_SSE3 5 | #include 6 | #endif 7 | #ifdef CT_FEATURE_SSE4 8 | #include 9 | #endif 10 | #include "math/vec.h" 11 | #include "mem/mem.h" 12 | 13 | #define VEC4OP_SSE(type, ptype, name, op) \ 14 | ct_export ct_inline type *name##v_imm(type *a, const type *b) { \ 15 | a->mmval op## = b->mmval; \ 16 | return a; \ 17 | } \ 18 | \ 19 | ct_export ct_inline type *name##v(const type *a, const type *b, type *out) { \ 20 | out->mmval = a->mmval op b->mmval; \ 21 | return out; \ 22 | } \ 23 | \ 24 | ct_export ct_inline type *name##n_imm(type *v, ptype n) { \ 25 | v->mmval op## = _mm_set1_ps(n); \ 26 | return v; \ 27 | } \ 28 | \ 29 | ct_export ct_inline type *name##n(const type *v, ptype n, type *out) { \ 30 | out->mmval = v->mmval op _mm_set1_ps(n); \ 31 | return out; \ 32 | } \ 33 | \ 34 | ct_export ct_inline type *name##xyzw_imm(type *v, ptype x, ptype y, ptype z, \ 35 | ptype w) { \ 36 | __m128 b = _mm_set_ps(w, z, y, x); \ 37 | v->mmval op## = b; \ 38 | return v; \ 39 | } \ 40 | \ 41 | ct_export ct_inline type *name##xyzw(const type *v, ptype x, ptype y, \ 42 | ptype z, ptype w, type *out) { \ 43 | __m128 b = _mm_set_ps(w, z, y, x); \ 44 | out->mmval = v->mmval op b; \ 45 | return out; \ 46 | } 47 | 48 | CT_BEGIN_DECLS 49 | 50 | typedef union { 51 | struct { 52 | float x, y, z, w; 53 | }; 54 | CT_Vec2f xy; 55 | CT_Vec3f xyz; 56 | float buf[4]; 57 | __m128 mmval; 58 | } CT_Vec4f CT_ALIGN(16); 59 | 60 | VEC4OP_SSE(CT_Vec4f, float, ct_add4f, +) 61 | VEC4OP_SSE(CT_Vec4f, float, ct_sub4f, -) 62 | VEC4OP_SSE(CT_Vec4f, float, ct_mul4f, *) 63 | VEC4OP_SSE(CT_Vec4f, float, ct_div4f, /) 64 | 65 | ct_export ct_inline float ct_dot4fv(const CT_Vec4f *a, const CT_Vec4f *b) { 66 | #ifdef CT_FEATURE_SSE4 67 | return _mm_dp_ps(a->mmval, b->mmval, 0xf1)[0]; 68 | #else 69 | __m128 d = a->mmval * b->mmval; 70 | #ifdef CT_FEATURE_SSE3 71 | d = _mm_hadd_ps(d, d); 72 | return d[0] + d[1]; 73 | #else 74 | return d[0] + d[1] + d[2] + d[3]; 75 | #endif 76 | #endif 77 | } 78 | 79 | ct_export ct_inline float ct_distsq4fv(const CT_Vec4f *a, const CT_Vec4f *b) { 80 | __m128 d = a->mmval - b->mmval; 81 | d *= d; 82 | #ifdef CT_FEATURE_SSE3 83 | d = _mm_hadd_ps(d, d); 84 | return d[0] + d[1]; 85 | #else 86 | return d[0] + d[1] + d[2] + d[3]; 87 | #endif 88 | } 89 | 90 | ct_export ct_inline CT_Vec4f *ct_madd4fv_imm(CT_Vec4f *a, 91 | const CT_Vec4f *b, 92 | const CT_Vec4f *c) { 93 | a->mmval = a->mmval * b->mmval + c->mmval; 94 | return a; 95 | } 96 | 97 | ct_export ct_inline float ct_magsq4f(const CT_Vec4f *v) { 98 | return ct_dot4fv(v, v); 99 | } 100 | 101 | ct_export ct_inline CT_Vec4f *ct_mix4fv_imm(CT_Vec4f *a, 102 | const CT_Vec4f *b, 103 | float t) { 104 | a->mmval += (b->mmval - a->mmval) * _mm_set1_ps(t); 105 | return a; 106 | } 107 | 108 | ct_export ct_inline CT_Vec4f *ct_negate4f_imm(CT_Vec4f *v) { 109 | v->mmval = _mm_setzero_ps() - v->mmval; 110 | return v; 111 | } 112 | 113 | ct_export ct_inline CT_Vec4f *ct_normalize4f_imm(CT_Vec4f *v, float len) { 114 | float m = sqrt(ct_magsq4f(v)); 115 | if (m > 0.0) { 116 | ct_mul4fn_imm(v, len / m); 117 | } 118 | return v; 119 | } 120 | 121 | ct_export ct_inline CT_Vec4f *ct_set4fv(CT_Vec4f *a, const CT_Vec4f *b) { 122 | a->mmval = b->mmval; 123 | return a; 124 | } 125 | 126 | ct_export ct_inline CT_Vec4f *ct_set4fn(CT_Vec4f *v, float n) { 127 | v->mmval = _mm_set1_ps(n); 128 | return v; 129 | } 130 | 131 | ct_export ct_inline CT_Vec4f *ct_set4fxyzw(CT_Vec4f *v, 132 | float x, 133 | float y, 134 | float z, 135 | float w) { 136 | v->mmval = _mm_set_ps(w, z, y, x); 137 | return v; 138 | } 139 | 140 | ct_export ct_inline CT_Vec4f *ct_set4fp(CT_Vec4f *v, const float *p) { 141 | v->mmval = _mm_load_ps(p); 142 | return v; 143 | } 144 | 145 | ct_export ct_inline CT_Vec4f *ct_set4fpua(CT_Vec4f *v, const float *p) { 146 | v->mmval = _mm_loadu_ps(p); 147 | return v; 148 | } 149 | 150 | CT_END_DECLS 151 | -------------------------------------------------------------------------------- /src/math/vec_arrayops.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "math/vec.h" 4 | 5 | #define VEC_ARRAYOP(name, type, ptype, fn) \ 6 | ct_export void ct_##name(ptype* ptr, type* t, size_t num, size_t stride) { \ 7 | if (num > 0) { \ 8 | while (num--) { \ 9 | fn((type*)ptr, t); \ 10 | ptr += stride; \ 11 | } \ 12 | } \ 13 | } 14 | 15 | CT_BEGIN_DECLS 16 | 17 | void ct_translate2f(float* ptr, CT_Vec2f* t, size_t num, size_t fstride); 18 | void ct_scale2f(float* ptr, CT_Vec2f* t, size_t num, size_t fstride); 19 | void ct_translate3f(float* ptr, CT_Vec3f* t, size_t num, size_t fstride); 20 | void ct_scale3f(float* ptr, CT_Vec3f* t, size_t num, size_t fstride); 21 | void ct_translate4f(float* ptr, CT_Vec4f* t, size_t num, size_t fstride); 22 | void ct_scale4f(float* ptr, CT_Vec4f* t, size_t num, size_t fstride); 23 | 24 | CT_Vec2f* ct_centroid2f(float* ptr, size_t num, size_t fstride, CT_Vec2f* out); 25 | CT_Vec3f* ct_centroid3f(float* ptr, size_t num, size_t fstride, CT_Vec3f* out); 26 | 27 | CT_Vec2f* ct_closest_point2f(float* ptr, 28 | CT_Vec2f* p, 29 | size_t num, 30 | size_t fstride); 31 | 32 | CT_Vec3f* ct_closest_point3f(float* ptr, 33 | CT_Vec3f* p, 34 | size_t num, 35 | size_t fstride); 36 | 37 | int ct_bounds2fp(float* ptr, 38 | size_t num, 39 | size_t fstride, 40 | CT_Vec2f* min, 41 | CT_Vec2f* max); 42 | int ct_bounds3fp(float* ptr, 43 | size_t num, 44 | size_t fstride, 45 | CT_Vec3f* min, 46 | CT_Vec3f* max); 47 | 48 | CT_END_DECLS 49 | -------------------------------------------------------------------------------- /src/mem/mem.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define CT_ALIGN(x) __attribute__((aligned(x))) 6 | 7 | #define CT_ALIGNED8(ptr) (!(((size_t)ptr) & 0x7)) 8 | #define CT_ALIGNED16(ptr) (!(((size_t)ptr) & 0xf)) 9 | 10 | #define container_of(ptr, type, member) \ 11 | ((type *)((uint8_t *)(ptr)-offsetof(type, member))) 12 | -------------------------------------------------------------------------------- /src/mem/mpool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | #define CT_MP_ALLOC(pool, type) \ 6 | ((pool) != NULL ? ct_mpool_alloc(pool) : malloc(sizeof(type))) 7 | 8 | #define CT_MP_FREE(pool, ptr) \ 9 | ((pool) != NULL ? ct_mpool_free_block(pool, (ptr)) : free(ptr)) 10 | 11 | #define CT_DEF_MPOOL(name, num, type) \ 12 | CT_MPool name; \ 13 | if (ct_mpool_init(&(name), (num), sizeof(type))) { \ 14 | CT_ERROR("out of memory (mpool)"); \ 15 | goto fail; \ 16 | } 17 | 18 | CT_BEGIN_DECLS 19 | 20 | typedef struct CT_MPoolFreeList CT_MPoolFreeList; 21 | typedef struct CT_MPoolList CT_MPoolList; 22 | 23 | struct CT_MPoolFreeList { 24 | CT_MPoolFreeList *next; 25 | }; 26 | 27 | struct CT_MPoolList { 28 | uint8_t *pool; 29 | CT_MPoolList *next; 30 | size_t nextID; 31 | }; 32 | 33 | typedef struct { 34 | CT_MPoolList *head; 35 | CT_MPoolFreeList *freeList; 36 | size_t blockSize; 37 | size_t numBlocks; 38 | size_t poolID; 39 | } CT_MPool; 40 | 41 | typedef struct { 42 | size_t blocks; 43 | size_t pools; 44 | } CT_MPCompactResult; 45 | 46 | CT_MPool *ct_mpool_new(); 47 | size_t ct_mpool_init(CT_MPool *pool, size_t num, size_t bsize); 48 | void *ct_mpool_alloc(CT_MPool *pool); 49 | void ct_mpool_free_block(CT_MPool *pool, const void *block); 50 | void ct_mpool_reset(CT_MPool *mp); 51 | void ct_mpool_free(CT_MPool *pool); 52 | int ct_mpool_is_valid_block(CT_MPool *pool, void *block); 53 | CT_MPCompactResult ct_mpool_compact(CT_MPool *mp); 54 | void ct_mpool_trace(const CT_MPool *pool); 55 | 56 | CT_END_DECLS 57 | -------------------------------------------------------------------------------- /src/mem/ref.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | #include "mem/mem.h" 6 | 7 | CT_BEGIN_DECLS 8 | 9 | typedef struct CT_Ref CT_Ref; 10 | 11 | struct CT_Ref { 12 | void (*free)(const CT_Ref *); 13 | size_t count; 14 | }; 15 | 16 | ct_inline void ct_ref_inc(const CT_Ref *ref) { 17 | ((CT_Ref *)ref)->count++; 18 | } 19 | 20 | ct_inline void ct_ref_dec(const CT_Ref *ref) { 21 | if (--((CT_Ref *)ref)->count == 0) { 22 | ref->free(ref); 23 | } 24 | } 25 | 26 | CT_END_DECLS 27 | -------------------------------------------------------------------------------- /src/rt_cthing.js: -------------------------------------------------------------------------------- 1 | // emscripten JS library support 2 | 3 | mergeInto(LibraryManager.library, { 4 | ct_js_test_call : function() { 5 | return 23; 6 | } 7 | }); 8 | -------------------------------------------------------------------------------- /src/sim/ca.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | enum { CT_CA_TILING = 1, CT_CA_AUTO_EXPIRE = 2 }; 6 | 7 | typedef struct { 8 | size_t rule; 9 | uint8_t maxBitValue; 10 | uint8_t numBits; 11 | uint8_t numStates; 12 | uint8_t kernelWidth; 13 | uint8_t flags; 14 | } CT_CARule1D; 15 | 16 | typedef struct { 17 | size_t *kernelOffsets; 18 | uint16_t birthRule; 19 | uint16_t survivalRule; 20 | uint8_t kernelWidth; 21 | uint8_t numStates; 22 | uint8_t flags; 23 | } CT_CARule2D; 24 | 25 | typedef struct { 26 | uint8_t *matrix; 27 | uint8_t *swap; 28 | size_t width; 29 | size_t height; 30 | size_t gen; 31 | } CT_CAMatrix; 32 | 33 | int ct_carule1d_init(CT_CARule1D *rule); 34 | void ct_carule1d_free(CT_CARule1D *rule); 35 | void ct_carule1d_evolve(const CT_CARule1D *rule, CT_CAMatrix *mat); 36 | 37 | int ct_carule2d_init(CT_CARule2D *rule); 38 | void ct_carule2d_free(CT_CARule2D *rule); 39 | void ct_carule2d_evolve(const CT_CARule2D *rule, CT_CAMatrix *mat); 40 | 41 | int ct_camatrix_init(CT_CAMatrix *mat); 42 | void ct_camatrix_free(CT_CAMatrix *mat); 43 | void ct_camatrix_clear(CT_CAMatrix *mat); 44 | void ct_camatrix_seed1d(CT_CAMatrix *mat, size_t seed); 45 | void ct_camatrix_seed2d(CT_CAMatrix *mat, 46 | size_t x, 47 | size_t y, 48 | size_t w, 49 | size_t h, 50 | const char *cells); 51 | void ct_camatrix_seed_noise(CT_CAMatrix *mat, float prob); 52 | void ct_camatrix_trace(const CT_CAMatrix *mat); 53 | -------------------------------------------------------------------------------- /src/sim/verlet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "cthing.h" 4 | 5 | #include "data/spatialgrid.h" 6 | 7 | CT_BEGIN_DECLS 8 | 9 | typedef struct { 10 | size_t a; 11 | size_t b; 12 | float restLen; 13 | float strength; 14 | } CT_VPSpring; 15 | 16 | typedef struct { 17 | float *pos, *prev, *force, *radius; 18 | CT_VPSpring *springs; 19 | CT_SpatialGrid accel; 20 | size_t numP; 21 | size_t numS; 22 | size_t strideP; 23 | size_t strideS; 24 | size_t iter; 25 | float dt; 26 | float friction; 27 | float repulsion; 28 | float maxForce; 29 | float gravity[4]; 30 | float bounds[8]; 31 | } CT_Verlet; 32 | 33 | int ct_verlet_init2d(CT_Verlet *v, size_t maxP, size_t maxS, size_t *grid); 34 | int ct_verlet_init3d(CT_Verlet *v, size_t maxP, size_t maxS, size_t *grid); 35 | void ct_verlet_free(CT_Verlet *v); 36 | void ct_verlet_update2d(CT_Verlet *v); 37 | void ct_verlet_update3d(CT_Verlet *v); 38 | void ct_verlet_trace(CT_Verlet *v); 39 | void ct_verlet_set2f(CT_Verlet *v, size_t i, const float *pos, float radius); 40 | void ct_verlet_set3f(CT_Verlet *v, size_t i, const float *pos, float radius); 41 | void ct_verlet_set_spring2d(CT_Verlet *v, 42 | size_t i, 43 | size_t a, 44 | size_t b, 45 | float len, 46 | float strength); 47 | void ct_verlet_set_spring3d(CT_Verlet *v, 48 | size_t i, 49 | size_t a, 50 | size_t b, 51 | float len, 52 | float strength); 53 | 54 | ct_export ct_inline void ct_verlet_pos2f(const CT_Verlet *v, 55 | size_t i, 56 | float *out) { 57 | out[2] = v->radius[i]; 58 | i <<= 1; 59 | out[0] = v->pos[i]; 60 | out[1] = v->pos[i + 1]; 61 | } 62 | 63 | ct_export ct_inline void ct_verlet_pos3f(const CT_Verlet *v, 64 | size_t i, 65 | float *out) { 66 | out[2] = v->radius[i]; 67 | i <<= 2; 68 | out[0] = v->pos[i]; 69 | out[1] = v->pos[i + 1]; 70 | out[2] = v->pos[i + 2]; 71 | } 72 | 73 | CT_END_DECLS 74 | -------------------------------------------------------------------------------- /test/adjacency.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/test.h" 2 | 3 | #include "data/adjacency.h" 4 | 5 | CT_TEST_DECLS 6 | 7 | static int edge_iter(size_t x, size_t y, void *s) { 8 | size_t *num = (size_t *)s; 9 | CT_DEBUG("edge: %zu -> %zu", x, y); 10 | *num = *num + 1; 11 | return 0; 12 | } 13 | 14 | static int count_edges(CT_AdjMatrix *mat) { 15 | size_t num = 0; 16 | ct_adjmat_iterate(mat, edge_iter, &num); 17 | return num; 18 | } 19 | 20 | int test_adjmatrix() { 21 | CT_AdjMatrix mat; 22 | CT_IS(!ct_adjmat_init(&mat, 32), "init"); 23 | CT_IS(!ct_adjmat_join(&mat, 23, 9), "23 -> 9"); 24 | CT_IS(ct_adjmat_is_join(&mat, 23, 9), "23 -> 9 ?"); 25 | CT_IS(ct_adjmat_is_join(&mat, 9, 23), "9 -> 23 ?"); 26 | CT_IS(!ct_adjmat_is_join(&mat, 10, 23), "10 -> 23 ?"); 27 | CT_IS(!ct_adjmat_join(&mat, 10, 23), "10 -> 23"); 28 | CT_IS(ct_adjmat_is_join(&mat, 10, 23), "10 -> 23 ?"); 29 | CT_IS(!ct_adjmat_join(&mat, 10, 9), "10 -> 9"); 30 | CT_IS(!ct_adjmat_join(&mat, 31, 31), "31 -> 31"); 31 | //CT_IS(ct_adjmat_join(&mat, 31, 32), "31 -> 32"); 32 | //ct_adjmat_trace(&mat); 33 | size_t num = count_edges(&mat); 34 | CT_IS(4 == num, "count: %zu", num); 35 | CT_IS(!ct_adjmat_disjoin(&mat, 9, 23), "remove 9 -> 23"); 36 | num = count_edges(&mat); 37 | CT_IS(3 == num, "count: %zu", num); 38 | ct_adjmat_free(&mat); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /test/circle.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/test.h" 2 | 3 | #include "geom/circle.h" 4 | 5 | //extern CT_IArea __ct_iarea_circle2; 6 | //extern CT_ICircumference __ct_icircumference_circle2; 7 | 8 | CT_TEST_DECLS 9 | 10 | int test_circle() { 11 | CT_Circle2f c, c2; 12 | ct_circle2f_initr(&c, 1); 13 | ct_circle2f_initr(&c2, 2); 14 | CT_IS(CT_PI == ct_circle2f_area(&c), "area c"); 15 | CT_IS(CT_PI * 4 == ct_circle2f_area(&c2), "area c2"); 16 | CT_IS(CT_TAU == ct_circle2f_circumference(&c), "circum c"); 17 | CT_IS(CT_TAU * 2 == ct_circle2f_circumference(&c2), "circum c2"); 18 | CT_Vec2f p = {.x = 0, .y = 0}; 19 | CT_IS(1 == ct_circle2f_classify_point(&c, &p), "classify 1"); 20 | CT_IS(0 == ct_circle2f_classify_point(&c, ct_set2fxy(&p, 1, 0)), 21 | "classify 0"); 22 | CT_IS(-1 == ct_circle2f_classify_point(&c, ct_set2fxy(&p, 1.001f, 0)), 23 | "classify -1"); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/clip.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/test.h" 2 | 3 | #include "geom/clip/liangbarsky.h" 4 | 5 | CT_TEST_DECLS 6 | 7 | static int clip(CT_Vec2f *p, CT_Vec2f *q, float *c) { 8 | CT_Vec2f a, b, ca, cb; 9 | ct_set2fp(&a, c); 10 | ct_set2fp(&b, c + 2); 11 | if (ct_clip2f_liangbarsky(p, q, &a, &b, &ca, &cb)) { 12 | return ct_deltaeq2fv(&ca, (CT_Vec2f *)&c[4], 0.1) && 13 | ct_deltaeq2fv(&cb, (CT_Vec2f *)&c[6], 0.1); 14 | } 15 | return -1; 16 | } 17 | 18 | int test_clipping() { 19 | CT_Vec2f p = {-100, -100}; 20 | CT_Vec2f q = {100, 100}; 21 | CT_IS(1 == clip(&p, &q, FVEC(0, -99, 0, 99, 0, -99, 0, 99)), "inside vert"); 22 | CT_IS(1 == clip(&p, &q, FVEC(-99, 0, 99, 0, -99, 0, 99, 0)), "inside horz"); 23 | CT_IS(1 == clip(&p, &q, FVEC(0, 0, 0, 0, 0, 0, 0, 0)), "inside p"); 24 | CT_IS(-1 == clip(&p, &q, FVEC(-101, -51, -101, 101)), "left"); 25 | CT_IS(-1 == clip(&p, &q, FVEC(101, -49, 101, 99)), "right"); 26 | CT_IS(-1 == clip(&p, &q, FVEC(-200, -101, 0, -101)), "top"); 27 | CT_IS(-1 == clip(&p, &q, FVEC(0, 101, 200, 101)), "bottom"); 28 | CT_IS(1 == clip(&p, &q, FVEC(-110, 100, 110, -100, -100, 90.9, 100, -90.9)), 29 | "bl tr"); 30 | CT_IS(1 == clip(&p, &q, FVEC(-100, 110, 100, -110, -90.9, 100, 90.9, -100)), 31 | "bl tr 2"); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /test/cons.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/test.h" 2 | 3 | #include "data/cons.h" 4 | #include "mem/mpool.h" 5 | 6 | CT_TEST_DECLS 7 | 8 | typedef struct { 9 | size_t count; 10 | size_t err; 11 | void *ref; 12 | } ConsTestState; 13 | 14 | static void trace_cons(CT_Cons *c, void *_) { 15 | CT_INFO("cell: %p, val: %s, next: %p", c, (char *)c->value, c->next); 16 | } 17 | 18 | static void trace_consf(CT_Cons *c, void *_) { 19 | CT_INFO("cell: %p, val: %f, next: %p", c, *((float *)c->value), c->next); 20 | } 21 | 22 | static void count_cons(CT_Cons *c, void *state) { 23 | //trace_cons(c, NULL); 24 | ((ConsTestState *)state)->count++; 25 | } 26 | 27 | static void verify_cons_char(CT_Cons *c, void *state) { 28 | ConsTestState *cc = (ConsTestState *)state; 29 | if ((char *)c->value == ((char **)cc->ref)[cc->count]) { 30 | cc->count++; 31 | } 32 | } 33 | 34 | static void verify_cons_float(CT_Cons *c, void *state) { 35 | ConsTestState *cc = (ConsTestState *)state; 36 | if ((float *)c->value == (float *)cc->ref + cc->count) { 37 | cc->count++; 38 | } 39 | } 40 | 41 | static ConsTestState *reset_state(ConsTestState *cs, void *ref) { 42 | cs->count = cs->err = 0; 43 | cs->ref = ref; 44 | return cs; 45 | } 46 | 47 | int test_cons() { 48 | CT_Cons *c = 49 | ct_cons("CCC", ct_cons("BBB", ct_cons("AAA", NULL, NULL), NULL), NULL); 50 | ConsTestState cs = {.count = 0, .err = 0}; 51 | ct_cons_iterate(c, count_cons, &cs); 52 | CT_IS(cs.count == 3, "c length != 3 (%zu)", cs.count); 53 | ct_cons_free_all(c, NULL, NULL, NULL); 54 | 55 | c = ct_cons_append("AAA", NULL, NULL); 56 | ct_cons_append("CCC", ct_cons_append("BBB", c, NULL), NULL); 57 | ct_cons_iterate(c, count_cons, reset_state(&cs, NULL)); 58 | CT_IS(cs.count == 3, "c append length != 3 (%zu)", cs.count); 59 | ct_cons_iterate(c, trace_cons, NULL); 60 | ct_cons_free_all(c, NULL, NULL, NULL); 61 | 62 | CT_DEF_MPOOL(pool, 256, CT_Cons); 63 | c = ct_cons("CCC", ct_cons("BBB", ct_cons("AAA", NULL, &pool), &pool), &pool); 64 | 65 | ct_cons_iterate(c, count_cons, reset_state(&cs, NULL)); 66 | CT_IS(cs.count == 3, "c mpool length != 3 (%zu)", cs.count); 67 | 68 | char *vals[] = {"DDD", "EEE", "FFF"}; 69 | CT_Cons *c2 = ct_cons_from_parray((void **)vals, 3, NULL, &pool); 70 | ct_cons_iterate(c2, verify_cons_char, reset_state(&cs, vals)); 71 | CT_IS(!cs.err, "cons != src array (%zu errors)", cs.err); 72 | CT_IS(cs.count == 3, "c2 length != 3 (%zu)", cs.count); 73 | 74 | float fvals[] = {23, 24, 25}; 75 | CT_Cons *cf = ct_cons_from_array(fvals, 3, sizeof(float), NULL, &pool); 76 | ct_cons_iterate(cf, verify_cons_float, reset_state(&cs, fvals)); 77 | CT_IS(!cs.err, "cons != src array (%zu errors)", cs.err); 78 | CT_IS(cs.count == 3, "c2 length != 3 (%zu)", cs.count); 79 | 80 | ct_cons_iterate(ct_cons_concat_imm(c, c2), count_cons, 81 | reset_state(&cs, NULL)); 82 | CT_IS(cs.count == 6, "concat_imm(c,c2) length != 6 (%zu)", cs.count); 83 | 84 | CT_Cons *c3 = ct_cons_concat(c, c, &pool); 85 | ct_cons_iterate(c3, count_cons, reset_state(&cs, NULL)); 86 | CT_IS(cs.count == 12, "concat(c,c) length != 12 (%zu)", cs.count); 87 | 88 | ct_cons_iterate(c2, verify_cons_char, reset_state(&cs, vals)); 89 | CT_IS(!cs.err, "cons != src array (%zu errors)", cs.err); 90 | CT_IS(cs.count == 3, "c2 length != 3 (%zu)", cs.count); 91 | 92 | ct_cons_iterate(ct_cons_take(ct_cons_concat_imm(c, c), 20, &pool), count_cons, 93 | reset_state(&cs, NULL)); 94 | 95 | ct_mpool_free(&pool); 96 | return 0; 97 | fail: 98 | return 1; 99 | } 100 | -------------------------------------------------------------------------------- /test/consrc.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "ct-head/test.h" 4 | 5 | #include "data/consrc.h" 6 | #include "data/object.h" 7 | 8 | #define BUF_SIZE 1024 9 | static char buf[BUF_SIZE]; 10 | 11 | extern CT_Object CT_NIL; 12 | 13 | CT_TEST_DECLS 14 | 15 | char *strdup(const char *s) { 16 | char *d = malloc(strlen(s) + 1); 17 | if (d != NULL) { 18 | strcpy(d, s); 19 | } 20 | return d; 21 | } 22 | 23 | int test_consrc() { 24 | CT_Object *a, *b, *c, *d, *e, *l, *l2; 25 | CT_IS(!ct_consrc_init(), "init consrc"); 26 | ct_object_assign(&a, ct_object_f32(23)); 27 | ct_object_assign(&b, ct_object_i32(-42)); 28 | ct_object_assign(&e, ct_object_u32(66)); 29 | ct_object_assign(&c, ct_object_vec4(-1, 2, -3, 4)); 30 | ct_object_assign(&d, ct_object_str(strdup("foo"), 1)); 31 | ct_object_assign(&l, ct_object_cons(d)); 32 | CT_IS(ct_object_is(a, CT_TYPE_F32), "f32"); 33 | CT_IS(ct_object_is(b, CT_TYPE_I32), "i32"); 34 | CT_IS(ct_object_is(c, CT_TYPE_VEC4), "vec4"); 35 | CT_IS(ct_object_is(d, CT_TYPE_STR), "str"); 36 | CT_IS(ct_object_is(e, CT_TYPE_U32), "u32"); 37 | CT_IS(ct_object_is(l, CT_TYPE_CONS), "cons"); 38 | ct_object_tostring(l, buf, BUF_SIZE); 39 | CT_IS(0 == strcmp("(\"foo\")", buf), "l: %s", buf); 40 | ct_consrc_push_imm(&l, e); 41 | ct_consrc_push_imm(&l, c); 42 | ct_consrc_push_imm(&l, b); 43 | ct_consrc_push_imm(&l, a); 44 | ct_consrc_push_imm(&l, ct_object_str("bar", 0)); 45 | ct_consrc_push_imm(&l, &CT_NIL); 46 | ct_object_tostring(l, buf, BUF_SIZE); 47 | CT_IS(0 == strcmp("(nil \"bar\" 23.000000 -42 [-1.000000 2.000000 -3.000000 " 48 | "4.000000] 66 \"foo\")", 49 | buf), 50 | "l: %s", buf); 51 | ct_object_unassign(&a); 52 | ct_object_unassign(&b); 53 | ct_object_tostring(l, buf, BUF_SIZE); 54 | CT_IS(0 == strcmp("(nil \"bar\" 23.000000 -42 [-1.000000 2.000000 -3.000000 " 55 | "4.000000] 66 \"foo\")", 56 | buf), 57 | "l: %s", buf); 58 | ct_object_assign(&l2, ct_object_cons(l)); 59 | ct_consrc_push_imm(&l2, d); 60 | ct_consrc_push_imm(&l2, d); 61 | ct_object_tostring(l2, buf, BUF_SIZE); 62 | CT_IS(0 == strcmp("(\"foo\" \"foo\" (nil \"bar\" 23.000000 -42 [-1.000000 " 63 | "2.000000 -3.000000 4.000000] 66 \"foo\"))", 64 | buf), 65 | "l2: %s", buf); 66 | ct_object_unassign(&l); 67 | ct_object_unassign(&d); 68 | ct_consrc_push_imm(&l2, l2); 69 | ct_object_tostring(l2, buf, BUF_SIZE); 70 | CT_IS(0 == strcmp("((\"foo\" \"foo\" (nil \"bar\" 23.000000 -42 [-1.000000 " 71 | "2.000000 -3.000000 4.000000] 66 \"foo\")) " 72 | "\"foo\" \"foo\" (nil \"bar\" 23.000000 -42 [-1.000000 " 73 | "2.000000 -3.000000 4.000000] 66 \"foo\"))", 74 | buf), 75 | "l2: %s", buf); 76 | fputs("l2: ", stderr); 77 | ct_object_print(l2, stderr); 78 | fputs("\n", stderr); 79 | ct_object_unassign(&l2); 80 | return 0; 81 | } 82 | 83 | int test_consrc2() { 84 | CT_Object *a, *b, *c, *l, *l2, *l3; 85 | CT_IS(!ct_consrc_init(), "init consrc"); 86 | ct_object_assign(&a, ct_object_f32(23)); 87 | ct_object_assign(&b, ct_object_u32(42)); 88 | ct_object_assign(&c, ct_object_u32(66)); 89 | ct_object_assign(&l, ct_object_cons(a)); 90 | //ct_object_print(l, stderr); 91 | CT_IS(1 == l->rc.count, "l count"); 92 | ct_object_assign(&l2, ct_consrc_cons(b, l)); 93 | //ct_object_print(l2, stderr); 94 | CT_IS(1 == l2->rc.count, "l2 count"); 95 | //ct_object_trace(l); 96 | //ct_object_trace(l2); 97 | ct_object_assign(&l3, ct_consrc_cons(c, l)); 98 | //ct_object_print(l3, stderr); 99 | CT_IS(3 == l->rc.count, "l count"); 100 | //ct_object_trace(l); 101 | //ct_object_trace(l2); 102 | //ct_object_trace(l3); 103 | CT_Object *tmp = l; 104 | ct_object_unassign(&l); 105 | CT_IS(2 == tmp->rc.count, "l count"); 106 | //ct_object_print(l2, stderr); 107 | ct_object_assign(&l, ct_consrc_cons(c, l2)); 108 | CT_IS(2 == l2->rc.count, "l2 count"); 109 | CT_IS(1 == l->rc.count, "l count"); 110 | //ct_object_print(l, stderr); 111 | //ct_object_print(l2, stderr); 112 | //ct_object_trace(l); 113 | //ct_object_trace(l2); 114 | //ct_object_trace(l3); 115 | CT_Object *tmp2 = l2; 116 | ct_object_unassign(&l2); 117 | CT_IS(1 == tmp2->rc.count, "l2 count"); 118 | tmp2 = l3; 119 | ct_object_unassign(&l3); 120 | CT_IS(0 == tmp2->rc.count, "l3 count"); 121 | //ct_object_trace(l); 122 | ct_object_unassign(&l); 123 | CT_IS(0 == tmp->rc.count, "l orig count"); 124 | return 0; 125 | } 126 | -------------------------------------------------------------------------------- /test/hash.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "ct-head/test.h" 4 | 5 | #include "math/hashfn.h" 6 | 7 | CT_TEST_DECLS 8 | 9 | int test_hash_fns() { 10 | uint32_t h; 11 | char *data = malloc(1024); 12 | strcpy(data, "abcdefghij"); 13 | h = ct_murmur3_32(data, strlen(data)); 14 | CT_IS(((uint32_t)0x88927791) == h, "m3 fail: %x", h); 15 | h = ct_murmur3_32(NULL, 100); 16 | CT_IS(0 == h, "m3 fail NULL: %x", h); 17 | free(data); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /test/hull.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/random.h" 2 | #include "ct-head/test.h" 3 | 4 | #include "geom/hull.h" 5 | 6 | #define ITER 1 7 | 8 | CT_TEST_DECLS 9 | 10 | int test_convex_hull() { 11 | CT_Vec2f points[] = {{0, 0}, {5, 0}, {2, 0.1}, {2, 0.2}, {0, 5}, {1, 2}}; 12 | CT_Vector *hull = ct_vector_new(8, sizeof(CT_Vec2f)); 13 | size_t len = ct_convexhull2f(points, 6, hull); 14 | CT_IS(3 == len, "hull len: %zu", len); 15 | //for(size_t i=0; i<6; i++) { 16 | // CT_INFO("%zu: %f,%f", i, points[i].x, points[i].y); 17 | //} 18 | //ct_array_reverse8_imm(points, 6); 19 | //for(size_t i=0; i<6; i++) { 20 | // CT_INFO("%zu: %f,%f", i, points[i].x, points[i].y); 21 | //} 22 | //for (size_t i = 0; i < len; i++) { 23 | // CT_INFO("hull %zu: %f,%f", i, hull[i].x, hull[i].y); 24 | //} 25 | srand(0); 26 | size_t num = (size_t)1e6; 27 | CT_Vec2f *samples = malloc(num * sizeof(CT_Vec2f)); 28 | for (size_t k = 0; k < ITER; k++) { 29 | for (size_t i = 0; i < num; i++) { 30 | ct_set2fxy(&samples[i], ct_rand_norm(), ct_rand_norm()); 31 | } 32 | ct_set2fxy(&samples[100], 1, -1); 33 | ct_set2fxy(&samples[500], 1, 1); 34 | ct_set2fxy(&samples[1000], -1, 1); 35 | ct_set2fxy(&samples[5000], -1, -1); 36 | len = ct_convexhull2f(samples, num, hull); 37 | CT_IS(4 == len, "hull len: %zu", len); 38 | } 39 | //for (size_t i = 0; i < len; i++) { 40 | // CT_INFO("hull %zu: %f,%f", i, hull[i].x, hull[i].y); 41 | //} 42 | free(samples); 43 | ct_vector_free(hull); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /test/main.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/test.h" 2 | 3 | extern int test_mpool(); 4 | extern int test_mpool_resize(); 5 | extern int test_mpool_compact(); 6 | extern int test_vec2f(); 7 | extern int test_vec3f(); 8 | extern int test_vec4f(); 9 | extern int test_swizzle(); 10 | extern int test_soa(); 11 | extern int test_vec_hash(); 12 | extern int test_random(); 13 | extern int test_convex_hull(); 14 | extern int test_mat4(); 15 | extern int test_circle(); 16 | extern int test_qedge(); 17 | extern int test_vector(); 18 | extern int test_cons(); 19 | extern int test_consrc(); 20 | extern int test_consrc2(); 21 | extern int test_hash_fns(); 22 | extern int test_quadtree(); 23 | extern int test_octree(); 24 | extern int test_spatialgrid1d(); 25 | extern int test_spatialgrid2d(); 26 | extern int test_spatialgrid3d(); 27 | extern int test_hashtable_char(); 28 | extern int test_hashtable_vec(); 29 | extern int test_hashtable_edge(); 30 | extern int test_hashset_char(); 31 | extern int test_hashset_vec(); 32 | extern int test_hashset_edge(); 33 | extern int test_adjmatrix(); 34 | extern int test_poisson(); 35 | extern int test_clipping(); 36 | 37 | extern int bench_vec3_create(); 38 | extern int bench_mat4_mul(); 39 | extern int bench_mat4_rotate_axis(); 40 | extern int bench_hashtable(); 41 | extern int bench_hashset(); 42 | 43 | #ifdef __EMSCRIPTEN__ 44 | extern int ct_js_test_call(); 45 | #else 46 | #endif 47 | 48 | CT_TEST_DECLS 49 | 50 | int all_tests() { 51 | #ifdef CT_FEATURE_CHECKS 52 | CT_INFO("using checks..."); 53 | #endif 54 | #ifdef CT_FEATURE_CHECK_MEM 55 | CT_INFO("using mem checks..."); 56 | #endif 57 | #ifdef CT_FEATURE_TRACE_MPOOL 58 | CT_INFO("tracing mpool..."); 59 | #endif 60 | #ifdef CT_FEATURE_SSE 61 | CT_INFO("using SSE..."); 62 | #endif 63 | #ifdef CT_FEATURE_SSE2 64 | CT_INFO("using SSE2..."); 65 | #endif 66 | #ifdef CT_FEATURE_SSE3 67 | CT_INFO("using SSE3..."); 68 | #endif 69 | #ifdef CT_FEATURE_SSE4 70 | CT_INFO("using SSE4..."); 71 | #endif 72 | CT_RUN_TEST(test_mpool); 73 | CT_RUN_TEST(test_mpool_resize); 74 | CT_RUN_TEST(test_mpool_compact); 75 | CT_RUN_TEST(test_vec2f); 76 | CT_RUN_TEST(test_vec3f); 77 | CT_RUN_TEST(test_vec4f); 78 | CT_RUN_TEST(test_swizzle); 79 | CT_RUN_TEST(test_soa); 80 | CT_RUN_TEST(test_vec_hash); 81 | CT_RUN_TEST(test_random); 82 | CT_RUN_TEST(test_convex_hull); 83 | CT_RUN_TEST(test_mat4); 84 | CT_RUN_TEST(test_circle); 85 | CT_RUN_TEST(test_qedge); 86 | CT_RUN_TEST(test_vector); 87 | CT_RUN_TEST(test_cons); 88 | CT_RUN_TEST(test_consrc); 89 | CT_RUN_TEST(test_consrc2); 90 | CT_RUN_TEST(test_hash_fns); 91 | CT_RUN_TEST(test_quadtree); 92 | CT_RUN_TEST(test_octree); 93 | CT_RUN_TEST(test_spatialgrid1d); 94 | CT_RUN_TEST(test_spatialgrid2d); 95 | CT_RUN_TEST(test_spatialgrid3d); 96 | CT_RUN_TEST(test_hashtable_char); 97 | CT_RUN_TEST(test_hashtable_vec); 98 | CT_RUN_TEST(test_hashtable_edge); 99 | CT_RUN_TEST(test_hashset_char); 100 | CT_RUN_TEST(test_hashset_vec); 101 | CT_RUN_TEST(test_hashset_edge); 102 | CT_RUN_TEST(test_adjmatrix); 103 | CT_RUN_TEST(test_poisson); 104 | CT_RUN_TEST(test_clipping); 105 | 106 | #ifdef __EMSCRIPTEN__ 107 | CT_INFO("JS test_call: %d", ct_js_test_call()); 108 | #else 109 | #endif 110 | 111 | //CT_RUN_TEST(bench_vec3_create); 112 | //CT_RUN_TEST(bench_mat4_mul); 113 | //CT_RUN_TEST(bench_mat4_rotate_axis); 114 | //CT_RUN_TEST(bench_hashtable); 115 | //CT_RUN_TEST(bench_hashset); 116 | 117 | return 0; 118 | } 119 | 120 | CT_RUN_TESTS(all_tests) 121 | -------------------------------------------------------------------------------- /test/matrix.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/test.h" 2 | 3 | #include "data/array.h" 4 | #include "math/matrix.h" 5 | #include "math/vec.h" 6 | 7 | CT_TEST_DECLS 8 | 9 | static char buf[256]; 10 | 11 | #define ASSERT_VEC(a, n, ...) \ 12 | { \ 13 | int res = ct_array_compare_f32((float*)a, FVEC(__VA_ARGS__), CT_EPS, n); \ 14 | __testAsserts++; \ 15 | if (res) { \ 16 | ct_array_tostring_f32(buf, 256, (float*)a, n, 1); \ 17 | CT_ERROR("%s", buf); \ 18 | return 1; \ 19 | } \ 20 | } 21 | 22 | #define ASSERT_VEC4F(v, ...) ASSERT_VEC(v, 4, __VA_ARGS__) 23 | #define ASSERT_MAT4F(m, ...) ASSERT_VEC(m, 16, __VA_ARGS__) 24 | 25 | int test_mat4() { 26 | CT_Mat4f a = {.mat = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}}; 27 | CT_Mat4f b; 28 | ct_mat4f_transpose_imm(&a); 29 | ASSERT_MAT4F(&a, 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); 30 | ct_mat4f_set_identity(&a); 31 | ct_mat4f_scalen_imm(&a, 2); 32 | ASSERT_MAT4F(&a, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1); 33 | ct_mat4f_translate3fp_imm(&a, FVEC(10, 20, 30)); 34 | ASSERT_MAT4F(&a, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 20, 40, 60, 1); 35 | CT_Vec4f p = {1, 1, 1, 1}; 36 | ct_mat4f_transform4fv_imm(&a, &p); 37 | ASSERT_VEC4F(&p, 22, 42, 62, 1); 38 | 39 | ct_mat4f_set_identity(&a); 40 | 41 | ct_set4fxyzw(&p, 0, 1, 0, 0); 42 | ct_mat4f_transform4fv_imm(ct_mat4f_rotatex(&a, CT_HALF_PI, &b), &p); 43 | ASSERT_VEC4F(&p, 0, 0, 1, 0); 44 | 45 | ct_set4fxyzw(&p, 1, 0, 0, 0); 46 | ct_mat4f_transform4fv_imm(ct_mat4f_rotatey(&a, CT_HALF_PI, &b), &p); 47 | ASSERT_VEC4F(&p, 0, 0, -1, 0); 48 | 49 | ct_set4fxyzw(&p, 1, 0, 0, 0); 50 | ct_mat4f_transform4fv_imm(ct_mat4f_rotatez(&a, CT_HALF_PI, &b), &p); 51 | ASSERT_VEC4F(&p, 0, 1, 0, 0); 52 | 53 | CT_Vec3f axis = {0, 1, 0}; 54 | ct_set4fxyzw(&p, 1, 0, 0, 0); 55 | ct_mat4f_transform4fv_imm(ct_mat4f_rotate_axis(&a, &axis, CT_HALF_PI, &b), 56 | &p); 57 | ASSERT_VEC4F(&p, 0, 0, -1, 0); 58 | 59 | return 0; 60 | } 61 | 62 | ct_export int bench_mat4_mul() { 63 | CT_Mat4f a, b; 64 | ct_mat4f_set_identity(&a); 65 | ct_mat4f_set_identity(&b); 66 | ct_mat4f_translate3fp_imm(&b, FVEC(1, 2, 3)); 67 | for (size_t i = 0; i < 1e6; i++) { 68 | ct_mat4f_mul_imm(&a, &b); 69 | } 70 | //ct_tostringfp(buf, 256, a.mat, 16); 71 | //CT_INFO("%s", buf); 72 | return 0; 73 | } 74 | 75 | ct_export int bench_mat4_rotate_axis() { 76 | CT_Mat4f a, b; 77 | ct_mat4f_set_identity(&a); 78 | CT_Vec3f axis = {1, 0, 0}; 79 | for (size_t i = 0; i < 1e6; i++) { 80 | ct_mat4f_rotatex(&a, CT_HALF_PI, &b); 81 | } 82 | //ct_tostringfp(buf, 256, a.mat, 16); 83 | //CT_INFO("%s", buf); 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /test/mpool.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/test.h" 2 | 3 | #include "mem/mpool.h" 4 | 5 | CT_TEST_DECLS 6 | 7 | int test_mpool() { 8 | CT_MPool pool; 9 | CT_IS(!ct_mpool_init(&pool, 16, 8), "can't init mpool"); 10 | float *a = ct_mpool_alloc(&pool); 11 | *a = 23; 12 | CT_IS(ct_mpool_is_valid_block(&pool, a), "a invalid"); 13 | CT_IS(!ct_mpool_is_valid_block(&pool, NULL), "NULL invalid"); 14 | CT_IS((uint8_t *)a == pool.head->pool, "*a not 1st block (%p, %p)", a, 15 | pool.head->pool); 16 | CT_IS(*a == 23, "a = %f", *a); 17 | 18 | float *b = ct_mpool_alloc(&pool); 19 | *b = 42; 20 | CT_IS((uint8_t *)b == pool.head->pool + 8, "*b not 2nd block (%p, %p)", b, 21 | pool.head->pool + 8); 22 | CT_IS(*b == 42, "b = %f", *b); 23 | 24 | ct_mpool_free_block(&pool, a); 25 | CT_IS((uint8_t *)pool.freeList == pool.head->pool, "block not freed"); 26 | 27 | a = ct_mpool_alloc(&pool); 28 | *a = 66; 29 | CT_IS((uint8_t *)a == pool.head->pool, "*a not 1st block (%p, %p)", a, 30 | pool.head->pool); 31 | CT_IS(*a == 66, "a = %f", *a); 32 | 33 | float *c = ct_mpool_alloc(&pool); 34 | *c = -1; 35 | CT_IS((uint8_t *)c == pool.head->pool + 16, "*c not 3rd block (%p, %p)", c, 36 | pool.head->pool + 16); 37 | CT_IS(*c == -1, "c = %f", *c); 38 | 39 | ct_mpool_free_block(&pool, c); 40 | ct_mpool_free_block(&pool, a); 41 | ct_mpool_free_block(&pool, b); 42 | CT_IS((uint8_t *)pool.freeList == (uint8_t *)b, "b not 1st free block"); 43 | CT_IS((uint8_t *)pool.freeList->next == (uint8_t *)a, "a not 2nd free block"); 44 | 45 | //ct_mpool_trace(&pool); 46 | ct_mpool_free(&pool); 47 | return 0; 48 | } 49 | 50 | int test_mpool_resize() { 51 | CT_MPool pool; 52 | void *blocks[12]; 53 | CT_IS(!ct_mpool_init(&pool, 4, 8), "can't init rmpool"); 54 | CT_MPoolList *oh = pool.head; 55 | for (int i = 0; i < 12; i++) { 56 | blocks[i] = ct_mpool_alloc(&pool); 57 | } 58 | CT_IS(oh != pool.head, "wrong head"); 59 | CT_IS(pool.head->next->next == oh, "wrong head chain"); 60 | CT_IS(pool.freeList == NULL, "should have no free list"); 61 | CT_IS(pool.head->next->pool == blocks[4], "2nd pool != blocks[4]"); 62 | for (int i = 0; i < 5; i++) { 63 | ct_mpool_free_block(&pool, blocks[i]); 64 | } 65 | CT_IS(pool.freeList == blocks[4], "free list != blocks[4]"); 66 | for (int i = 0; i < 4; i++) { 67 | blocks[i] = ct_mpool_alloc(&pool); 68 | } 69 | CT_IS(pool.freeList->next == NULL, "freelist length != 1"); 70 | ct_mpool_alloc(&pool); 71 | ct_mpool_alloc(&pool); 72 | //ct_mpool_trace(&pool); 73 | ct_mpool_free(&pool); 74 | return 0; 75 | } 76 | 77 | int test_mpool_compact() { 78 | CT_MPool pool; 79 | CT_IS(!ct_mpool_init(&pool, 2, 8), "init"); 80 | ct_mpool_alloc(&pool); 81 | ct_mpool_alloc(&pool); 82 | uint32_t *a = ct_mpool_alloc(&pool); 83 | uint32_t *b = ct_mpool_alloc(&pool); 84 | uint32_t *c = ct_mpool_alloc(&pool); 85 | uint32_t *d = ct_mpool_alloc(&pool); 86 | ct_mpool_free_block(&pool, a); 87 | ct_mpool_free_block(&pool, b); 88 | ct_mpool_free_block(&pool, c); 89 | CT_MPCompactResult res = ct_mpool_compact(&pool); 90 | CT_IS(2 == res.blocks, "blocks: %zu", res.blocks); 91 | CT_IS(1 == res.pools, "pools: %zu", res.pools); 92 | ct_mpool_free(&pool); 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /test/octree.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/random.h" 2 | #include "ct-head/test.h" 3 | 4 | #include "data/octree.h" 5 | 6 | CT_TEST_DECLS 7 | 8 | struct bounds_t { 9 | CT_Vec3f min, max; 10 | size_t num; 11 | }; 12 | 13 | int ct_octree_bounds(const CT_OTNode *node, void *state) { 14 | struct bounds_t *bounds = (struct bounds_t *)state; 15 | ct_min3fv_imm(&bounds->min, node->point); 16 | ct_max3fv_imm(&bounds->max, node->point); 17 | bounds->num++; 18 | return 0; 19 | } 20 | 21 | int test_octree() { 22 | CT_INFO("CT_Octree size: %zu", sizeof(CT_Octree)); 23 | CT_INFO("CT_OTNode size: %zu", sizeof(CT_OTNode)); 24 | 25 | CT_Octree t; 26 | ct_octree_init(&t, 0, 0, 0, 100, 100, 100, 0x10000); 27 | 28 | CT_DEF_MPOOL(vpool, 0x10000, CT_Vec3f); 29 | 30 | CT_Vec3f *a = ct_vec3f(10, 10, 10, &vpool); 31 | CT_Vec3f *b = ct_vec3f(10, 11, 10, &vpool); 32 | CT_Vec3f *b2 = ct_vec3f(10.1, 11, 10, &vpool); 33 | CT_Vec3f *c = ct_vec3f(50, 12, 50, &vpool); 34 | ct_octree_insert(&t, a, NULL); 35 | ct_octree_insert(&t, b, NULL); 36 | ct_octree_insert(&t, c, NULL); 37 | //ct_octree_trace(&t); 38 | CT_IS(ct_octree_find_leaf(&t, a), "can't find a"); 39 | CT_IS(ct_octree_find_leaf(&t, b), "can't find b"); 40 | CT_IS(!ct_octree_find_leaf(&t, b2), "shouldn't find b2"); 41 | ct_octree_remove(&t, a); 42 | CT_IS(!ct_octree_find_leaf(&t, a), "shouldn't find a"); 43 | CT_IS(ct_octree_remove(&t, a), "remove a again"); 44 | ct_octree_remove(&t, b); 45 | CT_IS(!ct_octree_find_leaf(&t, b), "shouldn't find b"); 46 | CT_IS(ct_octree_remove(&t, b), "remove b again"); 47 | ct_octree_remove(&t, c); 48 | CT_IS(!ct_octree_find_leaf(&t, c), "shouldn't find c"); 49 | CT_IS(ct_octree_remove(&t, c), "remove c again"); 50 | CT_IS(CT_TREE_EMPTY == t.root.type, "root is not empty: %zu", t.root.type); 51 | //srand(time(0)); 52 | int num = 1e5; 53 | for (int i = 0; i < num; i++) { 54 | CT_Vec3f *p = 55 | ct_vec3f(ct_rand_normpos() * 99.999, ct_rand_normpos() * 99.999, 56 | ct_rand_normpos() * 99.999, &vpool); 57 | int ok = !ct_octree_insert(&t, p, NULL); 58 | CT_CHECK(ok, "insert: %f,%f", p->x, p->y); 59 | } 60 | struct bounds_t bounds = {{1000, 1000, 1000}, {-1000, -1000, -1000}, 0}; 61 | ct_octree_visit_leaves(&t, ct_octree_bounds, &bounds); 62 | CT_IS(num == bounds.num, "wrong leaf count: %zu", bounds.num); 63 | CT_INFO("%f,%f,%f -> %f,%f,%f %zu", bounds.min.x, bounds.min.y, bounds.min.z, 64 | bounds.max.x, bounds.max.y, bounds.max.z, bounds.num); 65 | ct_mpool_free(&vpool); 66 | ct_octree_free(&t); 67 | return 0; 68 | fail: 69 | return 1; 70 | } 71 | -------------------------------------------------------------------------------- /test/poisson.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/test.h" 2 | 3 | #include "math/poisson.h" 4 | 5 | CT_TEST_DECLS 6 | 7 | int test_poisson() { 8 | srand(0); 9 | CT_DEF_MPOOL(vpool, 0x1000, CT_Vec2f); 10 | int w = 600; 11 | int h = 600; 12 | float r = 10; 13 | size_t count = 0; 14 | 15 | CT_Quadtree t; 16 | CT_IS(!ct_qtree_init(&t, 0, 0, w, h, 0x1000), "init"); 17 | 18 | size_t failed = 0; 19 | CT_Vec2f *p = (CT_Vec2f *)ct_mpool_alloc(&vpool); 20 | 21 | while (1) { 22 | if (!ct_poisson_sample2f(&t, r, 20, p)) { 23 | p = (CT_Vec2f *)ct_mpool_alloc(&vpool); 24 | count++; 25 | failed = 0; 26 | } else if (++failed > 50) { 27 | break; 28 | } 29 | } 30 | CT_IS(2000 < count, "count: %zu", count); 31 | 32 | ct_mpool_free(&vpool); 33 | ct_qtree_free(&t); 34 | return 0; 35 | 36 | fail: 37 | return 1; 38 | } 39 | -------------------------------------------------------------------------------- /test/qedge.c: -------------------------------------------------------------------------------- 1 | #include "cthing.h" 2 | #include "geom/quadedge.h" 3 | 4 | void trace_edge(CT_QuadEdgeRef e, void* _) { 5 | CT_INFO("edge: %zx next: %zx", e, ONEXT(e)); 6 | } 7 | 8 | int test_qedge() { 9 | CT_QuadEdgeRef a = ct_qedge(); 10 | CT_QuadEdgeRef b = ct_qedge(); 11 | CT_QuadEdgeRef c = ct_qedge(); 12 | CT_QuadEdgeRef d = ct_qedge(); 13 | ct_qedge_splice(a, b); 14 | ct_qedge_splice(b, c); 15 | ct_qedge_splice(d, a); 16 | ct_qedge_iterate(a, trace_edge, NULL); 17 | 18 | free((void*)a); 19 | free((void*)b); 20 | free((void*)c); 21 | free((void*)d); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /test/quadtree.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/random.h" 2 | #include "ct-head/test.h" 3 | 4 | #include "data/quadtree.h" 5 | #include "geom/isec.h" 6 | 7 | CT_TEST_DECLS 8 | 9 | struct bounds_t { 10 | CT_Vec2f min, max; 11 | size_t num; 12 | }; 13 | 14 | struct isec_t { 15 | CT_Vec2f c; 16 | float r; 17 | CT_Vec2f *sel[4]; 18 | size_t num; 19 | }; 20 | 21 | static int ct_qtree_bounds(const CT_QTNode *node, void *state) { 22 | struct bounds_t *bounds = (struct bounds_t *)state; 23 | ct_min2fv_imm(&bounds->min, node->point); 24 | ct_max2fv_imm(&bounds->max, node->point); 25 | bounds->num++; 26 | return 0; 27 | } 28 | 29 | static int ct_qtree_select(const CT_QTNode *node, void *state) { 30 | struct isec_t *isec = (struct isec_t *)state; 31 | CT_Vec2f p = {node->x + node->w, node->y + node->h}; 32 | int i = ct_intersect_rect_circle(&node->pos, &p, &isec->c, isec->r); 33 | //CT_INFO("isec: %d, n: %1.3f,%1.3f -> %1.3f,%1.3f c: %f,%f, r: %f", i, node->x, node->y, p.x, p.y, isec->c.x, isec->c.y, isec->r); 34 | if (i) { 35 | if (node->type == CT_TREE_LEAF) { 36 | if (ct_dist2fv(node->point, &isec->c) <= isec->r) { 37 | isec->sel[isec->num++] = node->point; 38 | } 39 | } 40 | return 0; 41 | } 42 | return 1; 43 | } 44 | 45 | static void print_isec_results(struct isec_t *isec) { 46 | for (size_t i = 0; i < isec->num; i++) { 47 | CT_INFO("isec %zu: (%f, %f)", i, isec->sel[i]->x, isec->sel[i]->y); 48 | } 49 | } 50 | 51 | int test_quadtree() { 52 | CT_INFO("CT_Quadtree size: %zu", sizeof(CT_Quadtree)); 53 | CT_INFO("CT_QTNode size: %zu", sizeof(CT_QTNode)); 54 | 55 | CT_Quadtree t; 56 | ct_qtree_init(&t, 0, 0, 100, 100, 0x10000); 57 | 58 | CT_DEF_MPOOL(vpool, 0x10000, CT_Vec2f); 59 | 60 | CT_Vec2f *a = ct_vec2f(10, 10, &vpool); 61 | CT_Vec2f *b = ct_vec2f(10, 11, &vpool); 62 | CT_Vec2f *b2 = ct_vec2f(10.1, 11, &vpool); 63 | CT_Vec2f *c = ct_vec2f(50, 12, &vpool); 64 | CT_IS(!ct_qtree_insert(&t, a, NULL), "add a"); 65 | CT_IS(!ct_qtree_insert(&t, b, NULL), "add b"); 66 | CT_IS(!ct_qtree_insert(&t, c, NULL), "add c"); 67 | //ct_qtree_trace(&t); 68 | struct isec_t isec = {{50, 50}, 70.f, {NULL, NULL, NULL, NULL}, 0}; 69 | ct_qtree_visit(&t, ct_qtree_select, &isec); 70 | CT_IS(3 == isec.num, "wrong isec count: %zu", isec.num); 71 | //print_isec_results(&isec); 72 | struct isec_t isec2 = {{10, 10}, 0.9f, {NULL, NULL, NULL, NULL}, 0}; 73 | ct_qtree_visit(&t, ct_qtree_select, &isec2); 74 | CT_IS(1 == isec2.num, "wrong isec2 count: %zu", isec2.num); 75 | struct isec_t isec3 = {{52, 12}, 5.f, {NULL, NULL, NULL, NULL}, 0}; 76 | ct_qtree_visit(&t, ct_qtree_select, &isec3); 77 | CT_IS(1 == isec3.num, "wrong isec3 count: %zu", isec3.num); 78 | CT_IS(ct_qtree_find_leaf(&t, a), "can't find a"); 79 | CT_IS(ct_qtree_find_leaf(&t, b), "can't find b"); 80 | CT_IS(!ct_qtree_find_leaf(&t, b2), "shouldn't find b2"); 81 | ct_qtree_remove(&t, a); 82 | CT_IS(!ct_qtree_find_leaf(&t, a), "shouldn't find a"); 83 | CT_IS(ct_qtree_remove(&t, a), "remove a again"); 84 | ct_qtree_remove(&t, b); 85 | CT_IS(!ct_qtree_find_leaf(&t, b), "shouldn't find b"); 86 | CT_IS(ct_qtree_remove(&t, b), "remove b again"); 87 | ct_qtree_remove(&t, c); 88 | CT_IS(!ct_qtree_find_leaf(&t, c), "shouldn't find c"); 89 | CT_IS(ct_qtree_remove(&t, c), "remove c again"); 90 | CT_IS(CT_TREE_EMPTY == t.root.type, "root is not empty: %zu", t.root.type); 91 | //srand(time(0)); 92 | int num = 1e5; 93 | for (int i = 0; i < num; i++) { 94 | CT_Vec2f *p = 95 | ct_vec2f(ct_rand_normpos() * 100, ct_rand_normpos() * 100, &vpool); 96 | ct_qtree_insert(&t, p, NULL); 97 | } 98 | struct bounds_t bounds = {{1000, 1000}, {-1000, -1000}, 0}; 99 | ct_qtree_visit_leaves(&t, ct_qtree_bounds, &bounds); 100 | CT_IS(num == bounds.num, "wrong leaf count: %zu", bounds.num); 101 | CT_INFO("%f,%f -> %f, %f, %zu", bounds.min.x, bounds.min.y, bounds.max.x, 102 | bounds.max.y, bounds.num); 103 | ct_mpool_free(&vpool); 104 | ct_qtree_free(&t); 105 | return 0; 106 | fail: 107 | return 1; 108 | } 109 | -------------------------------------------------------------------------------- /test/random.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/random.h" 2 | #include "ct-head/test.h" 3 | 4 | CT_TEST_DECLS 5 | 6 | #define NUM 16 7 | 8 | int test_random() { 9 | CT_Smush rnd; 10 | uint32_t expected[NUM] = {0x00000000, 0x9a2343da, 0xdb354663, 0x72f2735c, 11 | 0x9cf0caa5, 0x4509caf1, 0x875199db, 0x20a6a896, 12 | 0xe95ab6aa, 0x726b4880, 0xad879015, 0xa771cf8c, 13 | 0xac3ec833, 0xd78b95ff, 0x88aae504, 0x5490a69b}; 14 | ct_smush_init(&rnd, 0); 15 | for (size_t i = 0; i < NUM; i++) { 16 | uint32_t x = ct_smush(&rnd); 17 | CT_IS(x == expected[i], "rnd %zu: %08x", i, x); 18 | } 19 | return 0; 20 | } 21 | 22 | #undef NUM 23 | -------------------------------------------------------------------------------- /test/soa.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/test.h" 2 | 3 | #include "data/array.h" 4 | #include "data/soa.h" 5 | 6 | CT_TEST_DECLS 7 | 8 | #define NUM (1 << 2) 9 | 10 | static void trace_soa(CT_SOA *s) { 11 | float **c = (float **)s->comps; 12 | for (size_t i = 0; i < s->width; i++) { 13 | fprintf(stderr, "%zu: ", i); 14 | for (size_t j = 0; j < s->num; j++) { 15 | fprintf(stderr, "%f, ", c[i][j]); 16 | } 17 | fputs("\n", stderr); 18 | } 19 | } 20 | 21 | static void reset_soa2(CT_SOA *a, CT_SOA *b) { 22 | for (size_t i = 0; i < NUM; i++) { 23 | CT_Vec2f va = {i + 1, i + 1}; 24 | CT_Vec2f vb = {(i + 1) * 10, (i + 1) * 10}; 25 | ct_soa_set2f(a, i, &va); 26 | ct_soa_set2f(b, i, &vb); 27 | } 28 | } 29 | 30 | int test_soa() { 31 | CT_DEBUG("word size: %d, mask: %d, shift: %d", CT_SOA_WORD_SIZE, 32 | CT_SOA_SIZE_MASK, CT_SOA_WORD_SHIFT); 33 | 34 | CT_SOA a, b; 35 | float *buf = malloc(NUM * 4 * 4); 36 | float *xa = buf, *ya = buf + NUM, *xb = buf + NUM * 2, *yb = buf + NUM * 3; 37 | 38 | float *bufa[] = {xa, ya}; 39 | float *bufb[] = {xb, yb}; 40 | CT_IS(!ct_soa_init(&a, (void **)bufa, 2, NUM, sizeof(float)), "init a"); 41 | CT_IS(!ct_soa_init(&b, (void **)bufb, 2, NUM, sizeof(float)), "init b"); 42 | reset_soa2(&a, &b); 43 | 44 | ct_soa_add1f_imm(&a, 10); 45 | CT_IS(0 == ct_array_compare_f32(xa, FVEC(11, 12, 13, 14), CT_EPS, NUM), 46 | "add1x"); 47 | CT_IS(0 == ct_array_compare_f32(ya, FVEC(11, 12, 13, 14), CT_EPS, NUM), 48 | "add1y"); 49 | 50 | reset_soa2(&a, &b); 51 | ct_soa_add1fp_imm(&a, xb); 52 | CT_IS(0 == ct_array_compare_f32(xa, FVEC(11, 12, 13, 14), CT_EPS, NUM), 53 | "add1fpx"); 54 | CT_IS(0 == ct_array_compare_f32(ya, FVEC(21, 22, 23, 24), CT_EPS, NUM), 55 | "add1fpy"); 56 | 57 | CT_Vec2f v2; 58 | ct_soa_get2f(&a, 3, &v2); 59 | CT_IS(14 == v2.x && 24 == v2.y, "get2f"); 60 | 61 | ct_soa_max_imm(&a, &b); 62 | CT_IS(0 == ct_array_compare_f32(xa, FVEC(11, 20, 30, 40), CT_EPS, NUM), 63 | "max x"); 64 | CT_IS(0 == ct_array_compare_f32(ya, FVEC(21, 22, 30, 40), CT_EPS, NUM), 65 | "max y"); 66 | 67 | float *flat = ct_soa_flatten(&a, NULL); 68 | CT_IS(flat, "flat == NULL"); 69 | CT_IS(0 == ct_array_compare_f32(flat, FVEC(11, 20, 30, 40, 21, 22, 30, 40), 70 | CT_EPS, NUM * 2), 71 | "cmp flat"); 72 | free(flat); 73 | 74 | ct_soa_min_imm(&a, &b); 75 | CT_IS(0 == ct_array_compare_f32(xa, xb, CT_EPS, NUM), "min x"); 76 | CT_IS(0 == ct_array_compare_f32(ya, yb, CT_EPS, NUM), "min y"); 77 | 78 | reset_soa2(&a, &b); 79 | ct_soa_add_imm(&a, &b); 80 | CT_IS(0 == ct_array_compare_f32(xa, FVEC(11, 22, 33, 44), CT_EPS, NUM), 81 | "addx"); 82 | CT_IS(0 == ct_array_compare_f32(ya, FVEC(11, 22, 33, 44), CT_EPS, NUM), 83 | "addy"); 84 | 85 | reset_soa2(&a, &b); 86 | ct_soa_dot2(&a, &b, xa); 87 | CT_IS(0 == ct_array_compare_f32(xa, FVEC(20, 80, 180, 320), CT_EPS, NUM), 88 | "dot2"); 89 | 90 | reset_soa2(&a, &b); 91 | ct_soa_dist2(&a, &b, xa); 92 | CT_IS(0 == ct_array_compare_f32(xa, FVEC(12.73, 25.46, 38.18, 50.91), 0.01, 93 | NUM), 94 | "dist2"); 95 | 96 | reset_soa2(&a, &b); 97 | ct_soa_normalize2f_imm(&a, 1); 98 | CT_IS(0 == ct_array_compare_f32(xa, FVEC(0.707, 0.707, 0.707, 0.707), 0.01, 99 | NUM), 100 | "norm2x"); 101 | CT_IS(0 == ct_array_compare_f32(ya, FVEC(0.707, 0.707, 0.707, 0.707), 0.01, 102 | NUM), 103 | "norm2y"); 104 | 105 | free(buf); 106 | 107 | CT_SOA *aa = ct_soa_new(16, 16, 4); 108 | CT_IS(aa, "new 16x16"); 109 | float *data = calloc(aa->width * aa->num, sizeof(float)); 110 | float **comps = (float **)aa->comps; 111 | for (size_t i = 0; i < aa->width; i++) { 112 | float *dc = data + i * aa->num; 113 | float scale = powf(10, i); 114 | for (size_t j = 0; j < aa->num; j++) { 115 | comps[i][j] = (j + 1) * scale; 116 | dc[j] = comps[i][j] * 2; 117 | } 118 | } 119 | ct_soa_add_imm(aa, aa); 120 | for (size_t i = 0; i < aa->width; i++) { 121 | float *dc = data + i * aa->num; 122 | CT_IS(0 == ct_array_compare_f32(aa->comps[i], dc, CT_EPS, aa->num), 123 | "row %zu", i); 124 | } 125 | //trace_soa(aa); 126 | ct_soa_free(aa); 127 | free(data); 128 | 129 | return 0; 130 | } 131 | -------------------------------------------------------------------------------- /test/spatialgrid.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/test.h" 2 | 3 | #include "data/spatialgrid.h" 4 | #include "math/vec.h" 5 | 6 | CT_TEST_DECLS 7 | 8 | int test_spatialgrid1d() { 9 | CT_SpatialGrid grid; 10 | CT_IS(!ct_spgrid_init(&grid, FVEC(0), FVEC(100), IVEC(25), 1, 16), "init"); 11 | CT_Vec2f a = {23, 10}; 12 | CT_Vec2f b = {24, 11}; 13 | CT_Vec2f c = {22, 12}; 14 | CT_IS(!ct_spgrid_insert(&grid, a.buf, &a), "insert a"); 15 | CT_IS(!ct_spgrid_insert(&grid, b.buf, &b), "insert b"); 16 | CT_IS(!ct_spgrid_insert(&grid, c.buf, &c), "insert c"); 17 | ct_spgrid_trace(&grid); 18 | CT_Vec2f *results[4]; 19 | size_t num = ct_spgrid_select1d(&grid, a.x, 1, (void **)&results, 4); 20 | CT_IS(3 == num, "count: %zu", num); 21 | CT_IS(&c == results[0], "sel 0: %p", results[0]); 22 | CT_IS(&a == results[1], "sel 1: %p", results[1]); 23 | CT_IS(&b == results[2], "sel 2: %p", results[2]); 24 | num = ct_spgrid_select1d(&grid, a.x - 1, 1, (void **)&results, 4); 25 | CT_IS(2 == num, "count: %zu", num); 26 | num = ct_spgrid_select1d(&grid, b.x + 1, 1, (void **)&results, 4); 27 | CT_IS(1 == num, "count: %zu", num); 28 | CT_IS(!ct_spgrid_remove(&grid, a.buf, &a), "remove a"); 29 | num = ct_spgrid_select1d(&grid, c.x, 1, (void **)&results, 4); 30 | CT_IS(1 == num, "count: %zu", num); 31 | CT_IS(!ct_spgrid_remove(&grid, c.buf, &c), "remove c"); 32 | num = ct_spgrid_select1d(&grid, c.x, 1, (void **)&results, 4); 33 | CT_IS(0 == num, "count: %zu", num); 34 | num = ct_spgrid_select1d(&grid, c.x, 100, (void **)&results, 4); 35 | CT_IS(1 == num, "count: %zu", num); 36 | CT_IS(!ct_spgrid_update(&grid, b.buf, b.buf, b.buf), "update b"); 37 | num = ct_spgrid_select1d(&grid, b.x, 0, (void **)&results, 4); 38 | CT_IS(1 == num, "count: %zu", num); 39 | CT_IS(!ct_spgrid_update(&grid, b.buf, FVEC(90), &b), "update b"); 40 | num = ct_spgrid_select1d(&grid, 90, 0, (void **)&results, 4); 41 | CT_IS(1 == num, "count: %zu", num); 42 | ct_spgrid_free(&grid); 43 | return 0; 44 | } 45 | 46 | int test_spatialgrid2d() { 47 | CT_SpatialGrid grid; 48 | CT_IS(!ct_spgrid_init(&grid, FVEC(0, 0), FVEC(100, 100), IVEC(25, 25), 2, 16), 49 | "init"); 50 | CT_Vec2f a = {23, 10}; 51 | CT_Vec2f b = {24, 11}; 52 | CT_Vec2f c = {22, 12}; 53 | CT_Vec2f d = {23, 11}; 54 | CT_IS(!ct_spgrid_insert(&grid, a.buf, &a), "insert a"); 55 | CT_IS(!ct_spgrid_insert(&grid, b.buf, &b), "insert b"); 56 | CT_IS(!ct_spgrid_insert(&grid, c.buf, &c), "insert c"); 57 | CT_IS(!ct_spgrid_insert(&grid, d.buf, &d), "insert d"); 58 | ct_spgrid_trace(&grid); 59 | CT_Vec2f *results[4]; 60 | size_t num = 61 | ct_spgrid_select2d(&grid, a.buf, FVEC(2, 2), (void **)&results, 4); 62 | CT_IS(4 == num, "count: %zu", num); 63 | num = ct_spgrid_select2d(&grid, a.buf, FVEC(2, 0), (void **)&results, 4); 64 | CT_IS(1 == num, "count: %zu", num); 65 | num = ct_spgrid_select2d(&grid, FVEC(22.5, 11), FVEC(0.5, 1), 66 | (void **)&results, 4); 67 | CT_IS(3 == num, "count: %zu", num); 68 | CT_IS(!ct_spgrid_remove(&grid, a.buf, &a), "remove a"); 69 | num = ct_spgrid_select2d(&grid, FVEC(22.5, 11), FVEC(0.5, 1), 70 | (void **)&results, 4); 71 | CT_IS(2 == num, "count: %zu", num); 72 | CT_IS(!ct_spgrid_remove(&grid, c.buf, &c), "remove c"); 73 | num = ct_spgrid_select2d(&grid, FVEC(22.5, 11), FVEC(0.5, 100), 74 | (void **)&results, 4); 75 | CT_IS(1 == num, "count: %zu", num); 76 | CT_IS(!ct_spgrid_remove(&grid, d.buf, &d), "remove d"); 77 | num = ct_spgrid_select2d(&grid, FVEC(22.5, 11), FVEC(0.5, 100), 78 | (void **)&results, 4); 79 | CT_IS(0 == num, "count: %zu", num); 80 | ct_spgrid_free(&grid); 81 | return 0; 82 | } 83 | 84 | int test_spatialgrid3d() { 85 | CT_SpatialGrid grid; 86 | CT_IS(!ct_spgrid_init(&grid, FVEC(0, 0, 0), FVEC(100, 100, 100), 87 | IVEC(25, 25, 25), 3, 16), 88 | "init"); 89 | CT_Vec3f a = {23, 10, 50}; 90 | CT_Vec3f b = {24, 11, 51}; 91 | CT_Vec3f c = {22, 12, 49}; 92 | CT_Vec3f d = {23, 11, 50}; 93 | CT_IS(!ct_spgrid_insert(&grid, a.buf, &a), "insert a"); 94 | CT_IS(!ct_spgrid_insert(&grid, b.buf, &b), "insert b"); 95 | CT_IS(!ct_spgrid_insert(&grid, c.buf, &c), "insert c"); 96 | CT_IS(!ct_spgrid_insert(&grid, d.buf, &d), "insert d"); 97 | ct_spgrid_trace(&grid); 98 | CT_Vec3f *results[8]; 99 | size_t num = 100 | ct_spgrid_select3d(&grid, a.buf, FVEC(2, 2, 2), (void **)&results, 8); 101 | CT_IS(4 == num, "count: %zu", num); 102 | num = ct_spgrid_select3d(&grid, a.buf, FVEC(2, 0, 0), (void **)&results, 8); 103 | CT_IS(1 == num, "count: %zu", num); 104 | CT_IS(&a == results[0], "a"); 105 | num = ct_spgrid_select3d(&grid, FVEC(22.5, 11, 50), FVEC(0.5, 1, 100), 106 | (void **)&results, 8); 107 | CT_IS(3 == num, "count: %zu", num); 108 | ct_spgrid_free(&grid); 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /test/vector.c: -------------------------------------------------------------------------------- 1 | #include "ct-head/test.h" 2 | 3 | #include "data/vector.h" 4 | 5 | CT_TEST_DECLS 6 | 7 | int test_vector() { 8 | float data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 9 | size_t num = sizeof(data) / sizeof(float); 10 | 11 | CT_Vector *v = ct_vector_new(8, sizeof(float)); 12 | CT_IS(v, "init"); 13 | CT_IS(0 == ct_vector_size(v), "not empty"); 14 | CT_IS(NULL == ct_vector_peek(v), "peek"); 15 | CT_IS(1 == ct_vector_pop(v, NULL), "pop"); 16 | 17 | CT_VectorIter *iter = ct_vector_iter_new(v, 0); 18 | CT_IS(iter, "init"); 19 | CT_IS(!ct_vector_iter_next(iter), "fwd next != NULL"); 20 | CT_IS(!ct_vector_iter_prev(iter), "fwd prev != NULL"); 21 | 22 | ct_vector_iter_init(iter, v, 1); 23 | CT_IS(!ct_vector_iter_next(iter), "rev next != NULL"); 24 | CT_IS(!ct_vector_iter_prev(iter), "rev prev != NULL"); 25 | 26 | for (size_t i = 0; i < num; i++) { 27 | CT_IS(!ct_vector_push(v, &data[i]), "push %zu", i); 28 | CT_IS(data[i] == *((float *)ct_vector_get(v, i)), "get"); 29 | } 30 | CT_IS(num == ct_vector_size(v), "size != %zu", num); 31 | 32 | ct_vector_iter_init(iter, v, 0); 33 | float *val, last_val; 34 | while ((val = (float *)ct_vector_iter_next(iter))) { 35 | *val = *val * 10; 36 | last_val = *val; 37 | CT_DEBUG("next: %f", *val); 38 | } 39 | CT_IS(data[num - 1] * 10 == last_val, "last val"); 40 | 41 | ct_vector_iter_init(iter, v, 1); 42 | while ((val = (float *)ct_vector_iter_next(iter))) { 43 | CT_DEBUG("p: %p", val); 44 | *val = *val * 10; 45 | last_val = *val; 46 | CT_DEBUG("rnext: %f", *val); 47 | } 48 | CT_IS(data[0] * 100 == last_val, "last val"); 49 | 50 | while ((val = (float *)ct_vector_iter_prev(iter))) { 51 | CT_DEBUG("p: %p", val); 52 | *val = *val * 10; 53 | last_val = *val; 54 | CT_DEBUG("rprev: %f", *val); 55 | } 56 | CT_IS(data[num - 1] * 1000 == last_val, "last val"); 57 | 58 | float pop; 59 | while (!ct_vector_pop(v, &pop)) { 60 | CT_DEBUG("pop: %f", pop); 61 | } 62 | CT_IS(0 == ct_vector_size(v), "not empty"); 63 | 64 | ct_vector_free(v); 65 | free(iter); 66 | return 0; 67 | fail: 68 | return 1; 69 | } 70 | --------------------------------------------------------------------------------