From 8731d3d68a688a0fd838b7a2b66ac1d8ae422a1e Mon Sep 17 00:00:00 2001 From: Tyge Date: Wed, 15 Apr 2020 13:41:52 +0200 Subject: - Added cmat3, cmat4, cquat - Changed include folder name to stc - library name - Bug fix, memory leak in map values when overwritten. - Improvements in API --- EXAMPLE.md | 4 +- README.md | 20 +++--- benchmark.cpp | 4 +- stc/carray.h | 24 ++++++- stc/cdefs.h | 8 +-- stc/cmap.h | 60 +++++++++++------ stc/cmat3.h | 138 +++++++++++++++++++++++++++++++++++++++ stc/cmat4.h | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ stc/copt.h | 2 +- stc/cquat.h | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ stc/cstring.h | 102 ++++++++++++++++++++--------- stc/cvec3.h | 189 +++++++++++++++++++++++++++++++++-------------------- stc/cvec4.h | 156 ++++++++++++++++++++++++++++---------------- stc/cvector.h | 70 +++++++++++++------- 14 files changed, 968 insertions(+), 220 deletions(-) create mode 100644 stc/cmat3.h create mode 100644 stc/cmat4.h create mode 100644 stc/cquat.h diff --git a/EXAMPLE.md b/EXAMPLE.md index de1160ce..45be0d02 100644 --- a/EXAMPLE.md +++ b/EXAMPLE.md @@ -10,7 +10,7 @@ The difficulty with the hash function is that if your key type consists of sever Assuming a key-type like this, and want string as value, we define the functions person_make(), person_destroy() and person_compare(): ``` -#include +#include struct Person { @@ -51,7 +51,7 @@ size_t person_hash(const struct Person* p, size_t ignore) { ``` With this in place, you can instantiate a CMap with Person => CString: ``` -#include +#include declare_CMap(ex, struct Person, CString, cstring_destroy, person_hash, person_compare, person_destroy); int main() diff --git a/README.md b/README.md index 359be9fa..fd3781ee 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ccl +# stc Introduction ------------ @@ -10,7 +10,7 @@ Usage ----- CString demo: ``` -#include +#include int main() { CString cs = cstring_make("one-nine-three-seven-five"); @@ -36,7 +36,7 @@ int main() { ``` Simple CVector of 64bit ints: ``` -#include +#include declare_CVector(ix, int64_t); // ix is just an example tag name, use anything without underscore. int main() { @@ -54,8 +54,8 @@ int main() { ``` CVector of CString: ``` -#include -#include +#include +#include declare_CVector(cs, CString, cstring_destroy); // supply inline destructor of values int main() { @@ -70,7 +70,7 @@ int main() { ``` Simple CMap, int -> int: ``` -#include +#include declare_CMap(ii, int, int); int main() { @@ -84,8 +84,8 @@ int main() { ``` Simple CMap, CString -> int: ``` -#include -#include +#include +#include declare_CMap_stringkey(si, int); // Shorthand macro for the general declare_CMap expansion. // CString keys are "magically" managed internally, although CMap is ignorant of CString. @@ -108,8 +108,8 @@ int main() { ``` CMap, with CString -> CString. Temporary CString values are created by "make", and moved to the container. ``` -#include -#include +#include +#include declare_CMap_stringkey(ss, CString, cstring_destroy); int main() { diff --git a/benchmark.cpp b/benchmark.cpp index 79d8edb7..b9abce22 100644 --- a/benchmark.cpp +++ b/benchmark.cpp @@ -2,8 +2,8 @@ #include #include -#include "ccl/cstring.h" -#include "ccl/cmap.h" +#include "stc/cstring.h" +#include "stc/cmap.h" #ifdef __cplusplus #include #include "others/bytell_hash_map.hpp" diff --git a/stc/carray.h b/stc/carray.h index ddb4bd9d..eca07ed4 100644 --- a/stc/carray.h +++ b/stc/carray.h @@ -1,3 +1,25 @@ +// MIT License +// +// Copyright (c) 2020 Tyge Løvset, NORCE, www.norceresearch.no +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + #ifndef CARRAY__H__ #define CARRAY__H__ @@ -10,7 +32,7 @@ #define carray_unref(a) ({if (--(a)._refCount == 0) free((a).data);0;}) /* // demo: -#include "ccl/carray.h" +#include declare_CArray(f, float); int main() diff --git a/stc/cdefs.h b/stc/cdefs.h index 9a29c36b..f58eeeee 100644 --- a/stc/cdefs.h +++ b/stc/cdefs.h @@ -37,7 +37,6 @@ #define c_MACRO_OVERLOAD(NAME, ...) c_OVERLOAD_SELECT(NAME, c_VA_ARG_SIZE(__VA_ARGS__))(__VA_ARGS__) - #define c_new(...) c_MACRO_OVERLOAD(c_new, __VA_ARGS__) #define c_new_1(T) ((T *) malloc(sizeof(T))) #define c_new_2(T, n) ((T *) malloc(sizeof(T) * (n))) @@ -49,14 +48,13 @@ #define c_defaultInitRaw(x) (x) #define c_defaultGetRaw(x) (x) -#define c_defaultCompare(x, y) (*(x) == *(y) ? 0 : *(x) < *(y) ? -1 : 1) +#define c_defaultCompare(x, y) (*(x) == *(y) ? 0 : *(x) < *(y) ? -1 : 1) #define c_defaultEquals(x, y) (memcmp(x, y, sizeof(*(y))) == 0) -#define c_defaultDestroy(p) (p) -//static inline void c_defaultDestroy(void* value) {} +#define c_defaultDestroy(p) ((void)0) #define c_foreach(it, ctag, con) \ for (ctag##_iter_t it = ctag##_begin(con); it.item != ctag##_end(con).item; it = ctag##_next(it)) - + // One-byte-at-a-time hash based on Murmur's mix static inline uint32_t c_defaultHash(const void *data, size_t len) { const uint8_t *key = (const uint8_t *) data; diff --git a/stc/cmap.h b/stc/cmap.h index b14f9e3b..576a01d3 100644 --- a/stc/cmap.h +++ b/stc/cmap.h @@ -43,7 +43,8 @@ static inline struct CMapEntry_##tag cmapentry_##tag##_make(Key key, Value value struct CMapEntry_##tag e = {key, value, 0}; \ return e; \ } \ -static inline void cmapentry_##tag##_destroy(struct CMapEntry_##tag* e) { \ +static inline void \ +cmapentry_##tag##_destroy(struct CMapEntry_##tag* e) { \ keyDestroy(&e->key); \ valueDestroy(&e->value); \ e->hashx = 0; \ @@ -101,7 +102,8 @@ typedef struct cmap_##tag##_iter_t { \ CMapEntry_##tag *item, *_end; \ } cmap_##tag##_iter_t; \ \ -static inline void cmap_##tag##_destroy(CMap_##tag* self) { \ +static inline void \ +cmap_##tag##_destroy(CMap_##tag* self) { \ if (cmap_size(*self)) { \ size_t cap = _cvector_capacity(self->_table); \ CMapEntry_##tag* e = self->_table.data, *end = e + cap; \ @@ -110,30 +112,35 @@ static inline void cmap_##tag##_destroy(CMap_##tag* self) { \ free(_cvector_alloced(self->_table.data)); \ } \ \ -static inline size_t cmap_##tag##_reserve(CMap_##tag* self, size_t size); /* predeclared */ \ +static inline size_t \ +cmap_##tag##_reserve(CMap_##tag* self, size_t size); /* predeclared */ \ \ static inline void cmap_##tag##_clear(CMap_##tag* self) { \ memset(self->_table.data, 0, sizeof(CMapEntry_##tag) * _cvector_capacity(self->_table)); \ self->_size = 0; \ } \ \ -static inline void cmap_##tag##_swap(CMap_##tag* a, CMap_##tag* b) { \ +static inline void \ +cmap_##tag##_swap(CMap_##tag* a, CMap_##tag* b) { \ c_swap(CMap_##tag, *a, *b); \ } \ \ -static inline void cmap_##tag##_setMaxLoadFactor(CMap_##tag* self, double fac) { \ +static inline void \ +cmap_##tag##_setMaxLoadFactor(CMap_##tag* self, double fac) { \ self->maxLoadPercent = (uint8_t) (fac * 100); \ if (cmap_size(*self) >= cmap_bucketCount(*self) * fac) \ cmap_##tag##_reserve(self, (size_t) (cmap_size(*self) / fac)); \ } \ \ -static inline void cmap_##tag##_setShrinkLimitFactor(CMap_##tag* self, double limit) { \ +static inline void \ +cmap_##tag##_setShrinkLimitFactor(CMap_##tag* self, double limit) { \ self->shrinkLimitPercent = (uint8_t) (limit * 100); \ if (cmap_size(*self) < cmap_bucketCount(*self) * limit) \ cmap_##tag##_reserve(self, (size_t) (cmap_size(*self) * 1.2 / limit)); \ } \ \ -static inline size_t cmap_##tag##_bucket(CMap_##tag* self, cmap_##tag##_rawkey_t* const rawKey, uint32_t* hxPtr) { \ +static inline size_t \ +cmap_##tag##_bucket(CMap_##tag* self, cmap_##tag##_rawkey_t* const rawKey, uint32_t* hxPtr) { \ uint32_t hash = keyHashRaw(rawKey, sizeof(cmap_##tag##_rawkey_t)), hx = (hash & cmapentry_HASH) | cmapentry_USED; \ size_t cap = cvector_capacity(self->_table); \ size_t idx = cmap_reduce(hash, cap); \ @@ -145,25 +152,30 @@ static inline size_t cmap_##tag##_bucket(CMap_##tag* self, cmap_##tag##_rawkey_t return idx; \ } \ \ -static inline CMapEntry_##tag* cmap_##tag##_get(CMap_##tag map, cmap_##tag##_rawkey_t rawKey) { \ +static inline CMapEntry_##tag* \ +cmap_##tag##_get(CMap_##tag map, cmap_##tag##_rawkey_t rawKey) { \ if (cmap_size(map) == 0) return NULL; \ uint32_t hx; \ size_t idx = cmap_##tag##_bucket(&map, &rawKey, &hx); \ return map._table.data[idx].hashx ? &map._table.data[idx] : NULL; \ } \ \ -static inline void cmap_##tag##_expand(CMap_##tag* self) { \ +static inline void \ +cmap_##tag##_expand(CMap_##tag* self) { \ size_t cap = cvector_capacity(self->_table); \ if (cmap_size(*self) + 1 >= cap * self->maxLoadPercent * 0.01) \ cmap_##tag##_reserve(self, (size_t) 7 + (1.6 * cap)); \ } \ \ -static inline CMapEntry_##tag* cmap_##tag##_put(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey, Value value) { \ +static inline CMapEntry_##tag* \ +cmap_##tag##_put(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey, Value value) { \ cmap_##tag##_expand(self); \ uint32_t hx; \ size_t idx = cmap_##tag##_bucket(self, &rawKey, &hx); \ CMapEntry_##tag* e = &self->_table.data[idx]; \ - if (! e->hashx) { \ + if (e->hashx) \ + valueDestroy(&e->value); \ + else { \ e->key = keyInitRaw(rawKey); \ e->hashx = hx; \ ++self->_size; \ @@ -171,13 +183,16 @@ static inline CMapEntry_##tag* cmap_##tag##_put(CMap_##tag* self, cmap_##tag##_r e->value = value; \ return e; \ } \ - \ -static inline CMapEntry_##tag* cmap_##tag##_insert(CMap_##tag* self, CMapEntry_##tag entry) { \ +/* \ +static inline CMapEntry_##tag* \ +cmap_##tag##_insert(CMap_##tag* self, CMapEntry_##tag entry) { \ cmap_##tag##_expand(self); \ uint32_t hx; \ size_t idx = cmap_##tag##_bucket(self, (RawKey* const) keyGetRaw(&entry.key), &hx); \ CMapEntry_##tag* e = &self->_table.data[idx]; \ - if (! e->hashx) { \ + if (e->hashx) \ + valueDestroy(&e->value); \ + else { \ e->key = entry.key; \ e->hashx = hx; \ ++self->_size; \ @@ -185,8 +200,9 @@ static inline CMapEntry_##tag* cmap_##tag##_insert(CMap_##tag* self, CMapEntry_# e->value = entry.value; \ return e; \ } \ - \ -static inline size_t cmap_##tag##_reserve(CMap_##tag* self, size_t size) { \ +*/ \ +static inline size_t \ +cmap_##tag##_reserve(CMap_##tag* self, size_t size) { \ size_t oldcap = cvector_capacity(self->_table), newcap = 1 + (size / 2) * 2; \ if (cmap_size(*self) >= newcap * self->maxLoadPercent * 0.01) return oldcap; \ CVector_map_##tag vec = cvector_map_##tag##_init; \ @@ -203,7 +219,8 @@ static inline size_t cmap_##tag##_reserve(CMap_##tag* self, size_t size) { \ return newcap; \ } \ \ -static inline bool cmap_##tag##_erase(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey) { \ +static inline bool \ +cmap_##tag##_erase(CMap_##tag* self, cmap_##tag##_rawkey_t rawKey) { \ if (cmap_size(*self) == 0) \ return false; \ size_t cap = cvector_capacity(self->_table); \ @@ -227,7 +244,8 @@ static inline bool cmap_##tag##_erase(CMap_##tag* self, cmap_##tag##_rawkey_t ra return true; \ } \ \ -static inline cmap_##tag##_iter_t cmap_##tag##_begin(CMap_##tag map) { \ +static inline cmap_##tag##_iter_t \ +cmap_##tag##_begin(CMap_##tag map) { \ cmap_##tag##_iter_t null = {NULL, NULL}; \ if (cmap_size(map) == 0) return null; \ CMapEntry_##tag* e = map._table.data, *end = e + _cvector_capacity(map._table); \ @@ -235,12 +253,14 @@ static inline cmap_##tag##_iter_t cmap_##tag##_begin(CMap_##tag map) { \ cmap_##tag##_iter_t it = {e, end}; return it; \ } \ \ -static inline cmap_##tag##_iter_t cmap_##tag##_next(cmap_##tag##_iter_t it) { \ +static inline cmap_##tag##_iter_t \ +cmap_##tag##_next(cmap_##tag##_iter_t it) { \ do { ++it.item; } while (it.item != it._end && !it.item->hashx); \ return it; \ } \ \ -static inline cmap_##tag##_iter_t cmap_##tag##_end(CMap_##tag map) { \ +static inline cmap_##tag##_iter_t \ +cmap_##tag##_end(CMap_##tag map) { \ CMapEntry_##tag* end = (cmap_size(map) == 0) ? NULL : map._table.data + _cvector_capacity(map._table); \ cmap_##tag##_iter_t it = {end, end}; \ return it; \ diff --git a/stc/cmat3.h b/stc/cmat3.h new file mode 100644 index 00000000..95d5d7f1 --- /dev/null +++ b/stc/cmat3.h @@ -0,0 +1,138 @@ +// MIT License +// +// Copyright (c) 2020 Tyge Løvset, NORCE, www.norceresearch.no +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef CMAT3__H__ +#define CMAT3__H__ + +#include "cvec3.h" + +#define cmat3_identity_init {1, 0, 0, 0, 1, 0, 0, 0, 1} +#define cmat3_zero_init {0, 0, 0, 0, 0, 0, 0, 0, 0} + +#define cmat3f_identity ((CMat3f) cmat3_identity_init) +#define cmat3d_identity ((CMat3d) cmat3_identity_init) +#define cmat3f_zero ((CMat3f) cmat3_zero_init) +#define cmat3d_zero ((CMat3d) cmat3_zero_init) + +#define declare_CMat3(tag, T) \ + typedef T (*CMat3##tag##Raw)[3]; \ + typedef const T (*CMat3##tag##ConstRaw)[3]; \ + \ + typedef union CMat3##tag { \ + CVec3##tag v[3]; \ + T m[3][3], arr[3*3]; \ + } CMat3##tag; \ + \ + static inline CMat3##tag \ + cmat3##tag##_mult(CMat3##tag##ConstRaw m1, CMat3##tag##ConstRaw m2) { \ + const T *a = m1[0], *b = m2[0]; \ + return (CMat3##tag) { \ + a[0] * b[0] + a[3] * b[1] + a[6] * b[2], \ + a[1] * b[0] + a[4] * b[1] + a[7] * b[2], \ + a[2] * b[0] + a[5] * b[1] + a[8] * b[2], \ + a[0] * b[3] + a[3] * b[4] + a[6] * b[5], \ + a[1] * b[3] + a[4] * b[4] + a[7] * b[5], \ + a[2] * b[3] + a[5] * b[4] + a[8] * b[5], \ + a[0] * b[6] + a[3] * b[7] + a[6] * b[8], \ + a[1] * b[6] + a[4] * b[7] + a[7] * b[8], \ + a[2] * b[6] + a[5] * b[7] + a[8] * b[8], \ + }; \ + } \ + \ + static inline CMat3##tag* \ + cmat3##tag##_scale(CMat3##tag* self, T s) { \ + T* a = self->arr; \ + a[0] *= s, a[1] *= s, a[2] *= s, \ + a[3] *= s, a[4] *= s, a[5] *= s, \ + a[6] *= s, a[7] *= s, a[8] *= s; \ + return self; \ + } \ + static inline CMat3##tag \ + cmat3##tag##_scalarMult(CMat3##tag##ConstRaw m, T s) { \ + CMat3##tag dst; \ + T *c = dst.arr; const T *a = m[0]; \ + for (int i = 0; i < 9; ++i) *c++ = *a++ * s; \ + return dst; \ + } \ + static inline CMat3##tag \ + cmat3##tag##_compMult(CMat3##tag##ConstRaw m1, CMat3##tag##ConstRaw m2) { \ + CMat3##tag dst; \ + T *c = dst.arr; const T *a = m1[0], *b = m2[0]; \ + for (int i = 0; i < 9; ++i) *c++ = *a++ * *b++; \ + return dst; \ + } \ + static inline CVec3##tag \ + cmat3##tag##_vecMult(CMat3##tag##ConstRaw m, CVec3##tag v) { \ + return (CVec3##tag) { \ + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z, \ + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z, \ + m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z, \ + }; \ + } \ + \ + static inline CMat3##tag \ + cmat3##tag##_transpose(CMat3##tag##ConstRaw m) { \ + return (CMat3##tag) { \ + m[0][0], m[1][0], m[2][0], \ + m[0][1], m[1][1], m[2][1], \ + m[0][2], m[1][2], m[2][2], \ + }; \ + } \ + \ + static inline T \ + cmat3##tag##_trace(CMat3##tag##ConstRaw m) { \ + return m[0][0] + m[1][1] + m[2][2]; \ + } \ + \ + \ + static inline T \ + cmat3##tag##_determinant(CMat3##tag##ConstRaw m) { \ + const T *a = m[0]; \ + return a[0] * (a[4] * a[8] - a[7] * a[5]) \ + - a[3] * (a[1] * a[8] - a[2] * a[7]) \ + + a[6] * (a[1] * a[5] - a[2] * a[4]); \ + } \ + \ + static inline CMat3##tag \ + cmat3##tag##_inverse(CMat3##tag##ConstRaw m) { \ + const T *a = m[0]; \ + T k = 1.0f / cmat3##tag##_determinant(m); \ + return (CMat3##tag) { \ + (a[4] * a[8] - a[5] * a[7]) * k, \ + -(a[1] * a[8] - a[7] * a[2]) * k, \ + (a[1] * a[5] - a[4] * a[2]) * k, \ + -(a[3] * a[8] - a[6] * a[5]) * k, \ + (a[0] * a[8] - a[2] * a[6]) * k, \ + -(a[0] * a[5] - a[3] * a[2]) * k, \ + (a[3] * a[7] - a[6] * a[4]) * k, \ + -(a[0] * a[7] - a[6] * a[1]) * k, \ + (a[0] * a[4] - a[1] * a[3]) * k, \ + }; \ + } \ + \ + typedef T cmat3##tag##_value_t + +declare_CMat3(d, double); +declare_CMat3(f, float); + + +#endif diff --git a/stc/cmat4.h b/stc/cmat4.h new file mode 100644 index 00000000..18581c17 --- /dev/null +++ b/stc/cmat4.h @@ -0,0 +1,205 @@ +// MIT License +// +// Copyright (c) 2020 Tyge Løvset, NORCE, www.norceresearch.no +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef CMAT4__H__ +#define CMAT4__H__ + +#include "cmat3.h" +#include "cvec4.h" + +#define cmat4_identity_init {1, 0, 0, 0, 0, 1, 0, 0, \ + 0, 0, 1, 0, 0, 0, 0, 1} +#define cmat4_zero_init {0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0} + +#define cmat4f_identity ((CMat4f) cmat4_identity_init) +#define cmat4d_identity ((CMat4d) cmat4_identity_init) +#define cmat4f_zero ((CMat4f) cmat4_zero_init) +#define cmat4d_zero ((CMat4d) cmat4_zero_init) + +#define declare_CMat4(tag, T) \ + typedef T (*CMat4##tag##Raw)[4]; \ + typedef const T (*CMat4##tag##ConstRaw)[4]; \ + \ + typedef union CMat4##tag { \ + CVec4##tag v[4]; \ + T m[4][4], arr[4*4]; \ + } CMat4##tag; \ + \ + static inline CMat4##tag \ + cmat4##tag##_mult(CMat4##tag##ConstRaw mat1, CMat4##tag##ConstRaw mat2) { \ + const T *a = mat1[0], *b = mat2[0]; \ + return (CMat4##tag) { \ + a[ 0] * b[ 0] + a[ 4] * b[ 1] + a[ 8] * b[ 2] + a[12] * b[ 3], \ + a[ 1] * b[ 0] + a[ 5] * b[ 1] + a[ 9] * b[ 2] + a[13] * b[ 3], \ + a[ 2] * b[ 0] + a[ 6] * b[ 1] + a[10] * b[ 2] + a[14] * b[ 3], \ + a[ 3] * b[ 0] + a[ 7] * b[ 1] + a[11] * b[ 2] + a[15] * b[ 3], \ + a[ 0] * b[ 4] + a[ 4] * b[ 5] + a[ 8] * b[ 6] + a[12] * b[ 7], \ + a[ 1] * b[ 4] + a[ 5] * b[ 5] + a[ 9] * b[ 6] + a[13] * b[ 7], \ + a[ 2] * b[ 4] + a[ 6] * b[ 5] + a[10] * b[ 6] + a[14] * b[ 7], \ + a[ 3] * b[ 4] + a[ 7] * b[ 5] + a[11] * b[ 6] + a[15] * b[ 7], \ + a[ 0] * b[ 8] + a[ 4] * b[ 9] + a[ 8] * b[10] + a[12] * b[11], \ + a[ 1] * b[ 8] + a[ 5] * b[ 9] + a[ 9] * b[10] + a[13] * b[11], \ + a[ 2] * b[ 8] + a[ 6] * b[ 9] + a[10] * b[10] + a[14] * b[11], \ + a[ 3] * b[ 8] + a[ 7] * b[ 9] + a[11] * b[10] + a[15] * b[11], \ + a[ 0] * b[12] + a[ 4] * b[13] + a[ 8] * b[14] + a[12] * b[15], \ + a[ 1] * b[12] + a[ 5] * b[13] + a[ 9] * b[14] + a[13] * b[15], \ + a[ 2] * b[12] + a[ 6] * b[13] + a[10] * b[14] + a[14] * b[15], \ + a[ 3] * b[12] + a[ 7] * b[13] + a[11] * b[14] + a[15] * b[15], \ + }; \ + } \ + \ + static inline CMat4##tag* \ + cmat4##tag##_scale(CMat4##tag* self, T s) { \ + T* a = self->arr; \ + for (int i = 0; i < 16; ++i) *a++ *= s; \ + return self; \ + } \ + static inline CMat4##tag \ + cmat4##tag##_scalarMult(CMat4##tag##ConstRaw m, T s) { \ + CMat4##tag dst; \ + T *c = dst.arr; const T *a = m[0]; \ + for (int i = 0; i < 16; ++i) *c++ = *a++ * s; \ + return dst; \ + } \ + static inline CMat4##tag \ + cmat4##tag##_compMult(CMat4##tag##ConstRaw m1, CMat4##tag##ConstRaw m2) { \ + CMat4##tag dst; \ + T *c = dst.arr; const T *a = m1[0], *b = m2[0]; \ + for (int i = 0; i < 16; ++i) *c++ = *a++ * *b++; \ + return dst; \ + } \ + static inline CVec4##tag \ + cmat4##tag##_vecMult(CMat4##tag##ConstRaw m, CVec4##tag v) { \ + return (CVec4##tag) { \ + m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w, \ + m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w, \ + m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * v.w, \ + m[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z + m[3][3] * v.w, \ + }; \ + } \ + \ + static inline CMat4##tag \ + cmat4##tag##_transpose(CMat4##tag##ConstRaw m) { \ + return (CMat4##tag) { \ + m[0][0], m[1][0], m[2][0], m[3][0], \ + m[0][1], m[1][1], m[2][1], m[3][1], \ + m[0][2], m[1][2], m[2][2], m[3][2], \ + m[0][3], m[1][3], m[2][3], m[3][3], \ + }; \ + } \ + \ + static inline CMat3##tag \ + cmat4##tag##_transpose3(CMat4##tag##ConstRaw m) { \ + return (CMat3##tag) { \ + m[0][0], m[1][0], m[2][0], \ + m[0][1], m[1][1], m[2][1], \ + m[0][2], m[1][2], m[2][2], \ + }; \ + } \ + \ + static inline CMat3##tag \ + cmat4##tag##_to3(CMat4##tag##ConstRaw m) { \ + return (CMat3##tag) { \ + m[0][0], m[0][1], m[0][2], \ + m[1][0], m[1][1], m[1][2], \ + m[2][0], m[2][1], m[2][2], \ + }; \ + } \ + \ + static inline T \ + cmat4##tag##_trace(CMat4##tag##ConstRaw m) { \ + return m[0][0] + m[1][1] + m[2][2] + m[3][3]; \ + } \ + \ + static inline T \ + cmat4##tag##_determinant(CMat4##tag##ConstRaw mat) { \ + const T *p = mat[0]; \ + T a, b, c, d, e, f; \ + a = p[10] * p[15] - p[14] * p[11], \ + b = p[ 9] * p[15] - p[13] * p[11], \ + c = p[ 9] * p[14] - p[13] * p[10], \ + d = p[ 8] * p[15] - p[12] * p[11], \ + e = p[ 8] * p[14] - p[12] * p[10], \ + f = p[ 8] * p[13] - p[12] * p[ 9]; \ + return p[0] * (p[5] * a - p[6] * b + p[7] * c) \ + - p[1] * (p[4] * a - p[6] * d + p[7] * e) \ + + p[2] * (p[4] * b - p[5] * d + p[7] * f) \ + - p[3] * (p[4] * c - p[5] * e + p[6] * f); \ + } \ + \ + \ + static inline CMat4##tag \ + cmat4##tag##_inverse(CMat4##tag##ConstRaw mat) { \ + CMat4##tag dst; \ + const T *p = mat[0]; \ + T a, b, c, d, e, f, det; \ + a = p[10] * p[15] - p[14] * p[11], \ + b = p[ 9] * p[15] - p[13] * p[11], \ + c = p[ 9] * p[14] - p[13] * p[10], \ + d = p[ 8] * p[15] - p[12] * p[11], \ + e = p[ 8] * p[14] - p[12] * p[10], \ + f = p[ 8] * p[13] - p[12] * p[ 9]; \ + dst.m[0][0] = (p[5] * a - p[6] * b + p[7] * c); \ + dst.m[1][0] = -(p[4] * a - p[6] * d + p[7] * e); \ + dst.m[2][0] = (p[4] * b - p[5] * d + p[7] * f); \ + dst.m[3][0] = -(p[4] * c - p[5] * e + p[6] * f); \ + \ + dst.m[0][1] = -(p[1] * a - p[2] * b + p[3] * c); \ + dst.m[1][1] = (p[0] * a - p[2] * d + p[3] * e); \ + dst.m[2][1] = -(p[0] * b - p[1] * d + p[3] * f); \ + dst.m[3][1] = (p[0] * c - p[1] * e + p[2] * f); \ + \ + a = p[6] * p[15] - p[14] * p[7], \ + b = p[5] * p[15] - p[13] * p[7], \ + c = p[5] * p[14] - p[13] * p[6], \ + d = p[4] * p[15] - p[12] * p[7], \ + e = p[4] * p[14] - p[12] * p[6], \ + f = p[4] * p[13] - p[12] * p[5]; \ + dst.m[0][2] = (p[1] * a - p[2] * b + p[3] * c); \ + dst.m[1][2] = -(p[0] * a - p[2] * d + p[3] * e); \ + dst.m[2][2] = (p[0] * b - p[1] * d + p[3] * f); \ + dst.m[3][2] = -(p[0] * c - p[1] * e + p[2] * f); \ + \ + a = p[6] * p[11] - p[10] * p[7], \ + b = p[5] * p[11] - p[ 9] * p[7], \ + c = p[5] * p[10] - p[ 9] * p[6], \ + d = p[4] * p[11] - p[ 8] * p[7], \ + e = p[4] * p[10] - p[ 8] * p[6], \ + f = p[4] * p[ 9] - p[ 8] * p[5]; \ + dst.m[0][3] = -(p[1] * a - p[2] * b + p[3] * c); \ + dst.m[1][3] = (p[0] * a - p[2] * d + p[3] * e); \ + dst.m[2][3] = -(p[0] * b - p[1] * d + p[3] * f); \ + dst.m[3][3] = (p[0] * c - p[1] * e + p[2] * f); \ + \ + det = p[0] * dst.m[0][0] + p[1] * dst.m[1][0] \ + + p[2] * dst.m[2][0] + p[3] * dst.m[3][0]; \ + return *cmat4##tag##_scale(&dst, 1.0f / det); \ + } \ + \ + typedef T cmat4##tag##_value_t + +declare_CMat4(d, double); +declare_CMat4(f, float); + + +#endif diff --git a/stc/copt.h b/stc/copt.h index fb810e10..5c512698 100644 --- a/stc/copt.h +++ b/stc/copt.h @@ -153,7 +153,7 @@ static int copt_getopt(copt_t *opt, int argc, char *argv[], /* // demo: int main(int argc, char *argv[]) { - static struct copt_option longopts[] = { + struct copt_option longopts[] = { {"foo", copt_no_argument, 'f'}, {"bar", copt_required_argument, 'b'}, {"opt", copt_optional_argument, 'o'}, diff --git a/stc/cquat.h b/stc/cquat.h new file mode 100644 index 00000000..280a7e80 --- /dev/null +++ b/stc/cquat.h @@ -0,0 +1,206 @@ +// MIT License +// +// Copyright (c) 2020 Tyge Løvset, NORCE, www.norceresearch.no +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef CQUAT__H__ +#define CQUAT__H__ + +#include "cmat4.h" + +#define cquat_arr(q) (&(q).x) +#define cquatf_identity ((CQuatf) {0.f, 0.f, 0.f, 1.f}) +#define cquatd_identity ((CQuatd) {0.0, 0.0, 0.0, 1.0}) + +#define declare_CQuat(tag, T) \ + typedef CVec4##tag CQuat##tag; \ + \ + static inline CQuat##tag \ + cquat##tag(T x, T y, T z, T w) { return (CQuat##tag) {x, y, z, w}; } \ + \ + static inline CQuat##tag \ + cquat##tag##_unit(CQuat##tag q) { \ + T dot = _cvec4_DOT(q, q); \ + if (dot <= 0.0f) return cquat##tag##_identity; \ + return cvec4##tag##_mult(q, 1.0f / c_sqrt_##tag(dot)); \ + } \ + \ + static inline CQuat##tag \ + cquat##tag##_fromAxis(T angle, CVec3##tag axis) { \ + T a = angle * 0.5f, c = c_cos_##tag(a), s = c_sin_##tag(a); \ + CVec3##tag u = cvec3##tag##_unit(axis); \ + return (CQuat##tag) {s * u.x, s * u.y, s * u.z, c}; \ + } \ + \ + static inline CQuat##tag \ + cquat##tag##_fromVectors(CVec3##tag u, CVec3##tag v) { \ + T norm_u_norm_v = c_sqrt_##tag(cvec3##tag##_dot(u, u) * cvec3##tag##_dot(v, v)); \ + T real_part = norm_u_norm_v + cvec3##tag##_dot(u, v); \ + CVec3##tag t; \ + if (real_part < 1.e-6f * norm_u_norm_v) { \ + /* If u and v are exactly opposite, rotate 180 degrees */ \ + /* around an arbitrary orthogonal axis. */ \ + real_part = 0; \ + t = fabs(u.x) > fabs(u.z) ? (CVec3##tag) {-u.y, u.x, 0} : (CVec3##tag) {0, -u.z, u.y}; \ + } else \ + t = cvec3##tag##_cross(u, v); /* Otherwise, build quaternion the standard way.*/ \ + CQuat##tag q = (CQuat##tag) {t.x, t.y, t.z, real_part}; \ + return cquat##tag##_unit(q); \ + } \ + \ + static inline CQuat##tag \ + cquat##tag##_fromMat4(CMat4##tag##ConstRaw m) { \ + T trace = m[0][0] + m[1][1] + m[2][2], r, rinv; \ + CQuat##tag dst; \ + if (trace >= 0.0f) { \ + r = c_sqrt_##tag(1.0f + trace); \ + rinv = 0.5f / r; \ + dst.x = rinv * (m[1][2] - m[2][1]); \ + dst.y = rinv * (m[2][0] - m[0][2]); \ + dst.z = rinv * (m[0][1] - m[1][0]); \ + dst.w = r * 0.5f; \ + } else if (m[0][0] >= m[1][1] && m[0][0] >= m[2][2]) { \ + r = c_sqrt_##tag(1.0f + m[0][0] - m[1][1] - m[2][2]); \ + rinv = 0.5f / r; \ + dst.x = r * 0.5f; \ + dst.y = rinv * (m[0][1] + m[1][0]); \ + dst.z = rinv * (m[0][2] + m[2][0]); \ + dst.w = rinv * (m[1][2] - m[2][1]); \ + } else if (m[1][1] >= m[2][2]) { \ + r = c_sqrt_##tag(1.0f - m[0][0] + m[1][1] - m[2][2]); \ + rinv = 0.5f / r; \ + dst.x = rinv * (m[0][1] + m[1][0]); \ + dst.y = r * 0.5f; \ + dst.z = rinv * (m[1][2] + m[2][1]); \ + dst.w = rinv * (m[2][0] - m[0][2]); \ + } else { \ + r = c_sqrt_##tag(1.0f - m[0][0] - m[1][1] + m[2][2]); \ + rinv = 0.5f / r; \ + dst.x = rinv * (m[0][2] + m[2][0]); \ + dst.y = rinv * (m[1][2] + m[2][1]); \ + dst.z = r * 0.5f; \ + dst.w = rinv * (m[0][1] - m[1][0]); \ + } \ + return dst; \ + } \ + \ + static inline CMat4##tag \ + cquat##tag##_toMat4(CQuat##tag q) { \ + CMat4##tag dst; \ + T norm = cquat##tag##_length(q), \ + s = norm > 0.0f ? 2.0f / norm : 0.0f, \ + xx = s * q.x * q.x, xy = s * q.x * q.y, wx = s * q.w * q.x, \ + yy = s * q.y * q.y, yz = s * q.y * q.z, wy = s * q.w * q.y, \ + zz = s * q.z * q.z, xz = s * q.x * q.z, wz = s * q.w * q.z; \ + \ + dst.m[0][0] = 1.0f - yy - zz; \ + dst.m[1][1] = 1.0f - xx - zz; \ + dst.m[2][2] = 1.0f - xx - yy; \ + dst.m[0][1] = xy + wz; \ + dst.m[1][2] = yz + wx; \ + dst.m[2][0] = xz + wy; \ + dst.m[1][0] = xy - wz; \ + dst.m[2][1] = yz - wx; \ + dst.m[0][2] = xz - wy; \ + dst.m[0][3] = dst.m[1][3] = dst.m[2][3] = 0.0f; \ + dst.m[3][0] = dst.m[3][1] = dst.m[3][2] = 0.0f; \ + dst.m[3][3] = 1.0f; \ + return dst; \ + } \ + \ + static inline CQuat##tag \ + cquat##tag##_conjugate(CQuat##tag q) { \ + q.x = -q.x, q.y = -q.y, q.z = -q.z; \ + return q; \ + } \ + \ + static inline CQuat##tag \ + cquat##tag##_cross(CQuat##tag p, CQuat##tag q) { \ + return (CQuat##tag) {p.w * q.x + p.x * q.w + p.y * q.z - p.z * q.y, \ + p.w * q.y - p.x * q.z + p.y * q.w + p.z * q.x, \ + p.w * q.z + p.x * q.y - p.y * q.x + p.z * q.w, \ + p.w * q.w - p.x * q.x - p.y * q.y - p.z * q.z}; \ + } \ + static inline CQuat##tag \ + cquat##tag##_inverse(CQuat##tag q) { \ + q.x = -q.x, q.y = -q.y, q.z = -q.z; \ + return cvec4##tag##_mult(q, 1.0f / _cvec4_DOT(q, q)); \ + } \ + static inline T \ + cquat##tag##_angle(CQuat##tag q) { \ + /* sin(theta / 2) = length(x*x + y*y + z*z) */ \ + /* cos(theta / 2) = w */ \ + /* theta = 2 * atan(sin(theta / 2) / cos(theta / 2)) */ \ + return 2.0f * c_atan2_##tag(c_sqrt_##tag(_cvec3_DOT(q, q)), q.w); \ + } \ + static inline T \ + cquat##tag##_imagLength(CQuat##tag q) { \ + return c_sqrt_##tag(_cvec3_DOT(q, q)); \ + } \ + typedef T cquat##tag##_value_t + +#define cquatf_fromArray(arr) cvec4f_fromArray(arr) +#define cquatd_fromArray(arr) cvec4d_fromArray(arr) + +#define cquatf_assign(q, x, y, z, w) cvec4f_assign(q, x, y, z, w) +#define cquatd_assign(q, x, y, z, w) cvec4d_assign(q, x, y, z, w) + +#define cquatf_assignArray(q, arr) cvec4f_assignArray(q, arr) +#define cquatd_assignArray(q, arr) cvec4d_assignArray(q, arr) + +#define cquatf_length(q) cvec4f_length(q) +#define cquatd_length(q) cvec4d_length(q) + +#define cquatf_length2(q) cvec4f_length2(q) +#define cquatd_length2(q) cvec4d_length2(q) + +#define cquatf_dot(p, q) cvec4f_dot(p, q) +#define cquatd_dot(p, q) cvec4d_dot(p, q) + +#define cquatf_lerp(p, q, t) cvec4f_lerp(p, q, t) +#define cquatd_lerp(p, q, t) cvec4d_lerp(p, q, t) + +#define cquatf_swizzle(q, swz) cvec4f_swizzle(q, swz) +#define cquatd_swizzle(q, swz) cvec4d_swizzle(q, swz) + +#define cquatf_equals(p, q) cvec4f_equals(p, q) +#define cquatd_equals(p, q) cvec4d_equals(p, q) + +#define cquatf_compare(p, q) cvec4f_compare(p, q) +#define cquatd_compare(p, q) cvec4d_compare(p, q) + +#define cquatf_imag(q) cvec4f_to3(q) +#define cquatd_imag(q) cvec4d_to3(q) + +#define cquatf_real(q) ((float) (q).w) +#define cquatd_real(q) ((double) (q).w) + +declare_CQuat(f, float); +declare_CQuat(d, double); + + +static inline CQuatd cquatf_tod(CQuatf v) { + return (CQuatd) {v.x, v.y, v.z, v.w}; +} +static inline CQuatf cquatd_tof(CQuatd v) { + return (CQuatf) {(float) v.x, (float) v.y, (float) v.z, (float) v.w}; +} + +#endif diff --git a/stc/cstring.h b/stc/cstring.h index d0719cb6..ccc8c309 100644 --- a/stc/cstring.h +++ b/stc/cstring.h @@ -45,7 +45,8 @@ static size_t _cstring_null_rep[] = {0, 0, 0}; static const CString cstring_init = {(char* ) &_cstring_null_rep[2]}; -static inline void cstring_reserve(CString* self, size_t cap) { +static inline void +cstring_reserve(CString* self, size_t cap) { size_t len = cstring_size(*self), oldcap = cstring_capacity(*self); if (cap > oldcap) { size_t* rep = (size_t *) realloc(oldcap ? _cstring_rep(*self) : NULL, sizeof(size_t) * 2 + cap + 1); @@ -55,13 +56,30 @@ static inline void cstring_reserve(CString* self, size_t cap) { } } -static inline void cstring_destroy(CString* self) { +static inline void +cstring_resize(CString* self, size_t len, char fill) { + size_t n = cstring_size(*self); + cstring_reserve(self, len); + if (len > n) memset(self->str + n, fill, len - n); + self->str[ _cstring_rep(*self)[0] = len ] = '\0'; +} + +static inline void +cstring_destroy(CString* self) { if (cstring_capacity(*self)) { free(_cstring_rep(*self)); } } -static inline CString cstring_makeN(const char* str, size_t len) { +static inline CString +cstring_makeFill(size_t len, char fill) { + CString cs = cstring_init; + if (len) cstring_resize(&cs, len, fill); + return cs; +} + +static inline CString +cstring_makeN(const char* str, size_t len) { CString cs = cstring_init; if (len) { cstring_reserve(&cs, len); @@ -71,21 +89,25 @@ static inline CString cstring_makeN(const char* str, size_t len) { return cs; } -static inline CString cstring_make(const char* str) { +static inline CString +cstring_make(const char* str) { return cstring_makeN(str, strlen(str)); } -static inline CString cstring_makeCopy(CString cs) { +static inline CString +cstring_makeCopy(CString cs) { return cstring_makeN(cs.str, cstring_size(cs)); } -static inline void cstring_clear(CString* self) { +static inline void +cstring_clear(CString* self) { CString cs = cstring_init; cstring_destroy(self); *self = cs; } -static inline CString* cstring_assignN(CString* self, const char* str, size_t len) { +static inline CString* +cstring_assignN(CString* self, const char* str, size_t len) { if (len) { cstring_reserve(self, len); memmove(self->str, str, len); @@ -94,16 +116,19 @@ static inline CString* cstring_assignN(CString* self, const char* str, size_t le return self; } -static inline CString* cstring_assign(CString* self, const char* str) { +static inline CString* +cstring_assign(CString* self, const char* str) { return cstring_assignN(self, str, strlen(str)); } -static inline CString* cstring_copy(CString* self, CString cs2) { +static inline CString* +cstring_copy(CString* self, CString cs2) { return cstring_assignN(self, cs2.str, cstring_size(cs2)); } -static inline CString* cstring_appendN(CString* self, const char* str, size_t len) { +static inline CString* +cstring_appendN(CString* self, const char* str, size_t len) { if (len) { size_t oldlen = cstring_size(*self), newlen = oldlen + len; if (newlen > cstring_capacity(*self)) @@ -114,10 +139,12 @@ static inline CString* cstring_appendN(CString* self, const char* str, size_t le return self; } -static inline CString* cstring_append(CString* self, const char* str) { +static inline CString* +cstring_append(CString* self, const char* str) { return cstring_appendN(self, str, strlen(str)); } -static inline CString* cstring_appendS(CString* self, CString cs2) { +static inline CString* +cstring_appendS(CString* self, CString cs2) { return cstring_appendN(self, cs2.str, cstring_size(cs2)); } @@ -132,18 +159,21 @@ static inline void _cstring_internalMove(CString* self, size_t pos1, size_t pos2 self->str[_cstring_rep(*self)[0] = newlen] = '\0'; } -static inline void cstring_insertN(CString* self, size_t pos, const char* str, size_t n) { +static inline void +cstring_insertN(CString* self, size_t pos, const char* str, size_t n) { char* xstr = (char *) memcpy(n > c_max_alloca ? malloc(n) : alloca(n), str, n); _cstring_internalMove(self, pos, pos + n); memcpy(&self->str[pos], xstr, n); if (n > c_max_alloca) free(xstr); } -static inline void cstring_insert(CString* self, size_t pos, const char* str) { +static inline void +cstring_insert(CString* self, size_t pos, const char* str) { cstring_insertN(self, pos, str, strlen(str)); } -static inline void cstring_erase(CString* self, size_t pos, size_t n) { +static inline void +cstring_erase(CString* self, size_t pos, size_t n) { size_t len = cstring_size(*self); if (len) { memmove(&self->str[pos], &self->str[pos + n], len - (pos + n)); @@ -153,7 +183,8 @@ static inline void cstring_erase(CString* self, size_t pos, size_t n) { static inline size_t cstring_findN(CString cs, size_t pos, const char* needle, size_t n); -static inline size_t cstring_replaceN(CString* self, size_t pos, const char* s1, size_t n1, const char* s2, size_t n2) { +static inline size_t +cstring_replaceN(CString* self, size_t pos, const char* s1, size_t n1, const char* s2, size_t n2) { size_t pos2 = cstring_findN(*self, pos, s1, n1); if (pos2 == cstring_npos) return cstring_npos; char* xs2 = (char *) memcpy(n2 > c_max_alloca ? malloc(n2) : alloca(n2), s2, n2); @@ -163,38 +194,46 @@ static inline size_t cstring_replaceN(CString* self, size_t pos, const char* s1, return pos2; } -static inline size_t cstring_replace(CString* self, size_t pos, const char* s1, const char* s2) { +static inline size_t +cstring_replace(CString* self, size_t pos, const char* s1, const char* s2) { return cstring_replaceN(self, pos, s1, strlen(s1), s2, strlen(s2)); } -static inline char cstring_back(CString cs) { +static inline char +cstring_back(CString cs) { return cs.str[cstring_size(cs) - 1]; } -static inline CString* cstring_push(CString* self, char value) { +static inline CString* +cstring_push(CString* self, char value) { return cstring_appendN(self, &value, 1); } -static inline void cstring_pop(CString* self) { +static inline void +cstring_pop(CString* self) { --_cstring_rep(*self)[0]; } /* readonly */ -static inline bool cstring_empty(CString cs) { +static inline bool +cstring_empty(CString cs) { return cstring_size(cs) == 0; } -static inline bool cstring_equals(CString cs1, const char* str) { +static inline bool +cstring_equals(CString cs1, const char* str) { return strcmp(cs1.str, str) == 0; } -static inline bool cstring_equalsS(CString cs1, CString cs2) { +static inline bool +cstring_equalsS(CString cs1, CString cs2) { return strcmp(cs1.str, cs2.str) == 0; } -static inline char* cstring_strnstr(CString cs, size_t pos, const char* needle, size_t n) { +static inline char* +cstring_strnstr(CString cs, size_t pos, const char* needle, size_t n) { char *x = cs.str + pos, // haystack *z = cs.str + cstring_size(cs) - n + 1; if (x >= z) @@ -211,25 +250,30 @@ static inline char* cstring_strnstr(CString cs, size_t pos, const char* needle, return NULL; } -static inline size_t cstring_findN(CString cs, size_t pos, const char* needle, size_t n) { +static inline size_t +cstring_findN(CString cs, size_t pos, const char* needle, size_t n) { char* res = cstring_strnstr(cs, pos, needle, n); return res ? res - cs.str : cstring_npos; } -static inline size_t cstring_find(CString cs, size_t pos, const char* needle) { +static inline size_t +cstring_find(CString cs, size_t pos, const char* needle) { char* res = strstr(cs.str + pos, needle); return res ? res - cs.str : cstring_npos; } -static inline char* cstring_splitFirst(const char* delimiters, CString cs) { +static inline char* +cstring_splitFirst(const char* delimiters, CString cs) { return strtok(cs.str, delimiters); } -static inline char* cstring_splitNext(const char* delimiters) { +static inline char* +cstring_splitNext(const char* delimiters) { return strtok(NULL, delimiters); } -static inline CString cstring_temp(const char* str) { +static inline CString +cstring_temp(const char* str) { // May only be used for accessing .str CString temp = {(char *) str}; return temp; diff --git a/stc/cvec3.h b/stc/cvec3.h index 3d8d91dc..4c1bb7a7 100644 --- a/stc/cvec3.h +++ b/stc/cvec3.h @@ -27,125 +27,176 @@ #include #include -#define cvec3_data(v) (&(v).x) +#define c_sqrt_f(x) sqrtf(x) +#define c_sqrt_d(x) sqrt(x) +#define c_sin_f(x) sinf(x) +#define c_sin_d(x) sin(x) +#define c_cos_f(x) cosf(x) +#define c_cos_d(x) cos(x) +#define c_atan2_f(x, y) atan2f(x, y) +#define c_atan2_d(x, y) atan2(x, y) + +#ifdef c_NO_ANONYMOUS_STRUCT +#define CVEC3_DEF(tag, T) struct CVec3##tag { T x, y, z; } +#else +#define CVEC3_DEF(tag, T) union CVec3##tag { struct { T x, y, z; }; T arr[3]; } +#endif + +#define cvec3_arr(v) (&(v).x) +#define cvec3f_zero ((CVec3f) {0.f, 0.f, 0.f}) +#define cvec3d_zero ((CVec3d) {0.0, 0.0, 0.0}) + #define declare_CVec3(tag, T) \ - typedef struct CVec3##tag { T x, y, z; } CVec3##tag; \ - static CVec3##tag cvec3##tag##_null = {0, 0, 0}; \ - static CVec3##tag cvec3##tag##_axis[3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; \ + typedef CVEC3_DEF(tag, T) CVec3##tag; \ + static CVec3##tag \ + cvec3##tag##_axis[3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; \ \ - static inline CVec3##tag cvec3##tag(T x, T y, T z) { CVec3##tag v = {x, y, z}; return v; } \ - static inline CVec3##tag cvec3##tag##_init(const T* a) { CVec3##tag v = {a[0], a[1], a[2]}; return v; } \ + static inline CVec3##tag \ + cvec3##tag(T x, T y, T z) { return (CVec3##tag) {x, y, z}; } \ + static inline CVec3##tag \ + cvec3##tag##_fromArray(const T* a) { return (CVec3##tag) {a[0], a[1], a[2]}; } \ \ - static inline CVec3##tag cvec3##tag##_set(CVec3##tag* self, T x, T y, T z) { \ - self->x = x, self->y = y, self->z = z; return *self; \ + static inline CVec3##tag* \ + cvec3##tag##_assign(CVec3##tag* self, T x, T y, T z) { \ + self->x = x, self->y = y, self->z = z; return self; \ } \ - static inline CVec3##tag cvec3##tag##_setv(CVec3##tag* self, const T* a) { \ - self->x = a[0], self->y = a[1], self->z = a[2]; return *self; \ + static inline CVec3##tag* \ + cvec3##tag##_assignArray(CVec3##tag* self, const T* a) { \ + self->x = a[0], self->y = a[1], self->z = a[2]; return self; \ } \ - static inline CVec3##tag cvec3##tag##_add(CVec3##tag* self, CVec3##tag v) { \ - self->x += v.x, self->y += v.y, self->z += v.z; return *self; \ + static inline CVec3##tag* \ + cvec3##tag##_add(CVec3##tag* self, CVec3##tag v) { \ + self->x += v.x, self->y += v.y, self->z += v.z; return self; \ } \ - static inline CVec3##tag cvec3##tag##_subtract(CVec3##tag* self, CVec3##tag v) { \ - self->x -= v.x, self->y -= v.y, self->z -= v.z; return *self; \ + static inline CVec3##tag* \ + cvec3##tag##_sub(CVec3##tag* self, CVec3##tag v) { \ + self->x -= v.x, self->y -= v.y, self->z -= v.z; return self; \ } \ - static inline CVec3##tag cvec3##tag##_scale(CVec3##tag* self, double s) { \ - self->x = (T)(self->x*s), self->y = (T)(self->y*s), self->z = (T)(self->z*s); \ - return *self; \ + static inline CVec3##tag* \ + cvec3##tag##_scale(CVec3##tag* self, T s) { \ + self->x *= s, self->y *= s, self->z *= s; return self; \ } \ - static inline double cvec3##tag##_length(CVec3##tag v) { \ - return sqrt(_cvec3_DOT(v, v)); \ + static inline T \ + cvec3##tag##_length(CVec3##tag v) { \ + return c_sqrt_##tag(_cvec3_DOT(v, v)); \ } \ - static inline double cvec3##tag##_length2(CVec3##tag v) { \ + static inline T \ + cvec3##tag##_length2(CVec3##tag v) { \ return _cvec3_DOT(v, v); \ } \ - static inline CVec3##tag cvec3##tag##_plus(CVec3##tag u, CVec3##tag v) { \ + static inline CVec3##tag \ + cvec3##tag##_plus(CVec3##tag u, CVec3##tag v) { \ u.x += v.x, u.y += v.y, u.z += v.z; return u; \ } \ - static inline CVec3##tag cvec3##tag##_minus(CVec3##tag u, CVec3##tag v) { \ + static inline CVec3##tag \ + cvec3##tag##_minus(CVec3##tag u, CVec3##tag v) { \ u.x -= v.x, u.y -= v.y, u.z -= v.z; return u; \ } \ - static inline CVec3##tag cvec3##tag##_mult(CVec3##tag v, double s) { \ - v.x = (T)(s*v.x), v.y = (T)(s*v.y), v.z = (T)(s*v.z); return v; \ + static inline CVec3##tag \ + cvec3##tag##_mult(CVec3##tag v, T s) { \ + v.x *= s, v.y *= s, v.z *= s; return v; \ } \ - static inline CVec3##tag cvec3##tag##_multInverse(CVec3##tag v, double s) { \ - v.x = (T)(s/v.x), v.y = (T)(s/v.y), v.z = (T)(s/v.z); return v; \ - } \ - static inline CVec3##tag cvec3##tag##_neg(CVec3##tag v) { \ + static inline CVec3##tag \ + cvec3##tag##_neg(CVec3##tag v) { \ v.x = -v.x, v.y = -v.y, v.z = -v.z; return v; \ } \ - static inline CVec3##tag cvec3##tag##_unit(CVec3##tag v) { \ - double s = 1.0 / sqrt(_cvec3_DOT(v, v)); \ - v.x = (T)(s*v.x), v.y = (T)(s*v.y), v.z = (T)(s*v.z); return v; \ + static inline CVec3##tag \ + cvec3##tag##_unit(CVec3##tag v) { \ + T s = c_sqrt_##tag(_cvec3_DOT(v, v)); \ + if (s < 1e-8) return cvec3##tag##_zero; \ + s = 1.0f / s; v.x *= s, v.y *= s, v.z *= s; \ + return v; \ } \ - static inline double cvec3##tag##_dot(CVec3##tag u, CVec3##tag v) { \ + static inline T \ + cvec3##tag##_dot(CVec3##tag u, CVec3##tag v) { \ return _cvec3_DOT(u, v); \ } \ - static inline CVec3##tag cvec3##tag##_cross(CVec3##tag u, CVec3##tag v) { \ - CVec3##tag c = {_cvec3_CROSS(T, u, v)}; \ - return c; \ + static inline CVec3##tag \ + cvec3##tag##_cross(CVec3##tag u, CVec3##tag v) { \ + return (CVec3##tag) {_cvec3_CROSS(u, v)}; \ } \ - static inline double cvec3##tag##_triple(CVec3##tag u, CVec3##tag v, CVec3##tag w) { \ - CVec3##tag c = {_cvec3_CROSS(T, u, v)}; \ - return _cvec3_DOT(c, w); \ + static inline T \ + cvec3##tag##_triple(CVec3##tag u, CVec3##tag v, CVec3##tag w) { \ + CVec3##tag cross = {_cvec3_CROSS(u, v)}; \ + return _cvec3_DOT(cross, w); \ } \ - /* Reflect u on plane with given normal vector n */ \ - static inline CVec3##tag cvec3##tag##_reflect(CVec3##tag u, CVec3##tag pn) { \ - double dot2 = 2.0 * _cvec3_DOT(u, pn); \ - u.x = (T)(u.x - dot2*pn.x), u.y = (T)(u.y - dot2*pn.y), u.z = (T)(u.z - dot2*pn.z); \ + /* Reflect u on plane with given normal vector pn */ \ + static inline CVec3##tag \ + cvec3##tag##_reflect(CVec3##tag u, CVec3##tag pn) { \ + T dot2 = 2.0f * _cvec3_DOT(u, pn); \ + u.x -= dot2 * pn.x, u.y -= dot2 * pn.y, u.z -= dot2 * pn.z; \ return u; \ } \ + /* Refract u incident on plane with given normal vector pn */ \ + static inline CVec3##tag \ + cvec3##tag##_refract(CVec3##tag u, CVec3##tag pn, T eta) { \ + T dot = _cvec3_DOT(pn, u); \ + T k = 1.0f - eta * eta * (1.0f - dot * dot); \ + if (k < 0.0f) return cvec3##tag##_zero; \ + cvec3##tag##_scale(&u, eta); \ + cvec3##tag##_scale(&pn, eta * dot + c_sqrt_##tag(k)); \ + return *cvec3##tag##_sub(&u, pn); \ + } \ + static inline T \ + cvec3##tag##_distance(CVec3##tag u, CVec3##tag v) { \ + u.x -= v.x, u.y -= v.y, u.z -= v.z; \ + return c_sqrt_##tag(_cvec3_DOT(u, u)); \ + } \ /* Signed distance between point u and a plane (pp, pn), pn normalized. */ \ - static inline double cvec3##tag##_distanceToPlane(CVec3##tag u, CVec3##tag pp, CVec3##tag pn) { \ + static inline T \ + cvec3##tag##_distanceToPlane(CVec3##tag u, CVec3##tag pp, CVec3##tag pn) { \ u.x -= pp.x, u.y -= pp.y, u.z -= pp.z; \ return _cvec3_DOT(u, pn); \ } \ /* Linear interpolation */ \ - static inline CVec3##tag cvec3##tag##_lerp(CVec3##tag u, CVec3##tag v, double t) { \ - double m = 1.0 - t; \ - u.x = (T)(m*u.x + t*v.x), u.y = (T)(m*u.y + t*v.y), u.z = (T)(m*u.z + t*v.z); \ + static inline CVec3##tag \ + cvec3##tag##_lerp(CVec3##tag u, CVec3##tag v, T t) { \ + T s = 1.0f - t; \ + u.x = s*u.x + t*v.x, u.y = s*u.y + t*v.y, u.z = s*u.z + t*v.z; \ return u; \ } \ - static inline bool cvec3##tag##_rayPlaneIntersection(CVec3##tag* out, CVec3##tag u, CVec3##tag dir, \ + /* Swizzle */ \ + static inline CVec3##tag \ + cvec3##tag##_swizzle(CVec3##tag u, const char* swz) { \ + T* a = cvec3_arr(u); \ + return (CVec3##tag) {a[swz[0] - 'x'], a[swz[1] - 'x'], a[swz[2] - 'x']}; \ + } \ + static inline bool \ + cvec3##tag##_rayPlaneIntersection(CVec3##tag* out, CVec3##tag u, CVec3##tag dir, \ CVec3##tag pp, CVec3##tag pn) { \ - double d = _cvec3_DOT(dir, pn); if (d == 0) return false; \ - double t = (_cvec3_DOT(pp, pn) - _cvec3_DOT(u, pn)) / d; \ + T d = _cvec3_DOT(dir, pn); if (d == 0) return false; \ + T t = (_cvec3_DOT(pp, pn) - _cvec3_DOT(u, pn)) / d; \ if (t < 0) return false; \ - u.x = (T)(u.x + dir.x*t), u.y = (T)(u.y + dir.y*t), u.z = (T)(u.z + dir.z*t); \ + u.x += dir.x*t, u.y += dir.y*t, u.z += dir.z*t; \ *out = u; return true; \ } \ - static inline bool cvec3##tag##_equals(CVec3##tag u, CVec3##tag v) { \ + static inline bool \ + cvec3##tag##_equals(CVec3##tag u, CVec3##tag v) { \ if (u.x != v.x) return false; \ if (u.y != v.y) return false; \ return u.z == v.z; \ } \ - static inline int cvec3##tag##_compare(CVec3##tag* u, CVec3##tag* v) { \ - if (u->x != v->x) return 1 - ((u->x < v->x)<<1); \ - if (u->y != v->y) return 1 - ((u->y < v->y)<<1); \ + static inline int \ + cvec3##tag##_compare(CVec3##tag* u, CVec3##tag* v) { \ + if (u->x != v->x) return 1 - ((u->x < v->x)<<1); \ + if (u->y != v->y) return 1 - ((u->y < v->y)<<1); \ return u->z == v->z ? 0 : 1 - ((u->z < v->z)<<1); \ } \ - typedef T cvec3_##tag##_value_t + typedef T cvec3##tag##_value_t -#define _cvec3_DOT(u, v) ((double) u.x*v.x + u.y*v.y + u.z*v.z) +#define _cvec3_DOT(u, v) (u.x*v.x + u.y*v.y + u.z*v.z) #define _cvec3_SUB(u, v) u.x - v.x, u.y - v.y, u.z - v.z -#define _cvec3_CROSS(T, u, v) (T) (u.y*v.z - v.y*u.z), (T) (u.z*v.x - v.z*u.x), (T) (u.x*v.y - u.y*v.x) +#define _cvec3_CROSS(u, v) u.y*v.z - v.y*u.z, u.z*v.x - v.z*u.x, u.x*v.y - u.y*v.x declare_CVec3(d, double); declare_CVec3(f, float); -declare_CVec3(i, int32_t); -//declare_CVec3(ui, uint32_t); -//declare_CVec3(s, int16_t); -//declare_CVec3(us, uint16_t); -declare_CVec3(ub, uint8_t); -static inline CVec3f cvec3d_to3f(CVec3d v) { - CVec3f w = {(float) v.x, (float) v.y, (float) v.z}; return w; -} -static inline CVec3d cvec3f_to3d(CVec3f v) { - CVec3d w = {v.x, v.y, v.z}; return w; +static inline CVec3f cvec3d_tof(CVec3d v) { + return (CVec3f) {(float) v.x, (float) v.y, (float) v.z}; } -static inline CVec3d cvec3i_to3d(CVec3i v) { - CVec3d w = {(double) v.x, (double) v.y, (double) v.z}; return w; +static inline CVec3d cvec3f_tod(CVec3f v) { + return (CVec3d) {v.x, v.y, v.z}; } #endif diff --git a/stc/cvec4.h b/stc/cvec4.h index abc5f3dd..b8daf4a0 100644 --- a/stc/cvec4.h +++ b/stc/cvec4.h @@ -25,102 +25,146 @@ #include "cvec3.h" -#define cvec4_data(v) (&(v).x) +#ifdef c_NO_ANONYMOUS_STRUCT +#define CVEC4_DEF(tag, T) struct CVec4##tag { T x, y, z, w; } +#else +#define CVEC4_DEF(tag, T) union CVec4##tag { struct { T x, y, z, w; }; T arr[4]; } +#endif + +#define cvec4_arr(v) (&(v).x) +#define cvec4f_zero ((CVec4f) {0.f, 0.f, 0.f, 0.f}) +#define cvec4d_zero ((CVec4d) {0.0, 0.0, 0.0, 0.0}) #define declare_CVec4(tag, T) \ - typedef struct CVec4##tag { T x, y, z, w; } CVec4##tag; \ - static CVec4##tag cvec4##tag##_null = {0, 0, 0, 0}; \ + typedef CVEC4_DEF(tag, T) CVec4##tag; \ static CVec4##tag cvec4##tag##_axis[4] = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}}; \ \ - static inline CVec4##tag cvec4##tag(T x, T y, T z, T w) { CVec4##tag v = {x, y, z, w}; return v; } \ - static inline CVec4##tag cvec4##tag##_init(const T* a) { CVec4##tag v = {a[0], a[1], a[2], a[3]}; return v; } \ + static inline CVec4##tag \ + cvec4##tag(T x, T y, T z, T w) { return (CVec4##tag) {x, y, z, w}; } \ + static inline CVec4##tag \ + cvec4##tag##_fromArray(const T* a) { return (CVec4##tag) {a[0], a[1], a[2], a[3]}; } \ \ - static inline CVec4##tag cvec4##tag##_set(CVec4##tag* self, T x, T y, T z, T w) { \ - self->x = x, self->y = y, self->z = z, self->z = z, self->w = w; return *self; \ + static inline CVec4##tag* \ + cvec4##tag##_assign(CVec4##tag* self, T x, T y, T z, T w) { \ + self->x = x, self->y = y, self->z = z, self->z = z, self->w = w; return self; \ } \ - static inline CVec4##tag cvec4##tag##_setv(CVec4##tag* self, const T* a) { \ - self->x = a[0], self->y = a[1], self->z = a[2], self->w = a[3]; return *self; \ + static inline CVec4##tag* \ + cvec4##tag##_assignArray(CVec4##tag* self, const T* a) { \ + self->x = a[0], self->y = a[1], self->z = a[2], self->w = a[3]; return self; \ } \ - static inline CVec4##tag cvec4##tag##_add(CVec4##tag* self, CVec4##tag v) { \ - self->x += v.x, self->y += v.y, self->z += v.z, self->w += v.w; return *self; \ + static inline CVec4##tag* \ + cvec4##tag##_add(CVec4##tag* self, CVec4##tag v) { \ + self->x += v.x, self->y += v.y, self->z += v.z, self->w += v.w; return self; \ } \ - static inline CVec4##tag cvec4##tag##_subtract(CVec4##tag* self, CVec4##tag v) { \ - self->x -= v.x, self->y -= v.y, self->z -= v.z, self->w -= v.w; return *self; \ + static inline CVec4##tag* \ + cvec4##tag##_sub(CVec4##tag* self, CVec4##tag v) { \ + self->x -= v.x, self->y -= v.y, self->z -= v.z, self->w -= v.w; return self; \ } \ - static inline CVec4##tag cvec4##tag##_scale(CVec4##tag* self, double s) { \ - self->x = (T)(self->x*s), self->y = (T)(self->y*s), self->z = (T)(self->z*s), self->w = (T)(self->w*s); \ - return *self; \ + static inline CVec4##tag* \ + cvec4##tag##_scale(CVec4##tag* self, T s) { \ + self->x *= s, self->y *= s, self->z *= s, self->w *= s; return self; \ } \ - static inline double cvec4##tag##_length(CVec4##tag v) { \ - return sqrt(_cvec4_DOT(v, v)); \ + static inline T \ + cvec4##tag##_length(CVec4##tag v) { \ + return c_sqrt_##tag(_cvec4_DOT(v, v)); \ } \ - static inline double cvec4##tag##_length2(CVec4##tag v) { \ + static inline T \ + cvec4##tag##_length2(CVec4##tag v) { \ return _cvec4_DOT(v, v); \ } \ - static inline CVec4##tag cvec4##tag##_plus(CVec4##tag u, CVec4##tag v) { \ + static inline T \ + cvec4##tag##_distance(CVec4##tag u, CVec4##tag v) { \ + u.x -= v.x, u.y -= v.y, u.z -= v.z, u.w -= v.w; \ + return c_sqrt_##tag(_cvec4_DOT(u, u)); \ + } \ + static inline CVec4##tag \ + cvec4##tag##_plus(CVec4##tag u, CVec4##tag v) { \ u.x += v.x, u.y += v.y, u.z += v.z, u.w += v.w; return u; \ } \ - static inline CVec4##tag cvec4##tag##_minus(CVec4##tag u, CVec4##tag v) { \ + static inline CVec4##tag \ + cvec4##tag##_minus(CVec4##tag u, CVec4##tag v) { \ u.x -= v.x, u.y -= v.y, u.z -= v.z, u.w -= v.w; return u; \ } \ - static inline CVec4##tag cvec4##tag##_mult(CVec4##tag v, double s) { \ - v.x = (T)(s*v.x), v.y = (T)(s*v.y), v.z = (T)(s*v.z), v.w = (T)(s*v.w); return v; \ - } \ - static inline CVec4##tag cvec4##tag##_multInverse(CVec4##tag v, double s) { \ - v.x = (T)(s/v.x), v.y = (T)(s/v.y), v.z = (T)(s/v.z), v.w = (T)(s/v.w); return v; \ + static inline CVec4##tag \ + cvec4##tag##_mult(CVec4##tag v, T s) { \ + v.x *= s, v.y *= s, v.z *= s, v.w *= s; return v; \ } \ - static inline CVec4##tag cvec4##tag##_neg(CVec4##tag v) { \ + static inline CVec4##tag \ + cvec4##tag##_neg(CVec4##tag v) { \ v.x = -v.x, v.y = -v.y, v.z = -v.z, v.w = -v.w; return v; \ } \ - static inline CVec4##tag cvec4##tag##_unit(CVec4##tag v) { \ - double s = 1.0 / sqrt(_cvec4_DOT(v, v)); \ - v.x = (T)(s*v.x), v.y = (T)(s*v.y), v.z = (T)(s*v.z), v.w = (T)(s*v.w); return v; \ + static inline CVec4##tag \ + cvec4##tag##_unit(CVec4##tag v) { \ + T s = c_sqrt_##tag(_cvec4_DOT(v, v)); \ + if (s < 1e-8) return cvec4##tag##_zero; \ + s = 1.0f / s; v.x *= s, v.y *= s, v.z *= s, v.w *= s; \ + return v; \ } \ - static inline double cvec4##tag##_dot(CVec4##tag u, CVec4##tag v) { \ + static inline T \ + cvec4##tag##_dot(CVec4##tag u, CVec4##tag v) { \ return _cvec4_DOT(u, v); \ } \ + static inline CVec3##tag \ + cvec4##tag##_to3(CVec4##tag u) { \ + return (CVec3##tag) {u.x, u.y, u.z}; \ + } \ + static inline CVec4##tag \ + cvec3##tag##_to4(CVec3##tag u, T w) { \ + return (CVec4##tag) {u.x, u.y, u.z, w}; \ + } \ + /* Swizzle */ \ + static inline CVec4##tag \ + cvec4##tag##_swizzle(CVec4##tag u, const char* swz) { \ + const T* a = cvec4_arr(u); \ + return (CVec4##tag) {a[(swz[0] - 'x') & 3], \ + a[(swz[1] - 'x') & 3], \ + a[(swz[2] - 'x') & 3], \ + a[(swz[3] - 'x') & 3]}; \ + } \ + static inline CVec3##tag \ + cvec4##tag##_swizzle3(CVec4##tag u, const char* swz) { \ + const T* a = cvec4_arr(u); \ + return (CVec3##tag) {a[(swz[0] - 'x') & 3], \ + a[(swz[1] - 'x') & 3], \ + a[(swz[2] - 'x') & 3]}; \ + } \ /* Linear interpolation */ \ - static inline CVec4##tag cvec4##tag##_lerp(CVec4##tag u, CVec4##tag v, double t) { \ - double m = 1.0 - t; \ - u.x = (T)(m*u.x + t*v.x), u.y = (T)(m*u.y + t*v.y), u.z = (T)(m*u.z + t*v.z), u.w = (T)(m*u.w + t*v.w); \ + static inline CVec4##tag \ + cvec4##tag##_lerp(CVec4##tag u, CVec4##tag v, T t) { \ + T s = 1.0f - t; \ + u.x = s*u.x + t*v.x, u.y = s*u.y + t*v.y, \ + u.z = s*u.z + t*v.z, u.w = s*u.w + t*v.w; \ return u; \ } \ - static inline bool cvec4##tag##_equals(CVec4##tag u, CVec4##tag v) { \ + static inline bool \ + cvec4##tag##_equals(CVec4##tag u, CVec4##tag v) { \ if (u.x != v.x) return false; \ if (u.y != v.y) return false; \ if (u.z != v.z) return false; \ return u.w == v.w; \ } \ - static inline int cvec4##tag##_compare(CVec4##tag* u, CVec4##tag* v) { \ - if (u->x != v->x) return 1 - ((u->x < v->x)<<1); \ - if (u->y != v->y) return 1 - ((u->y < v->y)<<1); \ - if (u->z != v->z) return 1 - ((u->z < v->z)<<1); \ + static inline int \ + cvec4##tag##_compare(CVec4##tag* u, CVec4##tag* v) { \ + if (u->x != v->x) return 1 - ((u->x < v->x)<<1); \ + if (u->y != v->y) return 1 - ((u->y < v->y)<<1); \ + if (u->z != v->z) return 1 - ((u->z < v->z)<<1); \ return u->w == v->w ? 0 : 1 - ((u->w < v->w)<<1); \ } \ - typedef T cvec4_##tag##_value_t + typedef T cvec4##tag##_value_t -#define _cvec4_DOT(u, v) ((double) u.x*v.x + u.y*v.y + u.z*v.z + u.w*v.w) +#define _cvec4_DOT(u, v) (u.x*v.x + u.y*v.y + u.z*v.z + u.w*v.w) #define _cvec4_SUB(u, v) u.x - v.x, u.y - v.y, u.z - v.z, u.w - v.w declare_CVec4(d, double); declare_CVec4(f, float); -declare_CVec4(i, int32_t); -//declare_CVec4(ui, uint32_t); -//declare_CVec4(s, int16_t); -//declare_CVec4(us, uint16_t); -declare_CVec4(ub, uint8_t); -static inline CVec4d cvec4f_to4d(CVec4f v) { - CVec4d u = {v.x, v.y, v.z, v.w}; return u; -} -static inline CVec4f cvec4d_to4f(CVec4d v) { - CVec4f u = {(float) v.x, (float) v.y, (float) v.z, (float) v.w}; return u; -} -static inline CVec3d cvec4d_to3d(CVec4d v) { - CVec3d u = {v.x, v.y, v.z}; return u; +static inline CVec4d +cvec4f_tod(CVec4f v) { + return (CVec4d) {v.x, v.y, v.z, v.w}; } -static inline CVec3f cvec4d_to3f(CVec4d v) { - CVec3f u = {(float) v.x, (float) v.y, (float) v.z}; return u; +static inline CVec4f +cvec4d_tof(CVec4d v) { + return (CVec4f) {(float) v.x, (float) v.y, (float) v.z, (float) v.w}; } #endif diff --git a/stc/cvector.h b/stc/cvector.h index 93aaa550..68eddbfb 100644 --- a/stc/cvector.h +++ b/stc/cvector.h @@ -27,6 +27,8 @@ #include #include "cdefs.h" +extern void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*)); + #define cvector_init {NULL} #define cvector_size(cv) _cvector_safe_size((cv).data) #define cvector_capacity(cv) _cvector_safe_capacity((cv).data) @@ -48,22 +50,21 @@ typedef struct CVector_##tag { \ } CVector_##tag; \ static const CVector_##tag cvector_##tag##_init = cvector_init; \ \ -typedef struct cvector_##tag##_iter_t { \ - Value* item; \ -} cvector_##tag##_iter_t; \ - \ -static inline void cvector_##tag##_swap(CVector_##tag* a, CVector_##tag* b) { \ +static inline void \ +cvector_##tag##_swap(CVector_##tag* a, CVector_##tag* b) { \ Value* data = a->data; a->data = b->data; b->data = data; \ } \ \ -static inline void cvector_##tag##_destroy(CVector_##tag* self) { \ +static inline void \ +cvector_##tag##_destroy(CVector_##tag* self) { \ Value* p = self->data; \ size_t i = 0, n = cvector_size(*self); \ for (; i < n; ++p, ++i) valueDestroy(p); \ free(_cvector_alloced(self->data)); \ } \ \ -static inline void cvector_##tag##_reserve(CVector_##tag* self, size_t cap) { \ +static inline void \ +cvector_##tag##_reserve(CVector_##tag* self, size_t cap) { \ size_t len = cvector_size(*self); \ if (cap >= len) { \ size_t* rep = (size_t *) realloc(_cvector_alloced(self->data), 2 * sizeof(size_t) + cap * sizeof(Value)); \ @@ -73,29 +74,35 @@ static inline void cvector_##tag##_reserve(CVector_##tag* self, size_t cap) { \ } \ } \ \ -static inline void cvector_##tag##_clear(CVector_##tag* self) { \ +static inline void \ +cvector_##tag##_clear(CVector_##tag* self) { \ CVector_##tag cv = cvector_##tag##_init; \ cvector_##tag##_destroy(self); \ *self = cv; \ } \ \ \ -static inline void cvector_##tag##_push(CVector_##tag* self, Value value) { \ - size_t newsize = cvector_size(*self) + 1; \ - if (newsize > cvector_capacity(*self)) \ - cvector_##tag##_reserve(self, 7 + newsize * 5 / 3); \ +static inline void \ +cvector_##tag##_push(CVector_##tag* self, Value value) { \ + size_t len = cvector_size(*self); \ + if (len == cvector_capacity(*self)) \ + cvector_##tag##_reserve(self, 7 + len * 5 / 3); \ self->data[cvector_size(*self)] = value; \ - _cvector_size(*self) = newsize; \ + ++_cvector_size(*self); \ } \ \ -static inline void cvector_##tag##_insert(CVector_##tag* self, size_t pos, Value value) { \ - cvector_##tag##_push(self, value); \ +static inline void \ +cvector_##tag##_insert(CVector_##tag* self, size_t pos, Value value) { \ size_t len = cvector_size(*self); \ - memmove(&self->data[pos + 1], &self->data[pos], (len - pos - 1) * sizeof(Value)); \ + if (len == cvector_capacity(*self)) \ + cvector_##tag##_reserve(self, 7 + len * 5 / 3); \ + memmove(&self->data[pos + 1], &self->data[pos], (len - pos) * sizeof(Value)); \ self->data[pos] = value; \ + ++_cvector_size(*self); \ } \ \ -static inline void cvector_##tag##_erase(CVector_##tag* self, size_t pos, size_t size) { \ +static inline void \ +cvector_##tag##_erase(CVector_##tag* self, size_t pos, size_t size) { \ size_t len = cvector_size(*self); \ if (len) { \ Value* p = &self->data[pos], *start = p, *end = p + size; \ @@ -105,16 +112,19 @@ static inline void cvector_##tag##_erase(CVector_##tag* self, size_t pos, size_t } \ } \ \ -static inline int cvector_##tag##_sortCompare(const void* x, const void* y) { \ +static inline int \ +cvector_##tag##_sortCompare(const void* x, const void* y) { \ return valueCompare(valueGetRaw((const Value *) x), valueGetRaw((const Value *) y)); \ } \ \ -static inline void cvector_##tag##_sort(CVector_##tag* self) { \ +static inline void \ +cvector_##tag##_sort(CVector_##tag* self) { \ size_t len = cvector_size(*self); \ if (len) qsort(self->data, len, sizeof(Value), cvector_##tag##_sortCompare); \ } \ \ -static inline size_t cvector_##tag##_find(CVector_##tag cv, ValueRaw rawValue) { \ +static inline size_t \ +cvector_##tag##_find(CVector_##tag cv, ValueRaw rawValue) { \ size_t n = cvector_size(cv); \ for (size_t i = 0; i < n; ++i) { \ if (valueCompare(valueGetRaw(&cv.data[i]), &rawValue) == 0) return i; \ @@ -123,26 +133,36 @@ static inline size_t cvector_##tag##_find(CVector_##tag cv, ValueRaw rawValue) { } \ \ \ -static inline Value cvector_##tag##_back(CVector_##tag cv) { \ +static inline Value \ +cvector_##tag##_back(CVector_##tag cv) { \ return cv.data[_cvector_size(cv) - 1]; \ } \ \ -static inline void cvector_##tag##_pop(CVector_##tag* self) { \ +static inline void \ +cvector_##tag##_pop(CVector_##tag* self) { \ valueDestroy(&self->data[_cvector_size(*self) - 1]); \ --_cvector_size(*self); \ } \ \ -static inline cvector_##tag##_iter_t cvector_##tag##_begin(CVector_##tag vec) { \ + \ +typedef struct cvector_##tag##_iter_t { \ + Value* item; \ +} cvector_##tag##_iter_t; \ + \ +static inline cvector_##tag##_iter_t \ +cvector_##tag##_begin(CVector_##tag vec) { \ cvector_##tag##_iter_t it = {vec.data}; \ return it; \ } \ \ -static inline cvector_##tag##_iter_t cvector_##tag##_next(cvector_##tag##_iter_t it) { \ +static inline cvector_##tag##_iter_t \ +cvector_##tag##_next(cvector_##tag##_iter_t it) { \ ++it.item; \ return it; \ } \ \ -static inline cvector_##tag##_iter_t cvector_##tag##_end(CVector_##tag vec) { \ +static inline cvector_##tag##_iter_t \ +cvector_##tag##_end(CVector_##tag vec) { \ cvector_##tag##_iter_t it = {vec.data + cvector_size(vec)}; \ return it; \ } \ -- cgit v1.2.3