summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorTyge <[email protected]>2020-04-15 13:41:52 +0200
committerTyge <[email protected]>2020-04-15 13:41:52 +0200
commit8731d3d68a688a0fd838b7a2b66ac1d8ae422a1e (patch)
tree06637f343e9af1a362fea9f1fc9416523fdf5a64
parent2b3b428e4257dba3240afdedda8e16a35115d182 (diff)
downloadSTC-modified-8731d3d68a688a0fd838b7a2b66ac1d8ae422a1e.tar.gz
STC-modified-8731d3d68a688a0fd838b7a2b66ac1d8ae422a1e.zip
- Added cmat3, cmat4, cquat
- Changed include folder name to stc - library name - Bug fix, memory leak in map values when overwritten. - Improvements in API
-rw-r--r--EXAMPLE.md4
-rw-r--r--README.md20
-rw-r--r--benchmark.cpp4
-rw-r--r--stc/carray.h24
-rw-r--r--stc/cdefs.h8
-rw-r--r--stc/cmap.h60
-rw-r--r--stc/cmat3.h138
-rw-r--r--stc/cmat4.h205
-rw-r--r--stc/copt.h2
-rw-r--r--stc/cquat.h206
-rw-r--r--stc/cstring.h102
-rw-r--r--stc/cvec3.h189
-rw-r--r--stc/cvec4.h156
-rw-r--r--stc/cvector.h70
14 files changed, 968 insertions, 220 deletions
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 <ccl/cstring.h>
+#include <stc/cstring.h>
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 <ccl/CMap.h>
+#include <stc/CMap.h>
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 <ccl/cstring.h>
+#include <stc/cstring.h>
int main() {
CString cs = cstring_make("one-nine-three-seven-five");
@@ -36,7 +36,7 @@ int main() {
```
Simple CVector of 64bit ints:
```
-#include <ccl/cvector.h>
+#include <stc/cvector.h>
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 <ccl/cstring.h>
-#include <ccl/cvector.h>
+#include <stc/cstring.h>
+#include <stc/cvector.h>
declare_CVector(cs, CString, cstring_destroy); // supply inline destructor of values
int main() {
@@ -70,7 +70,7 @@ int main() {
```
Simple CMap, int -> int:
```
-#include <ccl/cmap.h>
+#include <stc/cmap.h>
declare_CMap(ii, int, int);
int main() {
@@ -84,8 +84,8 @@ int main() {
```
Simple CMap, CString -> int:
```
-#include <ccl/cstring.h>
-#include <ccl/cmap.h>
+#include <stc/cstring.h>
+#include <stc/cmap.h>
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 <ccl/cstring.h>
-#include <ccl/cmap.h>
+#include <stc/cstring.h>
+#include <stc/cmap.h>
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 <stdio.h>
#include <time.h>
-#include "ccl/cstring.h"
-#include "ccl/cmap.h"
+#include "stc/cstring.h"
+#include "stc/cmap.h"
#ifdef __cplusplus
#include <unordered_map>
#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 <stc/carray.h>
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 <stdbool.h>
#include <math.h>
-#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 <string.h>
#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; \
} \