Cleanup: move public doc-strings into headers for 'blenlib'

- Added space below non doc-string comments to make it clear
  these aren't comments for the symbols directly below them.
- Use doxy sections for some headers.
- Minor improvements to doc-strings.

Ref T92709
This commit is contained in:
2021-12-09 20:01:44 +11:00
parent d8b4275162
commit 9e365069af
133 changed files with 4413 additions and 3691 deletions

View File

@@ -28,7 +28,7 @@
/** \name Internal defines /** \name Internal defines
* \{ */ * \{ */
/** this returns the entire size of the array, including any buffering. */ /** This returns the entire size of the array, including any buffering. */
#define _bli_array_totalsize_dynamic(arr) \ #define _bli_array_totalsize_dynamic(arr) \
(((arr) == NULL) ? 0 : MEM_allocN_len(arr) / sizeof(*(arr))) (((arr) == NULL) ? 0 : MEM_allocN_len(arr) / sizeof(*(arr)))
@@ -44,8 +44,12 @@
/** /**
* BLI_array.c * BLI_array.c
* *
* Doing the realloc in a macro isn't so simple, * Doing the reallocation in a macro isn't so simple,
* so use a function the macros can use. * so use a function the macros can use.
*
* This function is only to be called via macros.
*
* \note The caller must adjust \a arr_len
*/ */
void _bli_array_grow_func(void **arr_p, void _bli_array_grow_func(void **arr_p,
const void *arr_static, const void *arr_static,
@@ -64,8 +68,9 @@ void _bli_array_grow_func(void **arr_p,
void *_##arr##_static = NULL void *_##arr##_static = NULL
/** /**
* this will use stack space, up to maxstatic array elements, before * This will use stack space, up to `maxstatic` array elements,
* switching to dynamic heap allocation */ * before switching to dynamic heap allocation.
*/
#define BLI_array_staticdeclare(arr, maxstatic) \ #define BLI_array_staticdeclare(arr, maxstatic) \
int _##arr##_len = 0; \ int _##arr##_len = 0; \
char _##arr##_static[maxstatic * sizeof(*(arr))] char _##arr##_static[maxstatic * sizeof(*(arr))]
@@ -77,7 +82,8 @@ void _bli_array_grow_func(void **arr_p,
* Grow the array by a fixed number of items. * Grow the array by a fixed number of items.
* *
* Allow for a large 'num' value when the new size is more than double * Allow for a large 'num' value when the new size is more than double
* to allocate the exact sized array. */ * to allocate the exact sized array.
*/
#define BLI_array_reserve(arr, num) \ #define BLI_array_reserve(arr, num) \
(void)((((void *)(arr) == NULL) && \ (void)((((void *)(arr) == NULL) && \
((void *)(_##arr##_static) != \ ((void *)(_##arr##_static) != \
@@ -95,12 +101,16 @@ void _bli_array_grow_func(void **arr_p,
num, \ num, \
"BLI_array." #arr))) "BLI_array." #arr)))
/** returns length of array */ /**
* Returns length of array.
*/
#define BLI_array_grow_items(arr, num) (BLI_array_reserve(arr, num), (_##arr##_len += num)) #define BLI_array_grow_items(arr, num) (BLI_array_reserve(arr, num), (_##arr##_len += num))
#define BLI_array_grow_one(arr) BLI_array_grow_items(arr, 1) #define BLI_array_grow_one(arr) BLI_array_grow_items(arr, 1)
/** appends an item to the array. */ /**
* Appends an item to the array.
*/
#define BLI_array_append(arr, item) \ #define BLI_array_append(arr, item) \
((void)BLI_array_grow_one(arr), (void)(arr[_##arr##_len - 1] = item)) ((void)BLI_array_grow_one(arr), (void)(arr[_##arr##_len - 1] = item))
@@ -111,7 +121,9 @@ void _bli_array_grow_func(void **arr_p,
#define BLI_array_append_r(arr, item) \ #define BLI_array_append_r(arr, item) \
((void)BLI_array_grow_one(arr), (void)(arr[_##arr##_len - 1] = item), (&arr[_##arr##_len - 1])) ((void)BLI_array_grow_one(arr), (void)(arr[_##arr##_len - 1] = item), (&arr[_##arr##_len - 1]))
/** appends (grows) & returns a pointer to the uninitialized memory */ /**
* Appends (grows) & returns a pointer to the uninitialized memory.
*/
#define BLI_array_append_ret(arr) (BLI_array_reserve(arr, 1), &arr[(_##arr##_len++)]) #define BLI_array_append_ret(arr) (BLI_array_reserve(arr, 1), &arr[(_##arr##_len++)])
#define BLI_array_free(arr) \ #define BLI_array_free(arr) \
@@ -127,7 +139,8 @@ void _bli_array_grow_func(void **arr_p,
/** /**
* Resets the logical size of an array to zero, but doesn't * Resets the logical size of an array to zero, but doesn't
* free the memory. */ * free the memory.
*/
#define BLI_array_clear(arr) \ #define BLI_array_clear(arr) \
{ \ { \
_##arr##_len = 0; \ _##arr##_len = 0; \
@@ -135,30 +148,32 @@ void _bli_array_grow_func(void **arr_p,
((void)0) ((void)0)
/** /**
* Set the length of the array, doesn't actually increase the allocated array * Set the length of the array, doesn't actually increase the allocated array size.
* size. don't use this unless you know what you're doing. */ * Don't use this unless you know what you're doing.
*/
#define BLI_array_len_set(arr, len) \ #define BLI_array_len_set(arr, len) \
{ \ { \
_##arr##_len = (len); \ _##arr##_len = (len); \
} \ } \
((void)0) ((void)0)
/** only to prevent unused warnings */ /**
* Only to prevent unused warnings.
*/
#define BLI_array_fake_user(arr) ((void)_##arr##_len, (void)_##arr##_static) #define BLI_array_fake_user(arr) ((void)_##arr##_len, (void)_##arr##_static)
/** \} */ /** \} */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/** \name Generic Array Utils /** \name Generic Array Utils
* other useful defines
* (unrelated to the main array macros)
* *
* Other useful defines (unrelated to the main array macros).
* \{ */ * \{ */
/** /**
* Not part of the 'API' but handy functions, * Not part of the 'API' but handy functions, same purpose as #BLI_array_staticdeclare()
* same purpose as #BLI_array_staticdeclare() * but use when the max size is known ahead of time.
* but use when the max size is known ahead of time */ */
#define BLI_array_fixedstack_declare(arr, maxstatic, realsize, allocstr) \ #define BLI_array_fixedstack_declare(arr, maxstatic, realsize, allocstr) \
char _##arr##_static[maxstatic * sizeof(*(arr))]; \ char _##arr##_static[maxstatic * sizeof(*(arr))]; \
const bool _##arr##_is_static = ((void *)_##arr##_static) != \ const bool _##arr##_is_static = ((void *)_##arr##_static) != \

View File

@@ -28,25 +28,88 @@ extern "C" {
typedef struct BArrayState BArrayState; typedef struct BArrayState BArrayState;
typedef struct BArrayStore BArrayStore; typedef struct BArrayStore BArrayStore;
/**
* Create a new array store, which can store any number of arrays
* as long as their stride matches.
*
* \param stride: `sizeof()` each element,
*
* \note while a stride of `1` will always work,
* its less efficient since duplicate chunks of memory will be searched
* at positions unaligned with the array data.
*
* \param chunk_count: Number of elements to split each chunk into.
* - A small value increases the ability to de-duplicate chunks,
* but adds overhead by increasing the number of chunks to look up when searching for duplicates,
* as well as some overhead constructing the original array again, with more calls to `memcpy`.
* - Larger values reduce the *book keeping* overhead,
* but increase the chance a small,
* isolated change will cause a larger amount of data to be duplicated.
*
* \return A new array store, to be freed with #BLI_array_store_destroy.
*/
BArrayStore *BLI_array_store_create(unsigned int stride, unsigned int chunk_count); BArrayStore *BLI_array_store_create(unsigned int stride, unsigned int chunk_count);
/**
* Free the #BArrayStore, including all states and chunks.
*/
void BLI_array_store_destroy(BArrayStore *bs); void BLI_array_store_destroy(BArrayStore *bs);
/**
* Clear all contents, allowing reuse of \a bs.
*/
void BLI_array_store_clear(BArrayStore *bs); void BLI_array_store_clear(BArrayStore *bs);
/* find the memory used by all states (expanded & real) */ /**
* Find the memory used by all states (expanded & real).
*
* \return the total amount of memory that would be used by getting the arrays for all states.
*/
size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs); size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs);
/**
* \return the amount of memory used by all #BChunk.data
* (duplicate chunks are only counted once).
*/
size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs); size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs);
/**
*
* \param data: Data used to create
* \param state_reference: The state to use as a reference when adding the new state,
* typically this is the previous state,
* however it can be any previously created state from this \a bs.
*
* \return The new state,
* which is used by the caller as a handle to get back the contents of \a data.
* This may be removed using #BLI_array_store_state_remove,
* otherwise it will be removed with #BLI_array_store_destroy.
*/
BArrayState *BLI_array_store_state_add(BArrayStore *bs, BArrayState *BLI_array_store_state_add(BArrayStore *bs,
const void *data, const void *data,
const size_t data_len, const size_t data_len,
const BArrayState *state_reference); const BArrayState *state_reference);
/**
* Remove a state and free any unused #BChunk data.
*
* The states can be freed in any order.
*/
void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state); void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state);
/**
* \return the expanded size of the array,
* use this to know how much memory to allocate #BLI_array_store_state_data_get's argument.
*/
size_t BLI_array_store_state_size_get(BArrayState *state); size_t BLI_array_store_state_size_get(BArrayState *state);
/**
* Fill in existing allocated memory with the contents of \a state.
*/
void BLI_array_store_state_data_get(BArrayState *state, void *data); void BLI_array_store_state_data_get(BArrayState *state, void *data);
/**
* Allocate an array for \a state and return it.
*/
void *BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len); void *BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len);
/* only for tests */ /**
* \note Only for tests.
*/
bool BLI_array_store_is_valid(BArrayStore *bs); bool BLI_array_store_is_valid(BArrayStore *bs);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -28,12 +28,29 @@
extern "C" { extern "C" {
#endif #endif
/**
* In-place array reverse.
*
* Access via #BLI_array_reverse
*/
void _bli_array_reverse(void *arr, uint arr_len, size_t arr_stride); void _bli_array_reverse(void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_reverse(arr, arr_len) _bli_array_reverse(arr, arr_len, sizeof(*(arr))) #define BLI_array_reverse(arr, arr_len) _bli_array_reverse(arr, arr_len, sizeof(*(arr)))
/**
* In-place array wrap.
* (rotate the array one step forward or backwards).
*
* Access via #BLI_array_wrap
*/
void _bli_array_wrap(void *arr, uint arr_len, size_t arr_stride, int dir); void _bli_array_wrap(void *arr, uint arr_len, size_t arr_stride, int dir);
#define BLI_array_wrap(arr, arr_len, dir) _bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir) #define BLI_array_wrap(arr, arr_len, dir) _bli_array_wrap(arr, arr_len, sizeof(*(arr)), dir)
/**
*In-place array permute.
* (re-arrange elements based on an array of indices).
*
* Access via #BLI_array_wrap
*/
void _bli_array_permute( void _bli_array_permute(
void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp); void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp);
#define BLI_array_permute(arr, arr_len, order) \ #define BLI_array_permute(arr, arr_len, order) \
@@ -41,13 +58,30 @@ void _bli_array_permute(
#define BLI_array_permute_ex(arr, arr_len, order, arr_temp) \ #define BLI_array_permute_ex(arr, arr_len, order, arr_temp) \
_bli_array_permute(arr, arr_len, sizeof(*(arr)), order, arr_temp) _bli_array_permute(arr, arr_len, sizeof(*(arr)), order, arr_temp)
/**
* In-place array de-duplication of an ordered array.
*
* \return The new length of the array.
*
* Access via #BLI_array_deduplicate_ordered
*/
uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride); uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_deduplicate_ordered(arr, arr_len) \ #define BLI_array_deduplicate_ordered(arr, arr_len) \
_bli_array_deduplicate_ordered(arr, arr_len, sizeof(*(arr))) _bli_array_deduplicate_ordered(arr, arr_len, sizeof(*(arr)))
/**
* Find the first index of an item in an array.
*
* Access via #BLI_array_findindex
*
* \note Not efficient, use for error checks/asserts.
*/
int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p); int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p);
#define BLI_array_findindex(arr, arr_len, p) _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p) #define BLI_array_findindex(arr, arr_len, p) _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p)
/**
* A version of #BLI_array_findindex that searches from the end of the list.
*/
int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p); int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p);
#define BLI_array_rfindindex(arr, arr_len, p) \ #define BLI_array_rfindindex(arr, arr_len, p) \
_bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p) _bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p)
@@ -66,6 +100,22 @@ void _bli_array_binary_or(
CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \ CHECK_TYPE_PAIR_INLINE(*(arr), *(arr_b)), \
_bli_array_binary_or(arr, arr_a, arr_b, arr_len, sizeof(*(arr)))) _bli_array_binary_or(arr, arr_a, arr_b, arr_len, sizeof(*(arr))))
/**
* Utility function to iterate over contiguous items in an array.
*
* \param use_wrap: Detect contiguous ranges across the first/last points.
* In this case the second index of \a span_step may be lower than the first,
* which indicates the values are wrapped.
* \param use_delimit_bounds: When false,
* ranges that defined by the start/end indices are excluded.
* This option has no effect when \a use_wrap is enabled.
* \param test_fn: Function to test if the item should be included in the range.
* \param user_data: User data for \a test_fn.
* \param span_step: Indices to iterate over,
* initialize both values to the array length to initialize iteration.
* \param r_span_len: The length of the span, useful when \a use_wrap is enabled,
* where calculating the length isn't a simple subtraction.
*/
bool _bli_array_iter_span(const void *arr, bool _bli_array_iter_span(const void *arr,
uint arr_len, uint arr_len,
size_t arr_stride, size_t arr_stride,
@@ -87,9 +137,19 @@ bool _bli_array_iter_span(const void *arr,
span_step, \ span_step, \
r_span_len) r_span_len)
/**
* Simple utility to check memory is zeroed.
*/
bool _bli_array_is_zeroed(const void *arr, uint arr_len, size_t arr_stride); bool _bli_array_is_zeroed(const void *arr, uint arr_len, size_t arr_stride);
#define BLI_array_is_zeroed(arr, arr_len) _bli_array_is_zeroed(arr, arr_len, sizeof(*(arr))) #define BLI_array_is_zeroed(arr, arr_len) _bli_array_is_zeroed(arr, arr_len, sizeof(*(arr)))
/**
* Smart function to sample a rectangle spiraling outside.
* Nice for selection ID.
*
* \param arr_shape: dimensions [w, h].
* \param center: coordinates [x, y] indicating where to start traversing.
*/
bool _bli_array_iter_spiral_square(const void *arr_v, bool _bli_array_iter_spiral_square(const void *arr_v,
const int arr_shape[2], const int arr_shape[2],
const size_t elem_size, const size_t elem_size,

View File

@@ -76,18 +76,52 @@ typedef struct BLI_AStarGraph {
struct MemArena *mem; /* Memory arena. */ struct MemArena *mem; /* Memory arena. */
} BLI_AStarGraph; } BLI_AStarGraph;
/**
* Initialize a node in A* graph.
*
* \param custom_data: an opaque pointer attached to this link,
* available e.g. to cost callback function.
*/
void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data); void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data);
/**
* Add a link between two nodes of our A* graph.
*
* \param cost: The 'length' of the link
* (actual distance between two vertices or face centers e.g.).
* \param custom_data: An opaque pointer attached to this link,
* available e.g. to cost callback function.
*/
void BLI_astar_node_link_add(BLI_AStarGraph *as_graph, void BLI_astar_node_link_add(BLI_AStarGraph *as_graph,
const int node1_index, const int node1_index,
const int node2_index, const int node2_index,
const float cost, const float cost,
void *custom_data); void *custom_data);
/**
* \return The index of the other node of given link.
*/
int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx); int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx);
/**
* Initialize a solution data for given A* graph. Does not compute anything!
*
* \param custom_data: an opaque pointer attached to this link, available e.g
* . to cost callback function.
*
* \note BLI_AStarSolution stores nearly all data needed during solution compute.
*/
void BLI_astar_solution_init(BLI_AStarGraph *as_graph, void BLI_astar_solution_init(BLI_AStarGraph *as_graph,
BLI_AStarSolution *as_solution, BLI_AStarSolution *as_solution,
void *custom_data); void *custom_data);
/**
* Clear given solution's data, but does not release its memory.
* Avoids having to recreate/allocate a memarena in loops, e.g.
*
* \note This *has to be called* between each path solving.
*/
void BLI_astar_solution_clear(BLI_AStarSolution *as_solution); void BLI_astar_solution_clear(BLI_AStarSolution *as_solution);
/**
* Release the memory allocated for this solution.
*/
void BLI_astar_solution_free(BLI_AStarSolution *as_solution); void BLI_astar_solution_free(BLI_AStarSolution *as_solution);
/** /**
@@ -108,8 +142,24 @@ typedef float (*astar_f_cost)(BLI_AStarGraph *as_graph,
const int node_idx_next, const int node_idx_next,
const int node_idx_dst); const int node_idx_dst);
/**
* Initialize an A* graph. Total number of nodes must be known.
*
* Nodes might be e.g. vertices, faces, ... etc.
*
* \param custom_data: an opaque pointer attached to this link,
* available e.g. to cost callback function.
*/
void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data); void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data);
void BLI_astar_graph_free(BLI_AStarGraph *as_graph); void BLI_astar_graph_free(BLI_AStarGraph *as_graph);
/**
* Solve a path in given graph, using given 'cost' callback function.
*
* \param max_steps: maximum number of nodes the found path may have.
* Useful in performance-critical usages.
* If no path is found within given steps, returns false too.
* \return true if a path was found, false otherwise.
*/
bool BLI_astar_graph_solve(BLI_AStarGraph *as_graph, bool BLI_astar_graph_solve(BLI_AStarGraph *as_graph,
const int node_index_src, const int node_index_src,
const int node_index_dst, const int node_index_dst,

View File

@@ -40,26 +40,38 @@ typedef unsigned int BLI_bitmap;
/* 0b11111 */ /* 0b11111 */
#define _BITMAP_MASK 31 #define _BITMAP_MASK 31
/* number of blocks needed to hold '_tot' bits */ /**
* Number of blocks needed to hold '_tot' bits.
*/
#define _BITMAP_NUM_BLOCKS(_tot) (((_tot) >> _BITMAP_POWER) + 1) #define _BITMAP_NUM_BLOCKS(_tot) (((_tot) >> _BITMAP_POWER) + 1)
/* size (in bytes) used to hold '_tot' bits */ /**
* Size (in bytes) used to hold '_tot' bits.
*/
#define BLI_BITMAP_SIZE(_tot) ((size_t)(_BITMAP_NUM_BLOCKS(_tot)) * sizeof(BLI_bitmap)) #define BLI_BITMAP_SIZE(_tot) ((size_t)(_BITMAP_NUM_BLOCKS(_tot)) * sizeof(BLI_bitmap))
/* allocate memory for a bitmap with '_tot' bits; free with MEM_freeN() */ /**
* Allocate memory for a bitmap with '_tot' bits; free with MEM_freeN().
*/
#define BLI_BITMAP_NEW(_tot, _alloc_string) \ #define BLI_BITMAP_NEW(_tot, _alloc_string) \
((BLI_bitmap *)MEM_callocN(BLI_BITMAP_SIZE(_tot), _alloc_string)) ((BLI_bitmap *)MEM_callocN(BLI_BITMAP_SIZE(_tot), _alloc_string))
/* allocate a bitmap on the stack */ /**
* Allocate a bitmap on the stack.
*/
#define BLI_BITMAP_NEW_ALLOCA(_tot) \ #define BLI_BITMAP_NEW_ALLOCA(_tot) \
((BLI_bitmap *)memset(alloca(BLI_BITMAP_SIZE(_tot)), 0, BLI_BITMAP_SIZE(_tot))) ((BLI_bitmap *)memset(alloca(BLI_BITMAP_SIZE(_tot)), 0, BLI_BITMAP_SIZE(_tot)))
/* Allocate using given MemArena */ /**
* Allocate using given MemArena.
*/
#define BLI_BITMAP_NEW_MEMARENA(_mem, _tot) \ #define BLI_BITMAP_NEW_MEMARENA(_mem, _tot) \
(CHECK_TYPE_INLINE(_mem, MemArena *), \ (CHECK_TYPE_INLINE(_mem, MemArena *), \
((BLI_bitmap *)BLI_memarena_calloc(_mem, BLI_BITMAP_SIZE(_tot)))) ((BLI_bitmap *)BLI_memarena_calloc(_mem, BLI_BITMAP_SIZE(_tot))))
/* get the value of a single bit at '_index' */ /**
* Get the value of a single bit at '_index'.
*/
#define BLI_BITMAP_TEST(_bitmap, _index) \ #define BLI_BITMAP_TEST(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \ (CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] & (1u << ((_index)&_BITMAP_MASK)))) ((_bitmap)[(_index) >> _BITMAP_POWER] & (1u << ((_index)&_BITMAP_MASK))))
@@ -74,22 +86,30 @@ typedef unsigned int BLI_bitmap;
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \ (CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
(BLI_BITMAP_TEST(_bitmap, _index) != 0)) (BLI_BITMAP_TEST(_bitmap, _index) != 0))
/* set the value of a single bit at '_index' */ /**
* Set the value of a single bit at '_index'.
*/
#define BLI_BITMAP_ENABLE(_bitmap, _index) \ #define BLI_BITMAP_ENABLE(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \ (CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] |= (1u << ((_index)&_BITMAP_MASK)))) ((_bitmap)[(_index) >> _BITMAP_POWER] |= (1u << ((_index)&_BITMAP_MASK))))
/* clear the value of a single bit at '_index' */ /**
* Clear the value of a single bit at '_index'.
*/
#define BLI_BITMAP_DISABLE(_bitmap, _index) \ #define BLI_BITMAP_DISABLE(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \ (CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] &= ~(1u << ((_index)&_BITMAP_MASK)))) ((_bitmap)[(_index) >> _BITMAP_POWER] &= ~(1u << ((_index)&_BITMAP_MASK))))
/* flip the value of a single bit at '_index' */ /**
* Flip the value of a single bit at '_index'.
*/
#define BLI_BITMAP_FLIP(_bitmap, _index) \ #define BLI_BITMAP_FLIP(_bitmap, _index) \
(CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \ (CHECK_TYPE_ANY(_bitmap, BLI_bitmap *, const BLI_bitmap *), \
((_bitmap)[(_index) >> _BITMAP_POWER] ^= (1u << ((_index)&_BITMAP_MASK)))) ((_bitmap)[(_index) >> _BITMAP_POWER] ^= (1u << ((_index)&_BITMAP_MASK))))
/* set or clear the value of a single bit at '_index' */ /**
* Set or clear the value of a single bit at '_index'.
*/
#define BLI_BITMAP_SET(_bitmap, _index, _set) \ #define BLI_BITMAP_SET(_bitmap, _index, _set) \
{ \ { \
CHECK_TYPE(_bitmap, BLI_bitmap *); \ CHECK_TYPE(_bitmap, BLI_bitmap *); \
@@ -102,7 +122,9 @@ typedef unsigned int BLI_bitmap;
} \ } \
(void)0 (void)0
/* resize bitmap to have space for '_tot' bits */ /**
* Resize bitmap to have space for '_tot' bits.
*/
#define BLI_BITMAP_RESIZE(_bitmap, _tot) \ #define BLI_BITMAP_RESIZE(_bitmap, _tot) \
{ \ { \
CHECK_TYPE(_bitmap, BLI_bitmap *); \ CHECK_TYPE(_bitmap, BLI_bitmap *); \
@@ -110,10 +132,25 @@ typedef unsigned int BLI_bitmap;
} \ } \
(void)0 (void)0
/**
* Set or clear all bits in the bitmap.
*/
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits); void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits);
/**
* Invert all bits in the bitmap.
*/
void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits); void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits);
/**
* Copy all bits from one bitmap to another.
*/
void BLI_bitmap_copy_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits); void BLI_bitmap_copy_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
/**
* Combine two bitmaps with boolean AND.
*/
void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits); void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
/**
* Combine two bitmaps with boolean OR.
*/
void BLI_bitmap_or_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits); void BLI_bitmap_or_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -24,17 +24,37 @@
extern "C" { extern "C" {
#endif #endif
/**
* Plot a line from \a p1 to \a p2 (inclusive).
*
* \note For clipped line drawing, see: http://stackoverflow.com/a/40902741/432509
*/
void BLI_bitmap_draw_2d_line_v2v2i(const int p1[2], void BLI_bitmap_draw_2d_line_v2v2i(const int p1[2],
const int p2[2], const int p2[2],
bool (*callback)(int, int, void *), bool (*callback)(int, int, void *),
void *user_data); void *user_data);
/**
* \note Unclipped (clipped version can be added if needed).
*/
void BLI_bitmap_draw_2d_tri_v2i(const int p1[2], void BLI_bitmap_draw_2d_tri_v2i(const int p1[2],
const int p2[2], const int p2[2],
const int p3[2], const int p3[2],
void (*callback)(int x, int x_end, int y, void *), void (*callback)(int x, int x_end, int y, void *),
void *user_data); void *user_data);
/**
* Draws a filled polygon with support for self intersections.
*
* \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
* note that \a x_end will always be greater than \a x, so we can use:
*
* \code{.c}
* do {
* func(x, y);
* } while (++x != x_end);
* \endcode
*/
void BLI_bitmap_draw_2d_poly_v2i_n(const int xmin, void BLI_bitmap_draw_2d_poly_v2i_n(const int xmin,
const int ymin, const int ymin,
const int xmax, const int xmax,

View File

@@ -44,6 +44,20 @@ typedef struct BoxPack {
int index; int index;
} BoxPack; } BoxPack;
/**
* Main box-packing function accessed from other functions
* This sets boxes x,y to positive values, sorting from 0,0 outwards.
* There is no limit to the space boxes may take, only that they will be packed
* tightly into the lower left hand corner (0,0)
*
* \param boxarray: a pre-allocated array of boxes.
* only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used,
* 'box->index' is not used at all, the only reason its there
* is that the box array is sorted by area and programs need to be able
* to have some way of writing the boxes back to the original data.
* \param len: the number of boxes in the array.
* \param r_tot_x, r_tot_y: set so you can normalize the data.
*/
void BLI_box_pack_2d(BoxPack *boxarray, const unsigned int len, float *r_tot_x, float *r_tot_y); void BLI_box_pack_2d(BoxPack *boxarray, const unsigned int len, float *r_tot_x, float *r_tot_y);
typedef struct FixedSizeBoxPack { typedef struct FixedSizeBoxPack {
@@ -52,6 +66,21 @@ typedef struct FixedSizeBoxPack {
int w, h; int w, h;
} FixedSizeBoxPack; } FixedSizeBoxPack;
/**
* Packs boxes into a fixed area.
*
* Boxes and packed are linked lists containing structs that can be cast to
* #FixedSizeBoxPack (i.e. contains a #FixedSizeBoxPack as its first element).
* Boxes that were packed successfully are placed into *packed and removed from *boxes.
*
* The algorithm is a simplified version of https://github.com/TeamHypersomnia/rectpack2D.
* Better ones could be used, but for the current use case (packing Image tiles into GPU
* textures) this is fine.
*
* Note that packing efficiency depends on the order of the input boxes. Generally speaking,
* larger boxes should come first, though how exactly size is best defined (e.g. area, perimeter)
* depends on the particular application.
*/
void BLI_box_pack_2d_fixedarea(struct ListBase *boxes, void BLI_box_pack_2d_fixedarea(struct ListBase *boxes,
int width, int width,
int height, int height,

View File

@@ -71,13 +71,25 @@ enum {
} \ } \
(void)0 (void)0
/* Never decreases the amount of memory allocated */ /**
* \note Never decreases the amount of memory allocated.
*/
void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count); void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count);
/* Ensure size, throwing away old data, respecting BLI_BUFFER_USE_CALLOC */ /**
* Ensure size, throwing away old data, respecting #BLI_BUFFER_USE_CALLOC.
*
* Similar to #BLI_buffer_resize, but use when the existing data can be:
* - Ignored (malloc'd).
* - Cleared (when #BLI_BUFFER_USE_CALLOC is set).
*/
void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count); void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count);
/* Append an array of elements. */ /**
* Append an array of elements.
*
* Callers use #BLI_buffer_append_array.
*/
void _bli_buffer_append_array(BLI_Buffer *buffer, void *data, size_t count); void _bli_buffer_append_array(BLI_Buffer *buffer, void *data, size_t count);
#define BLI_buffer_append_array(buffer_, type_, data_, count_) \ #define BLI_buffer_append_array(buffer_, type_, data_, count_) \
{ \ { \
@@ -87,7 +99,11 @@ void _bli_buffer_append_array(BLI_Buffer *buffer, void *data, size_t count);
} \ } \
(void)0 (void)0
/* Does not free the buffer structure itself */ /**
* Does not free the buffer structure itself.
*
* Callers use #BLI_buffer_free.
*/
void _bli_buffer_free(BLI_Buffer *buffer); void _bli_buffer_free(BLI_Buffer *buffer);
#define BLI_buffer_free(name_) \ #define BLI_buffer_free(name_) \
{ \ { \
@@ -96,7 +112,9 @@ void _bli_buffer_free(BLI_Buffer *buffer);
} \ } \
(void)0 (void)0
/* A buffer embedded in a struct. Using memcpy is allowed until first resize. */ /**
* A buffer embedded in a struct. Using #memcpy is allowed until first resize.
*/
#define BLI_buffer_field_init(name_, type_) \ #define BLI_buffer_field_init(name_, type_) \
{ \ { \
memset(name_, 0, sizeof(*name_)); \ memset(name_, 0, sizeof(*name_)); \

View File

@@ -24,10 +24,43 @@
extern "C" { extern "C" {
#endif #endif
/**
* A.M. Andrew's monotone chain 2D convex hull algorithm.
*
* \param points: An array of 2D points presorted by increasing x and y-coords.
* \param n: The number of points in points.
* \param r_points: An array of the convex hull vertex indices (max is n).
* \returns the number of points in r_points.
*/
int BLI_convexhull_2d_sorted(const float (*points)[2], const int n, int r_points[]); int BLI_convexhull_2d_sorted(const float (*points)[2], const int n, int r_points[]);
/**
* A.M. Andrew's monotone chain 2D convex hull algorithm.
*
* \param points: An array of 2D points.
* \param n: The number of points in points.
* \param r_points: An array of the convex hull vertex indices (max is n).
* _must_ be allocated as `n * 2` because of how its used internally,
* even though the final result will be no more than \a n in size.
* \returns the number of points in r_points.
*/
int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[]); int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[]);
/**
* \return The best angle for fitting the convex hull to an axis aligned bounding box.
*
* Intended to be used with #BLI_convexhull_2d
*
* \param points_hull: Ordered hull points
* (result of #BLI_convexhull_2d mapped to a contiguous array).
*
* \note we could return the index of the best edge too if its needed.
*/
float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned int n); float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned int n);
/**
* Wrap #BLI_convexhull_aabb_fit_hull_2d and do the convex hull calculation.
*
* \param points: arbitrary 2d points.
*/
float BLI_convexhull_aabb_fit_points_2d(const float (*points)[2], unsigned int n); float BLI_convexhull_aabb_fit_points_2d(const float (*points)[2], unsigned int n);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -21,23 +21,24 @@
/** \file /** \file
* \ingroup bli * \ingroup bli
*/ *
* Double-Linked Red-Black Tree Implementation:
#ifdef __cplusplus
extern "C" {
#endif
/* Double-Linked Red-Black Tree Implementation:
* *
* This is simply a Red-Black Tree implementation whose nodes can later * This is simply a Red-Black Tree implementation whose nodes can later
* be arranged + retrieved as elements in a Double-Linked list (i.e. ListBase). * be arranged + retrieved as elements in a Double-Linked list (i.e. ListBase).
* The Red-Black Tree implementation is based on the methods defined by Wikipedia. * The Red-Black Tree implementation is based on the methods defined by Wikipedia.
*/ */
#ifdef __cplusplus
extern "C" {
#endif
/* ********************************************** */ /* ********************************************** */
/* Data Types and Type Defines */ /* Data Types and Type Defines */
/* Base Structs --------------------------------- */ /* -------------------------------------------------------------------- */
/** \name Base Structs
* \{ */
/* Basic Layout for a Node */ /* Basic Layout for a Node */
typedef struct DLRBT_Node { typedef struct DLRBT_Node {
@@ -69,102 +70,149 @@ typedef struct DLRBT_Tree {
void *root; /* this should be based on DLRBT_Node-s */ void *root; /* this should be based on DLRBT_Node-s */
} DLRBT_Tree; } DLRBT_Tree;
/* Callback Types --------------------------------- */ /** \} */
/* Return -1, 0, 1 for whether the given data is less than, /* -------------------------------------------------------------------- */
/** \name Callback Types
* \{ */
/**
* Return -1, 0, 1 for whether the given data is less than,
* equal to, or greater than the given node. * equal to, or greater than the given node.
* - node: <DLRBT_Node> the node to compare to. * \param node: <DLRBT_Node> the node to compare to.
* - data: pointer to the relevant data or values stored in the bit-pattern. * \param data: pointer to the relevant data or values stored in the bit-pattern.
* dependent on the function. * Dependent on the function.
*/ */
typedef short (*DLRBT_Comparator_FP)(void *node, void *data); typedef short (*DLRBT_Comparator_FP)(void *node, void *data);
/* Return a new node instance wrapping the given data /**
* - data: Pointer to the relevant data to create a subclass of node from * Return a new node instance wrapping the given data
* - data: Pointer to the relevant data to create a subclass of node from.
*/ */
typedef DLRBT_Node *(*DLRBT_NAlloc_FP)(void *data); typedef DLRBT_Node *(*DLRBT_NAlloc_FP)(void *data);
/* Update an existing node instance accordingly to be in sync with the given data. /**
* - node: <DLRBT_Node> the node to update. * Update an existing node instance accordingly to be in sync with the given data.
* - data: Pointer to the relevant data or values stored in the bit-pattern. * \param node: <DLRBT_Node> the node to update.
* dependent on the function. * \param data: Pointer to the relevant data or values stored in the bit-pattern.
* Dependent on the function.
*/ */
typedef void (*DLRBT_NUpdate_FP)(void *node, void *data); typedef void (*DLRBT_NUpdate_FP)(void *node, void *data);
/* ********************************************** */ /* ********************************************** */
/* Public API */ /* Public API */
/* ADT Management ------------------------------- */ /** \} */
/* Create a new tree, and initialize as necessary */ /* -------------------------------------------------------------------- */
/** \name ADT Management
* \{ */
/**
* Create a new tree, and initialize as necessary.
*/
DLRBT_Tree *BLI_dlrbTree_new(void); DLRBT_Tree *BLI_dlrbTree_new(void);
/* Initializes some given trees */ /**
* Initializes some given trees.
* Just zero out the pointers used.
*/
void BLI_dlrbTree_init(DLRBT_Tree *tree); void BLI_dlrbTree_init(DLRBT_Tree *tree);
/* Free some tree */ /**
* Free the given tree's data but not the tree itself.
*/
void BLI_dlrbTree_free(DLRBT_Tree *tree); void BLI_dlrbTree_free(DLRBT_Tree *tree);
/* Make sure the tree's Double-Linked list representation is valid */ /**
* Make sure the tree's Double-Linked list representation is valid.
*/
void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree); void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree);
/* Searching ------------------------------------ */ /** \} */
/* Find the node which matches or is the closest to the requested node */ /* -------------------------------------------------------------------- */
/** \name Tree Searching Utilities
* \{ */
/**
* Find the node which matches or is the closest to the requested node.
*/
DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree, DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb, DLRBT_Comparator_FP cmp_cb,
void *search_data); void *search_data);
/* Find the node which exactly matches the required data */ /**
* Find the node which exactly matches the required data.
*/
DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree, DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb, DLRBT_Comparator_FP cmp_cb,
void *search_data); void *search_data);
/* Find the node which occurs immediately before the best matching node */ /**
* Find the node which occurs immediately before the best matching node.
*/
DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree, DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb, DLRBT_Comparator_FP cmp_cb,
void *search_data); void *search_data);
/* Find the node which occurs immediately after the best matching node */ /**
* Find the node which occurs immediately after the best matching node.
*/
DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree, DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb, DLRBT_Comparator_FP cmp_cb,
void *search_data); void *search_data);
/* Check whether there is a node matching the requested node */ /**
* Check whether there is a node matching the requested node.
*/
short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data); short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data);
/* Node Operations (Managed) --------------------- */ /** \} */
/* These methods automate the process of adding/removing nodes from the BST,
* using the supplied data and callbacks /* -------------------------------------------------------------------- */
/** \name Node Operations (Managed)
* \{ */
/**
* These methods automate the process of adding/removing nodes from the BST,
* using the supplied data and callbacks.
*/ */
/* Add the given data to the tree, and return the node added */ /**
/* NOTE: for duplicates, the update_cb is called (if available), * Add the given data to the tree, and return the node added.
* and the existing node is returned. */ * \note for duplicates, the update_cb is called (if available),
* and the existing node is returned.
*/
DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree, DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb, DLRBT_Comparator_FP cmp_cb,
DLRBT_NAlloc_FP new_cb, DLRBT_NAlloc_FP new_cb,
DLRBT_NUpdate_FP update_cb, DLRBT_NUpdate_FP update_cb,
void *data); void *data);
/* Remove the given element from the tree and balance again */ /* FIXME: this is not implemented yet. */
/* FIXME: this is not implemented yet... */ /**
* Remove the given element from the tree and balance again.
*/
// void BLI_dlrbTree_remove(DLRBT_Tree *tree, DLRBT_Node *node); // void BLI_dlrbTree_remove(DLRBT_Tree *tree, DLRBT_Node *node);
/* Node Operations (Manual) --------------------- */ /** \} */
/* These methods require custom code for creating BST nodes and adding them to the
/* -------------------------------------------------------------------- */
/** \name Node Operations (Manual)
*
* These methods require custom code for creating BST nodes and adding them to the
* tree in special ways, such that the node can then be balanced. * tree in special ways, such that the node can then be balanced.
* *
* It is recommended that these methods are only used where the other method is too cumbersome... * It is recommended that these methods are only used where the other method is too cumbersome.
*/ * \{ */
/* Balance the tree after the given node has been added to it /**
* Balance the tree after the given node has been added to it
* (using custom code, in the Binary Tree way). * (using custom code, in the Binary Tree way).
*/ */
void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node); void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node);
/* ********************************************** */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -39,25 +39,85 @@ extern "C" {
struct DynStr; struct DynStr;
/** The abstract DynStr type */ /** The abstract DynStr type. */
typedef struct DynStr DynStr; typedef struct DynStr DynStr;
/**
* Create a new #DynStr.
*
* \return Pointer to a new #DynStr.
*/
DynStr *BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; DynStr *BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
/**
* Create a new #DynStr.
*
* \return Pointer to a new #DynStr.
*/
DynStr *BLI_dynstr_new_memarena(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; DynStr *BLI_dynstr_new_memarena(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
/**
* Append a c-string to a #DynStr.
*
* \param ds: The #DynStr to append to.
* \param cstr: The c-string to append.
*/
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL(); void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL();
/**
* Append a length clamped c-string to a #DynStr.
*
* \param ds: The #DynStr to append to.
* \param cstr: The c-string to append.
* \param len: The maximum length of the c-string to copy.
*/
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL(); void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL();
/**
* Append a c-string to a #DynStr, but with formatting like `printf`.
*
* \param ds: The #DynStr to append to.
* \param format: The `printf` format string to use.
*/
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...) void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...)
ATTR_PRINTF_FORMAT(2, 3) ATTR_NONNULL(1, 2); ATTR_PRINTF_FORMAT(2, 3) ATTR_NONNULL(1, 2);
void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, va_list args) void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, va_list args)
ATTR_PRINTF_FORMAT(2, 0) ATTR_NONNULL(1, 2); ATTR_PRINTF_FORMAT(2, 0) ATTR_NONNULL(1, 2);
/**
* Find the length of a #DynStr.
*
* \param ds: The #DynStr of interest.
* \return The length of \a ds.
*/
int BLI_dynstr_get_len(const DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BLI_dynstr_get_len(const DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Get a #DynStr's contents as a c-string.
* \return The c-string which must be freed using #MEM_freeN.
*
* \param ds: The #DynStr of interest.
* \return The contents of \a ds as a c-string.
*/
char *BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); char *BLI_dynstr_get_cstring(const DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Get a #DynStr's contents as a c-string.
* The \a rets argument must be allocated to be at
* least the size of `BLI_dynstr_get_len(ds) + 1`.
*
* \param ds: The DynStr of interest.
* \param rets: The string to fill.
*/
void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict rets) ATTR_NONNULL(); void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict rets) ATTR_NONNULL();
/**
* Clear the #DynStr
*
* \param ds: The DynStr to clear.
*/
void BLI_dynstr_clear(DynStr *ds) ATTR_NONNULL(); void BLI_dynstr_clear(DynStr *ds) ATTR_NONNULL();
/**
* Free the #DynStr
*
* \param ds: The DynStr to free.
*/
void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL(); void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL();
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -48,42 +48,120 @@ typedef struct EdgeHashIterator {
typedef void (*EdgeHashFreeFP)(void *key); typedef void (*EdgeHashFreeFP)(void *key);
enum { enum {
EDGEHASH_FLAG_ALLOW_DUPES = (1 << 0), /* only checked for in debug mode */ /**
* Only checked for in debug mode.
*/
EDGEHASH_FLAG_ALLOW_DUPES = (1 << 0),
}; };
EdgeHash *BLI_edgehash_new_ex(const char *info, const unsigned int nentries_reserve); EdgeHash *BLI_edgehash_new_ex(const char *info, const unsigned int nentries_reserve);
EdgeHash *BLI_edgehash_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; EdgeHash *BLI_edgehash_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP free_value); void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP free_value);
void BLI_edgehash_print(EdgeHash *eh); void BLI_edgehash_print(EdgeHash *eh);
/**
* Insert edge (\a v0, \a v1) into hash with given value, does
* not check for duplicates.
*/
void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val); void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val);
/**
* Assign a new value to a key that may already be in edgehash.
*/
bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val); bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val);
/**
* Return value for given edge (\a v0, \a v1), or NULL if
* if key does not exist in hash. (If need exists
* to differentiate between key-value being NULL and
* lack of key then see #BLI_edgehash_lookup_p().
*/
void *BLI_edgehash_lookup(const EdgeHash *eh, void *BLI_edgehash_lookup(const EdgeHash *eh,
unsigned int v0, unsigned int v0,
unsigned int v1) ATTR_WARN_UNUSED_RESULT; unsigned int v1) ATTR_WARN_UNUSED_RESULT;
/**
* A version of #BLI_edgehash_lookup which accepts a fallback argument.
*/
void *BLI_edgehash_lookup_default(const EdgeHash *eh, void *BLI_edgehash_lookup_default(const EdgeHash *eh,
unsigned int v0, unsigned int v0,
unsigned int v1, unsigned int v1,
void *default_value) ATTR_WARN_UNUSED_RESULT; void *default_value) ATTR_WARN_UNUSED_RESULT;
/**
* Return pointer to value for given edge (\a v0, \a v1),
* or NULL if key does not exist in hash.
*/
void **BLI_edgehash_lookup_p(EdgeHash *eh, void **BLI_edgehash_lookup_p(EdgeHash *eh,
unsigned int v0, unsigned int v0,
unsigned int v1) ATTR_WARN_UNUSED_RESULT; unsigned int v1) ATTR_WARN_UNUSED_RESULT;
/**
* Ensure \a (v0, v1) is exists in \a eh.
*
* This handles the common situation where the caller needs ensure a key is added to \a eh,
* constructing a new value in the case the key isn't found.
* Otherwise use the existing value.
*
* Such situations typically incur multiple lookups, however this function
* avoids them by ensuring the key is added,
* returning a pointer to the value so it can be used or initialized by the caller.
*
* \return true when the value didn't need to be added.
* (when false, the caller _must_ initialize the value).
*/
bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val) bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val)
ATTR_WARN_UNUSED_RESULT; ATTR_WARN_UNUSED_RESULT;
/**
* Remove \a key (v0, v1) from \a eh, or return false if the key wasn't found.
*
* \param v0, v1: The key to remove.
* \param free_value: Optional callback to free the value.
* \return true if \a key was removed from \a eh.
*/
bool BLI_edgehash_remove(EdgeHash *eh, bool BLI_edgehash_remove(EdgeHash *eh,
unsigned int v0, unsigned int v0,
unsigned int v1, unsigned int v1,
EdgeHashFreeFP free_value); EdgeHashFreeFP free_value);
/**
* Remove \a key (v0, v1) from \a eh, returning the value or NULL if the key wasn't found.
*
* \param v0, v1: The key to remove.
* \return the value of \a key int \a eh or NULL.
*/
void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT; void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT;
/**
* Return boolean true/false if edge (v0,v1) in hash.
*/
bool BLI_edgehash_haskey(const EdgeHash *eh, bool BLI_edgehash_haskey(const EdgeHash *eh,
unsigned int v0, unsigned int v0,
unsigned int v1) ATTR_WARN_UNUSED_RESULT; unsigned int v1) ATTR_WARN_UNUSED_RESULT;
/**
* Return number of keys in hash.
*/
int BLI_edgehash_len(const EdgeHash *eh) ATTR_WARN_UNUSED_RESULT; int BLI_edgehash_len(const EdgeHash *eh) ATTR_WARN_UNUSED_RESULT;
/**
* Remove all edges from hash.
*/
void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint reserve); void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint reserve);
/**
* Wraps #BLI_edgehash_clear_ex with zero entries reserved.
*/
void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value); void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value);
/**
* Create a new #EdgeHashIterator. The hash table must not be mutated
* while the iterator is in use, and the iterator will step exactly
* #BLI_edgehash_len(eh) times before becoming done.
*/
EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
/**
* Initialize an already allocated #EdgeHashIterator. The hash table must not
* be mutated while the iterator is in use, and the iterator will
* step exactly BLI_edgehash_len(eh) times before becoming done.
*
* \param ehi: The #EdgeHashIterator to initialize.
* \param eh: The #EdgeHash to iterate over.
*/
void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh); void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh);
/**
* Free an #EdgeHashIterator.
*/
void BLI_edgehashIterator_free(EdgeHashIterator *ehi); void BLI_edgehashIterator_free(EdgeHashIterator *ehi);
BLI_INLINE void BLI_edgehashIterator_step(EdgeHashIterator *ehi) BLI_INLINE void BLI_edgehashIterator_step(EdgeHashIterator *ehi)
@@ -133,7 +211,17 @@ EdgeSet *BLI_edgeset_new_ex(const char *info, const unsigned int nentries_reserv
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
EdgeSet *BLI_edgeset_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; EdgeSet *BLI_edgeset_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
int BLI_edgeset_len(const EdgeSet *es) ATTR_WARN_UNUSED_RESULT; int BLI_edgeset_len(const EdgeSet *es) ATTR_WARN_UNUSED_RESULT;
/**
* A version of BLI_edgeset_insert which checks first if the key is in the set.
* \returns true if a new key has been added.
*
* \note #EdgeHash has no equivalent to this because typically the value would be different.
*/
bool BLI_edgeset_add(EdgeSet *es, unsigned int v0, unsigned int v1); bool BLI_edgeset_add(EdgeSet *es, unsigned int v0, unsigned int v1);
/**
* Adds the key to the set (no checks for unique keys!).
* Matching #BLI_edgehash_insert
*/
void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1); void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1);
bool BLI_edgeset_haskey(const EdgeSet *es, bool BLI_edgeset_haskey(const EdgeSet *es,
unsigned int v0, unsigned int v0,
@@ -141,6 +229,7 @@ bool BLI_edgeset_haskey(const EdgeSet *es,
void BLI_edgeset_free(EdgeSet *es); void BLI_edgeset_free(EdgeSet *es);
/* rely on inline api for now */ /* rely on inline api for now */
EdgeSetIterator *BLI_edgesetIterator_new(EdgeSet *es); EdgeSetIterator *BLI_edgesetIterator_new(EdgeSet *es);
void BLI_edgesetIterator_free(EdgeSetIterator *esi); void BLI_edgesetIterator_free(EdgeSetIterator *esi);

View File

@@ -41,13 +41,35 @@ typedef enum eExprPyLike_EvalStatus {
EXPR_PYLIKE_FATAL_ERROR, EXPR_PYLIKE_FATAL_ERROR,
} eExprPyLike_EvalStatus; } eExprPyLike_EvalStatus;
/**
* Free the parsed data; NULL argument is ok.
*/
void BLI_expr_pylike_free(struct ExprPyLike_Parsed *expr); void BLI_expr_pylike_free(struct ExprPyLike_Parsed *expr);
/**
* Check if the parsing result is valid for evaluation.
*/
bool BLI_expr_pylike_is_valid(struct ExprPyLike_Parsed *expr); bool BLI_expr_pylike_is_valid(struct ExprPyLike_Parsed *expr);
/**
* Check if the parsed expression always evaluates to the same value.
*/
bool BLI_expr_pylike_is_constant(struct ExprPyLike_Parsed *expr); bool BLI_expr_pylike_is_constant(struct ExprPyLike_Parsed *expr);
/**
* Check if the parsed expression uses the parameter with the given index.
*/
bool BLI_expr_pylike_is_using_param(struct ExprPyLike_Parsed *expr, int index); bool BLI_expr_pylike_is_using_param(struct ExprPyLike_Parsed *expr, int index);
/**
* Compile the expression and return the result.
*
* Parse the expression for evaluation later.
* Returns non-NULL even on failure; use is_valid to check.
*/
ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression, ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression,
const char **param_names, const char **param_names,
int param_names_len); int param_names_len);
/**
* Evaluate the expression with the given parameters.
* The order and number of parameters must match the names given to parse.
*/
eExprPyLike_EvalStatus BLI_expr_pylike_eval(struct ExprPyLike_Parsed *expr, eExprPyLike_EvalStatus BLI_expr_pylike_eval(struct ExprPyLike_Parsed *expr,
const double *param_values, const double *param_values,
int param_values_len, int param_values_len,

View File

@@ -45,19 +45,40 @@ extern "C" {
# define PATH_MAX 4096 # define PATH_MAX 4096
#endif #endif
/* Common */ /* -------------------------------------------------------------------- */
/** \name Common
* \{ */
/**
* Returns the st_mode from stat-ing the specified path name, or 0 if stat fails
* (most likely doesn't exist or no access).
*/
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_copy(const char *file, const char *to) ATTR_NONNULL(); int BLI_copy(const char *file, const char *to) ATTR_NONNULL();
/**
* \return zero on success (matching 'rename' behavior).
*/
int BLI_rename(const char *from, const char *to) ATTR_NONNULL(); int BLI_rename(const char *from, const char *to) ATTR_NONNULL();
/**
* Deletes the specified file or directory (depending on dir), optionally
* doing recursive delete of directory contents.
*
* \return zero on success (matching 'remove' behavior).
*/
int BLI_delete(const char *file, bool dir, bool recursive) ATTR_NONNULL(); int BLI_delete(const char *file, bool dir, bool recursive) ATTR_NONNULL();
/**
* Soft deletes the specified file or directory (depending on dir) by moving the files to the
* recycling bin, optionally doing recursive delete of directory contents.
*
* \return zero on success (matching 'remove' behavior).
*/
int BLI_delete_soft(const char *file, const char **error_message) ATTR_NONNULL(); int BLI_delete_soft(const char *file, const char **error_message) ATTR_NONNULL();
#if 0 /* Unused */ #if 0 /* Unused */
int BLI_move(const char *path, const char *to) ATTR_NONNULL(); int BLI_move(const char *path, const char *to) ATTR_NONNULL();
int BLI_create_symlink(const char *path, const char *to) ATTR_NONNULL(); int BLI_create_symlink(const char *path, const char *to) ATTR_NONNULL();
#endif #endif
/* keep in sync with the definition of struct direntry in BLI_fileops_types.h */ /* Keep in sync with the definition of struct `direntry` in `BLI_fileops_types.h`. */
#ifdef WIN32 #ifdef WIN32
# if defined(_MSC_VER) # if defined(_MSC_VER)
typedef struct _stat64 BLI_stat_t; typedef struct _stat64 BLI_stat_t;
@@ -101,40 +122,102 @@ typedef enum eFileAttributes {
(FILE_ATTR_ALIAS | FILE_ATTR_REPARSE_POINT | FILE_ATTR_SYMLINK | FILE_ATTR_JUNCTION_POINT | \ (FILE_ATTR_ALIAS | FILE_ATTR_REPARSE_POINT | FILE_ATTR_SYMLINK | FILE_ATTR_JUNCTION_POINT | \
FILE_ATTR_MOUNT_POINT | FILE_ATTR_HARDLINK) FILE_ATTR_MOUNT_POINT | FILE_ATTR_HARDLINK)
/* Directories */ /** \} */
/* -------------------------------------------------------------------- */
/** \name Directories
* \{ */
struct direntry; struct direntry;
/**
* Does the specified path point to a directory?
* \note Would be better in `fileops.c` except that it needs `stat.h` so add here.
*/
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Does the specified path point to a non-directory?
*/
bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BLI_is_file(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* \return true on success (i.e. given path now exists on FS), false otherwise.
*/
bool BLI_dir_create_recursive(const char *dir) ATTR_NONNULL(); bool BLI_dir_create_recursive(const char *dir) ATTR_NONNULL();
/**
* Returns the number of free bytes on the volume containing the specified pathname.
*
* \note Not actually used anywhere.
*/
double BLI_dir_free_space(const char *dir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); double BLI_dir_free_space(const char *dir) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Copies the current working directory into *dir (max size maxncpy), and
* returns a pointer to same.
*
* \note can return NULL when the size is not big enough
*/
char *BLI_current_working_dir(char *dir, const size_t maxncpy) ATTR_WARN_UNUSED_RESULT char *BLI_current_working_dir(char *dir, const size_t maxncpy) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(); ATTR_NONNULL();
eFileAttributes BLI_file_attributes(const char *path); eFileAttributes BLI_file_attributes(const char *path);
/* Filelist */ /** \} */
/* -------------------------------------------------------------------- */
/** \name File-List
* \{ */
/**
* Scans the contents of the directory named *dirname, and allocates and fills in an
* array of entries describing them in *filelist.
*
* \return The length of filelist array.
*/
unsigned int BLI_filelist_dir_contents(const char *dir, struct direntry **r_filelist); unsigned int BLI_filelist_dir_contents(const char *dir, struct direntry **r_filelist);
/**
* Deep-duplicate of a single direntry.
*/
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src); void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src);
/**
* Deep-duplicate of a #direntry array including the array itself.
*/
void BLI_filelist_duplicate(struct direntry **dest_filelist, void BLI_filelist_duplicate(struct direntry **dest_filelist,
struct direntry *const src_filelist, struct direntry *const src_filelist,
const unsigned int nrentries); const unsigned int nrentries);
/**
* Frees storage for a single direntry, not the direntry itself.
*/
void BLI_filelist_entry_free(struct direntry *entry); void BLI_filelist_entry_free(struct direntry *entry);
/**
* Frees storage for an array of #direntry, including the array itself.
*/
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries); void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries);
/**
* Convert given entry's size into human-readable strings.
*/
void BLI_filelist_entry_size_to_string(const struct stat *st, void BLI_filelist_entry_size_to_string(const struct stat *st,
const uint64_t sz, const uint64_t sz,
const bool compact, const bool compact,
char r_size[FILELIST_DIRENTRY_SIZE_LEN]); char r_size[FILELIST_DIRENTRY_SIZE_LEN]);
/**
* Convert given entry's modes into human-readable strings.
*/
void BLI_filelist_entry_mode_to_string(const struct stat *st, void BLI_filelist_entry_mode_to_string(const struct stat *st,
const bool compact, const bool compact,
char r_mode1[FILELIST_DIRENTRY_MODE_LEN], char r_mode1[FILELIST_DIRENTRY_MODE_LEN],
char r_mode2[FILELIST_DIRENTRY_MODE_LEN], char r_mode2[FILELIST_DIRENTRY_MODE_LEN],
char r_mode3[FILELIST_DIRENTRY_MODE_LEN]); char r_mode3[FILELIST_DIRENTRY_MODE_LEN]);
/**
* Convert given entry's owner into human-readable strings.
*/
void BLI_filelist_entry_owner_to_string(const struct stat *st, void BLI_filelist_entry_owner_to_string(const struct stat *st,
const bool compact, const bool compact,
char r_owner[FILELIST_DIRENTRY_OWNER_LEN]); char r_owner[FILELIST_DIRENTRY_OWNER_LEN]);
/**
* Convert given entry's time into human-readable strings.
*
* \param r_is_today: optional, returns true if the date matches today's.
* \param r_is_yesterday: optional, returns true if the date matches yesterday's.
*/
void BLI_filelist_entry_datetime_to_string(const struct stat *st, void BLI_filelist_entry_datetime_to_string(const struct stat *st,
const int64_t ts, const int64_t ts,
const bool compact, const bool compact,
@@ -143,14 +226,28 @@ void BLI_filelist_entry_datetime_to_string(const struct stat *st,
bool *r_is_today, bool *r_is_today,
bool *r_is_yesterday); bool *r_is_yesterday);
/* Files */ /** \} */
/* -------------------------------------------------------------------- */
/** \name Files
* \{ */
FILE *BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); FILE *BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void *BLI_gzopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void *BLI_gzopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_open(const char *filename, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BLI_open(const char *filename, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_access(const char *filename, int mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BLI_access(const char *filename, int mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Returns true if the file with the specified name can be written.
* This implementation uses access(2), which makes the check according
* to the real UID and GID of the process, not its effective UID and GID.
* This shouldn't matter for Blender, which is not going to run privileged anyway.
*/
bool BLI_file_is_writable(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BLI_file_is_writable(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Creates the file with nothing in it, or updates its last-modified date if it already exists.
* Returns true if successful (like the unix touch command).
*/
bool BLI_file_touch(const char *file) ATTR_NONNULL(); bool BLI_file_touch(const char *file) ATTR_NONNULL();
bool BLI_file_alias_target(const char *filepath, char *r_targetpath) ATTR_WARN_UNUSED_RESULT; bool BLI_file_alias_target(const char *filepath, char *r_targetpath) ATTR_WARN_UNUSED_RESULT;
@@ -165,23 +262,67 @@ size_t BLI_file_unzstd_to_mem_at_pos(void *buf, size_t len, FILE *file, size_t f
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BLI_file_magic_is_zstd(const char header[4]); bool BLI_file_magic_is_zstd(const char header[4]);
/**
* Returns the file size of an opened file descriptor.
*/
size_t BLI_file_descriptor_size(int file) ATTR_WARN_UNUSED_RESULT; size_t BLI_file_descriptor_size(int file) ATTR_WARN_UNUSED_RESULT;
/**
* Returns the size of a file.
*/
size_t BLI_file_size(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); size_t BLI_file_size(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* compare if one was last modified before the other */ /**
* Compare if one was last modified before the other.
*
* \return true when is `file1` older than `file2`.
*/
bool BLI_file_older(const char *file1, const char *file2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BLI_file_older(const char *file1, const char *file2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* read ascii file as lines, empty list if reading fails */ /**
* Reads the contents of a text file.
*
* \return the lines in a linked list (an empty list when file reading fails).
*/
struct LinkNode *BLI_file_read_as_lines(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); struct LinkNode *BLI_file_read_as_lines(const char *file) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void *BLI_file_read_text_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size); void *BLI_file_read_text_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size);
/**
* Return the text file data with:
* - Newlines replaced with '\0'.
* - Optionally trim white-space, replacing trailing <space> & <tab> with '\0'.
*
* This is an alternative to using #BLI_file_read_as_lines,
* allowing us to loop over lines without converting it into a linked list
* with individual allocations.
*
* \param trim_trailing_space: Replace trailing spaces & tabs with nil.
* This arguments prevents the caller from counting blank lines (if that's important).
* \param pad_bytes: When this is non-zero, the first byte is set to nil,
* to simplify parsing the file.
* It's recommended to pass in 1, so all text is nil terminated.
*
* Example looping over lines:
*
* \code{.c}
* size_t data_len;
* char *data = BLI_file_read_text_as_mem_with_newline_as_nil(filepath, true, 1, &data_len);
* char *data_end = data + data_len;
* for (char *line = data; line != data_end; line = strlen(line) + 1) {
* printf("line='%s'\n", line);
* }
* \endcode
*/
void *BLI_file_read_text_as_mem_with_newline_as_nil(const char *filepath, void *BLI_file_read_text_as_mem_with_newline_as_nil(const char *filepath,
bool trim_trailing_space, bool trim_trailing_space,
size_t pad_bytes, size_t pad_bytes,
size_t *r_size); size_t *r_size);
void *BLI_file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size); void *BLI_file_read_binary_as_mem(const char *filepath, size_t pad_bytes, size_t *r_size);
/**
* Frees memory from a previous call to #BLI_file_read_as_lines.
*/
void BLI_file_free_lines(struct LinkNode *lines); void BLI_file_free_lines(struct LinkNode *lines);
/* this weirdo pops up in two places ... */ /* This weirdo pops up in two places. */
#if !defined(WIN32) #if !defined(WIN32)
# ifndef O_BINARY # ifndef O_BINARY
# define O_BINARY 0 # define O_BINARY 0
@@ -190,6 +331,8 @@ void BLI_file_free_lines(struct LinkNode *lines);
void BLI_get_short_name(char short_name[256], const char *filename); void BLI_get_short_name(char short_name[256], const char *filename);
#endif #endif
/** \} */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -80,47 +80,183 @@ enum {
* Defined in `BLI_ghash.c` * Defined in `BLI_ghash.c`
* \{ */ * \{ */
/**
* Creates a new, empty GHash.
*
* \param hashfp: Hash callback.
* \param cmpfp: Comparison callback.
* \param info: Identifier string for the GHash.
* \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
* Use this to avoid resizing buckets if the size is known or can be closely approximated.
* \return An empty GHash.
*/
GHash *BLI_ghash_new_ex(GHashHashFP hashfp, GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
GHashCmpFP cmpfp, GHashCmpFP cmpfp,
const char *info, const char *info,
const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
/**
* Wraps #BLI_ghash_new_ex with zero entries reserved.
*/
GHash *BLI_ghash_new(GHashHashFP hashfp, GHash *BLI_ghash_new(GHashHashFP hashfp,
GHashCmpFP cmpfp, GHashCmpFP cmpfp,
const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
/**
* Copy given GHash. Keys and values are also copied if relevant callback is provided,
* else pointers remain the same.
*/
GHash *BLI_ghash_copy(const GHash *gh, GHash *BLI_ghash_copy(const GHash *gh,
GHashKeyCopyFP keycopyfp, GHashKeyCopyFP keycopyfp,
GHashValCopyFP valcopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; GHashValCopyFP valcopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
/**
* Frees the GHash and its members.
*
* \param gh: The GHash to free.
* \param keyfreefp: Optional callback to free the key.
* \param valfreefp: Optional callback to free the value.
*/
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
/**
* Reserve given amount of entries (resize \a gh accordingly if needed).
*/
void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve); void BLI_ghash_reserve(GHash *gh, const unsigned int nentries_reserve);
/**
* Insert a key/value pair into the \a gh.
*
* \note Duplicates are not checked,
* the caller is expected to ensure elements are unique unless
* GHASH_FLAG_ALLOW_DUPES flag is set.
*/
void BLI_ghash_insert(GHash *gh, void *key, void *val); void BLI_ghash_insert(GHash *gh, void *key, void *val);
/**
* Inserts a new value to a key that may already be in ghash.
*
* Avoids #BLI_ghash_remove, #BLI_ghash_insert calls (double lookups)
*
* \returns true if a new key has been added.
*/
bool BLI_ghash_reinsert( bool BLI_ghash_reinsert(
GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
/**
* Replaces the key of an item in the \a gh.
*
* Use when a key is re-allocated or its memory location is changed.
*
* \returns The previous key or NULL if not found, the caller may free if it's needed.
*/
void *BLI_ghash_replace_key(GHash *gh, void *key); void *BLI_ghash_replace_key(GHash *gh, void *key);
/**
* Lookup the value of \a key in \a gh.
*
* \param key: The key to lookup.
* \returns the value for \a key or NULL.
*
* \note When NULL is a valid value, use #BLI_ghash_lookup_p to differentiate a missing key
* from a key with a NULL value. (Avoids calling #BLI_ghash_haskey before #BLI_ghash_lookup)
*/
void *BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; void *BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
/**
* A version of #BLI_ghash_lookup which accepts a fallback argument.
*/
void *BLI_ghash_lookup_default(const GHash *gh, void *BLI_ghash_lookup_default(const GHash *gh,
const void *key, const void *key,
void *val_default) ATTR_WARN_UNUSED_RESULT; void *val_default) ATTR_WARN_UNUSED_RESULT;
/**
* Lookup a pointer to the value of \a key in \a gh.
*
* \param key: The key to lookup.
* \returns the pointer to value for \a key or NULL.
*
* \note This has 2 main benefits over #BLI_ghash_lookup.
* - A NULL return always means that \a key isn't in \a gh.
* - The value can be modified in-place without further function calls (faster).
*/
void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; void **BLI_ghash_lookup_p(GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
/**
* Ensure \a key is exists in \a gh.
*
* This handles the common situation where the caller needs ensure a key is added to \a gh,
* constructing a new value in the case the key isn't found.
* Otherwise use the existing value.
*
* Such situations typically incur multiple lookups, however this function
* avoids them by ensuring the key is added,
* returning a pointer to the value so it can be used or initialized by the caller.
*
* \returns true when the value didn't need to be added.
* (when false, the caller _must_ initialize the value).
*/
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT; bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT;
/**
* A version of #BLI_ghash_ensure_p that allows caller to re-assign the key.
* Typically used when the key is to be duplicated.
*
* \warning Caller _must_ write to \a r_key when returning false.
*/
bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val) bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val)
ATTR_WARN_UNUSED_RESULT; ATTR_WARN_UNUSED_RESULT;
/**
* Remove \a key from \a gh, or return false if the key wasn't found.
*
* \param key: The key to remove.
* \param keyfreefp: Optional callback to free the key.
* \param valfreefp: Optional callback to free the value.
* \return true if \a key was removed from \a gh.
*/
bool BLI_ghash_remove(GHash *gh, bool BLI_ghash_remove(GHash *gh,
const void *key, const void *key,
GHashKeyFreeFP keyfreefp, GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp); GHashValFreeFP valfreefp);
/**
* Wraps #BLI_ghash_clear_ex with zero entries reserved.
*/
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp); void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp);
/**
* Reset \a gh clearing all entries.
*
* \param keyfreefp: Optional callback to free the key.
* \param valfreefp: Optional callback to free the value.
* \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
*/
void BLI_ghash_clear_ex(GHash *gh, void BLI_ghash_clear_ex(GHash *gh,
GHashKeyFreeFP keyfreefp, GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp, GHashValFreeFP valfreefp,
const unsigned int nentries_reserve); const unsigned int nentries_reserve);
/**
* Remove \a key from \a gh, returning the value or NULL if the key wasn't found.
*
* \param key: The key to remove.
* \param keyfreefp: Optional callback to free the key.
* \return the value of \a key int \a gh or NULL.
*/
void *BLI_ghash_popkey(GHash *gh, void *BLI_ghash_popkey(GHash *gh,
const void *key, const void *key,
GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT; GHashKeyFreeFP keyfreefp) ATTR_WARN_UNUSED_RESULT;
/**
* \return true if the \a key is in \a gh.
*/
bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT; bool BLI_ghash_haskey(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT;
/**
* Remove a random entry from \a gh, returning true
* if a key/value pair could be removed, false otherwise.
*
* \param r_key: The removed key.
* \param r_val: The removed value.
* \param state: Used for efficient removal.
* \return true if there was something to pop, false if ghash was already empty.
*/
bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val) bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* \return size of the GHash.
*/
unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT; unsigned int BLI_ghash_len(const GHash *gh) ATTR_WARN_UNUSED_RESULT;
/**
* Sets a GHash flag.
*/
void BLI_ghash_flag_set(GHash *gh, unsigned int flag); void BLI_ghash_flag_set(GHash *gh, unsigned int flag);
/**
* Clear a GHash flag.
*/
void BLI_ghash_flag_clear(GHash *gh, unsigned int flag); void BLI_ghash_flag_clear(GHash *gh, unsigned int flag);
/** \} */ /** \} */
@@ -129,10 +265,36 @@ void BLI_ghash_flag_clear(GHash *gh, unsigned int flag);
/** \name GHash Iterator /** \name GHash Iterator
* \{ */ * \{ */
/**
* Create a new GHashIterator. The hash table must not be mutated
* while the iterator is in use, and the iterator will step exactly
* #BLI_ghash_len(gh) times before becoming done.
*
* \param gh: The GHash to iterate over.
* \return Pointer to a new iterator.
*/
GHashIterator *BLI_ghashIterator_new(GHash *gh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; GHashIterator *BLI_ghashIterator_new(GHash *gh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
/**
* Init an already allocated GHashIterator. The hash table must not
* be mutated while the iterator is in use, and the iterator will
* step exactly #BLI_ghash_len(gh) times before becoming done.
*
* \param ghi: The GHashIterator to initialize.
* \param gh: The GHash to iterate over.
*/
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh); void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh);
/**
* Free a GHashIterator.
*
* \param ghi: The iterator to free.
*/
void BLI_ghashIterator_free(GHashIterator *ghi); void BLI_ghashIterator_free(GHashIterator *ghi);
/**
* Steps the iterator to the next index.
*
* \param ghi: The iterator.
*/
void BLI_ghashIterator_step(GHashIterator *ghi); void BLI_ghashIterator_step(GHashIterator *ghi);
BLI_INLINE void *BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT; BLI_INLINE void *BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT;
@@ -195,6 +357,10 @@ typedef GHashKeyCopyFP GSetKeyCopyFP;
typedef GHashIterState GSetIterState; typedef GHashIterState GSetIterState;
/** \name GSet Public API
*
* Use ghash API to give 'set' functionality
* \{ */
GSet *BLI_gset_new_ex(GSetHashFP hashfp, GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSetCmpFP cmpfp, GSetCmpFP cmpfp,
const char *info, const char *info,
@@ -202,17 +368,55 @@ GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSet *BLI_gset_new(GSetHashFP hashfp, GSet *BLI_gset_new(GSetHashFP hashfp,
GSetCmpFP cmpfp, GSetCmpFP cmpfp,
const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
/**
* Copy given GSet. Keys are also copied if callback is provided, else pointers remain the same.
*/
GSet *BLI_gset_copy(const GSet *gs, GSetKeyCopyFP keycopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT; GSet *BLI_gset_copy(const GSet *gs, GSetKeyCopyFP keycopyfp) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
unsigned int BLI_gset_len(const GSet *gs) ATTR_WARN_UNUSED_RESULT; unsigned int BLI_gset_len(const GSet *gs) ATTR_WARN_UNUSED_RESULT;
void BLI_gset_flag_set(GSet *gs, unsigned int flag); void BLI_gset_flag_set(GSet *gs, unsigned int flag);
void BLI_gset_flag_clear(GSet *gs, unsigned int flag); void BLI_gset_flag_clear(GSet *gs, unsigned int flag);
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp); void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp);
/**
* Adds the key to the set (no checks for unique keys!).
* Matching #BLI_ghash_insert
*/
void BLI_gset_insert(GSet *gs, void *key); void BLI_gset_insert(GSet *gs, void *key);
/**
* A version of BLI_gset_insert which checks first if the key is in the set.
* \returns true if a new key has been added.
*
* \note GHash has no equivalent to this because typically the value would be different.
*/
bool BLI_gset_add(GSet *gs, void *key); bool BLI_gset_add(GSet *gs, void *key);
/**
* Set counterpart to #BLI_ghash_ensure_p_ex.
* similar to BLI_gset_add, except it returns the key pointer.
*
* \warning Caller _must_ write to \a r_key when returning false.
*/
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key); bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key);
/**
* Adds the key to the set (duplicates are managed).
* Matching #BLI_ghash_reinsert
*
* \returns true if a new key has been added.
*/
bool BLI_gset_reinsert(GSet *gh, void *key, GSetKeyFreeFP keyfreefp); bool BLI_gset_reinsert(GSet *gh, void *key, GSetKeyFreeFP keyfreefp);
/**
* Replaces the key to the set if it's found.
* Matching #BLI_ghash_replace_key
*
* \returns The old key or NULL if not found.
*/
void *BLI_gset_replace_key(GSet *gs, void *key); void *BLI_gset_replace_key(GSet *gs, void *key);
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT; bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
/**
* Remove a random entry from \a gs, returning true if a key could be removed, false otherwise.
*
* \param r_key: The removed key.
* \param state: Used for efficient removal.
* \return true if there was something to pop, false if gset was already empty.
*/
bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key) ATTR_WARN_UNUSED_RESULT bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(); ATTR_NONNULL();
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp); bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp);
@@ -220,7 +424,14 @@ void BLI_gset_clear_ex(GSet *gs, GSetKeyFreeFP keyfreefp, const unsigned int nen
void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp); void BLI_gset_clear(GSet *gs, GSetKeyFreeFP keyfreefp);
/* When set's are used for key & value. */ /* When set's are used for key & value. */
/**
* Returns the pointer to the key if it's found.
*/
void *BLI_gset_lookup(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT; void *BLI_gset_lookup(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
/**
* Returns the pointer to the key if it's found, removing it from the GSet.
* \note Caller must handle freeing.
*/
void *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT; void *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT;
/** \} */ /** \} */
@@ -282,9 +493,19 @@ BLI_INLINE bool BLI_gsetIterator_done(const GSetIterator *gsi)
/* For testing, debugging only */ /* For testing, debugging only */
#ifdef GHASH_INTERNAL_API #ifdef GHASH_INTERNAL_API
/**
* \return number of buckets in the GHash.
*/
int BLI_ghash_buckets_len(const GHash *gh); int BLI_ghash_buckets_len(const GHash *gh);
int BLI_gset_buckets_len(const GSet *gs); int BLI_gset_buckets_len(const GSet *gs);
/**
* Measure how well the hash function performs (1.0 is approx as good as random distribution),
* and return a few other stats like load,
* variance of the distribution of the entries in the buckets, etc.
*
* Smaller is better!
*/
double BLI_ghash_calc_quality_ex(GHash *gh, double BLI_ghash_calc_quality_ex(GHash *gh,
double *r_load, double *r_load,
double *r_variance, double *r_variance,
@@ -346,6 +567,15 @@ double BLI_gset_calc_quality(GSet *gs);
unsigned int BLI_ghashutil_ptrhash(const void *key); unsigned int BLI_ghashutil_ptrhash(const void *key);
bool BLI_ghashutil_ptrcmp(const void *a, const void *b); bool BLI_ghashutil_ptrcmp(const void *a, const void *b);
/**
* This function implements the widely used "djb" hash apparently posted
* by Daniel Bernstein to comp.lang.c some time ago. The 32 bit
* unsigned hash value starts at 5381 and for each byte 'c' in the
* string, is updated: `hash = hash * 33 + c`.
* This function uses the signed value of each byte.
*
* NOTE: this is the same hash method that glib 2.34.0 uses.
*/
unsigned int BLI_ghashutil_strhash_n(const char *key, size_t n); unsigned int BLI_ghashutil_strhash_n(const char *key, size_t n);
#define BLI_ghashutil_strhash(key) \ #define BLI_ghashutil_strhash(key) \
(CHECK_TYPE_ANY(key, char *, const char *, const char *const), BLI_ghashutil_strhash_p(key)) (CHECK_TYPE_ANY(key, char *, const char *, const char *const), BLI_ghashutil_strhash_p(key))

View File

@@ -32,10 +32,30 @@ extern "C" {
typedef struct _GSQueue GSQueue; typedef struct _GSQueue GSQueue;
GSQueue *BLI_gsqueue_new(const size_t elem_size); GSQueue *BLI_gsqueue_new(const size_t elem_size);
/**
* Returns true if the queue is empty, false otherwise.
*/
bool BLI_gsqueue_is_empty(const GSQueue *queue); bool BLI_gsqueue_is_empty(const GSQueue *queue);
size_t BLI_gsqueue_len(const GSQueue *queue); size_t BLI_gsqueue_len(const GSQueue *queue);
/**
* Retrieves and removes the first element from the queue.
* The value is copies to \a r_item, which must be at least \a elem_size bytes.
*
* Does not reduce amount of allocated memory.
*/
void BLI_gsqueue_pop(GSQueue *queue, void *r_item); void BLI_gsqueue_pop(GSQueue *queue, void *r_item);
/**
* Copies the source value onto the end of the queue
*
* \note This copies #GSQueue.elem_size bytes from \a item,
* (the pointer itself is not stored).
*
* \param item: source data to be copied to the queue.
*/
void BLI_gsqueue_push(GSQueue *queue, const void *item); void BLI_gsqueue_push(GSQueue *queue, const void *item);
/**
* Free the queue's data and the queue itself.
*/
void BLI_gsqueue_free(GSQueue *queue); void BLI_gsqueue_free(GSQueue *queue);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -24,17 +24,18 @@
extern "C" { extern "C" {
#endif #endif
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The /**
* result is always in little endian byte order, so that a byte-wise * Compute MD5 message digest for 'len' bytes beginning at 'buffer'.
* output yields to the wanted ASCII representation of the message * The result is always in little endian byte order,
* digest. */ * so that a byte-wise output yields to the wanted ASCII representation of the message digest.
*/
void *BLI_hash_md5_buffer(const char *buffer, size_t len, void *resblock); void *BLI_hash_md5_buffer(const char *buffer, size_t len, void *resblock);
/* Compute MD5 message digest for bytes read from STREAM. The /**
* resulting message digest number will be written into the 16 bytes * Compute MD5 message digest for bytes read from 'stream'.
* beginning at RESBLOCK. */ * The resulting message digest number will be written into the 16 bytes beginning at 'resblock'.
* \return Non-zero if an error occurred.
*/
int BLI_hash_md5_stream(FILE *stream, void *resblock); int BLI_hash_md5_stream(FILE *stream, void *resblock);
char *BLI_hash_md5_to_hexdigest(void *resblock, char r_hex_digest[33]); char *BLI_hash_md5_to_hexdigest(void *resblock, char r_hex_digest[33]);

View File

@@ -41,6 +41,9 @@ void BLI_hash_mm2a_add_int(BLI_HashMurmur2A *mm2, int data);
uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2); uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2);
/**
* Non-incremental version, quicker for small keys.
*/
uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed); uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -34,27 +34,59 @@ typedef struct HeapNode HeapNode;
typedef void (*HeapFreeFP)(void *ptr); typedef void (*HeapFreeFP)(void *ptr);
/**
* Creates a new heap. Removed nodes are recycled, so memory usage will not shrink.
*
* \note Use when the size of the heap is known in advance.
*/
Heap *BLI_heap_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT; Heap *BLI_heap_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT;
Heap *BLI_heap_new(void) ATTR_WARN_UNUSED_RESULT; Heap *BLI_heap_new(void) ATTR_WARN_UNUSED_RESULT;
void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1); void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1);
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1); void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1);
/**
* Insert heap node with a value (often a 'cost') and pointer into the heap,
* duplicate values are allowed.
*/
HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1); HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1);
/**
* Convenience function since this is a common pattern.
*/
void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr) void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr)
ATTR_NONNULL(1, 2); ATTR_NONNULL(1, 2);
void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1, 2); void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1, 2);
bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1); bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1);
unsigned int BLI_heap_len(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); unsigned int BLI_heap_len(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Return the top node of the heap.
* This is the node with the lowest value.
*/
HeapNode *BLI_heap_top(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); HeapNode *BLI_heap_top(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Return the value of top node of the heap.
* This is the node with the lowest value.
*/
float BLI_heap_top_value(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); float BLI_heap_top_value(const Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Pop the top node off the heap and return its pointer.
*/
void *BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1); void *BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1);
/**
* Can be used to avoid #BLI_heap_remove, #BLI_heap_insert calls,
* balancing the tree still has a performance cost,
* but is often much less than remove/insert, difference is most noticeable with large heaps.
*/
void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value) ATTR_NONNULL(1, 2); void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value) ATTR_NONNULL(1, 2);
void BLI_heap_node_value_update_ptr(Heap *heap, HeapNode *node, float value, void *ptr) void BLI_heap_node_value_update_ptr(Heap *heap, HeapNode *node, float value, void *ptr)
ATTR_NONNULL(1, 2); ATTR_NONNULL(1, 2);
/* Return the value or pointer of a heap node. */ /**
* Return the value or pointer of a heap node.
*/
float BLI_heap_node_value(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); float BLI_heap_node_value(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void *BLI_heap_node_ptr(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); void *BLI_heap_node_ptr(const HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/* only for gtest */ /**
* Only for checking internal errors (gtest).
*/
bool BLI_heap_is_valid(const Heap *heap); bool BLI_heap_is_valid(const Heap *heap);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -30,14 +30,29 @@ typedef struct HeapSimple HeapSimple;
typedef void (*HeapSimpleFreeFP)(void *ptr); typedef void (*HeapSimpleFreeFP)(void *ptr);
/**
* Creates a new simple heap, which only supports insertion and removal from top.
*
* \note Use when the size of the heap is known in advance.
*/
HeapSimple *BLI_heapsimple_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT; HeapSimple *BLI_heapsimple_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT;
HeapSimple *BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT; HeapSimple *BLI_heapsimple_new(void) ATTR_WARN_UNUSED_RESULT;
void BLI_heapsimple_clear(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1); void BLI_heapsimple_clear(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1);
void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1); void BLI_heapsimple_free(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp) ATTR_NONNULL(1);
/**
* Insert heap node with a value (often a 'cost') and pointer into the heap,
* duplicate values are allowed.
*/
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1); void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) ATTR_NONNULL(1);
bool BLI_heapsimple_is_empty(const HeapSimple *heap) ATTR_NONNULL(1); bool BLI_heapsimple_is_empty(const HeapSimple *heap) ATTR_NONNULL(1);
uint BLI_heapsimple_len(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); uint BLI_heapsimple_len(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Return the lowest value of the heap.
*/
float BLI_heapsimple_top_value(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); float BLI_heapsimple_top_value(const HeapSimple *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Pop the top node off the heap and return its pointer.
*/
void *BLI_heapsimple_pop_min(HeapSimple *heap) ATTR_NONNULL(1); void *BLI_heapsimple_pop_min(HeapSimple *heap) ATTR_NONNULL(1);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -45,11 +45,11 @@ namespace blender {
class IndexMask { class IndexMask {
private: private:
/* The underlying reference to sorted integers. */ /** The underlying reference to sorted integers. */
Span<int64_t> indices_; Span<int64_t> indices_;
public: public:
/* Creates an IndexMask that contains no indices. */ /** Creates an IndexMask that contains no indices. */
IndexMask() = default; IndexMask() = default;
/** /**
@@ -224,6 +224,24 @@ class IndexMask {
} }
IndexMask slice(IndexRange slice) const; IndexMask slice(IndexRange slice) const;
/**
* Create a sub-mask that is also shifted to the beginning.
* The shifting to the beginning allows code to work with smaller indices,
* which is more memory efficient.
*
* \return New index mask with the size of #slice. It is either empty or starts with 0.
* It might reference indices that have been appended to #r_new_indices.
*
* Example:
* \code{.unparsed}
* this: [2, 3, 5, 7, 8, 9, 10]
* slice: ^--------^
* output: [0, 2, 4, 5]
* \endcode
*
* All the indices in the sub-mask are shifted by 3 towards zero,
* so that the first index in the output is zero.
*/
IndexMask slice_and_offset(IndexRange slice, Vector<int64_t> &r_new_indices) const; IndexMask slice_and_offset(IndexRange slice, Vector<int64_t> &r_new_indices) const;
}; };

View File

@@ -104,25 +104,35 @@ enum {
#define BVH_RAYCAST_DEFAULT (BVH_RAYCAST_WATERTIGHT) #define BVH_RAYCAST_DEFAULT (BVH_RAYCAST_WATERTIGHT)
#define BVH_RAYCAST_DIST_MAX (FLT_MAX / 2.0f) #define BVH_RAYCAST_DIST_MAX (FLT_MAX / 2.0f)
/* callback must update nearest in case it finds a nearest result */ /**
* Callback must update nearest in case it finds a nearest result.
*/
typedef void (*BVHTree_NearestPointCallback)(void *userdata, typedef void (*BVHTree_NearestPointCallback)(void *userdata,
int index, int index,
const float co[3], const float co[3],
BVHTreeNearest *nearest); BVHTreeNearest *nearest);
/* callback must update hit in case it finds a nearest successful hit */ /**
* Callback must update hit in case it finds a nearest successful hit.
*/
typedef void (*BVHTree_RayCastCallback)(void *userdata, typedef void (*BVHTree_RayCastCallback)(void *userdata,
int index, int index,
const BVHTreeRay *ray, const BVHTreeRay *ray,
BVHTreeRayHit *hit); BVHTreeRayHit *hit);
/* callback to check if 2 nodes overlap (use thread if intersection results need to be stored) */ /**
* Callback to check if 2 nodes overlap (use thread if intersection results need to be stored).
*/
typedef bool (*BVHTree_OverlapCallback)(void *userdata, int index_a, int index_b, int thread); typedef bool (*BVHTree_OverlapCallback)(void *userdata, int index_a, int index_b, int thread);
/* callback to range search query */ /**
* Callback to range search query.
*/
typedef void (*BVHTree_RangeQuery)(void *userdata, int index, const float co[3], float dist_sq); typedef void (*BVHTree_RangeQuery)(void *userdata, int index, const float co[3], float dist_sq);
/* callback to find nearest projected */ /**
* Callback to find nearest projected.
*/
typedef void (*BVHTree_NearestProjectedCallback)(void *userdata, typedef void (*BVHTree_NearestProjectedCallback)(void *userdata,
int index, int index,
const struct DistProjectedAABBPrecalc *precalc, const struct DistProjectedAABBPrecalc *precalc,
@@ -131,42 +141,67 @@ typedef void (*BVHTree_NearestProjectedCallback)(void *userdata,
BVHTreeNearest *nearest); BVHTreeNearest *nearest);
/* callbacks to BLI_bvhtree_walk_dfs */ /* callbacks to BLI_bvhtree_walk_dfs */
/* return true to traverse into this nodes children, else skip. */
/**
* Return true to traverse into this nodes children, else skip.
*/
typedef bool (*BVHTree_WalkParentCallback)(const BVHTreeAxisRange *bounds, void *userdata); typedef bool (*BVHTree_WalkParentCallback)(const BVHTreeAxisRange *bounds, void *userdata);
/* return true to keep walking, else early-exit the search. */ /**
* Return true to keep walking, else early-exit the search.
*/
typedef bool (*BVHTree_WalkLeafCallback)(const BVHTreeAxisRange *bounds, typedef bool (*BVHTree_WalkLeafCallback)(const BVHTreeAxisRange *bounds,
int index, int index,
void *userdata); void *userdata);
/* return true to search (min, max) else (max, min). */ /**
* Return true to search (min, max) else (max, min).
*/
typedef bool (*BVHTree_WalkOrderCallback)(const BVHTreeAxisRange *bounds, typedef bool (*BVHTree_WalkOrderCallback)(const BVHTreeAxisRange *bounds,
char axis, char axis,
void *userdata); void *userdata);
/**
* \note many callers don't check for `NULL` return.
*/
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis); BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis);
void BLI_bvhtree_free(BVHTree *tree); void BLI_bvhtree_free(BVHTree *tree);
/* construct: first insert points, then call balance */ /**
* Construct: first insert points, then call balance.
*/
void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints); void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoints);
void BLI_bvhtree_balance(BVHTree *tree); void BLI_bvhtree_balance(BVHTree *tree);
/* update: first update points/nodes, then call update_tree to refit the bounding volumes */ /**
* Update: first update points/nodes, then call update_tree to refit the bounding volumes.
* \note call before #BLI_bvhtree_update_tree().
*/
bool BLI_bvhtree_update_node( bool BLI_bvhtree_update_node(
BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints); BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints);
/**
* Call #BLI_bvhtree_update_node() first for every node/point/triangle.
*/
void BLI_bvhtree_update_tree(BVHTree *tree); void BLI_bvhtree_update_tree(BVHTree *tree);
/**
* Use to check the total number of threads #BLI_bvhtree_overlap will use.
*
* \warning Must be the first tree passed to #BLI_bvhtree_overlap!
*/
int BLI_bvhtree_overlap_thread_num(const BVHTree *tree); int BLI_bvhtree_overlap_thread_num(const BVHTree *tree);
/* collision/overlap: check two trees if they overlap, /**
* alloc's *overlap with length of the int return value */ * Collision/overlap: check two trees if they overlap,
BVHTreeOverlap *BLI_bvhtree_overlap_ex( * alloc's *overlap with length of the int return value.
const BVHTree *tree1, *
const BVHTree *tree2, * \param callback: optional, to test the overlap before adding (must be thread-safe!).
uint *r_overlap_tot, */
/* optional callback to test the overlap before adding (must be thread-safe!) */ BVHTreeOverlap *BLI_bvhtree_overlap_ex(const BVHTree *tree1,
BVHTree_OverlapCallback callback, const BVHTree *tree2,
void *userdata, uint *r_overlap_tot,
const uint max_interactions, BVHTree_OverlapCallback callback,
const int flag); void *userdata,
const uint max_interactions,
const int flag);
BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1, BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
const BVHTree *tree2, const BVHTree *tree2,
unsigned int *r_overlap_tot, unsigned int *r_overlap_tot,
@@ -175,14 +210,26 @@ BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1,
int *BLI_bvhtree_intersect_plane(BVHTree *tree, float plane[4], uint *r_intersect_tot); int *BLI_bvhtree_intersect_plane(BVHTree *tree, float plane[4], uint *r_intersect_tot);
/**
* Number of times #BLI_bvhtree_insert has been called.
* mainly useful for asserts functions to check we added the correct number.
*/
int BLI_bvhtree_get_len(const BVHTree *tree); int BLI_bvhtree_get_len(const BVHTree *tree);
/**
* Maximum number of children that a node can have.
*/
int BLI_bvhtree_get_tree_type(const BVHTree *tree); int BLI_bvhtree_get_tree_type(const BVHTree *tree);
float BLI_bvhtree_get_epsilon(const BVHTree *tree); float BLI_bvhtree_get_epsilon(const BVHTree *tree);
/**
* This function returns the bounding box of the BVH tree.
*/
void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3]); void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3]);
/* find nearest node to the given coordinates /**
* Find nearest node to the given coordinates
* (if nearest is given it will only search nodes where * (if nearest is given it will only search nodes where
* square distance is smaller than nearest->dist) */ * square distance is smaller than nearest->dist).
*/
int BLI_bvhtree_find_nearest_ex(BVHTree *tree, int BLI_bvhtree_find_nearest_ex(BVHTree *tree,
const float co[3], const float co[3],
BVHTreeNearest *nearest, BVHTreeNearest *nearest,
@@ -195,6 +242,10 @@ int BLI_bvhtree_find_nearest(BVHTree *tree,
BVHTree_NearestPointCallback callback, BVHTree_NearestPointCallback callback,
void *userdata); void *userdata);
/**
* Find the first node nearby.
* Favors speed over quality since it doesn't find the best target node.
*/
int BLI_bvhtree_find_nearest_first(BVHTree *tree, int BLI_bvhtree_find_nearest_first(BVHTree *tree,
const float co[3], const float co[3],
const float dist_sq, const float dist_sq,
@@ -217,6 +268,15 @@ int BLI_bvhtree_ray_cast(BVHTree *tree,
BVHTree_RayCastCallback callback, BVHTree_RayCastCallback callback,
void *userdata); void *userdata);
/**
* Calls the callback for every ray intersection
*
* \note Using a \a callback which resets or never sets the #BVHTreeRayHit index & dist works too,
* however using this function means existing generic callbacks can be used from custom callbacks
* without having to handle resetting the hit beforehand.
* It also avoid redundant argument and return value which aren't meaningful
* when collecting multiple hits.
*/
void BLI_bvhtree_ray_cast_all_ex(BVHTree *tree, void BLI_bvhtree_ray_cast_all_ex(BVHTree *tree,
const float co[3], const float co[3],
const float dir[3], const float dir[3],
@@ -238,7 +298,9 @@ float BLI_bvhtree_bb_raycast(const float bv[6],
const float light_end[3], const float light_end[3],
float pos[3]); float pos[3]);
/* range query */ /**
* Range query.
*/
int BLI_bvhtree_range_query( int BLI_bvhtree_range_query(
BVHTree *tree, const float co[3], float radius, BVHTree_RangeQuery callback, void *userdata); BVHTree *tree, const float co[3], float radius, BVHTree_RangeQuery callback, void *userdata);
@@ -252,13 +314,27 @@ int BLI_bvhtree_find_nearest_projected(BVHTree *tree,
BVHTree_NearestProjectedCallback callback, BVHTree_NearestProjectedCallback callback,
void *userdata); void *userdata);
/**
* This is a generic function to perform a depth first search on the #BVHTree
* where the search order and nodes traversed depend on callbacks passed in.
*
* \param tree: Tree to walk.
* \param walk_parent_cb: Callback on a parents bound-box to test if it should be traversed.
* \param walk_leaf_cb: Callback to test leaf nodes, callback must store its own result,
* returning false exits early.
* \param walk_order_cb: Callback that indicates which direction to search,
* either from the node with the lower or higher K-DOP axis value.
* \param userdata: Argument passed to all callbacks.
*/
void BLI_bvhtree_walk_dfs(BVHTree *tree, void BLI_bvhtree_walk_dfs(BVHTree *tree,
BVHTree_WalkParentCallback walk_parent_cb, BVHTree_WalkParentCallback walk_parent_cb,
BVHTree_WalkLeafCallback walk_leaf_cb, BVHTree_WalkLeafCallback walk_leaf_cb,
BVHTree_WalkOrderCallback walk_order_cb, BVHTree_WalkOrderCallback walk_order_cb,
void *userdata); void *userdata);
/* expose for bvh callbacks to use */ /**
* Expose for BVH callbacks to use.
*/
extern const float bvhtree_kdop_axes[13][3]; extern const float bvhtree_kdop_axes[13][3];
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -35,6 +35,9 @@ bool BLI_lasso_is_point_inside(const int mcoords[][2],
const int sx, const int sx,
const int sy, const int sy,
const int error_value); const int error_value);
/**
* Edge version for lasso select. We assume bound-box check was done.
*/
bool BLI_lasso_is_edge_inside(const int mcoords[][2], bool BLI_lasso_is_edge_inside(const int mcoords[][2],
const unsigned int mcoords_len, const unsigned int mcoords_len,
int x0, int x0,

View File

@@ -58,8 +58,15 @@ LinkNode *BLI_linklist_find_last(LinkNode *list) ATTR_WARN_UNUSED_RESULT;
void BLI_linklist_reverse(LinkNode **listp) ATTR_NONNULL(1); void BLI_linklist_reverse(LinkNode **listp) ATTR_NONNULL(1);
/**
* Move an item from its current position to a new one inside a single-linked list.
* \note `*listp` may be modified.
*/
void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index) ATTR_NONNULL(1); void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index) ATTR_NONNULL(1);
/**
* A version of #BLI_linklist_prepend that takes the allocated link.
*/
void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink) ATTR_NONNULL(1, 3); void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink) ATTR_NONNULL(1, 3);
void BLI_linklist_prepend(LinkNode **listp, void *ptr) ATTR_NONNULL(1); void BLI_linklist_prepend(LinkNode **listp, void *ptr) ATTR_NONNULL(1);
void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, struct MemArena *ma) void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, struct MemArena *ma)
@@ -67,7 +74,11 @@ void BLI_linklist_prepend_arena(LinkNode **listp, void *ptr, struct MemArena *ma
void BLI_linklist_prepend_pool(LinkNode **listp, void *ptr, struct BLI_mempool *mempool) void BLI_linklist_prepend_pool(LinkNode **listp, void *ptr, struct BLI_mempool *mempool)
ATTR_NONNULL(1, 3); ATTR_NONNULL(1, 3);
/* use LinkNodePair to avoid full search */ /* Use #LinkNodePair to avoid full search. */
/**
* A version of append that takes the allocated link.
*/
void BLI_linklist_append_nlink(LinkNodePair *list_pair, void *ptr, LinkNode *nlink) void BLI_linklist_append_nlink(LinkNodePair *list_pair, void *ptr, LinkNode *nlink)
ATTR_NONNULL(1, 3); ATTR_NONNULL(1, 3);
void BLI_linklist_append(LinkNodePair *list_pair, void *ptr) ATTR_NONNULL(1); void BLI_linklist_append(LinkNodePair *list_pair, void *ptr) ATTR_NONNULL(1);

View File

@@ -33,89 +33,233 @@
extern "C" { extern "C" {
#endif #endif
/**
* Returns the position of \a vlink within \a listbase, numbering from 0, or -1 if not found.
*/
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1); ATTR_NONNULL(1);
/**
* Returns the 0-based index of the first element of listbase which contains the specified
* null-terminated string at the specified offset, or -1 if not found.
*/
int BLI_findstringindex(const struct ListBase *listbase, int BLI_findstringindex(const struct ListBase *listbase,
const char *id, const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/* find forwards */ /* Find forwards. */
/**
* Returns the nth element of \a listbase, numbering from 0.
*/
void *BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT void *BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1); ATTR_NONNULL(1);
/**
* Finds the first element of \a listbase which contains the null-terminated
* string \a id at the specified offset, returning NULL if not found.
*/
void *BLI_findstring(const struct ListBase *listbase, void *BLI_findstring(const struct ListBase *listbase,
const char *id, const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Finds the first element of \a listbase which contains a pointer to the
* null-terminated string \a id at the specified offset, returning NULL if not found.
*/
void *BLI_findstring_ptr(const struct ListBase *listbase, void *BLI_findstring_ptr(const struct ListBase *listbase,
const char *id, const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Finds the first element of listbase which contains the specified pointer value
* at the specified offset, returning NULL if not found.
*/
void *BLI_findptr(const struct ListBase *listbase, void *BLI_findptr(const struct ListBase *listbase,
const void *ptr, const void *ptr,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Finds the first element of listbase which contains the specified bytes
* at the specified offset, returning NULL if not found.
*/
void *BLI_listbase_bytes_find(const ListBase *listbase, void *BLI_listbase_bytes_find(const ListBase *listbase,
const void *bytes, const void *bytes,
const size_t bytes_size, const size_t bytes_size,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
/**
* Find the first item in the list that matches the given string, or the given index as fallback.
*
* \note The string is only used is non-NULL and non-empty.
*
* \return The found item, or NULL.
*/
void *BLI_listbase_string_or_index_find(const struct ListBase *listbase, void *BLI_listbase_string_or_index_find(const struct ListBase *listbase,
const char *string, const char *string,
const size_t string_offset, const size_t string_offset,
const int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); const int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/* find backwards */ /* Find backwards. */
/**
* Returns the nth-last element of \a listbase, numbering from 0.
*/
void *BLI_rfindlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT void *BLI_rfindlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1); ATTR_NONNULL(1);
/**
* Finds the last element of \a listbase which contains the
* null-terminated string \a id at the specified offset, returning NULL if not found.
*/
void *BLI_rfindstring(const struct ListBase *listbase, void *BLI_rfindstring(const struct ListBase *listbase,
const char *id, const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Finds the last element of \a listbase which contains a pointer to the
* null-terminated string \a id at the specified offset, returning NULL if not found.
*/
void *BLI_rfindstring_ptr(const struct ListBase *listbase, void *BLI_rfindstring_ptr(const struct ListBase *listbase,
const char *id, const char *id,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Finds the last element of listbase which contains the specified pointer value
* at the specified offset, returning NULL if not found.
*/
void *BLI_rfindptr(const struct ListBase *listbase, void *BLI_rfindptr(const struct ListBase *listbase,
const void *ptr, const void *ptr,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Finds the last element of listbase which contains the specified bytes
* at the specified offset, returning NULL if not found.
*/
void *BLI_listbase_bytes_rfind(const ListBase *listbase, void *BLI_listbase_bytes_rfind(const ListBase *listbase,
const void *bytes, const void *bytes,
const size_t bytes_size, const size_t bytes_size,
const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
/**
* Removes and disposes of the entire contents of \a listbase using guardedalloc.
*/
void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1); void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1);
/**
* Appends \a vlink (assumed to begin with a Link) onto listbase.
*/
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1); void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
/**
* Removes \a vlink from \a listbase. Assumes it is linked into there!
*/
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1); void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
/**
* Checks that \a vlink is linked into listbase, removing it from there if so.
*/
bool BLI_remlink_safe(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1); bool BLI_remlink_safe(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
/**
* Removes the head from \a listbase and returns it.
*/
void *BLI_pophead(ListBase *listbase) ATTR_NONNULL(1); void *BLI_pophead(ListBase *listbase) ATTR_NONNULL(1);
/**
* Removes the tail from \a listbase and returns it.
*/
void *BLI_poptail(ListBase *listbase) ATTR_NONNULL(1); void *BLI_poptail(ListBase *listbase) ATTR_NONNULL(1);
/**
* Prepends \a vlink (assumed to begin with a Link) onto listbase.
*/
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1); void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
/**
* Inserts \a vnewlink immediately preceding \a vnextlink in listbase.
* Or, if \a vnextlink is NULL, puts \a vnewlink at the end of the list.
*/
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink)
ATTR_NONNULL(1); ATTR_NONNULL(1);
/**
* Inserts \a vnewlink immediately following \a vprevlink in \a listbase.
* Or, if \a vprevlink is NULL, puts \a vnewlink at the front of the list.
*/
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink)
ATTR_NONNULL(1); ATTR_NONNULL(1);
/**
* Insert a link in place of another, without changing its position in the list.
*
* Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`.
* - `vreplacelink` *must* be in the list.
* - `vnewlink` *must not* be in the list.
*/
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink) void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
ATTR_NONNULL(1, 2, 3); ATTR_NONNULL(1, 2, 3);
/**
* Sorts the elements of listbase into the order defined by cmp
* (which should return 1 if its first arg should come after its second arg).
* This uses insertion sort, so NOT ok for large list.
*/
void BLI_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const void *)) void BLI_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const void *))
ATTR_NONNULL(1, 2); ATTR_NONNULL(1, 2);
void BLI_listbase_sort_r(ListBase *listbase, void BLI_listbase_sort_r(ListBase *listbase,
int (*cmp)(void *, const void *, const void *), int (*cmp)(void *, const void *, const void *),
void *thunk) ATTR_NONNULL(1, 2); void *thunk) ATTR_NONNULL(1, 2);
/**
* Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
* item if new position would exceed list (could optionally move to head/tail).
*
* \param step: Absolute value defines step size, sign defines direction. E.g pass -1
* to move \a vlink before previous, or 1 to move behind next.
* \return If position of \a vlink has changed.
*/
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL(); bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL();
/**
* Move the link at the index \a from to the position at index \a to.
*
* \return If the move was successful.
*/
bool BLI_listbase_move_index(ListBase *listbase, int from, int to) ATTR_NONNULL(); bool BLI_listbase_move_index(ListBase *listbase, int from, int to) ATTR_NONNULL();
/**
* Removes and disposes of the entire contents of listbase using direct free(3).
*/
void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1); void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
/**
* Returns the number of elements in \a listbase, up until (and including count_max)
*
* \note Use to avoid redundant looping.
*/
int BLI_listbase_count_at_most(const struct ListBase *listbase, int BLI_listbase_count_at_most(const struct ListBase *listbase,
const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Returns the number of elements in \a listbase.
*/
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Removes \a vlink from listbase and disposes of it. Assumes it is linked into there!
*/
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1); void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
/**
* Swaps \a vlinka and \a vlinkb in the list. Assumes they are both already in the list!
*/
void BLI_listbase_swaplinks(struct ListBase *listbase, void *vlinka, void *vlinkb) void BLI_listbase_swaplinks(struct ListBase *listbase, void *vlinka, void *vlinkb)
ATTR_NONNULL(1, 2); ATTR_NONNULL(1, 2);
/**
* Swaps \a vlinka and \a vlinkb from their respective lists.
* Assumes they are both already in their \a listbasea!
*/
void BLI_listbases_swaplinks(struct ListBase *listbasea, void BLI_listbases_swaplinks(struct ListBase *listbasea,
struct ListBase *listbaseb, struct ListBase *listbaseb,
void *vlinka, void *vlinka,
void *vlinkb) ATTR_NONNULL(2, 3); void *vlinkb) ATTR_NONNULL(2, 3);
/**
* Moves the entire contents of \a src onto the end of \a dst.
*/
void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2); void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
/**
* Moves the entire contents of \a src at the beginning of \a dst.
*/
void BLI_movelisttolist_reverse(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2); void BLI_movelisttolist_reverse(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
/**
* Sets dst to a duplicate of the entire contents of src. dst may be the same as src.
*/
void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1, 2); void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1, 2);
void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1); void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1);
/**
* \param vlink: Link to make first.
*/
void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2); void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
/**
* \param vlink: Link to make last.
*/
void BLI_listbase_rotate_last(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2); void BLI_listbase_rotate_last(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
/** /**
@@ -134,7 +278,9 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
lb->first = lb->last = (void *)0; lb->first = lb->last = (void *)0;
} }
/* create a generic list node containing link to provided data */ /**
* Create a generic list node containing link to provided data.
*/
struct LinkData *BLI_genericNodeN(void *data); struct LinkData *BLI_genericNodeN(void *data);
/** /**
@@ -188,13 +334,17 @@ struct LinkData *BLI_genericNodeN(void *data);
#define LISTBASE_FOREACH_BACKWARD(type, var, list) \ #define LISTBASE_FOREACH_BACKWARD(type, var, list) \
for (type var = (type)((list)->last); var != NULL; var = (type)(((Link *)(var))->prev)) for (type var = (type)((list)->last); var != NULL; var = (type)(((Link *)(var))->prev))
/** A version of #LISTBASE_FOREACH that supports removing the item we're looping over. */ /**
* A version of #LISTBASE_FOREACH that supports removing the item we're looping over.
*/
#define LISTBASE_FOREACH_MUTABLE(type, var, list) \ #define LISTBASE_FOREACH_MUTABLE(type, var, list) \
for (type var = (type)((list)->first), *var##_iter_next; \ for (type var = (type)((list)->first), *var##_iter_next; \
((var != NULL) ? ((void)(var##_iter_next = (type)(((Link *)(var))->next)), 1) : 0); \ ((var != NULL) ? ((void)(var##_iter_next = (type)(((Link *)(var))->next)), 1) : 0); \
var = var##_iter_next) var = var##_iter_next)
/** A version of #LISTBASE_FOREACH_BACKWARD that supports removing the item we're looping over. */ /**
* A version of #LISTBASE_FOREACH_BACKWARD that supports removing the item we're looping over.
*/
#define LISTBASE_FOREACH_BACKWARD_MUTABLE(type, var, list) \ #define LISTBASE_FOREACH_BACKWARD_MUTABLE(type, var, list) \
for (type var = (type)((list)->last), *var##_iter_prev; \ for (type var = (type)((list)->last), *var##_iter_prev; \
((var != NULL) ? ((void)(var##_iter_prev = (type)(((Link *)(var))->prev)), 1) : 0); \ ((var != NULL) ? ((void)(var##_iter_prev = (type)(((Link *)(var))->prev)), 1) : 0); \

View File

@@ -97,6 +97,7 @@ extern "C" {
/******************************* Float ******************************/ /******************************* Float ******************************/
/* powf is really slow for raising to integer powers. */
MINLINE float pow2f(float x); MINLINE float pow2f(float x);
MINLINE float pow3f(float x); MINLINE float pow3f(float x);
MINLINE float pow4f(float x); MINLINE float pow4f(float x);
@@ -120,11 +121,18 @@ MINLINE double interpd(double a, double b, double t);
MINLINE float ratiof(float min, float max, float pos); MINLINE float ratiof(float min, float max, float pos);
MINLINE double ratiod(double min, double max, double pos); MINLINE double ratiod(double min, double max, double pos);
/**
* Map a normalized value, i.e. from interval [0, 1] to interval [a, b].
*/
MINLINE float scalenorm(float a, float b, float x); MINLINE float scalenorm(float a, float b, float x);
/**
* Map a normalized value, i.e. from interval [0, 1] to interval [a, b].
*/
MINLINE double scalenormd(double a, double b, double x); MINLINE double scalenormd(double a, double b, double x);
/* NOTE: Compilers will upcast all types smaller than int to int when performing arithmetic /* NOTE: Compilers will upcast all types smaller than int to int when performing arithmetic
* operation. */ * operation. */
MINLINE int square_s(short a); MINLINE int square_s(short a);
MINLINE int square_uchar(unsigned char a); MINLINE int square_uchar(unsigned char a);
MINLINE int cube_s(short a); MINLINE int cube_s(short a);
@@ -170,7 +178,23 @@ MINLINE int clamp_i(int value, int min, int max);
MINLINE float clamp_f(float value, float min, float max); MINLINE float clamp_f(float value, float min, float max);
MINLINE size_t clamp_z(size_t value, size_t min, size_t max); MINLINE size_t clamp_z(size_t value, size_t min, size_t max);
/**
* Almost-equal for IEEE floats, using absolute difference method.
*
* \param max_diff: the maximum absolute difference.
*/
MINLINE int compare_ff(float a, float b, const float max_diff); MINLINE int compare_ff(float a, float b, const float max_diff);
/**
* Almost-equal for IEEE floats, using their integer representation
* (mixing ULP and absolute difference methods).
*
* \param max_diff: is the maximum absolute difference (allows to take care of the near-zero area,
* where relative difference methods cannot really work).
* \param max_ulps: is the 'maximum number of floats + 1'
* allowed between \a a and \a b to consider them equal.
*
* \see https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
*/
MINLINE int compare_ff_relative(float a, float b, const float max_diff, const int max_ulps); MINLINE int compare_ff_relative(float a, float b, const float max_diff, const int max_ulps);
MINLINE bool compare_threshold_relative(const float value1, MINLINE bool compare_threshold_relative(const float value1,
const float value2, const float value2,
@@ -180,13 +204,25 @@ MINLINE float signf(float f);
MINLINE int signum_i_ex(float a, float eps); MINLINE int signum_i_ex(float a, float eps);
MINLINE int signum_i(float a); MINLINE int signum_i(float a);
/**
* Used for zoom values.
*/
MINLINE float power_of_2(float f); MINLINE float power_of_2(float f);
/**
* Returns number of (base ten) *significant* digits of integer part of given float
* (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
*/
MINLINE int integer_digits_f(const float f); MINLINE int integer_digits_f(const float f);
/**
* Returns number of (base ten) *significant* digits of integer part of given double
* (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
*/
MINLINE int integer_digits_d(const double d); MINLINE int integer_digits_d(const double d);
MINLINE int integer_digits_i(const int i); MINLINE int integer_digits_i(const int i);
/* these don't really fit anywhere but were being copied about a lot */ /* These don't really fit anywhere but were being copied about a lot. */
MINLINE int is_power_of_2_i(int n); MINLINE int is_power_of_2_i(int n);
MINLINE int power_of_2_max_i(int n); MINLINE int power_of_2_max_i(int n);
MINLINE int power_of_2_min_i(int n); MINLINE int power_of_2_min_i(int n);
@@ -196,9 +232,19 @@ MINLINE unsigned int power_of_2_min_u(unsigned int x);
MINLINE unsigned int log2_floor_u(unsigned int x); MINLINE unsigned int log2_floor_u(unsigned int x);
MINLINE unsigned int log2_ceil_u(unsigned int x); MINLINE unsigned int log2_ceil_u(unsigned int x);
/**
* Integer division that rounds 0.5 up, particularly useful for color blending
* with integers, to avoid gradual darkening when rounding down.
*/
MINLINE int divide_round_i(int a, int b); MINLINE int divide_round_i(int a, int b);
/**
* modulo that handles negative numbers, works the same as Python's.
*/
MINLINE int mod_i(int i, int n); MINLINE int mod_i(int i, int n);
/**
* Round to closest even number, halfway cases are rounded away from zero.
*/
MINLINE float round_to_even(float f); MINLINE float round_to_even(float f);
MINLINE signed char round_fl_to_char(float a); MINLINE signed char round_fl_to_char(float a);
@@ -230,18 +276,40 @@ MINLINE int round_db_to_int_clamp(double a);
MINLINE unsigned int round_db_to_uint_clamp(double a); MINLINE unsigned int round_db_to_uint_clamp(double a);
int pow_i(int base, int exp); int pow_i(int base, int exp);
/**
* \param ndigits: must be between 0 and 21.
*/
double double_round(double x, int ndigits); double double_round(double x, int ndigits);
/**
* Floor to the nearest power of 10, e.g.:
* - 15.0 -> 10.0
* - 0.015 -> 0.01
* - 1.0 -> 1.0
*
* \param f: Value to floor, must be over 0.0.
* \note If we wanted to support signed values we could if this becomes necessary.
*/
float floor_power_of_10(float f); float floor_power_of_10(float f);
/**
* Ceiling to the nearest power of 10, e.g.:
* - 15.0 -> 100.0
* - 0.015 -> 0.1
* - 1.0 -> 1.0
*
* \param f: Value to ceiling, must be over 0.0.
* \note If we wanted to support signed values we could if this becomes necessary.
*/
float ceil_power_of_10(float f); float ceil_power_of_10(float f);
#ifdef BLI_MATH_GCC_WARN_PRAGMA #ifdef BLI_MATH_GCC_WARN_PRAGMA
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
/* asserts, some math functions expect normalized inputs /* Asserts, some math functions expect normalized inputs
* check the vector is unit length, or zero length (which can't be helped in some cases). * check the vector is unit length, or zero length (which can't be helped in some cases). */
*/
#ifndef NDEBUG #ifndef NDEBUG
/** \note 0.0001 is too small because normals may be converted from short's: see T34322. */ /** \note 0.0001 is too small because normals may be converted from short's: see T34322. */
# define BLI_ASSERT_UNIT_EPSILON 0.0002f # define BLI_ASSERT_UNIT_EPSILON 0.0002f

View File

@@ -32,20 +32,24 @@
namespace blender { namespace blender {
/* #orient2d gives the exact result, using multi-precision arithmetic when result /**
* #orient2d gives the exact result, using multi-precision arithmetic when result
* is close to zero. orient3d_fast just uses double arithmetic, so may be * is close to zero. orient3d_fast just uses double arithmetic, so may be
* wrong if the answer is very close to zero. * wrong if the answer is very close to zero.
* Similarly, for #incircle and #incircle_fast. */ * Similarly, for #incircle and #incircle_fast.
*/
int orient2d(const double2 &a, const double2 &b, const double2 &c); int orient2d(const double2 &a, const double2 &b, const double2 &c);
int orient2d_fast(const double2 &a, const double2 &b, const double2 &c); int orient2d_fast(const double2 &a, const double2 &b, const double2 &c);
int incircle(const double2 &a, const double2 &b, const double2 &c, const double2 &d); int incircle(const double2 &a, const double2 &b, const double2 &c, const double2 &d);
int incircle_fast(const double2 &a, const double2 &b, const double2 &c, const double2 &d); int incircle_fast(const double2 &a, const double2 &b, const double2 &c, const double2 &d);
/* #orient3d gives the exact result, using multi-precision arithmetic when result /**
* #orient3d gives the exact result, using multi-precision arithmetic when result
* is close to zero. orient3d_fast just uses double arithmetic, so may be * is close to zero. orient3d_fast just uses double arithmetic, so may be
* wrong if the answer is very close to zero. * wrong if the answer is very close to zero.
* Similarly, for #insphere and #insphere_fast. */ * Similarly, for #insphere and #insphere_fast.
*/
int orient3d(const double3 &a, const double3 &b, const double3 &c, const double3 &d); int orient3d(const double3 &a, const double3 &b, const double3 &c, const double3 &d);
int orient3d_fast(const double3 &a, const double3 &b, const double3 &c, const double3 &d); int orient3d_fast(const double3 &a, const double3 &b, const double3 &c, const double3 &d);
@@ -55,8 +59,23 @@ int insphere_fast(
const double3 &a, const double3 &b, const double3 &c, const double3 &d, const double3 &e); const double3 &a, const double3 &b, const double3 &c, const double3 &d, const double3 &e);
#ifdef WITH_GMP #ifdef WITH_GMP
/**
* Return +1 if a, b, c are in CCW order around a circle in the plane.
* Return -1 if they are in CW order, and 0 if they are in line.
*/
int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c); int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c);
/**
* Return +1 if d is in the oriented circle through a, b, and c.
* The oriented circle goes CCW through a, b, and c.
* Return -1 if d is outside, and 0 if it is on the circle.
*/
int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d); int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d);
/**
* Return +1 if d is below the plane containing a, b, c (which appear
* CCW when viewed from above the plane).
* Return -1 if d is above the plane.
* Return 0 if it is on the plane.
*/
int orient3d(const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &d); int orient3d(const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &d);
#endif #endif
} // namespace blender } // namespace blender

View File

@@ -31,6 +31,10 @@
extern "C" { extern "C" {
#endif #endif
/* -------------------------------------------------------------------- */
/** \name Defines
* \{ */
/* YCbCr */ /* YCbCr */
#define BLI_YCC_ITU_BT601 0 #define BLI_YCC_ITU_BT601 0
#define BLI_YCC_ITU_BT709 1 #define BLI_YCC_ITU_BT709 1
@@ -40,7 +44,11 @@ extern "C" {
#define BLI_YUV_ITU_BT601 0 #define BLI_YUV_ITU_BT601 0
#define BLI_YUV_ITU_BT709 1 #define BLI_YUV_ITU_BT709 1
/******************* Conversion to RGB ********************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Conversion to RGB
* \{ */
void hsv_to_rgb(float h, float s, float v, float *r_r, float *r_g, float *r_b); void hsv_to_rgb(float h, float s, float v, float *r_r, float *r_g, float *r_b);
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3]); void hsv_to_rgb_v(const float hsv[3], float r_rgb[3]);
@@ -51,9 +59,18 @@ void yuv_to_rgb(float y, float u, float v, float *r_r, float *r_g, float *r_b, i
void ycc_to_rgb(float y, float cb, float cr, float *r_r, float *r_g, float *r_b, int colorspace); void ycc_to_rgb(float y, float cb, float cr, float *r_r, float *r_g, float *r_b, int colorspace);
void cpack_to_rgb(unsigned int col, float *r_r, float *r_g, float *r_b); void cpack_to_rgb(unsigned int col, float *r_r, float *r_g, float *r_b);
/***************** Conversion from RGB ********************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Conversion from RGB
* \{ */
void rgb_to_yuv(float r, float g, float b, float *r_y, float *r_u, float *r_v, int colorspace); void rgb_to_yuv(float r, float g, float b, float *r_y, float *r_u, float *r_v, int colorspace);
/**
* The RGB inputs are supposed gamma corrected and in the range 0 - 1.0f
*
* Output YCC have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255.
*/
void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr, int colorspace); void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr, int colorspace);
void rgb_to_hsv(float r, float g, float b, float *r_h, float *r_s, float *r_v); void rgb_to_hsv(float r, float g, float b, float *r_h, float *r_s, float *r_v);
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3]); void rgb_to_hsv_v(const float rgb[3], float r_hsv[3]);
@@ -64,9 +81,19 @@ void rgb_to_hsl_compat_v(const float rgb[3], float r_hsl[3]);
void rgb_to_hsv_compat(float r, float g, float b, float *r_h, float *r_s, float *r_v); void rgb_to_hsv_compat(float r, float g, float b, float *r_h, float *r_s, float *r_v);
void rgb_to_hsv_compat_v(const float rgb[3], float r_hsv[3]); void rgb_to_hsv_compat_v(const float rgb[3], float r_hsv[3]);
unsigned int rgb_to_cpack(float r, float g, float b); unsigned int rgb_to_cpack(float r, float g, float b);
/**
* We define a 'cpack' here as a (3 byte color code)
* number that can be expressed like 0xFFAA66 or so.
* For that reason it is sensitive for endianness... with this function it works correctly.
* \see #imm_cpack
*/
unsigned int hsv_to_cpack(float h, float s, float v); unsigned int hsv_to_cpack(float h, float s, float v);
/**************** Profile Transformations *****************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Profile Transformations
* \{ */
float srgb_to_linearrgb(float c); float srgb_to_linearrgb(float c);
float linearrgb_to_srgb(float c); float linearrgb_to_srgb(float c);
@@ -90,7 +117,11 @@ MINLINE void linearrgb_to_srgb_uchar4(unsigned char srgb[4], const float linear[
void BLI_init_srgb_conversion(void); void BLI_init_srgb_conversion(void);
/**************** Alpha Transformations *****************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Alpha Transformations
* \{ */
MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4]); MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4]);
MINLINE void premul_to_straight_v4(float color[4]); MINLINE void premul_to_straight_v4(float color[4]);
@@ -99,13 +130,34 @@ MINLINE void straight_to_premul_v4(float color[4]);
MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4]); MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4]);
MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4]); MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float color[4]);
/************************** Other *************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Other
* \{ */
/**
* If the requested RGB shade contains a negative weight for
* one of the primaries, it lies outside the color gamut
* accessible from the given triple of primaries. Desaturate
* it by adding white, equal quantities of R, G, and B, enough
* to make RGB all positive. The function returns 1 if the
* components were modified, zero otherwise.
*/
int constrain_rgb(float *r, float *g, float *b); int constrain_rgb(float *r, float *g, float *b);
void minmax_rgb(short c[3]); void minmax_rgb(short c[3]);
/**
* Clamp `hsv` to usable values.
*/
void hsv_clamp_v(float hsv[3], float v_max); void hsv_clamp_v(float hsv[3], float v_max);
/**
* Applies an HUE offset to a float RGB color.
*/
void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset); void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset);
/**
* Applies an HUE offset to a byte RGB color.
*/
void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset); void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset);
void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3]); void rgb_uchar_to_float(float r_col[3], const unsigned char col_ub[3]);
@@ -113,11 +165,28 @@ void rgba_uchar_to_float(float r_col[4], const unsigned char col_ub[4]);
void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3]); void rgb_float_to_uchar(unsigned char r_col[3], const float col_f[3]);
void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4]); void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4]);
/**
* ITU-R BT.709 primaries
* https://en.wikipedia.org/wiki/Relative_luminance
*
* Real values are:
* `Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`
* according to: "Derivation of Basic Television Color Equations", RP 177-1993
*
* As this sums slightly above 1.0, the document recommends to use:
* `0.2126(R) + 0.7152(G) + 0.0722(B)`, as used here.
*
* The high precision values are used to calculate the rounded byte weights so they add up to 255:
* `54(R) + 182(G) + 19(B)`
*/
MINLINE float rgb_to_grayscale(const float rgb[3]); MINLINE float rgb_to_grayscale(const float rgb[3]);
MINLINE unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3]); MINLINE unsigned char rgb_to_grayscale_byte(const unsigned char rgb[3]);
MINLINE int compare_rgb_uchar(const unsigned char a[3], const unsigned char b[3], const int limit); MINLINE int compare_rgb_uchar(const unsigned char a[3], const unsigned char b[3], const int limit);
/**
* Return triangle noise in [-0.5..1.5] range.
*/
MINLINE float dither_random_value(float s, float t); MINLINE float dither_random_value(float s, float t);
MINLINE void float_to_byte_dither_v3( MINLINE void float_to_byte_dither_v3(
unsigned char b[3], const float f[3], float dither, float s, float t); unsigned char b[3], const float f[3], float dither, float s, float t);
@@ -145,7 +214,11 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack);
void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, float max); void blackbody_temperature_to_rgb_table(float *r_table, int width, float min, float max);
void wavelength_to_xyz_table(float *r_table, int width); void wavelength_to_xyz_table(float *r_table, int width);
/********* lift/gamma/gain / ASC-CDL conversion ***********/ /** \} */
/* -------------------------------------------------------------------- */
/** \name lift/gamma/gain / ASC-CDL conversion
* \{ */
void lift_gamma_gain_to_asc_cdl(const float *lift, void lift_gamma_gain_to_asc_cdl(const float *lift,
const float *gamma, const float *gamma,
@@ -158,6 +231,8 @@ void lift_gamma_gain_to_asc_cdl(const float *lift,
# include "intern/math_color_inline.c" # include "intern/math_color_inline.c"
#endif #endif
/** \} */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -77,7 +77,8 @@ typedef void (*ewa_filter_read_pixel_cb)(void *userdata, int x, int y, float res
void BLI_ewa_imp2radangle( void BLI_ewa_imp2radangle(
float A, float B, float C, float F, float *a, float *b, float *th, float *ecc); float A, float B, float C, float F, float *a, float *b, float *th, float *ecc);
/* TODO(sergey): Consider making this function inlined, so the pixel read callback /**
* TODO(sergey): Consider making this function inlined, so the pixel read callback
* could also be inlined in order to avoid per-pixel function calls. * could also be inlined in order to avoid per-pixel function calls.
*/ */
void BLI_ewa_filter(const int width, void BLI_ewa_filter(const int width,

View File

@@ -32,7 +32,11 @@
extern "C" { extern "C" {
#endif #endif
/********************************* Init **************************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Init
* \{ */
void zero_m2(float m[2][2]); void zero_m2(float m[2][2]);
void zero_m3(float m[3][3]); void zero_m3(float m[3][3]);
@@ -66,7 +70,11 @@ void swap_m4m4(float m1[4][4], float m2[4][4]);
/* Build index shuffle matrix */ /* Build index shuffle matrix */
void shuffle_m4(float R[4][4], const int index[4]); void shuffle_m4(float R[4][4], const int index[4]);
/******************************** Arithmetic *********************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Arithmetic
* \{ */
void add_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]); void add_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]);
void add_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]); void add_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]);
@@ -81,14 +89,21 @@ void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3]);
void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4]); void mul_m4_m3m4(float R[4][4], const float A[3][3], const float B[4][4]);
void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3]); void mul_m4_m4m3(float R[4][4], const float A[4][4], const float B[3][3]);
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]); void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4]);
/**
* `R = A * B`, ignore the elements on the 4th row/column of A.
*/
void mul_m3_m3m4(float R[3][3], const float A[3][3], const float B[4][4]); void mul_m3_m3m4(float R[3][3], const float A[3][3], const float B[4][4]);
/**
* `R = A * B`, ignore the elements on the 4th row/column of B.
*/
void mul_m3_m4m3(float R[3][3], const float A[4][4], const float B[3][3]); void mul_m3_m4m3(float R[3][3], const float A[4][4], const float B[3][3]);
void mul_m3_m4m4(float R[3][3], const float A[4][4], const float B[4][4]); void mul_m3_m4m4(float R[3][3], const float A[4][4], const float B[4][4]);
/* special matrix multiplies /**
* uniq: R <-- AB, R is neither A nor B * Special matrix multiplies
* pre: R <-- AR * - uniq: `R <-- AB`, R is neither A nor B
* post: R <-- RB * - pre: `R <-- AR`
* - post: `R <-- RB`.
*/ */
void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3]); void mul_m3_m3m3_uniq(float R[3][3], const float A[3][3], const float B[3][3]);
void mul_m3_m3_pre(float R[3][3], const float A[3][3]); void mul_m3_m3_pre(float R[3][3], const float A[3][3]);
@@ -192,6 +207,7 @@ void mul_v4_m4v3_db(double r[4], const double mat[4][4], const double vec[3]);
void mul_v2_m4v3(float r[2], const float M[4][4], const float v[3]); void mul_v2_m4v3(float r[2], const float M[4][4], const float v[3]);
void mul_v2_m2v2(float r[2], const float M[2][2], const float v[2]); void mul_v2_m2v2(float r[2], const float M[2][2], const float v[2]);
void mul_m2_v2(const float M[2][2], float v[2]); void mul_m2_v2(const float M[2][2], float v[2]);
/** Same as #mul_m4_v3() but doesn't apply translation component. */
void mul_mat3_m4_v3(const float M[4][4], float r[3]); void mul_mat3_m4_v3(const float M[4][4], float r[3]);
void mul_v3_mat3_m4v3(float r[3], const float M[4][4], const float v[3]); void mul_v3_mat3_m4v3(float r[3], const float M[4][4], const float v[3]);
void mul_v3_mat3_m4v3_db(double r[3], const double M[4][4], const double v[3]); void mul_v3_mat3_m4v3_db(double r[3], const double M[4][4], const double v[3]);
@@ -211,7 +227,18 @@ void mul_transposed_m3_v3(const float M[3][3], float r[3]);
void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3]); void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3]);
void mul_m3_v3_double(const float M[3][3], double r[3]); void mul_m3_v3_double(const float M[3][3], double r[3]);
/**
* Combines transformations, handling scale separately in a manner equivalent
* to the Aligned Inherit Scale mode, in order to avoid creating shear.
* If A scale is uniform, the result is equivalent to ordinary multiplication.
*
* NOTE: this effectively takes output location from simple multiplication,
* and uses mul_m4_m4m4_split_channels for rotation and scale.
*/
void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4]); void mul_m4_m4m4_aligned_scale(float R[4][4], const float A[4][4], const float B[4][4]);
/**
* Separately combines location, rotation and scale of the input matrices.
*/
void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float B[4][4]); void mul_m4_m4m4_split_channels(float R[4][4], const float A[4][4], const float B[4][4]);
void mul_m3_fl(float R[3][3], float f); void mul_m3_fl(float R[3][3], float f);
@@ -229,6 +256,16 @@ bool invert_m3(float R[3][3]);
bool invert_m3_m3(float R[3][3], const float A[3][3]); bool invert_m3_m3(float R[3][3], const float A[3][3]);
bool invert_m4(float R[4][4]); bool invert_m4(float R[4][4]);
bool invert_m4_m4(float R[4][4], const float A[4][4]); bool invert_m4_m4(float R[4][4], const float A[4][4]);
/**
* Computes the inverse of mat and puts it in inverse.
* Uses Gaussian Elimination with partial (maximal column) pivoting.
* \return true on success (i.e. can always find a pivot) and false on failure.
* Mark Segal - 1992.
*
* \note this has worse performance than #EIG_invert_m4_m4 (Eigen), but e.g.
* for non-invertible scale matrices, finding a partial solution can
* be useful to have a valid local transform center, see T57767.
*/
bool invert_m4_m4_fallback(float R[4][4], const float A[4][4]); bool invert_m4_m4_fallback(float R[4][4], const float A[4][4]);
/* double arithmetic (mixed float/double) */ /* double arithmetic (mixed float/double) */
@@ -239,10 +276,15 @@ void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]);
void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]); void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]);
void mul_m3_v3_db(const double M[3][3], double r[3]); void mul_m3_v3_db(const double M[3][3], double r[3]);
/****************************** Linear Algebra *******************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Linear Algebra
* \{ */
void transpose_m3(float R[3][3]); void transpose_m3(float R[3][3]);
void transpose_m3_m3(float R[3][3], const float M[3][3]); void transpose_m3_m3(float R[3][3], const float M[3][3]);
/* seems obscure but in-fact a common operation */
void transpose_m3_m4(float R[3][3], const float M[4][4]); void transpose_m3_m4(float R[3][3], const float M[4][4]);
void transpose_m4(float R[4][4]); void transpose_m4(float R[4][4]);
void transpose_m4_m4(float R[4][4], const float M[4][4]); void transpose_m4_m4(float R[4][4], const float M[4][4]);
@@ -262,10 +304,36 @@ void normalize_m4(float R[4][4]) ATTR_NONNULL();
void normalize_m4_m4_ex(float R[4][4], const float M[4][4], float r_scale[3]) ATTR_NONNULL(); void normalize_m4_m4_ex(float R[4][4], const float M[4][4], float r_scale[3]) ATTR_NONNULL();
void normalize_m4_m4(float R[4][4], const float M[4][4]) ATTR_NONNULL(); void normalize_m4_m4(float R[4][4], const float M[4][4]) ATTR_NONNULL();
/**
* Make an orthonormal matrix around the selected axis of the given matrix.
*
* \param axis: Axis to build the orthonormal basis around.
*/
void orthogonalize_m3(float R[3][3], int axis); void orthogonalize_m3(float R[3][3], int axis);
/**
* Make an orthonormal matrix around the selected axis of the given matrix.
*
* \param axis: Axis to build the orthonormal basis around.
*/
void orthogonalize_m4(float R[4][4], int axis); void orthogonalize_m4(float R[4][4], int axis);
/**
* Make an orthonormal matrix around the selected axis of the given matrix,
* in a way that is symmetric and stable to variations in the input, and
* preserving the value of the determinant, i.e. the overall volume change.
*
* \param axis: Axis to build the orthonormal basis around.
* \param normalize: Normalize the matrix instead of preserving volume.
*/
void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize); void orthogonalize_m3_stable(float R[3][3], int axis, bool normalize);
/**
* Make an orthonormal matrix around the selected axis of the given matrix,
* in a way that is symmetric and stable to variations in the input, and
* preserving the value of the determinant, i.e. the overall volume change.
*
* \param axis: Axis to build the orthonormal basis around.
* \param normalize: Normalize the matrix instead of preserving volume.
*/
void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize); void orthogonalize_m4_stable(float R[4][4], int axis, bool normalize);
bool orthogonalize_m3_zero_axes(float R[3][3], const float unit_length); bool orthogonalize_m3_zero_axes(float R[3][3], const float unit_length);
@@ -281,8 +349,8 @@ bool is_uniform_scaled_m4(const float m[4][4]);
/* NOTE: 'adjoint' here means the adjugate (adjunct, "classical adjoint") matrix! /* NOTE: 'adjoint' here means the adjugate (adjunct, "classical adjoint") matrix!
* Nowadays 'adjoint' usually refers to the conjugate transpose, * Nowadays 'adjoint' usually refers to the conjugate transpose,
* which for real-valued matrices is simply the transpose. * which for real-valued matrices is simply the transpose. */
*/
void adjoint_m2_m2(float R[2][2], const float M[2][2]); void adjoint_m2_m2(float R[2][2], const float M[2][2]);
void adjoint_m3_m3(float R[3][3], const float M[3][3]); void adjoint_m3_m3(float R[3][3], const float M[3][3]);
void adjoint_m4_m4(float R[4][4], const float M[4][4]); void adjoint_m4_m4(float R[4][4], const float M[4][4]);
@@ -297,6 +365,13 @@ float determinant_m4(const float m[4][4]);
#define PSEUDOINVERSE_EPSILON 1e-8f #define PSEUDOINVERSE_EPSILON 1e-8f
/**
* Compute the Single Value Decomposition of an arbitrary matrix A
* That is compute the 3 matrices U,W,V with U column orthogonal (m,n)
* ,W a diagonal matrix and V an orthogonal square matrix `s.t.A = U.W.Vt`.
* From this decomposition it is trivial to compute the (pseudo-inverse)
* of `A` as `Ainv = V.Winv.transpose(U)`.
*/
void svd_m4(float U[4][4], float s[4], float V[4][4], float A[4][4]); void svd_m4(float U[4][4], float s[4], float V[4][4], float A[4][4]);
void pseudoinverse_m4_m4(float Ainv[4][4], const float A[4][4], float epsilon); void pseudoinverse_m4_m4(float Ainv[4][4], const float A[4][4], float epsilon);
void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon); void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon);
@@ -306,18 +381,39 @@ bool has_zero_axis_m4(const float matrix[4][4]);
void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]); void invert_m4_m4_safe(float Ainv[4][4], const float A[4][4]);
void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3]); void invert_m3_m3_safe_ortho(float Ainv[3][3], const float A[3][3]);
/**
* A safe version of invert that uses valid axes, calculating the zero'd axis
* based on the non-zero ones.
*
* This works well for transformation matrices, when a single axis is zerod.
*/
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4]); void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4]);
/****************************** Transformations ******************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Transformations
* \{ */
void scale_m3_fl(float R[3][3], float scale); void scale_m3_fl(float R[3][3], float scale);
void scale_m4_fl(float R[4][4], float scale); void scale_m4_fl(float R[4][4], float scale);
/**
* This computes the overall volume scale factor of a transformation matrix.
* For an orthogonal matrix, it is the product of all three scale values.
* Returns a negative value if the transform is flipped by negative scale.
*/
float mat3_to_volume_scale(const float M[3][3]); float mat3_to_volume_scale(const float M[3][3]);
float mat4_to_volume_scale(const float M[4][4]); float mat4_to_volume_scale(const float M[4][4]);
/**
* This gets the average scale of a matrix, only use when your scaling
* data that has no idea of scale axis, examples are bone-envelope-radius
* and curve radius.
*/
float mat3_to_scale(const float M[3][3]); float mat3_to_scale(const float M[3][3]);
float mat4_to_scale(const float M[4][4]); float mat4_to_scale(const float M[4][4]);
/** Return 2D scale (in XY plane) of given mat4. */
float mat4_to_xy_scale(const float M[4][4]); float mat4_to_xy_scale(const float M[4][4]);
void size_to_mat3(float R[3][3], const float size[3]); void size_to_mat3(float R[3][3], const float size[3]);
@@ -326,11 +422,31 @@ void size_to_mat4(float R[4][4], const float size[3]);
void mat3_to_size(float size[3], const float M[3][3]); void mat3_to_size(float size[3], const float M[3][3]);
void mat4_to_size(float size[3], const float M[4][4]); void mat4_to_size(float size[3], const float M[4][4]);
/**
* Extract scale factors from the matrix, with correction to ensure
* exact volume in case of a sheared matrix.
*/
void mat4_to_size_fix_shear(float size[3], const float M[4][4]); void mat4_to_size_fix_shear(float size[3], const float M[4][4]);
void translate_m4(float mat[4][4], float tx, float ty, float tz); void translate_m4(float mat[4][4], float tx, float ty, float tz);
/**
* Rotate a matrix in-place.
*
* \note To create a new rotation matrix see:
* #axis_angle_to_mat4_single, #axis_angle_to_mat3_single, #angle_to_mat2
* (axis & angle args are compatible).
*/
void rotate_m4(float mat[4][4], const char axis, const float angle); void rotate_m4(float mat[4][4], const char axis, const float angle);
/** Scale a matrix in-place. */
void rescale_m4(float mat[4][4], const float scale[3]); void rescale_m4(float mat[4][4], const float scale[3]);
/**
* Scale or rotate around a pivot point,
* a convenience function to avoid having to do inline.
*
* Since its common to make a scale/rotation matrix that pivots around an arbitrary point.
*
* Typical use case is to make 3x3 matrix, copy to 4x4, then pass to this function.
*/
void transform_pivot_set_m4(float mat[4][4], const float pivot[3]); void transform_pivot_set_m4(float mat[4][4], const float pivot[3]);
void mat4_to_rot(float rot[3][3], const float wmat[4][4]); void mat4_to_rot(float rot[3][3], const float wmat[4][4]);
@@ -341,16 +457,34 @@ void mat4_decompose(float loc[3], float quat[4], float size[3], const float wmat
void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]); void mat3_polar_decompose(const float mat3[3][3], float r_U[3][3], float r_P[3][3]);
/**
* Make a 4x4 matrix out of 3 transform components.
* Matrices are made in the order: `scale * rot * loc`
*/
void loc_rot_size_to_mat4(float R[4][4], void loc_rot_size_to_mat4(float R[4][4],
const float loc[3], const float loc[3],
const float rot[3][3], const float rot[3][3],
const float size[3]); const float size[3]);
/**
* Make a 4x4 matrix out of 3 transform components.
* Matrices are made in the order: `scale * rot * loc`
*
* TODO: need to have a version that allows for rotation order.
*/
void loc_eul_size_to_mat4(float R[4][4], void loc_eul_size_to_mat4(float R[4][4],
const float loc[3], const float loc[3],
const float eul[3], const float eul[3],
const float size[3]); const float size[3]);
/**
* Make a 4x4 matrix out of 3 transform components.
* Matrices are made in the order: `scale * rot * loc`
*/
void loc_eulO_size_to_mat4( void loc_eulO_size_to_mat4(
float R[4][4], const float loc[3], const float eul[3], const float size[3], const short order); float R[4][4], const float loc[3], const float eul[3], const float size[3], const short order);
/**
* Make a 4x4 matrix out of 3 transform components.
* Matrices are made in the order: `scale * rot * loc`
*/
void loc_quat_size_to_mat4(float R[4][4], void loc_quat_size_to_mat4(float R[4][4],
const float loc[3], const float loc[3],
const float quat[4], const float quat[4],
@@ -370,7 +504,32 @@ void blend_m4_m4m4(float out[4][4],
const float src[4][4], const float src[4][4],
const float srcweight); const float srcweight);
/**
* A polar-decomposition-based interpolation between matrix A and matrix B.
*
* \note This code is about five times slower as the 'naive' interpolation done by #blend_m3_m3m3
* (it typically remains below 2 usec on an average i74700,
* while #blend_m3_m3m3 remains below 0.4 usec).
* However, it gives expected results even with non-uniformly scaled matrices,
* see T46418 for an example.
*
* Based on "Matrix Animation and Polar Decomposition", by Ken Shoemake & Tom Duff
*
* \param R: Resulting interpolated matrix.
* \param A: Input matrix which is totally effective with `t = 0.0`.
* \param B: Input matrix which is totally effective with `t = 1.0`.
* \param t: Interpolation factor.
*/
void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t); void interp_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3], const float t);
/**
* Complete transform matrix interpolation,
* based on polar-decomposition-based interpolation from #interp_m3_m3m3.
*
* \param R: Resulting interpolated matrix.
* \param A: Input matrix which is totally effective with `t = 0.0`.
* \param B: Input matrix which is totally effective with `t = 1.0`.
* \param t: Interpolation factor.
*/
void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t); void interp_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4], const float t);
bool is_negative_m3(const float mat[3][3]); bool is_negative_m3(const float mat[3][3]);
@@ -382,16 +541,57 @@ bool is_zero_m4(const float mat[4][4]);
bool equals_m3m3(const float mat1[3][3], const float mat2[3][3]); bool equals_m3m3(const float mat1[3][3], const float mat2[3][3]);
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4]); bool equals_m4m4(const float mat1[4][4], const float mat2[4][4]);
/* SpaceTransform helper */ /**
* #SpaceTransform struct encapsulates all needed data to convert between two coordinate spaces
* (where conversion can be represented by a matrix multiplication).
*
* A #SpaceTransform is initialized using:
* - #BLI_SPACE_TRANSFORM_SETUP(&data, ob1, ob2)
*
* After that the following calls can be used:
* - Converts a coordinate in ob1 space to the corresponding ob2 space:
* #BLI_space_transform_apply(&data, co);
* - Converts a coordinate in ob2 space to the corresponding ob1 space:
* #BLI_space_transform_invert(&data, co);
*
* Same concept as #BLI_space_transform_apply and #BLI_space_transform_invert,
* but no is normalized after conversion (and not translated at all!):
* - #BLI_space_transform_apply_normal(&data, no);
* - #BLI_space_transform_invert_normal(&data, no);
*/
typedef struct SpaceTransform { typedef struct SpaceTransform {
float local2target[4][4]; float local2target[4][4];
float target2local[4][4]; float target2local[4][4];
} SpaceTransform; } SpaceTransform;
/**
* Global-invariant transform.
*
* This defines a matrix transforming a point in local space to a point in target space
* such that its global coordinates remain unchanged.
*
* In other words, if we have a global point P with local coordinates (x, y, z)
* and global coordinates (X, Y, Z),
* this defines a transform matrix TM such that (x', y', z') = TM * (x, y, z)
* where (x', y', z') are the coordinates of P' in target space
* such that it keeps (X, Y, Z) coordinates in global space.
*/
void BLI_space_transform_from_matrices(struct SpaceTransform *data, void BLI_space_transform_from_matrices(struct SpaceTransform *data,
const float local[4][4], const float local[4][4],
const float target[4][4]); const float target[4][4]);
/**
* Local-invariant transform.
*
* This defines a matrix transforming a point in global space
* such that its local coordinates (from local space to target space) remain unchanged.
*
* In other words, if we have a local point p with local coordinates (x, y, z)
* and global coordinates (X, Y, Z),
* this defines a transform matrix TM such that (X', Y', Z') = TM * (X, Y, Z)
* where (X', Y', Z') are the coordinates of p' in global space
* such that it keeps (x, y, z) coordinates in target space.
*/
void BLI_space_transform_global_from_matrices(struct SpaceTransform *data, void BLI_space_transform_global_from_matrices(struct SpaceTransform *data,
const float local[4][4], const float local[4][4],
const float target[4][4]); const float target[4][4]);
@@ -403,7 +603,11 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float
#define BLI_SPACE_TRANSFORM_SETUP(data, local, target) \ #define BLI_SPACE_TRANSFORM_SETUP(data, local, target) \
BLI_space_transform_from_matrices((data), (local)->obmat, (target)->obmat) BLI_space_transform_from_matrices((data), (local)->obmat, (target)->obmat)
/*********************************** Other ***********************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Other
* \{ */
void print_m3(const char *str, const float M[3][3]); void print_m3(const char *str, const float M[3][3]);
void print_m4(const char *str, const float M[4][4]); void print_m4(const char *str, const float M[4][4]);
@@ -411,6 +615,8 @@ void print_m4(const char *str, const float M[4][4]);
#define print_m3_id(M) print_m3(STRINGIFY(M), M) #define print_m3_id(M) print_m3(STRINGIFY(M), M)
#define print_m4_id(M) print_m4(STRINGIFY(M), M) #define print_m4_id(M) print_m4(STRINGIFY(M), M)
/** \} */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -38,25 +38,62 @@ extern "C" {
#define RAD2DEGF(_rad) ((_rad) * (float)(180.0 / M_PI)) #define RAD2DEGF(_rad) ((_rad) * (float)(180.0 / M_PI))
#define DEG2RADF(_deg) ((_deg) * (float)(M_PI / 180.0)) #define DEG2RADF(_deg) ((_deg) * (float)(M_PI / 180.0))
/******************************** Quaternions ********************************/ /** \} */
/* stored in (w, x, y, z) order */
/* -------------------------------------------------------------------- */
/** \name Quaternions
* Stored in (w, x, y, z) order.
* \{ */
/* Initialize */
/* Convenience, avoids setting Y axis everywhere. */
/* init */
void unit_axis_angle(float axis[3], float *angle); void unit_axis_angle(float axis[3], float *angle);
void unit_qt(float q[4]); void unit_qt(float q[4]);
void copy_qt_qt(float q[4], const float a[4]); void copy_qt_qt(float q[4], const float a[4]);
/* arithmetic */ /* arithmetic */
void mul_qt_qtqt(float q[4], const float a[4], const float b[4]); void mul_qt_qtqt(float q[4], const float a[4], const float b[4]);
/**
* \note
* Assumes a unit quaternion?
*
* in fact not, but you may want to use a unit quaternion read on...
*
* Shortcut for 'q v q*' when \a v is actually a quaternion.
* This removes the need for converting a vector to a quaternion,
* calculating q's conjugate and converting back to a vector.
* It also happens to be faster (17+,24* vs * 24+,32*).
* If \a q is not a unit quaternion, then \a v will be both rotated by
* the same amount as if q was a unit quaternion, and scaled by the square of
* the length of q.
*
* For people used to python mathutils, its like:
* def mul_qt_v3(q, v): (q * Quaternion((0.0, v[0], v[1], v[2])) * q.conjugated())[1:]
*
* \note Multiplying by 3x3 matrix is ~25% faster.
*/
void mul_qt_v3(const float q[4], float r[3]); void mul_qt_v3(const float q[4], float r[3]);
/**
* Simple multiply.
*/
void mul_qt_fl(float q[4], const float f); void mul_qt_fl(float q[4], const float f);
/**
* Raise a unit quaternion to the specified power.
*/
void pow_qt_fl_normalized(float q[4], const float f); void pow_qt_fl_normalized(float q[4], const float f);
void sub_qt_qtqt(float q[4], const float a[4], const float b[4]); void sub_qt_qtqt(float q[4], const float a[4], const float b[4]);
void invert_qt(float q[4]); void invert_qt(float q[4]);
void invert_qt_qt(float q1[4], const float q2[4]); void invert_qt_qt(float q1[4], const float q2[4]);
/**
* This is just conjugate_qt for cases we know \a q is unit-length.
* we could use #conjugate_qt directly, but use this function to show intent,
* and assert if its ever becomes non-unit-length.
*/
void invert_qt_normalized(float q[4]); void invert_qt_normalized(float q[4]);
void invert_qt_qt_normalized(float q1[4], const float q2[4]); void invert_qt_qt_normalized(float q1[4], const float q2[4]);
void conjugate_qt(float q[4]); void conjugate_qt(float q[4]);
@@ -69,6 +106,14 @@ float normalize_qt_qt(float r[4], const float q[4]);
bool is_zero_qt(const float q[4]); bool is_zero_qt(const float q[4]);
/* interpolation */ /* interpolation */
/**
* Generic function for implementing slerp
* (quaternions and spherical vector coords).
*
* \param t: factor in [0..1]
* \param cosom: dot product from normalized vectors/quats.
* \param r_w: calculated weights.
*/
void interp_dot_slerp(const float t, const float cosom, float w[2]); void interp_dot_slerp(const float t, const float cosom, float w[2]);
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], const float t); void interp_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t); void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
@@ -77,24 +122,51 @@ void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t);
void quat_to_mat3(float mat[3][3], const float q[4]); void quat_to_mat3(float mat[3][3], const float q[4]);
void quat_to_mat4(float mat[4][4], const float q[4]); void quat_to_mat4(float mat[4][4], const float q[4]);
/**
* Apply the rotation of \a a to \a q keeping the values compatible with \a old.
* Avoid axis flipping for animated f-curves for eg.
*/
void quat_to_compatible_quat(float q[4], const float a[4], const float old[4]); void quat_to_compatible_quat(float q[4], const float a[4], const float old[4]);
void mat3_normalized_to_quat(float q[4], const float mat[3][3]); void mat3_normalized_to_quat(float q[4], const float mat[3][3]);
void mat4_normalized_to_quat(float q[4], const float mat[4][4]); void mat4_normalized_to_quat(float q[4], const float mat[4][4]);
void mat3_to_quat(float q[4], const float mat[3][3]); void mat3_to_quat(float q[4], const float mat[3][3]);
void mat4_to_quat(float q[4], const float mat[4][4]); void mat4_to_quat(float q[4], const float mat[4][4]);
/**
* Same as tri_to_quat() but takes pre-computed normal from the triangle
* used for ngons when we know their normal.
*/
void tri_to_quat_ex(float quat[4], void tri_to_quat_ex(float quat[4],
const float v1[3], const float v1[3],
const float v2[3], const float v2[3],
const float v3[3], const float v3[3],
const float no_orig[3]); const float no_orig[3]);
/**
* \return the length of the normal, use to test for degenerate triangles.
*/
float tri_to_quat(float q[4], const float a[3], const float b[3], const float c[3]); float tri_to_quat(float q[4], const float a[3], const float b[3], const float c[3]);
void vec_to_quat(float q[4], const float vec[3], short axis, const short upflag); void vec_to_quat(float q[4], const float vec[3], short axis, const short upflag);
/* NOTE: v1 and v2 must be normalized. */ /**
* Calculate a rotation matrix from 2 normalized vectors.
* \note `v1` and `v2` must be normalized.
*/
void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float v2[3]); void rotation_between_vecs_to_mat3(float m[3][3], const float v1[3], const float v2[3]);
/**
* \note Expects vectors to be normalized.
*/
void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3]); void rotation_between_vecs_to_quat(float q[4], const float v1[3], const float v2[3]);
void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q2[4]); void rotation_between_quats_to_quat(float q[4], const float q1[4], const float q2[4]);
/**
* Decompose a quaternion into a swing rotation (quaternion with the selected
* axis component locked at zero), followed by a twist rotation around the axis.
*
* \param q: input quaternion.
* \param axis: twist axis in [0,1,2]
* \param r_swing: if not NULL, receives the swing quaternion.
* \param r_twist: if not NULL, receives the twist quaternion.
* \returns twist angle.
*/
float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4]); float quat_split_swing_and_twist(const float q[4], int axis, float r_swing[4], float r_twist[4]);
float angle_normalized_qt(const float q[4]); float angle_normalized_qt(const float q[4]);
@@ -107,7 +179,9 @@ float angle_signed_normalized_qtqt(const float q1[4], const float q2[4]);
float angle_signed_qt(const float q[4]); float angle_signed_qt(const float q[4]);
float angle_signed_qtqt(const float q1[4], const float q2[4]); float angle_signed_qtqt(const float q1[4], const float q2[4]);
/* TODO: don't what this is, but it's not the same as mat3_to_quat */ /**
* TODO: don't what this is, but it's not the same as #mat3_to_quat.
*/
void mat3_to_quat_is_ok(float q[4], const float mat[3][3]); void mat3_to_quat_is_ok(float q[4], const float mat[3][3]);
/* other */ /* other */
@@ -115,61 +189,120 @@ void print_qt(const char *str, const float q[4]);
#define print_qt_id(q) print_qt(STRINGIFY(q), q) #define print_qt_id(q) print_qt(STRINGIFY(q), q)
/******************************** Axis Angle *********************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Axis Angle
* \{ */
/* conversion */ /* conversion */
void axis_angle_normalized_to_quat(float r[4], const float axis[3], const float angle); void axis_angle_normalized_to_quat(float r[4], const float axis[3], const float angle);
void axis_angle_to_quat(float r[4], const float axis[3], const float angle); void axis_angle_to_quat(float r[4], const float axis[3], const float angle);
/**
* Axis angle to 3x3 matrix - safer version (normalization of axis performed).
*/
void axis_angle_to_mat3(float R[3][3], const float axis[3], const float angle); void axis_angle_to_mat3(float R[3][3], const float axis[3], const float angle);
/**
* axis angle to 3x3 matrix
*
* This takes the angle with sin/cos applied so we can avoid calculating it in some cases.
*
* \param axis: rotation axis (must be normalized).
* \param angle_sin: sin(angle)
* \param angle_cos: cos(angle)
*/
void axis_angle_normalized_to_mat3_ex(float mat[3][3], void axis_angle_normalized_to_mat3_ex(float mat[3][3],
const float axis[3], const float axis[3],
const float angle_sin, const float angle_sin,
const float angle_cos); const float angle_cos);
void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], const float angle); void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], const float angle);
/**
* Axis angle to 4x4 matrix - safer version (normalization of axis performed).
*/
void axis_angle_to_mat4(float R[4][4], const float axis[3], const float angle); void axis_angle_to_mat4(float R[4][4], const float axis[3], const float angle);
/**
* 3x3 matrix to axis angle.
*/
void mat3_normalized_to_axis_angle(float axis[3], float *angle, const float M[3][3]); void mat3_normalized_to_axis_angle(float axis[3], float *angle, const float M[3][3]);
/**
* 4x4 matrix to axis angle.
*/
void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float M[4][4]); void mat4_normalized_to_axis_angle(float axis[3], float *angle, const float M[4][4]);
void mat3_to_axis_angle(float axis[3], float *angle, const float M[3][3]); void mat3_to_axis_angle(float axis[3], float *angle, const float M[3][3]);
/**
* 4x4 matrix to axis angle.
*/
void mat4_to_axis_angle(float axis[3], float *angle, const float M[4][4]); void mat4_to_axis_angle(float axis[3], float *angle, const float M[4][4]);
/**
* Quaternions to Axis Angle.
*/
void quat_to_axis_angle(float axis[3], float *angle, const float q[4]); void quat_to_axis_angle(float axis[3], float *angle, const float q[4]);
void angle_to_mat2(float R[2][2], const float angle); void angle_to_mat2(float R[2][2], const float angle);
/**
* Create a 3x3 rotation matrix from a single axis.
*/
void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle); void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle);
/**
* Create a 4x4 rotation matrix from a single axis.
*/
void axis_angle_to_mat4_single(float R[4][4], const char axis, const float angle); void axis_angle_to_mat4_single(float R[4][4], const char axis, const float angle);
void axis_angle_to_quat_single(float q[4], const char axis, const float angle); void axis_angle_to_quat_single(float q[4], const char axis, const float angle);
/****************************** Exponential Map ******************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Exponential Map
* \{ */
void quat_to_expmap(float expmap[3], const float q[4]); void quat_to_expmap(float expmap[3], const float q[4]);
void quat_normalized_to_expmap(float expmap[3], const float q[4]); void quat_normalized_to_expmap(float expmap[3], const float q[4]);
void expmap_to_quat(float r[4], const float expmap[3]); void expmap_to_quat(float r[4], const float expmap[3]);
/******************************** XYZ Eulers *********************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name XYZ Eulers
* \{ */
/* XYZ order. */
void eul_to_quat(float quat[4], const float eul[3]); void eul_to_quat(float quat[4], const float eul[3]);
/* XYZ order */
void eul_to_mat3(float mat[3][3], const float eul[3]); void eul_to_mat3(float mat[3][3], const float eul[3]);
/* XYZ order */
void eul_to_mat4(float mat[4][4], const float eul[3]); void eul_to_mat4(float mat[4][4], const float eul[3]);
/* XYZ order */
void mat3_normalized_to_eul(float eul[3], const float mat[3][3]); void mat3_normalized_to_eul(float eul[3], const float mat[3][3]);
/* XYZ order */
void mat4_normalized_to_eul(float eul[3], const float mat[4][4]); void mat4_normalized_to_eul(float eul[3], const float mat[4][4]);
void mat3_to_eul(float eul[3], const float mat[3][3]); void mat3_to_eul(float eul[3], const float mat[3][3]);
void mat4_to_eul(float eul[3], const float mat[4][4]); void mat4_to_eul(float eul[3], const float mat[4][4]);
/* XYZ order */
void quat_to_eul(float eul[3], const float quat[4]); void quat_to_eul(float eul[3], const float quat[4]);
/* XYZ order */
void mat3_normalized_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]); void mat3_normalized_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void mat3_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]); void mat3_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]);
void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4]); void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4]);
/* order independent! */
void compatible_eul(float eul[3], const float old[3]); void compatible_eul(float eul[3], const float old[3]);
/* XYZ order */
void rotate_eul(float eul[3], const char axis, const float angle); void rotate_eul(float eul[3], const char axis, const float angle);
void add_eul_euleul(float r_eul[3], float a[3], float b[3], const short order); void add_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
void sub_eul_euleul(float r_eul[3], float a[3], float b[3], const short order); void sub_eul_euleul(float r_eul[3], float a[3], float b[3], const short order);
/************************** Arbitrary Order Eulers ***************************/ /** \} */
/* warning: must match the eRotationModes in DNA_action_types.h /* -------------------------------------------------------------------- */
/** \name Arbitrary Order Eulers
* \{ */
/* WARNING: must match the #eRotationModes in `DNA_action_types.h`
* order matters - types are saved to file. */ * order matters - types are saved to file. */
typedef enum eEulerRotationOrders { typedef enum eEulerRotationOrders {
@@ -183,19 +316,48 @@ typedef enum eEulerRotationOrders {
/* There are 6 more entries with duplicate entries included. */ /* There are 6 more entries with duplicate entries included. */
} eEulerRotationOrders; } eEulerRotationOrders;
/**
* Construct quaternion from Euler angles (in radians).
*/
void eulO_to_quat(float quat[4], const float eul[3], const short order); void eulO_to_quat(float quat[4], const float eul[3], const short order);
/**
* Construct 3x3 matrix from Euler angles (in radians).
*/
void eulO_to_mat3(float mat[3][3], const float eul[3], const short order); void eulO_to_mat3(float mat[3][3], const float eul[3], const short order);
/**
* Construct 4x4 matrix from Euler angles (in radians).
*/
void eulO_to_mat4(float mat[4][4], const float eul[3], const short order); void eulO_to_mat4(float mat[4][4], const float eul[3], const short order);
/**
* Euler Rotation to Axis Angle.
*/
void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const short order); void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const short order);
/**
* The matrix is written to as 3 axis vectors.
*/
void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order); void eulO_to_gimbal_axis(float gmat[3][3], const float eul[3], const short order);
/**
* Convert 3x3 matrix to Euler angles (in radians).
*/
void mat3_normalized_to_eulO(float eul[3], const short order, const float mat[3][3]); void mat3_normalized_to_eulO(float eul[3], const short order, const float mat[3][3]);
/**
* Convert 4x4 matrix to Euler angles (in radians).
*/
void mat4_normalized_to_eulO(float eul[3], const short order, const float mat[4][4]); void mat4_normalized_to_eulO(float eul[3], const short order, const float mat[4][4]);
void mat3_to_eulO(float eul[3], const short order, const float mat[3][3]); void mat3_to_eulO(float eul[3], const short order, const float mat[3][3]);
void mat4_to_eulO(float eul[3], const short order, const float mat[4][4]); void mat4_to_eulO(float eul[3], const short order, const float mat[4][4]);
/**
* Convert quaternion to Euler angles (in radians).
*/
void quat_to_eulO(float eul[3], const short order, const float quat[4]); void quat_to_eulO(float eul[3], const short order, const float quat[4]);
/**
* Axis Angle to Euler Rotation.
*/
void axis_angle_to_eulO(float eul[3], const short order, const float axis[3], const float angle); void axis_angle_to_eulO(float eul[3], const short order, const float axis[3], const float angle);
/* Uses 2 methods to retrieve eulers, and picks the closest. */
void mat3_normalized_to_compatible_eulO(float eul[3], void mat3_normalized_to_compatible_eulO(float eul[3],
const float old[3], const float old[3],
const short order, const short order,
@@ -219,7 +381,11 @@ void quat_to_compatible_eulO(float eul[3],
void rotate_eulO(float eul[3], const short order, char axis, float angle); void rotate_eulO(float eul[3], const short order, char axis, float angle);
/******************************* Dual Quaternions ****************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Dual Quaternions
* \{ */
void copy_dq_dq(DualQuat *r, const DualQuat *dq); void copy_dq_dq(DualQuat *r, const DualQuat *dq);
void normalize_dq(DualQuat *dq, float totw); void normalize_dq(DualQuat *dq, float totw);
@@ -229,21 +395,39 @@ void mul_v3m3_dq(float r[3], float R[3][3], DualQuat *dq);
void mat4_to_dquat(DualQuat *dq, const float basemat[4][4], const float mat[4][4]); void mat4_to_dquat(DualQuat *dq, const float basemat[4][4], const float mat[4][4]);
void dquat_to_mat4(float R[4][4], const DualQuat *dq); void dquat_to_mat4(float R[4][4], const DualQuat *dq);
/**
* Axis matches #eTrackToAxis_Modes.
*/
void quat_apply_track(float quat[4], short axis, short upflag); void quat_apply_track(float quat[4], short axis, short upflag);
void vec_apply_track(float vec[3], short axis); void vec_apply_track(float vec[3], short axis);
/**
* Lens/angle conversion (radians).
*/
float focallength_to_fov(float focal_length, float sensor); float focallength_to_fov(float focal_length, float sensor);
float fov_to_focallength(float fov, float sensor); float fov_to_focallength(float fov, float sensor);
float angle_wrap_rad(float angle); float angle_wrap_rad(float angle);
float angle_wrap_deg(float angle); float angle_wrap_deg(float angle);
/**
* Returns an angle compatible with angle_compat.
*/
float angle_compat_rad(float angle, float angle_compat); float angle_compat_rad(float angle, float angle_compat);
/**
* Each argument us an axis in ['X', 'Y', 'Z', '-X', '-Y', '-Z']
* where the first 2 are a source and the second 2 are the target.
*/
bool mat3_from_axis_conversion( bool mat3_from_axis_conversion(
int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3]); int src_forward, int src_up, int dst_forward, int dst_up, float r_mat[3][3]);
/**
* Use when the second axis can be guessed.
*/
bool mat3_from_axis_conversion_single(int src_axis, int dst_axis, float r_mat[3][3]); bool mat3_from_axis_conversion_single(int src_axis, int dst_axis, float r_mat[3][3]);
/** \} */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -35,22 +35,61 @@ extern "C" {
# pragma GCC diagnostic ignored "-Wredundant-decls" # pragma GCC diagnostic ignored "-Wredundant-decls"
#endif #endif
/********************************** Eigen Solvers *********************************/ /* -------------------------------------------------------------------- */
/** \name Eigen Solvers
* \{ */
/**
* \brief Compute the eigen values and/or vectors of given 3D symmetric (aka adjoint) matrix.
*
* \param m3: the 3D symmetric matrix.
* \return r_eigen_values the computed eigen values (NULL if not needed).
* \return r_eigen_vectors the computed eigen vectors (NULL if not needed).
*/
bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3], bool BLI_eigen_solve_selfadjoint_m3(const float m3[3][3],
float r_eigen_values[3], float r_eigen_values[3],
float r_eigen_vectors[3][3]); float r_eigen_vectors[3][3]);
/**
* \brief Compute the SVD (Singular Values Decomposition) of given 3D matrix (m3 = USV*).
*
* \param m3: the matrix to decompose.
* \return r_U the computed left singular vector of \a m3 (NULL if not needed).
* \return r_S the computed singular values of \a m3 (NULL if not needed).
* \return r_V the computed right singular vector of \a m3 (NULL if not needed).
*/
void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3][3]); void BLI_svd_m3(const float m3[3][3], float r_U[3][3], float r_S[3], float r_V[3][3]);
/***************************** Simple Solvers ************************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Simple Solvers
* \{ */
/**
* \brief Solve a tridiagonal system of equations:
*
* a[i] * r_x[i-1] + b[i] * r_x[i] + c[i] * r_x[i+1] = d[i]
*
* Ignores a[0] and c[count-1]. Uses the Thomas algorithm, e.g. see wiki.
*
* \param r_x: output vector, may be shared with any of the input ones
* \return true if success
*/
bool BLI_tridiagonal_solve( bool BLI_tridiagonal_solve(
const float *a, const float *b, const float *c, const float *d, float *r_x, const int count); const float *a, const float *b, const float *c, const float *d, float *r_x, const int count);
/**
* \brief Solve a possibly cyclic tridiagonal system using the Sherman-Morrison formula.
*
* \param r_x: output vector, may be shared with any of the input ones
* \return true if success
*/
bool BLI_tridiagonal_solve_cyclic( bool BLI_tridiagonal_solve_cyclic(
const float *a, const float *b, const float *c, const float *d, float *r_x, const int count); const float *a, const float *b, const float *c, const float *d, float *r_x, const int count);
/* Generic 3 variable Newton's method solver. */ /**
* Generic 3 variable Newton's method solver.
*/
typedef void (*Newton3D_DeltaFunc)(void *userdata, const float x[3], float r_delta[3]); typedef void (*Newton3D_DeltaFunc)(void *userdata, const float x[3], float r_delta[3]);
typedef void (*Newton3D_JacobianFunc)(void *userdata, const float x[3], float r_jacobian[3][3]); typedef void (*Newton3D_JacobianFunc)(void *userdata, const float x[3], float r_jacobian[3][3]);
typedef bool (*Newton3D_CorrectionFunc)(void *userdata, typedef bool (*Newton3D_CorrectionFunc)(void *userdata,
@@ -58,6 +97,21 @@ typedef bool (*Newton3D_CorrectionFunc)(void *userdata,
float step[3], float step[3],
float x_next[3]); float x_next[3]);
/**
* \brief Solve a generic f(x) = 0 equation using Newton's method.
*
* \param func_delta: Callback computing the value of f(x).
* \param func_jacobian: Callback computing the Jacobian matrix of the function at x.
* \param func_correction: Callback for forcing the search into an arbitrary custom domain.
* May be NULL.
* \param userdata: Data for the callbacks.
* \param epsilon: Desired precision.
* \param max_iterations: Limit on the iterations.
* \param trace: Enables logging to console.
* \param x_init: Initial solution vector.
* \param result: Final result.
* \return true if success
*/
bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta, bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta,
Newton3D_JacobianFunc func_jacobian, Newton3D_JacobianFunc func_jacobian,
Newton3D_CorrectionFunc func_correction, Newton3D_CorrectionFunc func_correction,
@@ -72,6 +126,8 @@ bool BLI_newton3d_solve(Newton3D_DeltaFunc func_delta,
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
/** \} */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -35,14 +35,36 @@ extern "C" {
# pragma GCC diagnostic ignored "-Wredundant-decls" # pragma GCC diagnostic ignored "-Wredundant-decls"
#endif #endif
/********************************** Covariance Matrices *********************************/ /* -------------------------------------------------------------------- */
/** \name Covariance Matrices
* \{ */
/**
* \brief Compute the covariance matrix of given set of nD coordinates.
*
* \param n: the dimension of the vectors (and hence, of the covariance matrix to compute).
* \param cos_vn: the nD points to compute covariance from.
* \param nbr_cos_vn: the number of nD coordinates in cos_vn.
* \param center: the center (or mean point) of cos_vn. If NULL,
* it is assumed cos_vn is already centered.
* \param use_sample_correction: whether to apply sample correction
* (i.e. get 'sample variance' instead of 'population variance').
* \return r_covmat the computed covariance matrix.
*/
void BLI_covariance_m_vn_ex(const int n, void BLI_covariance_m_vn_ex(const int n,
const float *cos_vn, const float *cos_vn,
const int nbr_cos_vn, const int nbr_cos_vn,
const float *center, const float *center,
const bool use_sample_correction, const bool use_sample_correction,
float *r_covmat); float *r_covmat);
/**
* \brief Compute the covariance matrix of given set of 3D coordinates.
*
* \param cos_v3: the 3D points to compute covariance from.
* \param nbr_cos_v3: the number of 3D coordinates in cos_v3.
* \return r_covmat the computed covariance matrix.
* \return r_center the computed center (mean) of 3D points (may be NULL).
*/
void BLI_covariance_m3_v3n(const float (*cos_v3)[3], void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
const int nbr_cos_v3, const int nbr_cos_v3,
const bool use_sample_correction, const bool use_sample_correction,
@@ -53,6 +75,8 @@ void BLI_covariance_m3_v3n(const float (*cos_v3)[3],
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
/** \} */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -27,7 +27,10 @@
extern "C" { extern "C" {
#endif #endif
/************************ Time constants definitions***************************/ /* -------------------------------------------------------------------- */
/** \name Time Constants Definitions
* \{ */
#define SECONDS_IN_MILLISECONDS 0.001 #define SECONDS_IN_MILLISECONDS 0.001
#define SECONDS_IN_MINUTE 60.0 #define SECONDS_IN_MINUTE 60.0
#define MINUTES_IN_HOUR 60.0 #define MINUTES_IN_HOUR 60.0
@@ -37,6 +40,15 @@ extern "C" {
#define SECONDS_IN_DAY (MINUTES_IN_DAY * SECONDS_IN_MINUTE) #define SECONDS_IN_DAY (MINUTES_IN_DAY * SECONDS_IN_MINUTE)
#define SECONDS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE) #define SECONDS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE)
/** \} */
/** Explode given time value expressed in seconds, into a set of days, hours, minutes, seconds
* and/or milliseconds (depending on which return parameters are not NULL).
*
* \note The smallest given return parameter will get the potential fractional remaining time
* value. E.g. if you give `seconds=90.0` and do not pass `r_seconds` and `r_milliseconds`,
* `r_minutes` will be set to `1.5`.
*/
void BLI_math_time_seconds_decompose(double seconds, void BLI_math_time_seconds_decompose(double seconds,
double *r_days, double *r_days,
double *r_hours, double *r_hours,
@@ -44,7 +56,15 @@ void BLI_math_time_seconds_decompose(double seconds,
double *r_seconds, double *r_seconds,
double *r_milliseconds); double *r_milliseconds);
/**************************** Inline Definitions ******************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Inline Definitions
* \{ */
/* None. */
/** \} */
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -33,7 +33,9 @@
extern "C" { extern "C" {
#endif #endif
/************************************* Init ***********************************/ /* -------------------------------------------------------------------- */
/** \name Init
* \{ */
#ifdef BLI_MATH_GCC_WARN_PRAGMA #ifdef BLI_MATH_GCC_WARN_PRAGMA
# pragma GCC diagnostic push # pragma GCC diagnostic push
@@ -57,6 +59,7 @@ MINLINE void swap_v3_v3(float a[3], float b[3]);
MINLINE void swap_v4_v4(float a[4], float b[4]); MINLINE void swap_v4_v4(float a[4], float b[4]);
/* unsigned char */ /* unsigned char */
MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]); MINLINE void copy_v2_v2_uchar(unsigned char r[2], const unsigned char a[2]);
MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3]); MINLINE void copy_v3_v3_uchar(unsigned char r[3], const unsigned char a[3]);
MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4]); MINLINE void copy_v4_v4_uchar(unsigned char r[4], const unsigned char a[4]);
@@ -66,10 +69,13 @@ MINLINE void copy_v3_uchar(unsigned char r[3], const unsigned char a);
MINLINE void copy_v4_uchar(unsigned char r[4], const unsigned char a); MINLINE void copy_v4_uchar(unsigned char r[4], const unsigned char a);
/* char */ /* char */
MINLINE void copy_v2_v2_char(char r[2], const char a[2]); MINLINE void copy_v2_v2_char(char r[2], const char a[2]);
MINLINE void copy_v3_v3_char(char r[3], const char a[3]); MINLINE void copy_v3_v3_char(char r[3], const char a[3]);
MINLINE void copy_v4_v4_char(char r[4], const char a[4]); MINLINE void copy_v4_v4_char(char r[4], const char a[4]);
/* short */ /* short */
MINLINE void copy_v2_v2_short(short r[2], const short a[2]); MINLINE void copy_v2_v2_short(short r[2], const short a[2]);
MINLINE void copy_v3_v3_short(short r[3], const short a[3]); MINLINE void copy_v3_v3_short(short r[3], const short a[3]);
MINLINE void copy_v4_v4_short(short r[4], const short a[4]); MINLINE void copy_v4_v4_short(short r[4], const short a[4]);
@@ -78,30 +84,49 @@ MINLINE void zero_v3_int(int r[3]);
MINLINE void copy_v2_v2_int(int r[2], const int a[2]); MINLINE void copy_v2_v2_int(int r[2], const int a[2]);
MINLINE void copy_v3_v3_int(int r[3], const int a[3]); MINLINE void copy_v3_v3_int(int r[3], const int a[3]);
MINLINE void copy_v4_v4_int(int r[4], const int a[4]); MINLINE void copy_v4_v4_int(int r[4], const int a[4]);
/* double */ /* double */
MINLINE void zero_v3_db(double r[3]); MINLINE void zero_v3_db(double r[3]);
MINLINE void copy_v2_v2_db(double r[2], const double a[2]); MINLINE void copy_v2_v2_db(double r[2], const double a[2]);
MINLINE void copy_v3_v3_db(double r[3], const double a[3]); MINLINE void copy_v3_v3_db(double r[3], const double a[3]);
MINLINE void copy_v4_v4_db(double r[4], const double a[4]); MINLINE void copy_v4_v4_db(double r[4], const double a[4]);
/* short -> float */ /* short -> float */
MINLINE void copy_v3fl_v3s(float r[3], const short a[3]); MINLINE void copy_v3fl_v3s(float r[3], const short a[3]);
/* int <-> float */ /* int <-> float */
MINLINE void copy_v2fl_v2i(float r[2], const int a[2]); MINLINE void copy_v2fl_v2i(float r[2], const int a[2]);
/* int <-> float */
MINLINE void round_v2i_v2fl(int r[2], const float a[2]); MINLINE void round_v2i_v2fl(int r[2], const float a[2]);
/* double -> float */ /* double -> float */
MINLINE void copy_v2fl_v2db(float r[2], const double a[2]); MINLINE void copy_v2fl_v2db(float r[2], const double a[2]);
MINLINE void copy_v3fl_v3db(float r[3], const double a[3]); MINLINE void copy_v3fl_v3db(float r[3], const double a[3]);
MINLINE void copy_v4fl_v4db(float r[4], const double a[4]); MINLINE void copy_v4fl_v4db(float r[4], const double a[4]);
/* float -> double */ /* float -> double */
MINLINE void copy_v2db_v2fl(double r[2], const float a[2]); MINLINE void copy_v2db_v2fl(double r[2], const float a[2]);
MINLINE void copy_v3db_v3fl(double r[3], const float a[3]); MINLINE void copy_v3db_v3fl(double r[3], const float a[3]);
MINLINE void copy_v4db_v4fl(double r[4], const float a[4]); MINLINE void copy_v4db_v4fl(double r[4], const float a[4]);
/* float args -> vec */ /* float args -> vec */
MINLINE void copy_v2_fl2(float v[2], float x, float y); MINLINE void copy_v2_fl2(float v[2], float x, float y);
MINLINE void copy_v3_fl3(float v[3], float x, float y, float z); MINLINE void copy_v3_fl3(float v[3], float x, float y, float z);
MINLINE void copy_v4_fl4(float v[4], float x, float y, float z, float w); MINLINE void copy_v4_fl4(float v[4], float x, float y, float z, float w);
/********************************* Arithmetic ********************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Arithmetic
* \{ */
MINLINE void add_v2_fl(float r[2], float f); MINLINE void add_v2_fl(float r[2], float f);
MINLINE void add_v3_fl(float r[3], float f); MINLINE void add_v3_fl(float r[3], float f);
@@ -149,11 +174,30 @@ MINLINE void mul_v4_v4(float r[4], const float a[4]);
MINLINE void mul_v4_v4fl(float r[4], const float a[4], float f); MINLINE void mul_v4_v4fl(float r[4], const float a[4], float f);
MINLINE void mul_v2_v2_cw(float r[2], const float mat[2], const float vec[2]); MINLINE void mul_v2_v2_cw(float r[2], const float mat[2], const float vec[2]);
MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2]); MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2]);
/**
* Convenience function to get the projected depth of a position.
* This avoids creating a temporary 4D vector and multiplying it - only for the 4th component.
*
* Matches logic for:
*
* \code{.c}
* float co_4d[4] = {co[0], co[1], co[2], 1.0};
* mul_m4_v4(mat, co_4d);
* return co_4d[3];
* \endcode
*/
MINLINE float mul_project_m4_v3_zfac(const float mat[4][4], MINLINE float mul_project_m4_v3_zfac(const float mat[4][4],
const float co[3]) ATTR_WARN_UNUSED_RESULT; const float co[3]) ATTR_WARN_UNUSED_RESULT;
/**
* Has the effect of #mul_m3_v3(), on a single axis.
*/
MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m3_v3_row_y(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float dot_m3_v3_row_y(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
/**
* Has the effect of #mul_mat3_m4_v3(), on a single axis.
* (no adding translation)
*/
MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float dot_m4_v3_row_x(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m4_v3_row_y(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float dot_m4_v3_row_y(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m4_v3_row_z(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float dot_m4_v3_row_z(const float M[4][4], const float a[3]) ATTR_WARN_UNUSED_RESULT;
@@ -180,12 +224,17 @@ MINLINE void negate_v3_v3(float r[3], const float a[3]);
MINLINE void negate_v4(float r[4]); MINLINE void negate_v4(float r[4]);
MINLINE void negate_v4_v4(float r[4], const float a[4]); MINLINE void negate_v4_v4(float r[4], const float a[4]);
/* could add more... */
MINLINE void negate_v3_short(short r[3]); MINLINE void negate_v3_short(short r[3]);
MINLINE void negate_v3_db(double r[3]); MINLINE void negate_v3_db(double r[3]);
MINLINE void invert_v2(float r[2]); MINLINE void invert_v2(float r[2]);
MINLINE void invert_v3(float r[3]); MINLINE void invert_v3(float r[3]);
MINLINE void invert_v3_safe(float r[3]); /* Invert the vector, but leaves zero values as zero. */ /**
* Invert the vector, but leaves zero values as zero.
*/
MINLINE void invert_v3_safe(float r[3]);
MINLINE void abs_v2(float r[2]); MINLINE void abs_v2(float r[2]);
MINLINE void abs_v2_v2(float r[2], const float a[2]); MINLINE void abs_v2_v2(float r[2], const float a[2]);
@@ -209,14 +258,26 @@ MINLINE double dot_v3v3_db(const double a[3], const double b[3]) ATTR_WARN_UNUSE
MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; MINLINE float cross_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE double cross_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT; MINLINE double cross_v2v2_db(const double a[2], const double b[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]); MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3]);
/**
* Cross product suffers from severe precision loss when vectors are
* nearly parallel or opposite; doing the computation in double helps a lot.
*/
MINLINE void cross_v3_v3v3_hi_prec(float r[3], const float a[3], const float b[3]); MINLINE void cross_v3_v3v3_hi_prec(float r[3], const float a[3], const float b[3]);
MINLINE void cross_v3_v3v3_db(double r[3], const double a[3], const double b[3]); MINLINE void cross_v3_v3v3_db(double r[3], const double a[3], const double b[3]);
/**
* Excuse this fairly specific function, its used for polygon normals all over the place
* (could use a better name).
*/
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3]); MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3]);
MINLINE void star_m3_v3(float rmat[3][3], const float a[3]); MINLINE void star_m3_v3(float rmat[3][3], const float a[3]);
/*********************************** Length **********************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Length
* \{ */
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT; MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT;
@@ -241,8 +302,14 @@ MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESU
MINLINE double len_v3_db(const double a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE double len_v3_db(const double a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE double len_squared_v3_db(const double v[3]) ATTR_WARN_UNUSED_RESULT; MINLINE double len_squared_v3_db(const double v[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float normalize_v2_length(float r[2], const float unit_scale); MINLINE float normalize_v2_length(float r[2], const float unit_scale);
/**
* \note any vectors containing `nan` will be zeroed out.
*/
MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_scale); MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_scale);
MINLINE float normalize_v3_length(float r[3], const float unit_scale); MINLINE float normalize_v3_length(float r[3], const float unit_scale);
/**
* \note any vectors containing `nan` will be zeroed out.
*/
MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_scale); MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_scale);
MINLINE double normalize_v3_length_db(double n[3], const double unit_scale); MINLINE double normalize_v3_length_db(double n[3], const double unit_scale);
MINLINE double normalize_v3_v3_length_db(double r[3], const double a[3], const double unit_scale); MINLINE double normalize_v3_v3_length_db(double r[3], const double a[3], const double unit_scale);
@@ -254,16 +321,32 @@ MINLINE float normalize_v3_v3(float r[3], const float a[3]);
MINLINE double normalize_v3_v3_db(double r[3], const double a[3]); MINLINE double normalize_v3_v3_db(double r[3], const double a[3]);
MINLINE double normalize_v3_db(double n[3]); MINLINE double normalize_v3_db(double n[3]);
/******************************* Interpolation *******************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Interpolation
* \{ */
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], const float t); void interp_v2_v2v2(float r[2], const float a[2], const float b[2], const float t);
void interp_v2_v2v2_db(double target[2], const double a[2], const double b[2], const double t); void interp_v2_v2v2_db(double target[2], const double a[2], const double b[2], const double t);
/**
* Weight 3 2D vectors,
* 'w' must be unit length but is not a vector, just 3 weights.
*/
void interp_v2_v2v2v2( void interp_v2_v2v2v2(
float r[2], const float a[2], const float b[2], const float c[2], const float t[3]); float r[2], const float a[2], const float b[2], const float c[2], const float t[3]);
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t); void interp_v3_v3v3(float r[3], const float a[3], const float b[3], const float t);
void interp_v3_v3v3_db(double target[3], const double a[3], const double b[3], const double t); void interp_v3_v3v3_db(double target[3], const double a[3], const double b[3], const double t);
/**
* Weight 3 vectors,
* 'w' must be unit length but is not a vector, just 3 weights.
*/
void interp_v3_v3v3v3( void interp_v3_v3v3v3(
float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3]); float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3]);
/**
* Weight 3 vectors,
* 'w' must be unit length but is not a vector, just 4 weights.
*/
void interp_v3_v3v3v3v3(float p[3], void interp_v3_v3v3v3v3(float p[3],
const float v1[3], const float v1[3],
const float v2[3], const float v2[3],
@@ -282,11 +365,20 @@ void interp_v4_v4v4v4v4(float p[4],
void interp_v3_v3v3v3_uv( void interp_v3_v3v3v3_uv(
float p[3], const float v1[3], const float v2[3], const float v3[3], const float uv[2]); float p[3], const float v1[3], const float v2[3], const float v3[3], const float uv[2]);
/**
* slerp, treat vectors as spherical coordinates
* \see #interp_qt_qtqt
*
* \return success
*/
bool interp_v3_v3v3_slerp(float target[3], const float a[3], const float b[3], const float t) bool interp_v3_v3v3_slerp(float target[3], const float a[3], const float b[3], const float t)
ATTR_WARN_UNUSED_RESULT; ATTR_WARN_UNUSED_RESULT;
bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], const float t) bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], const float t)
ATTR_WARN_UNUSED_RESULT; ATTR_WARN_UNUSED_RESULT;
/**
* Same as #interp_v3_v3v3_slerp but uses fallback values for opposite vectors.
*/
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t); void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t);
void interp_v2_v2v2_slerp_safe(float target[2], const float a[2], const float b[2], const float t); void interp_v2_v2v2_slerp_safe(float target[2], const float a[2], const float b[2], const float t);
@@ -316,14 +408,34 @@ void mid_v3_v3v3v3v3(
float v[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]); float v[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const unsigned int nbr); void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const unsigned int nbr);
/**
* Specialized function for calculating normals.
* Fast-path for:
*
* \code{.c}
* add_v3_v3v3(r, a, b);
* normalize_v3(r)
* mul_v3_fl(r, angle_normalized_v3v3(a, b) / M_PI_2);
* \endcode
*
* We can use the length of (a + b) to calculate the angle.
*/
void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3]); void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3]);
/**
* Same as mid_v3_v3v3_angle_weighted
* but \a r is assumed to be accumulated normals, divided by their total.
*/
void mid_v3_angle_weighted(float r[3]); void mid_v3_angle_weighted(float r[3]);
void flip_v4_v4v4(float v[4], const float v1[4], const float v2[4]); void flip_v4_v4v4(float v[4], const float v1[4], const float v2[4]);
void flip_v3_v3v3(float v[3], const float v1[3], const float v2[3]); void flip_v3_v3v3(float v[3], const float v1[3], const float v2[3]);
void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2]); void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2]);
/********************************* Comparison ********************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Comparison
* \{ */
MINLINE bool is_zero_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT; MINLINE bool is_zero_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT;
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT;
@@ -378,24 +490,64 @@ MINLINE bool compare_size_v3v3(const float a[3],
const float b[3], const float b[3],
const float limit) ATTR_WARN_UNUSED_RESULT; const float limit) ATTR_WARN_UNUSED_RESULT;
/**
* <pre>
* + l1
* |
* neg <- | -> pos
* |
* + l2
* </pre>
*
* \return Positive value when 'pt' is left-of-line
* (looking from 'l1' -> 'l2').
*/
MINLINE float line_point_side_v2(const float l1[2], MINLINE float line_point_side_v2(const float l1[2],
const float l2[2], const float l2[2],
const float pt[2]) ATTR_WARN_UNUSED_RESULT; const float pt[2]) ATTR_WARN_UNUSED_RESULT;
/********************************** Angles ***********************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Angles
* \{ */
/* - angle with 2 arguments is angle between vector. /* - angle with 2 arguments is angle between vector.
* - angle with 3 arguments is angle between 3 points at the middle point. * - angle with 3 arguments is angle between 3 points at the middle point.
* - angle_normalized_* is faster equivalent if vectors are normalized. * - angle_normalized_* is faster equivalent if vectors are normalized.
*/ */
/**
* Return the shortest angle in radians between the 2 vectors.
*/
float angle_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; float angle_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
float angle_signed_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT; float angle_signed_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT;
float angle_v2v2v2(const float a[2], const float b[2], const float c[2]) ATTR_WARN_UNUSED_RESULT; float angle_v2v2v2(const float a[2], const float b[2], const float c[2]) ATTR_WARN_UNUSED_RESULT;
float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT; float angle_normalized_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT;
/**
* Return the shortest angle in radians between the 2 vectors.
*/
float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT; float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT;
/**
* Return the angle in radians between vecs 1-2 and 2-3 in radians
* If v1 is a shoulder, v2 is the elbow and v3 is the hand,
* this would return the angle at the elbow.
*
* note that when v1/v2/v3 represent 3 points along a straight line
* that the angle returned will be pi (180deg), rather than 0.0.
*/
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT; float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT;
/**
* Quicker than full angle computation.
*/
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) ATTR_WARN_UNUSED_RESULT; float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) ATTR_WARN_UNUSED_RESULT;
/**
* Quicker than full angle computation.
*/
float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2]) ATTR_WARN_UNUSED_RESULT; float cos_v2v2v2(const float p1[2], const float p2[2], const float p3[2]) ATTR_WARN_UNUSED_RESULT;
/**
* Angle between 2 vectors, about an axis (axis can be considered a plane).
*/
float angle_on_axis_v3v3_v3(const float v1[3], float angle_on_axis_v3v3_v3(const float v1[3],
const float v2[3], const float v2[3],
const float axis[3]) ATTR_WARN_UNUSED_RESULT; const float axis[3]) ATTR_WARN_UNUSED_RESULT;
@@ -403,6 +555,9 @@ float angle_signed_on_axis_v3v3_v3(const float v1[3],
const float v2[3], const float v2[3],
const float axis[3]) ATTR_WARN_UNUSED_RESULT; const float axis[3]) ATTR_WARN_UNUSED_RESULT;
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT; float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT;
/**
* Angle between 2 vectors defined by 3 coords, about an axis (axis can be considered a plane).
*/
float angle_on_axis_v3v3v3_v3(const float v1[3], float angle_on_axis_v3v3v3_v3(const float v1[3],
const float v2[3], const float v2[3],
const float v3[3], const float v3[3],
@@ -416,32 +571,107 @@ void angle_quad_v3(
float angles[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3]); float angles[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
void angle_poly_v3(float *angles, const float *verts[3], int len); void angle_poly_v3(float *angles, const float *verts[3], int len);
/********************************* Geometry **********************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Geometry
* \{ */
/**
* Project \a p onto \a v_proj
*/
void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2]); void project_v2_v2v2(float out[2], const float p[2], const float v_proj[2]);
/**
* Project \a p onto \a v_proj
*/
void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]); void project_v3_v3v3(float out[3], const float p[3], const float v_proj[3]);
void project_v3_v3v3_db(double out[3], const double p[3], const double v_proj[3]); void project_v3_v3v3_db(double out[3], const double p[3], const double v_proj[3]);
/**
* Project \a p onto a unit length \a v_proj
*/
void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2]); void project_v2_v2v2_normalized(float out[2], const float p[2], const float v_proj[2]);
/**
* Project \a p onto a unit length \a v_proj
*/
void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3]); void project_v3_v3v3_normalized(float out[3], const float p[3], const float v_proj[3]);
/**
* In this case plane is a 3D vector only (no 4th component).
*
* Projecting will make \a out a copy of \a p orthogonal to \a v_plane.
*
* \note If \a p is exactly perpendicular to \a v_plane, \a out will just be a copy of \a p.
*
* \note This function is a convenience to call:
* \code{.c}
* project_v3_v3v3(out, p, v_plane);
* sub_v3_v3v3(out, p, out);
* \endcode
*/
void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3]); void project_plane_v3_v3v3(float out[3], const float p[3], const float v_plane[3]);
void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2]); void project_plane_v2_v2v2(float out[2], const float p[2], const float v_plane[2]);
void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3]); void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3]);
void project_plane_normalized_v2_v2v2(float out[2], const float p[2], const float v_plane[2]); void project_plane_normalized_v2_v2v2(float out[2], const float p[2], const float v_plane[2]);
/**
* Project a vector on a plane defined by normal and a plane point p.
*/
void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3]); void project_v3_plane(float out[3], const float plane_no[3], const float plane_co[3]);
/**
* Returns a reflection vector from a vector and a normal vector
* reflect = vec - ((2 * dot(vec, mirror)) * mirror).
*
* <pre>
* v
* + ^
* \ |
* \|
* + normal: axis of reflection
* /
* /
* +
* out: result (negate for a 'bounce').
* </pre>
*/
void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3]); void reflect_v3_v3v3(float out[3], const float vec[3], const float normal[3]);
void reflect_v3_v3v3_db(double out[3], const double vec[3], const double normal[3]); void reflect_v3_v3v3_db(double out[3], const double vec[3], const double normal[3]);
/**
* Takes a vector and computes 2 orthogonal directions.
*
* \note if \a n is n unit length, computed values will be too.
*/
void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]); void ortho_basis_v3v3_v3(float r_n1[3], float r_n2[3], const float n[3]);
/**
* Calculates \a p - a perpendicular vector to \a v
*
* \note return vector won't maintain same length.
*/
void ortho_v3_v3(float out[3], const float v[3]); void ortho_v3_v3(float out[3], const float v[3]);
/**
* no brainer compared to v3, just have for consistency.
*/
void ortho_v2_v2(float out[2], const float v[2]); void ortho_v2_v2(float out[2], const float v[2]);
/**
* Returns a vector bisecting the angle at b formed by a, b and c.
*/
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]); void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]);
/**
* Rotate a point \a p by \a angle around origin (0, 0)
*/
void rotate_v2_v2fl(float r[2], const float p[2], const float angle); void rotate_v2_v2fl(float r[2], const float p[2], const float angle);
void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], const float angle); void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], const float angle);
/**
* Rotate a point \a p by \a angle around an arbitrary unit length \a axis.
* http://local.wasp.uwa.edu.au/~pbourke/geometry/
*/
void rotate_normalized_v3_v3v3fl(float out[3], void rotate_normalized_v3_v3v3fl(float out[3],
const float p[3], const float p[3],
const float axis[3], const float axis[3],
const float angle); const float angle);
/*********************************** Other ***********************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Other
* \{ */
void print_v2(const char *str, const float v[2]); void print_v2(const char *str, const float v[2]);
void print_v3(const char *str, const float v[3]); void print_v3(const char *str, const float v[3]);
@@ -464,6 +694,7 @@ void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]);
void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float (*vec_arr)[3], int nbr); void minmax_v3v3_v3_array(float r_min[3], float r_max[3], const float (*vec_arr)[3], int nbr);
/** ensure \a v1 is \a dist from \a v2 */
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist); void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist);
void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist); void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist);
@@ -476,8 +707,16 @@ MINLINE void clamp_v2_v2v2(float vec[2], const float min[2], const float max[2])
MINLINE void clamp_v3_v3v3(float vec[3], const float min[3], const float max[3]); MINLINE void clamp_v3_v3v3(float vec[3], const float min[3], const float max[3]);
MINLINE void clamp_v4_v4v4(float vec[4], const float min[4], const float max[4]); MINLINE void clamp_v4_v4v4(float vec[4], const float min[4], const float max[4]);
/***************************** Array Functions *******************************/ /** \} */
/* follow fixed length vector function conventions. */
/* -------------------------------------------------------------------- */
/** \name Array Functions
* \{ */
/**
* Follow fixed length vector function conventions.
*/
double dot_vn_vn(const float *array_src_a, double dot_vn_vn(const float *array_src_a,
const float *array_src_b, const float *array_src_b,
const int size) ATTR_WARN_UNUSED_RESULT; const int size) ATTR_WARN_UNUSED_RESULT;
@@ -532,7 +771,11 @@ void add_vn_vnvn_d(double *array_tar,
const int size); const int size);
void mul_vn_db(double *array_tar, const int size, const double f); void mul_vn_db(double *array_tar, const int size, const double f);
/**************************** Inline Definitions ******************************/ /** \} */
/* -------------------------------------------------------------------- */
/** \name Inline Definitions
* \{ */
#if BLI_MATH_DO_INLINE #if BLI_MATH_DO_INLINE
# include "intern/math_vector_inline.c" # include "intern/math_vector_inline.c"
@@ -542,6 +785,8 @@ void mul_vn_db(double *array_tar, const int size, const double f);
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
/** \} */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -29,8 +29,8 @@
extern "C" { extern "C" {
#endif #endif
/* A reasonable standard buffer size, big /**
* enough to not cause much internal fragmentation, * A reasonable standard buffer size, big enough to not cause much internal fragmentation,
* small enough not to waste resources * small enough not to waste resources
*/ */
#define BLI_MEMARENA_STD_BUFSIZE MEM_SIZE_OPTIMAL(1 << 14) #define BLI_MEMARENA_STD_BUFSIZE MEM_SIZE_OPTIMAL(1 << 14)
@@ -50,8 +50,22 @@ void *BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESU
void *BLI_memarena_calloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT void *BLI_memarena_calloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2); ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2);
/**
* Transfer ownership of allocated blocks from `ma_src` into `ma_dst`,
* cleaning the contents of `ma_src`.
*
* \note Useful for multi-threaded tasks that need a thread-local #MemArena
* that is kept after the multi-threaded operation is completed.
*
* \note Avoid accumulating memory pools where possible
* as any unused memory in `ma_src` is wasted every merge.
*/
void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src) ATTR_NONNULL(1, 2); void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src) ATTR_NONNULL(1, 2);
/**
* Clear for reuse, avoids re-allocation when an arena may
* otherwise be free'd and recreated.
*/
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1); void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -38,6 +38,10 @@ typedef void (*MemblockValFreeFP)(void *val);
BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size) ATTR_WARN_UNUSED_RESULT; BLI_memblock *BLI_memblock_create_ex(uint elem_size, uint chunk_size) ATTR_WARN_UNUSED_RESULT;
void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); void *BLI_memblock_alloc(BLI_memblock *mblk) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Reset elem count to 0 but keep as much memory allocated needed
* for at least the previous elem count.
*/
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1); void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1);
void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1); void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback) ATTR_NONNULL(1);
@@ -56,6 +60,11 @@ typedef struct BLI_memblock_iter {
void BLI_memblock_iternew(BLI_memblock *mblk, BLI_memblock_iter *iter) ATTR_NONNULL(); void BLI_memblock_iternew(BLI_memblock *mblk, BLI_memblock_iter *iter) ATTR_NONNULL();
void *BLI_memblock_iterstep(BLI_memblock_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void *BLI_memblock_iterstep(BLI_memblock_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Direct access. elem is element index inside the chosen chunk.
* Double usage: You can set chunk to 0 and set the absolute elem index.
* The correct chunk will be retrieve.
*/
void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) ATTR_WARN_UNUSED_RESULT void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(); ATTR_NONNULL();

View File

@@ -35,10 +35,19 @@ struct BLI_memiter;
typedef struct BLI_memiter BLI_memiter; typedef struct BLI_memiter BLI_memiter;
/* warning, ATTR_MALLOC flag on BLI_memiter_alloc causes crash, see: D2756 */ /**
* \param chunk_size_min: Should be a power of two and
* significantly larger than the average element size used.
*
* While allocations of any size are supported, they won't be efficient
* (effectively becoming a single-linked list).
*
* Its intended that many elements can be stored per chunk.
*/
BLI_memiter *BLI_memiter_create(unsigned int chunk_size) BLI_memiter *BLI_memiter_create(unsigned int chunk_size)
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL; ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL;
void *BLI_memiter_alloc(BLI_memiter *mi, unsigned int size) void *BLI_memiter_alloc(BLI_memiter *mi, unsigned int size)
/* WARNING: `ATTR_MALLOC` attribute on #BLI_memiter_alloc causes crash, see: D2756. */
ATTR_RETURNS_NONNULL ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1); ATTR_RETURNS_NONNULL ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1);
void BLI_memiter_alloc_from(BLI_memiter *mi, uint elem_size, const void *data_from) void BLI_memiter_alloc_from(BLI_memiter *mi, uint elem_size, const void *data_from)
ATTR_NONNULL(1, 3); ATTR_NONNULL(1, 3);
@@ -48,11 +57,15 @@ void BLI_memiter_destroy(BLI_memiter *mi) ATTR_NONNULL(1);
void BLI_memiter_clear(BLI_memiter *mi) ATTR_NONNULL(1); void BLI_memiter_clear(BLI_memiter *mi) ATTR_NONNULL(1);
unsigned int BLI_memiter_count(const BLI_memiter *mi) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); unsigned int BLI_memiter_count(const BLI_memiter *mi) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/* utils */ /* Utilities. */
/**
* Support direct lookup for the first item.
*/
void *BLI_memiter_elem_first(BLI_memiter *mi); void *BLI_memiter_elem_first(BLI_memiter *mi);
void *BLI_memiter_elem_first_size(BLI_memiter *mi, unsigned int *r_size); void *BLI_memiter_elem_first_size(BLI_memiter *mi, unsigned int *r_size);
/* private structure */ /** Private structure. */
typedef struct BLI_memiter_handle { typedef struct BLI_memiter_handle {
struct BLI_memiter_elem *elem; struct BLI_memiter_elem *elem;
uint elem_left; uint elem_left;

View File

@@ -44,19 +44,52 @@ void *BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT A
ATTR_NONNULL(1); ATTR_NONNULL(1);
void *BLI_mempool_calloc(BLI_mempool *pool) void *BLI_mempool_calloc(BLI_mempool *pool)
ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1); ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1);
/**
* Free an element from the mempool.
*
* \note doesn't protect against double frees, take care!
*/
void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1, 2); void BLI_mempool_free(BLI_mempool *pool, void *addr) ATTR_NONNULL(1, 2);
/**
* Empty the pool, as if it were just created.
*
* \param pool: The pool to clear.
* \param totelem_reserve: Optionally reserve how many items should be kept from clearing.
*/
void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve) ATTR_NONNULL(1); void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve) ATTR_NONNULL(1);
/**
* Wrap #BLI_mempool_clear_ex with no reserve set.
*/
void BLI_mempool_clear(BLI_mempool *pool) ATTR_NONNULL(1); void BLI_mempool_clear(BLI_mempool *pool) ATTR_NONNULL(1);
/**
* Free the mempool its self (and all elements).
*/
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1); void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1);
int BLI_mempool_len(const BLI_mempool *pool) ATTR_NONNULL(1); int BLI_mempool_len(const BLI_mempool *pool) ATTR_NONNULL(1);
void *BLI_mempool_findelem(BLI_mempool *pool, unsigned int index) ATTR_WARN_UNUSED_RESULT void *BLI_mempool_findelem(BLI_mempool *pool, unsigned int index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1); ATTR_NONNULL(1);
/**
* Fill in \a data with pointers to each element of the mempool,
* to create lookup table.
*
* \param pool: Pool to create a table from.
* \param data: array of pointers at least the size of 'pool->totused'
*/
void BLI_mempool_as_table(BLI_mempool *pool, void **data) ATTR_NONNULL(1, 2); void BLI_mempool_as_table(BLI_mempool *pool, void **data) ATTR_NONNULL(1, 2);
/**
* A version of #BLI_mempool_as_table that allocates and returns the data.
*/
void **BLI_mempool_as_tableN(BLI_mempool *pool, void **BLI_mempool_as_tableN(BLI_mempool *pool,
const char *allocstr) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT const char *allocstr) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2); ATTR_NONNULL(1, 2);
/**
* Fill in \a data with the contents of the mempool.
*/
void BLI_mempool_as_array(BLI_mempool *pool, void *data) ATTR_NONNULL(1, 2); void BLI_mempool_as_array(BLI_mempool *pool, void *data) ATTR_NONNULL(1, 2);
/**
* A version of #BLI_mempool_as_array that allocates and returns the data.
*/
void *BLI_mempool_as_arrayN(BLI_mempool *pool, void *BLI_mempool_as_arrayN(BLI_mempool *pool,
const char *allocstr) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT const char *allocstr) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 2); ATTR_NONNULL(1, 2);
@@ -67,9 +100,10 @@ void BLI_mempool_set_memory_debug(void);
/** /**
* Iteration stuff. * Iteration stuff.
* NOTE: this may easy to produce bugs with. * \note this may easy to produce bugs with.
*/ */
/* private structure */
/* Private structure. */
typedef struct BLI_mempool_iter { typedef struct BLI_mempool_iter {
BLI_mempool *pool; BLI_mempool *pool;
struct BLI_mempool_chunk *curchunk; struct BLI_mempool_chunk *curchunk;
@@ -89,7 +123,13 @@ enum {
BLI_MEMPOOL_ALLOW_ITER = (1 << 0), BLI_MEMPOOL_ALLOW_ITER = (1 << 0),
}; };
/**
* Initialize a new mempool iterator, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
*/
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL(); void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) ATTR_NONNULL();
/**
* Step over the iterator, returning the mempool item or NULL.
*/
void *BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void *BLI_mempool_iterstep(BLI_mempool_iter *iter) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -93,13 +93,16 @@ struct Plane {
Plane(const mpq3 &norm_exact, const mpq_class &d_exact); Plane(const mpq3 &norm_exact, const mpq_class &d_exact);
Plane(const double3 &norm, const double d); Plane(const double3 &norm, const double d);
/* Test equality on the exact fields. */ /** Test equality on the exact fields. */
bool operator==(const Plane &other) const; bool operator==(const Plane &other) const;
/* Hash on the exact fields. */ /** Hash on the exact fields. */
uint64_t hash() const; uint64_t hash() const;
void make_canonical(); void make_canonical();
/**
* This is wrong for degenerate planes, but we don't expect to call it on those.
*/
bool exact_populated() const; bool exact_populated() const;
void populate_exact(); void populate_exact();
}; };
@@ -395,10 +398,16 @@ struct BoundingBox {
} }
}; };
/** Assume bounding boxes have been expanded by a sufficient epsilon. */ /**
* Assume bounding boxes have been expanded by a sufficient epsilon on all sides
* so that the comparisons against the bb bounds are sufficient to guarantee that
* if an overlap or even touching could happen, this will return true.
*/
bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b); bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b);
/** /**
* This is the main routine for calculating the self_intersection of a triangle mesh.
*
* The output will have duplicate vertices merged and degenerate triangles ignored. * The output will have duplicate vertices merged and degenerate triangles ignored.
* If the input has overlapping co-planar triangles, then there will be * If the input has overlapping co-planar triangles, then there will be
* as many duplicates as there are overlaps in each overlapping triangular region. * as many duplicates as there are overlaps in each overlapping triangular region.
@@ -406,7 +415,7 @@ bool bbs_might_intersect(const BoundingBox &bb_a, const BoundingBox &bb_b);
* that the output triangle was a part of (input can have -1 for that field and then * that the output triangle was a part of (input can have -1 for that field and then
* the index in `tri[]` will be used as the original index). * the index in `tri[]` will be used as the original index).
* The orig structure of the output #IMesh gives the originals for vertices and edges. * The orig structure of the output #IMesh gives the originals for vertices and edges.
* NOTE: if the input tm_in has a non-empty orig structure, then it is ignored. * \note if the input tm_in has a non-empty orig structure, then it is ignored.
*/ */
IMesh trimesh_self_intersect(const IMesh &tm_in, IMeshArena *arena); IMesh trimesh_self_intersect(const IMesh &tm_in, IMeshArena *arena);
@@ -416,10 +425,17 @@ IMesh trimesh_nary_intersect(const IMesh &tm_in,
bool use_self, bool use_self,
IMeshArena *arena); IMeshArena *arena);
/** Return an IMesh that is a triangulation of a mesh with general polygonal faces. */ /**
* Return an #IMesh that is a triangulation of a mesh with general
* polygonal faces, #IMesh.
* Added diagonals will be distinguishable by having edge original
* indices of #NO_INDEX.
*/
IMesh triangulate_polymesh(IMesh &imesh, IMeshArena *arena); IMesh triangulate_polymesh(IMesh &imesh, IMeshArena *arena);
/** This has the side effect of populating verts in the #IMesh. */ /**
* Writing the obj_mesh has the side effect of populating verts in the #IMesh.
*/
void write_obj_mesh(IMesh &m, const std::string &objname); void write_obj_mesh(IMesh &m, const std::string &objname);
} /* namespace blender::meshintersect */ } /* namespace blender::meshintersect */

View File

@@ -29,21 +29,65 @@ extern "C" {
float BLI_noise_hnoise(float noisesize, float x, float y, float z); float BLI_noise_hnoise(float noisesize, float x, float y, float z);
float BLI_noise_hnoisep(float noisesize, float x, float y, float z); float BLI_noise_hnoisep(float noisesize, float x, float y, float z);
/**
* Original turbulence functions.
*/
float BLI_noise_turbulence(float noisesize, float x, float y, float z, int nr); float BLI_noise_turbulence(float noisesize, float x, float y, float z, int nr);
/* newnoise: generic noise & turbulence functions /**
* newnoise: generic noise & turbulence functions
* to replace the above BLI_noise_hnoise/p & BLI_noise_turbulence/1. * to replace the above BLI_noise_hnoise/p & BLI_noise_turbulence/1.
* This is done so different noise basis functions can be used */ * This is done so different noise basis functions can be used.
*/
/**
* newnoise: generic noise function for use with different `noisebasis`.
*/
float BLI_noise_generic_noise( float BLI_noise_generic_noise(
float noisesize, float x, float y, float z, bool hard, int noisebasis); float noisesize, float x, float y, float z, bool hard, int noisebasis);
/**
* newnoise: generic turbulence function for use with different `noisebasis`.
*/
float BLI_noise_generic_turbulence( float BLI_noise_generic_turbulence(
float noisesize, float x, float y, float z, int oct, bool hard, int noisebasis); float noisesize, float x, float y, float z, int oct, bool hard, int noisebasis);
/* newnoise: musgrave functions */ /* newnoise: musgrave functions */
/**
* Procedural `fBm` evaluated at "point"; returns value stored in "value".
*
* \param H: is the fractal increment parameter.
* \param lacunarity: is the gap between successive frequencies.
* \param octaves: is the number of frequencies in the `fBm`.
*/
float BLI_noise_mg_fbm( float BLI_noise_mg_fbm(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis); float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis);
/**
* Procedural multi-fractal evaluated at "point";
* returns value stored in "value".
*
* \param H: determines the highest fractal dimension.
* \param lacunarity: is gap between successive frequencies.
* \param octaves: is the number of frequencies in the `fBm`.
*
* \note There used to be a parameter called `offset`, old docs read:
* is the zero offset, which determines multi-fractality.
*/
float BLI_noise_mg_multi_fractal( float BLI_noise_mg_multi_fractal(
float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis); float x, float y, float z, float H, float lacunarity, float octaves, int noisebasis);
/**
* "Variable Lacunarity Noise"
* A distorted variety of Perlin noise.
*/
float BLI_noise_mg_variable_lacunarity( float BLI_noise_mg_variable_lacunarity(
float x, float y, float z, float distortion, int nbas1, int nbas2); float x, float y, float z, float distortion, int nbas1, int nbas2);
/**
* Heterogeneous procedural terrain function: stats by altitude method.
* Evaluated at "point"; returns value stored in "value".
*
* \param H: Determines the fractal dimension of the roughest areas.
* \param lacunarity: Is the gap between successive frequencies.
* \param octaves: Is the number of frequencies in the `fBm`.
* \param offset: Raises the terrain from `sea level`.
*/
float BLI_noise_mg_hetero_terrain(float x, float BLI_noise_mg_hetero_terrain(float x,
float y, float y,
float z, float z,
@@ -52,6 +96,14 @@ float BLI_noise_mg_hetero_terrain(float x,
float octaves, float octaves,
float offset, float offset,
int noisebasis); int noisebasis);
/**
* Hybrid additive/multiplicative multi-fractal terrain model.
*
* Some good parameter values to start with:
*
* \param H: 0.25
* \param offset: 0.7
*/
float BLI_noise_mg_hybrid_multi_fractal(float x, float BLI_noise_mg_hybrid_multi_fractal(float x,
float y, float y,
float z, float z,
@@ -61,6 +113,15 @@ float BLI_noise_mg_hybrid_multi_fractal(float x,
float offset, float offset,
float gain, float gain,
int noisebasis); int noisebasis);
/**
* Ridged multi-fractal terrain model.
*
* Some good parameter values to start with:
*
* \param H: 1.0
* \param offset: 1.0
* \param gain: 2.0
*/
float BLI_noise_mg_ridged_multi_fractal(float x, float BLI_noise_mg_ridged_multi_fractal(float x,
float y, float y,
float z, float z,
@@ -71,9 +132,20 @@ float BLI_noise_mg_ridged_multi_fractal(float x,
float gain, float gain,
int noisebasis); int noisebasis);
/* newnoise: voronoi */ /* newnoise: voronoi */
/**
* Not 'pure' Worley, but the results are virtually the same.
* Returns distances in da and point coords in `pa`.
*/
void BLI_noise_voronoi(float x, float y, float z, float *da, float *pa, float me, int dtype); void BLI_noise_voronoi(float x, float y, float z, float *da, float *pa, float me, int dtype);
/* newnoise: BLI_noise_cell & BLI_noise_cell_v3 (for vector/point/color) */ /**
* newnoise: BLI_noise_cell & BLI_noise_cell_v3 (for vector/point/color).
* idem, signed.
*/
float BLI_noise_cell(float x, float y, float z); float BLI_noise_cell(float x, float y, float z);
/**
* Returns a vector/point/color in `r_ca`, using point hash-array directly.
*/
void BLI_noise_cell_v3(float x, float y, float z, float r_ca[3]); void BLI_noise_cell_v3(float x, float y, float z, float r_ca[3]);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -29,27 +29,109 @@
extern "C" { extern "C" {
#endif #endif
/**
* Sets the specified environment variable to the specified value,
* and clears it if `val == NULL`.
*/
void BLI_setenv(const char *env, const char *val) ATTR_NONNULL(1); void BLI_setenv(const char *env, const char *val) ATTR_NONNULL(1);
/**
* Only set an environment variable if already not there.
* Like Unix `setenv(env, val, 0);`
*
* (not used anywhere).
*/
void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1); void BLI_setenv_if_new(const char *env, const char *val) ATTR_NONNULL(1);
/**
* Get an environment variable, result has to be used immediately.
*
* On windows #getenv gets its variables from a static copy of the environment variables taken at
* process start-up, causing it to not pick up on environment variables created during runtime.
* This function uses an alternative method to get environment variables that does pick up on
* runtime environment variables. The result will be UTF-8 encoded.
*/
const char *BLI_getenv(const char *env) ATTR_NONNULL(1); const char *BLI_getenv(const char *env) ATTR_NONNULL(1);
/**
* Returns in `string` the concatenation of `dir` and `file` (also with `relabase` on the
* front if specified and `dir` begins with "//"). Normalizes all occurrences of path
* separators, including ensuring there is exactly one between the copies of `dir` and `file`,
* and between the copies of `relabase` and `dir`.
*
* \param relabase: Optional prefix to substitute for "//" on front of `dir`.
* \param string: Area to return result.
*/
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file); void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file);
/**
* Ensures that the parent directory of `name` exists.
*
* \return true on success (i.e. given path now exists on file-system), false otherwise.
*/
bool BLI_make_existing_file(const char *name); bool BLI_make_existing_file(const char *name);
/**
* Converts `/foo/bar.txt` to `/foo/` and `bar.txt`
*
* - Won't change \a string.
* - Won't create any directories.
* - Doesn't use CWD, or deal with relative paths.
* - Only fill's in \a dir and \a file when they are non NULL.
*/
void BLI_split_dirfile( void BLI_split_dirfile(
const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen); const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen);
/**
* Copies the parent directory part of string into `dir`, max length `dirlen`.
*/
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen); void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen);
/**
* Copies the leaf filename part of string into `file`, max length `filelen`.
*/
void BLI_split_file_part(const char *string, char *file, const size_t filelen); void BLI_split_file_part(const char *string, char *file, const size_t filelen);
/**
* Returns a pointer to the last extension (e.g. the position of the last period).
* Returns NULL if there is no extension.
*/
const char *BLI_path_extension(const char *filepath) ATTR_NONNULL(); const char *BLI_path_extension(const char *filepath) ATTR_NONNULL();
/**
* Append a filename to a dir, ensuring slash separates.
*/
void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file) void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file)
ATTR_NONNULL(); ATTR_NONNULL();
/**
* Simple appending of filename to dir, does not check for valid path!
* Puts result into `dst`, which may be same area as `dir`.
*
* \note Consider using #BLI_path_join for more general path joining
* that de-duplicates separators and can handle an arbitrary number of paths.
*/
void BLI_join_dirfile(char *__restrict dst, void BLI_join_dirfile(char *__restrict dst,
const size_t maxlen, const size_t maxlen,
const char *__restrict dir, const char *__restrict dir,
const char *__restrict file) ATTR_NONNULL(); const char *__restrict file) ATTR_NONNULL();
/**
* Join multiple strings into a path, ensuring only a single path separator between each,
* and trailing slash is kept.
*
* \note If you want a trailing slash, add `SEP_STR` as the last path argument,
* duplicate slashes will be cleaned up.
*/
size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path_first, ...) size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path_first, ...)
ATTR_NONNULL(1, 3) ATTR_SENTINEL(0); ATTR_NONNULL(1, 3) ATTR_SENTINEL(0);
/**
* Like Python's `os.path.basename()`
*
* \return The pointer into \a path string immediately after last slash,
* or start of \a path if none found.
*/
const char *BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; const char *BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
/**
* Get an element of the path at an index, eg:
* "/some/path/file.txt" where an index of:
* - 0 or -3: "some"
* - 1 or -2: "path"
* - 2 or -1: "file.txt"
*
* Ignores multiple slashes at any point in the path (including start/end).
*/
bool BLI_path_name_at_index(const char *__restrict path, bool BLI_path_name_at_index(const char *__restrict path,
const int index, const int index,
int *__restrict r_offset, int *__restrict r_offset,
@@ -59,59 +141,217 @@ bool BLI_path_name_at_index(const char *__restrict path,
bool BLI_path_contains(const char *container_path, bool BLI_path_contains(const char *container_path,
const char *containee_path) ATTR_WARN_UNUSED_RESULT; const char *containee_path) ATTR_WARN_UNUSED_RESULT;
/**
* Returns pointer to the rightmost path separator in string.
*/
const char *BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; const char *BLI_path_slash_rfind(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
/**
* Appends a slash to string if there isn't one there already.
* Returns the new length of the string.
*/
int BLI_path_slash_ensure(char *string) ATTR_NONNULL(); int BLI_path_slash_ensure(char *string) ATTR_NONNULL();
/**
* Removes the last slash and everything after it to the end of string, if there is one.
*/
void BLI_path_slash_rstrip(char *string) ATTR_NONNULL(); void BLI_path_slash_rstrip(char *string) ATTR_NONNULL();
/**
* Returns pointer to the leftmost path separator in string. Not actually used anywhere.
*/
const char *BLI_path_slash_find(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; const char *BLI_path_slash_find(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
/**
* Changes to the path separators to the native ones for this OS.
*/
void BLI_path_slash_native(char *path) ATTR_NONNULL(); void BLI_path_slash_native(char *path) ATTR_NONNULL();
#ifdef _WIN32 #ifdef _WIN32
bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen); bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen);
#endif #endif
/**
* Search for a binary (executable)
*/
bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name); bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *name);
/**
* \return true when `str` end with `ext` (case insensitive).
*/
bool BLI_path_extension_check(const char *str, const char *ext) bool BLI_path_extension_check(const char *str, const char *ext)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
bool BLI_path_extension_check_n(const char *str, ...) ATTR_NONNULL(1) ATTR_SENTINEL(0); bool BLI_path_extension_check_n(const char *str, ...) ATTR_NONNULL(1) ATTR_SENTINEL(0);
/**
* \return true when `str` ends with any of the suffixes in `ext_array`.
*/
bool BLI_path_extension_check_array(const char *str, const char **ext_array) bool BLI_path_extension_check_array(const char *str, const char **ext_array)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
/**
* Semicolon separated wildcards, eg: `*.zip;*.py;*.exe`
* does `str` match any of the semicolon-separated glob patterns in #fnmatch.
*/
bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch) bool BLI_path_extension_check_glob(const char *str, const char *ext_fnmatch)
ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
/**
* Does basic validation of the given glob string, to prevent common issues from string
* truncation.
*
* For now, only forbids last group to be a wildcard-only one, if there are more than one group
* (i.e. things like `*.txt;*.cpp;*` are changed to `*.txt;*.cpp;`)
*
* \returns true if it had to modify given \a ext_fnmatch pattern.
*/
bool BLI_path_extension_glob_validate(char *ext_fnmatch) ATTR_NONNULL(); bool BLI_path_extension_glob_validate(char *ext_fnmatch) ATTR_NONNULL();
/**
* Removes any existing extension on the end of \a path and appends \a ext.
* \return false if there was no room.
*/
bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) ATTR_NONNULL(); bool BLI_path_extension_replace(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
/**
* Strip's trailing '.'s and adds the extension only when needed
*/
bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext) ATTR_NONNULL(); bool BLI_path_extension_ensure(char *path, size_t maxlen, const char *ext) ATTR_NONNULL();
bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL(); bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL();
/**
* Looks for a sequence of decimal digits in string, preceding any filename extension,
* returning the integer value if found, or 0 if not.
*
* \param string: String to scan.
* \param head: Optional area to return copy of part of string prior to digits,
* or before dot if no digits.
* \param tail: Optional area to return copy of part of string following digits,
* or from dot if no digits.
* \param r_num_len: Optional to return number of digits found.
*/
int BLI_path_sequence_decode(const char *string, int BLI_path_sequence_decode(const char *string,
char *head, char *head,
char *tail, char *tail,
unsigned short *r_num_len); unsigned short *r_num_len);
/**
* Returns in area pointed to by string a string of the form `<head><pic><tail>`,
* where pic is formatted as `numlen` digits with leading zeroes.
*/
void BLI_path_sequence_encode( void BLI_path_sequence_encode(
char *string, const char *head, const char *tail, unsigned short numlen, int pic); char *string, const char *head, const char *tail, unsigned short numlen, int pic);
/**
* Remove redundant characters from \a path and optionally make absolute.
*
* \param relabase: The path this is relative to, or ignored when NULL.
* \param path: Can be any input, and this function converts it to a regular full path.
* Also removes garbage from directory paths, like `/../` or double slashes etc.
*
* \note \a path isn't protected for max string names.
*/
void BLI_path_normalize(const char *relabase, char *path) ATTR_NONNULL(2); void BLI_path_normalize(const char *relabase, char *path) ATTR_NONNULL(2);
/* Same as above but adds a trailing slash. */ /**
* Cleanup file-path ensuring a trailing slash.
*
* \note Same as #BLI_path_normalize but adds a trailing slash.
*/
void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2); void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2);
/**
* Make given name safe to be used in paths.
*
* \return true if \a fname was changed, false otherwise.
*
* For now, simply replaces reserved chars (as listed in
* https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
* by underscores ('_').
*
* \note Space case ' ' is a bit of an edge case here - in theory it is allowed,
* but again can be an issue in some cases, so we simply replace it by an underscore too
* (good practice anyway).
* REMOVED based on popular demand (see T45900).
* Percent '%' char is a bit same case - not recommended to use it,
* but supported by all decent file-systems/operating-systems around.
*
* \note On Windows, it also ensures there is no '.' (dot char) at the end of the file,
* this can lead to issues.
*
* \note On Windows, it also checks for forbidden names
* (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
*/
bool BLI_filename_make_safe(char *fname) ATTR_NONNULL(1); bool BLI_filename_make_safe(char *fname) ATTR_NONNULL(1);
/**
* Make given path OS-safe.
*
* \return true if \a path was changed, false otherwise.
*/
bool BLI_path_make_safe(char *path) ATTR_NONNULL(1); bool BLI_path_make_safe(char *path) ATTR_NONNULL(1);
/* Go back one directory. */ /**
* Go back one directory.
*
* Replaces path with the path of its parent directory, returning true if
* it was able to find a parent directory within the path.
*/
bool BLI_path_parent_dir(char *path) ATTR_NONNULL(); bool BLI_path_parent_dir(char *path) ATTR_NONNULL();
/* Go back until the directory is found. */ /**
* Go back until the directory is found.
*
* Strips off nonexistent (or non-accessible) sub-directories from the end of `dir`,
* leaving the path of the lowest-level directory that does exist and we can read.
*/
bool BLI_path_parent_dir_until_exists(char *path) ATTR_NONNULL(); bool BLI_path_parent_dir_until_exists(char *path) ATTR_NONNULL();
/**
* If path begins with "//", strips that and replaces it with `basepath` directory.
*
* \note Also converts drive-letter prefix to something more sensible
* if this is a non-drive-letter-based system.
*
* \param path: The path to convert.
* \param basepath: The directory to base relative paths with.
* \return true if the path was relative (started with "//").
*/
bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL(); bool BLI_path_abs(char *path, const char *basepath) ATTR_NONNULL();
/**
* Replaces "#" character sequence in last slash-separated component of `path`
* with frame as decimal integer, with leading zeroes as necessary, to make digits digits.
*/
bool BLI_path_frame(char *path, int frame, int digits) ATTR_NONNULL(); bool BLI_path_frame(char *path, int frame, int digits) ATTR_NONNULL();
/**
* Replaces "#" character sequence in last slash-separated component of `path`
* with sta and end as decimal integers, with leading zeroes as necessary, to make digits
* digits each, with a hyphen in-between.
*/
bool BLI_path_frame_range(char *path, int sta, int end, int digits) ATTR_NONNULL(); bool BLI_path_frame_range(char *path, int sta, int end, int digits) ATTR_NONNULL();
/**
* Get the frame from a filename formatted by blender's frame scheme
*/
bool BLI_path_frame_get(char *path, int *r_frame, int *numdigits) ATTR_NONNULL(); bool BLI_path_frame_get(char *path, int *r_frame, int *numdigits) ATTR_NONNULL();
void BLI_path_frame_strip(char *path, char *ext) ATTR_NONNULL(); void BLI_path_frame_strip(char *path, char *ext) ATTR_NONNULL();
/**
* Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
*/
bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL(); bool BLI_path_frame_check_chars(const char *path) ATTR_NONNULL();
/**
* Checks for relative path, expanding them relative to the current working directory.
* Returns true if the expansion was performed.
*
* \note Should only be called with command line paths.
* This is _not_ something Blender's internal paths support, instead they use the "//" prefix.
* In most cases #BLI_path_abs should be used instead.
*/
bool BLI_path_abs_from_cwd(char *path, const size_t maxlen) ATTR_NONNULL(); bool BLI_path_abs_from_cwd(char *path, const size_t maxlen) ATTR_NONNULL();
/**
* Replaces `file` with a relative version (prefixed by "//") such that #BLI_path_abs, given
* the same `relfile`, will convert it back to its original value.
*/
void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL(); void BLI_path_rel(char *file, const char *relfile) ATTR_NONNULL();
/**
* Does path begin with the special "//" prefix that Blender uses to indicate
* a path relative to the .blend file.
*/
bool BLI_path_is_rel(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT; bool BLI_path_is_rel(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
/**
* Return true if the path is a UNC share.
*/
bool BLI_path_is_unc(const char *path); bool BLI_path_is_unc(const char *path);
/**
* Creates a display string from path to be used menus and the user interface.
* Like `bpy.path.display_name()`.
*/
void BLI_path_to_display_name(char *display_name, int maxlen, const char *name) ATTR_NONNULL(); void BLI_path_to_display_name(char *display_name, int maxlen, const char *name) ATTR_NONNULL();
#if defined(WIN32) #if defined(WIN32)
@@ -119,10 +359,22 @@ void BLI_path_normalize_unc_16(wchar_t *path_16);
void BLI_path_normalize_unc(char *path_16, int maxlen); void BLI_path_normalize_unc(char *path_16, int maxlen);
#endif #endif
/**
* Appends a suffix to the string, fitting it before the extension
*
* string = Foo.png, suffix = 123, separator = _
* Foo.png -> Foo_123.png
*
* \param string: original (and final) string
* \param maxlen: Maximum length of string
* \param suffix: String to append to the original string
* \param sep: Optional separator character
* \return true if succeeded
*/
bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep) bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep)
ATTR_NONNULL(); ATTR_NONNULL();
/* path string comparisons: case-insensitive for Windows, case-sensitive otherwise */ /* Path string comparisons: case-insensitive for Windows, case-sensitive otherwise. */
#if defined(WIN32) #if defined(WIN32)
# define BLI_path_cmp BLI_strcasecmp # define BLI_path_cmp BLI_strcasecmp
# define BLI_path_ncmp BLI_strncasecmp # define BLI_path_ncmp BLI_strncasecmp
@@ -131,8 +383,8 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
# define BLI_path_ncmp strncmp # define BLI_path_ncmp strncmp
#endif #endif
/* these values need to be hardcoded in structs, dna does not recognize defines */ /* These values need to be hard-coded in structs, dna does not recognize defines */
/* also defined in DNA_space_types.h */ /* also defined in `DNA_space_types.h`. */
#ifndef FILE_MAXDIR #ifndef FILE_MAXDIR
# define FILE_MAXDIR 768 # define FILE_MAXDIR 768
# define FILE_MAXFILE 256 # define FILE_MAXFILE 256
@@ -155,7 +407,7 @@ bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char
#define FILENAME_PARENT ".." #define FILENAME_PARENT ".."
#define FILENAME_CURRENT "." #define FILENAME_CURRENT "."
/* Avoid calling strcmp on one or two chars! */ /* Avoid calling `strcmp` on one or two chars! */
#define FILENAME_IS_PARENT(_n) (((_n)[0] == '.') && ((_n)[1] == '.') && ((_n)[2] == '\0')) #define FILENAME_IS_PARENT(_n) (((_n)[0] == '.') && ((_n)[1] == '.') && ((_n)[2] == '\0'))
#define FILENAME_IS_CURRENT(_n) (((_n)[0] == '.') && ((_n)[1] == '\0')) #define FILENAME_IS_CURRENT(_n) (((_n)[0] == '.') && ((_n)[1] == '\0'))
#define FILENAME_IS_CURRPAR(_n) \ #define FILENAME_IS_CURRPAR(_n) \

View File

@@ -26,6 +26,9 @@ extern "C" {
struct MemArena; struct MemArena;
/**
* A version of #BLI_polyfill_calc that uses a memory arena to avoid re-allocations.
*/
void BLI_polyfill_calc_arena(const float (*coords)[2], void BLI_polyfill_calc_arena(const float (*coords)[2],
const unsigned int coords_tot, const unsigned int coords_tot,
const int coords_sign, const int coords_sign,
@@ -33,6 +36,19 @@ void BLI_polyfill_calc_arena(const float (*coords)[2],
struct MemArena *arena); struct MemArena *arena);
/**
* Triangulates the given (convex or concave) simple polygon to a list of triangle vertices.
*
* \param coords: 2D coordinates describing vertices of the polygon,
* in either clockwise or counterclockwise order.
* \param coords_tot: Total points in the array.
* \param coords_sign: Pass this when we know the sign in advance to avoid extra calculations.
*
* \param r_tris: This array is filled in with triangle indices in clockwise order.
* The length of the array must be `coords_tot - 2`.
* Indices are guaranteed to be assigned to unique triangles, with valid indices,
* even in the case of degenerate input (self intersecting polygons, zero area ears... etc).
*/
void BLI_polyfill_calc(const float (*coords)[2], void BLI_polyfill_calc(const float (*coords)[2],
const unsigned int coords_tot, const unsigned int coords_tot,
const int coords_sign, const int coords_sign,

View File

@@ -27,6 +27,12 @@ extern "C" {
struct Heap; struct Heap;
struct MemArena; struct MemArena;
/**
* The intention is that this calculates the output of #BLI_polyfill_calc
* \note assumes the \a coords form a boundary,
* so any edges running along contiguous (wrapped) indices,
* are ignored since the edges won't share 2 faces.
*/
void BLI_polyfill_beautify(const float (*coords)[2], void BLI_polyfill_beautify(const float (*coords)[2],
const unsigned int coords_tot, const unsigned int coords_tot,
unsigned int (*tris)[3], unsigned int (*tris)[3],
@@ -35,6 +41,21 @@ void BLI_polyfill_beautify(const float (*coords)[2],
struct MemArena *arena, struct MemArena *arena,
struct Heap *eheap); struct Heap *eheap);
/**
* Assuming we have 2 triangles sharing an edge (2 - 4),
* check if the edge running from (1 - 3) gives better results.
*
* \param lock_degenerate: Use to avoid rotating out of a degenerate state:
* - When true, an existing zero area face on either side of the (2 - 4
* split will return a positive value.
* - When false, the check must be non-biased towards either split direction.
* \param r_area: Return the area of the quad,
* This can be useful when comparing the return value with near zero epsilons.
* In this case the epsilon can be scaled by the area to avoid the return value
* of very large faces not having a reliable way to detect near-zero output.
*
* \return (negative number means the edge can be rotated, lager == better).
*/
float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2], float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2],
const float v2[2], const float v2[2],
const float v3[2], const float v3[2],

View File

@@ -31,7 +31,8 @@
extern "C" { extern "C" {
#endif #endif
/* RNG is an abstract random number generator type that avoids using globals. /**
* RNG is an abstract random number generator type that avoids using globals.
* Always use this instead of the global RNG unless you have a good reason, * Always use this instead of the global RNG unless you have a good reason,
* the global RNG is not thread safe and will not give repeatable results. * the global RNG is not thread safe and will not give repeatable results.
*/ */
@@ -42,19 +43,34 @@ struct RNG_THREAD_ARRAY;
typedef struct RNG_THREAD_ARRAY RNG_THREAD_ARRAY; typedef struct RNG_THREAD_ARRAY RNG_THREAD_ARRAY;
struct RNG *BLI_rng_new(unsigned int seed); struct RNG *BLI_rng_new(unsigned int seed);
/**
* A version of #BLI_rng_new that hashes the seed.
*/
struct RNG *BLI_rng_new_srandom(unsigned int seed); struct RNG *BLI_rng_new_srandom(unsigned int seed);
struct RNG *BLI_rng_copy(struct RNG *rng) ATTR_NONNULL(1); struct RNG *BLI_rng_copy(struct RNG *rng) ATTR_NONNULL(1);
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1); void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1);
void BLI_rng_seed(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1); void BLI_rng_seed(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
/**
* Use a hash table to create better seed.
*/
void BLI_rng_srandom(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1); void BLI_rng_srandom(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
void BLI_rng_get_char_n(RNG *rng, char *bytes, size_t bytes_len) ATTR_NONNULL(1, 2); void BLI_rng_get_char_n(RNG *rng, char *bytes, size_t bytes_len) ATTR_NONNULL(1, 2);
int BLI_rng_get_int(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); int BLI_rng_get_int(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
unsigned int BLI_rng_get_uint(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); unsigned int BLI_rng_get_uint(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* \return Random value (0..1), but never 1.0.
*/
double BLI_rng_get_double(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); double BLI_rng_get_double(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* \return Random value (0..1), but never 1.0.
*/
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void BLI_rng_get_float_unit_v2(struct RNG *rng, float v[2]) ATTR_NONNULL(1, 2); void BLI_rng_get_float_unit_v2(struct RNG *rng, float v[2]) ATTR_NONNULL(1, 2);
void BLI_rng_get_float_unit_v3(struct RNG *rng, float v[3]) ATTR_NONNULL(1, 2); void BLI_rng_get_float_unit_v3(struct RNG *rng, float v[3]) ATTR_NONNULL(1, 2);
/**
* Generate a random point inside given tri.
*/
void BLI_rng_get_tri_sample_float_v2(struct RNG *rng, void BLI_rng_get_tri_sample_float_v2(struct RNG *rng,
const float v1[2], const float v1[2],
const float v2[2], const float v2[2],
@@ -75,9 +91,16 @@ void BLI_rng_shuffle_bitmap(struct RNG *rng, unsigned int *bitmap, unsigned int
ATTR_NONNULL(1, 2); ATTR_NONNULL(1, 2);
/** Note that skipping is as slow as generating n numbers! */ /** Note that skipping is as slow as generating n numbers! */
/**
* Simulate getting \a n random values.
*
* \note Useful when threaded code needs consistent values, independent of task division.
*/
void BLI_rng_skip(struct RNG *rng, int n) ATTR_NONNULL(1); void BLI_rng_skip(struct RNG *rng, int n) ATTR_NONNULL(1);
/* fill an array with random numbers */ /**
* Fill an array with random numbers.
*/
void BLI_array_frand(float *ar, int count, unsigned int seed); void BLI_array_frand(float *ar, int count, unsigned int seed);
/** Return a pseudo-random (hash) float from an integer value */ /** Return a pseudo-random (hash) float from an integer value */

View File

@@ -47,6 +47,9 @@ class RandomNumberGenerator {
x_ = (static_cast<uint64_t>(seed) << 16) | lowseed; x_ = (static_cast<uint64_t>(seed) << 16) | lowseed;
} }
/**
* Set a randomized hash of the value as seed.
*/
void seed_random(uint32_t seed); void seed_random(uint32_t seed);
uint32_t get_uint32() uint32_t get_uint32()
@@ -117,6 +120,9 @@ class RandomNumberGenerator {
float2 get_unit_float2(); float2 get_unit_float2();
float3 get_unit_float3(); float3 get_unit_float3();
/**
* Generate a random point inside the given triangle.
*/
float2 get_triangle_sample(float2 v1, float2 v2, float2 v3); float2 get_triangle_sample(float2 v1, float2 v2, float2 v3);
float3 get_triangle_sample_3d(float3 v1, float3 v2, float3 v3); float3 get_triangle_sample_3d(float3 v1, float3 v2, float3 v3);
void get_bytes(MutableSpan<char> r_bytes); void get_bytes(MutableSpan<char> r_bytes);

View File

@@ -34,12 +34,28 @@ struct rcti;
extern "C" { extern "C" {
#endif #endif
/**
* Determine if a `rect` is empty.
* An empty `rect` is one with a zero (or negative) width or height.
*
* \return True if \a rect is empty.
*/
bool BLI_rcti_is_empty(const struct rcti *rect); bool BLI_rcti_is_empty(const struct rcti *rect);
bool BLI_rctf_is_empty(const struct rctf *rect); bool BLI_rctf_is_empty(const struct rctf *rect);
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax); void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax);
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax); void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax);
/**
* Check if X-min and Y-min are less than or equal to X-max and Y-max, respectively.
* If this returns false, #BLI_rctf_sanitize() can be called to address this.
*
* This is not a hard constraint or invariant for rectangles, in some cases it may be useful to
* have max < min. Usually this is what you'd want though.
*/
bool BLI_rctf_is_valid(const struct rctf *rect); bool BLI_rctf_is_valid(const struct rctf *rect);
bool BLI_rcti_is_valid(const struct rcti *rect); bool BLI_rcti_is_valid(const struct rcti *rect);
/**
* Ensure X-min and Y-min are less than or equal to X-max and Y-max, respectively.
*/
void BLI_rctf_sanitize(struct rctf *rect); void BLI_rctf_sanitize(struct rctf *rect);
void BLI_rcti_sanitize(struct rcti *rect); void BLI_rcti_sanitize(struct rcti *rect);
void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size); void BLI_rctf_init_pt_radius(struct rctf *rect, const float xy[2], float size);
@@ -50,10 +66,19 @@ void BLI_rcti_do_minmax_v(struct rcti *rect, const int xy[2]);
void BLI_rctf_do_minmax_v(struct rctf *rect, const float xy[2]); void BLI_rctf_do_minmax_v(struct rctf *rect, const float xy[2]);
void BLI_rcti_do_minmax_rcti(struct rcti *rect, const struct rcti *other); void BLI_rcti_do_minmax_rcti(struct rcti *rect, const struct rcti *other);
/**
* Given 2 rectangles, transform a point from one to another.
*/
void BLI_rctf_transform_pt_v(const rctf *dst, void BLI_rctf_transform_pt_v(const rctf *dst,
const rctf *src, const rctf *src,
float xy_dst[2], float xy_dst[2],
const float xy_src[2]); const float xy_src[2]);
/**
* Calculate a 4x4 matrix representing the transformation between two rectangles.
*
* \note Multiplying a vector by this matrix does *not*
* give the same value as #BLI_rctf_transform_pt_v.
*/
void BLI_rctf_transform_calc_m4_pivot_min_ex( void BLI_rctf_transform_calc_m4_pivot_min_ex(
const rctf *dst, const rctf *src, float matrix[4][4], uint x, uint y); const rctf *dst, const rctf *src, float matrix[4][4], uint x, uint y);
void BLI_rctf_transform_calc_m4_pivot_min(const rctf *dst, const rctf *src, float matrix[4][4]); void BLI_rctf_transform_calc_m4_pivot_min(const rctf *dst, const rctf *src, float matrix[4][4]);
@@ -63,7 +88,13 @@ void BLI_rcti_translate(struct rcti *rect, int x, int y);
void BLI_rcti_recenter(struct rcti *rect, int x, int y); void BLI_rcti_recenter(struct rcti *rect, int x, int y);
void BLI_rctf_recenter(struct rctf *rect, float x, float y); void BLI_rctf_recenter(struct rctf *rect, float x, float y);
void BLI_rcti_resize(struct rcti *rect, int x, int y); void BLI_rcti_resize(struct rcti *rect, int x, int y);
/**
* Change width & height around the central X location.
*/
void BLI_rcti_resize_x(struct rcti *rect, int x); void BLI_rcti_resize_x(struct rcti *rect, int x);
/**
* Change width & height around the central Y location.
*/
void BLI_rcti_resize_y(struct rcti *rect, int y); void BLI_rcti_resize_y(struct rcti *rect, int y);
void BLI_rcti_pad(struct rcti *rect, int pad_x, int pad_y); void BLI_rcti_pad(struct rcti *rect, int pad_x, int pad_y);
void BLI_rctf_pad(struct rctf *rect, float pad_x, float pad_y); void BLI_rctf_pad(struct rctf *rect, float pad_x, float pad_y);
@@ -83,6 +114,14 @@ void BLI_rctf_interp(struct rctf *rect,
// void BLI_rcti_interp(struct rctf *rect, struct rctf *rect_a, struct rctf *rect_b, float fac); // void BLI_rcti_interp(struct rctf *rect, struct rctf *rect_a, struct rctf *rect_b, float fac);
bool BLI_rctf_clamp_pt_v(const struct rctf *rect, float xy[2]); bool BLI_rctf_clamp_pt_v(const struct rctf *rect, float xy[2]);
bool BLI_rcti_clamp_pt_v(const struct rcti *rect, int xy[2]); bool BLI_rcti_clamp_pt_v(const struct rcti *rect, int xy[2]);
/**
* Clamp \a rect within \a rect_bounds, setting \a r_xy to the offset.
*
* Keeps the top left corner within the bounds, which for user interface
* elements is typically where the most important information is.
*
* \return true if a change is made.
*/
bool BLI_rctf_clamp(struct rctf *rect, const struct rctf *rect_bounds, float r_xy[2]); bool BLI_rctf_clamp(struct rctf *rect, const struct rctf *rect_bounds, float r_xy[2]);
bool BLI_rcti_clamp(struct rcti *rect, const struct rcti *rect_bounds, int r_xy[2]); bool BLI_rcti_clamp(struct rcti *rect, const struct rcti *rect_bounds, int r_xy[2]);
bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, const float limit); bool BLI_rctf_compare(const struct rctf *rect_a, const struct rctf *rect_b, const float limit);
@@ -101,7 +140,13 @@ bool BLI_rctf_isect_x(const rctf *rect, const float x);
bool BLI_rctf_isect_y(const rctf *rect, const float y); bool BLI_rctf_isect_y(const rctf *rect, const float y);
bool BLI_rctf_isect_pt(const struct rctf *rect, const float x, const float y); bool BLI_rctf_isect_pt(const struct rctf *rect, const float x, const float y);
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2]); bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2]);
/**
* \returns shortest distance from \a rect to x (0 if inside)
*/
int BLI_rcti_length_x(const rcti *rect, const int x); int BLI_rcti_length_x(const rcti *rect, const int x);
/**
* \returns shortest distance from \a rect to y (0 if inside)
*/
int BLI_rcti_length_y(const rcti *rect, const int y); int BLI_rcti_length_y(const rcti *rect, const int y);
float BLI_rctf_length_x(const rctf *rect, const float x); float BLI_rctf_length_x(const rctf *rect, const float x);
float BLI_rctf_length_y(const rctf *rect, const float y); float BLI_rctf_length_y(const rctf *rect, const float y);
@@ -110,6 +155,9 @@ bool BLI_rctf_isect_segment(const struct rctf *rect, const float s1[2], const fl
bool BLI_rcti_isect_circle(const struct rcti *rect, const float xy[2], const float radius); bool BLI_rcti_isect_circle(const struct rcti *rect, const float xy[2], const float radius);
bool BLI_rctf_isect_circle(const struct rctf *rect, const float xy[2], const float radius); bool BLI_rctf_isect_circle(const struct rctf *rect, const float xy[2], const float radius);
bool BLI_rcti_inside_rcti(const rcti *rct_a, const rcti *rct_b); bool BLI_rcti_inside_rcti(const rcti *rct_a, const rcti *rct_b);
/**
* is \a rct_b inside \a rct_a
*/
bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b); bool BLI_rctf_inside_rctf(const rctf *rct_a, const rctf *rct_b);
void BLI_rcti_union(struct rcti *rct_a, const struct rcti *rct_b); void BLI_rcti_union(struct rcti *rct_a, const struct rcti *rct_b);
void BLI_rctf_union(struct rctf *rct_a, const struct rctf *rct_b); void BLI_rctf_union(struct rctf *rct_a, const struct rctf *rct_b);
@@ -118,6 +166,9 @@ void BLI_rctf_rcti_copy(struct rctf *dst, const struct rcti *src);
void BLI_rcti_rctf_copy_floor(struct rcti *dst, const struct rctf *src); void BLI_rcti_rctf_copy_floor(struct rcti *dst, const struct rctf *src);
void BLI_rcti_rctf_copy_round(struct rcti *dst, const struct rctf *src); void BLI_rcti_rctf_copy_round(struct rcti *dst, const struct rctf *src);
/**
* Expand the rectangle to fit a rotated \a src.
*/
void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle); void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle);
void print_rctf(const char *str, const struct rctf *rect); void print_rctf(const char *str, const struct rctf *rect);

View File

@@ -123,6 +123,12 @@ void BLI_scanfill_begin_arena(ScanFillContext *sf_ctx, struct MemArena *arena);
void BLI_scanfill_end_arena(ScanFillContext *sf_ctx, struct MemArena *arena); void BLI_scanfill_end_arena(ScanFillContext *sf_ctx, struct MemArena *arena);
/* scanfill_utils.c */ /* scanfill_utils.c */
/**
* Call before scan-fill to remove self intersections.
*
* \return false if no changes were made.
*/
bool BLI_scanfill_calc_self_isect(ScanFillContext *sf_ctx, bool BLI_scanfill_calc_self_isect(ScanFillContext *sf_ctx,
ListBase *fillvertbase, ListBase *fillvertbase,
ListBase *filledgebase); ListBase *filledgebase);

View File

@@ -34,8 +34,10 @@ typedef struct {
void *val; void *val;
} SmallHashEntry; } SmallHashEntry;
/* How much stack space to use before dynamically allocating memory. /**
* set to match one of the values in 'hashsizes' to avoid too many mallocs. */ * How much stack space to use before dynamically allocating memory.
* set to match one of the values in 'hashsizes' to avoid too many mallocs.
*/
#define SMSTACKSIZE 131 #define SMSTACKSIZE 131
typedef struct SmallHash { typedef struct SmallHash {
unsigned int nbuckets; unsigned int nbuckets;
@@ -53,8 +55,18 @@ typedef struct {
void BLI_smallhash_init_ex(SmallHash *sh, const unsigned int nentries_reserve) ATTR_NONNULL(1); void BLI_smallhash_init_ex(SmallHash *sh, const unsigned int nentries_reserve) ATTR_NONNULL(1);
void BLI_smallhash_init(SmallHash *sh) ATTR_NONNULL(1); void BLI_smallhash_init(SmallHash *sh) ATTR_NONNULL(1);
/**
* \note does *not* free *sh itself! only the direct data!
*/
void BLI_smallhash_release(SmallHash *sh) ATTR_NONNULL(1); void BLI_smallhash_release(SmallHash *sh) ATTR_NONNULL(1);
void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1); void BLI_smallhash_insert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
/**
* Inserts a new value to a key that may already be in ghash.
*
* Avoids #BLI_smallhash_remove, #BLI_smallhash_insert calls (double lookups)
*
* \returns true if a new key has been added.
*/
bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1); bool BLI_smallhash_reinsert(SmallHash *sh, uintptr_t key, void *item) ATTR_NONNULL(1);
bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1); bool BLI_smallhash_remove(SmallHash *sh, uintptr_t key) ATTR_NONNULL(1);
void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key) void *BLI_smallhash_lookup(const SmallHash *sh, uintptr_t key)
@@ -74,6 +86,12 @@ void **BLI_smallhash_iternew_p(const SmallHash *sh, SmallHashIter *iter, uintptr
/* void BLI_smallhash_print(SmallHash *sh); */ /* UNUSED */ /* void BLI_smallhash_print(SmallHash *sh); */ /* UNUSED */
#ifdef DEBUG #ifdef DEBUG
/**
* Measure how well the hash function performs
* (1.0 is perfect - no stepping needed).
*
* Smaller is better!
*/
double BLI_smallhash_calc_quality(SmallHash *sh); double BLI_smallhash_calc_quality(SmallHash *sh);
#endif #endif

View File

@@ -31,24 +31,73 @@ typedef struct BLI_Stack BLI_Stack;
BLI_Stack *BLI_stack_new_ex(const size_t elem_size, BLI_Stack *BLI_stack_new_ex(const size_t elem_size,
const char *description, const char *description,
const size_t chunk_size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); const size_t chunk_size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Create a new homogeneous stack with elements of 'elem_size' bytes.
*/
BLI_Stack *BLI_stack_new(const size_t elem_size, const char *description) ATTR_WARN_UNUSED_RESULT BLI_Stack *BLI_stack_new(const size_t elem_size, const char *description) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(); ATTR_NONNULL();
/**
* Free the stack's data and the stack itself
*/
void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL(); void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL();
/**
* Push a new item onto the stack.
*
* \return a pointer #BLI_Stack.elem_size
* bytes of uninitialized memory (caller must fill in).
*/
void *BLI_stack_push_r(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void *BLI_stack_push_r(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Copies the source value onto the stack
*
* \note This copies #BLI_Stack.elem_size bytes from \a src,
* (the pointer itself is not stored).
*
* \param src: source data to be copied to the stack.
*/
void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL(); void BLI_stack_push(BLI_Stack *stack, const void *src) ATTR_NONNULL();
/**
* A version of #BLI_stack_pop which fills in an array.
*
* \param dst: The destination array,
* must be at least (#BLI_Stack.elem_size * \a n) bytes long.
* \param n: The number of items to pop.
*
* \note The first item in the array will be last item added to the stack.
*/
void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL(); void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL();
/**
* A version of #BLI_stack_pop_n which fills in an array (in the reverse order).
*
* \note The first item in the array will be first item added to the stack.
*/
void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL(); void BLI_stack_pop_n_reverse(BLI_Stack *stack, void *dst, unsigned int n) ATTR_NONNULL();
/**
* Retrieves and removes the top element from the stack.
* The value is copies to \a dst, which must be at least \a elem_size bytes.
*
* Does not reduce amount of allocated memory.
*/
void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL(); void BLI_stack_pop(BLI_Stack *stack, void *dst) ATTR_NONNULL();
void *BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void *BLI_stack_peek(BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Removes the top element from the stack.
*/
void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL(); void BLI_stack_discard(BLI_Stack *stack) ATTR_NONNULL();
/**
* Discards all elements without freeing.
*/
void BLI_stack_clear(BLI_Stack *stack) ATTR_NONNULL(); void BLI_stack_clear(BLI_Stack *stack) ATTR_NONNULL();
size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Returns true if the stack is empty, false otherwise
*/
bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -33,23 +33,78 @@
extern "C" { extern "C" {
#endif #endif
/**
* Duplicates the first \a len bytes of cstring \a str
* into a newly mallocN'd string and returns it. \a str
* is assumed to be at least len bytes long.
*
* \param str: The string to be duplicated
* \param len: The number of bytes to duplicate
* \retval Returns the duplicated string
*/
char *BLI_strdupn(const char *str, const size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT char *BLI_strdupn(const char *str, const size_t len) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(); ATTR_NONNULL();
/**
* Duplicates the cstring \a str into a newly mallocN'd
* string and returns it.
*
* \param str: The string to be duplicated
* \retval Returns the duplicated string
*/
char *BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC; char *BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC;
/**
* Appends the two strings, and returns new mallocN'ed string
* \param str1: first string for copy
* \param str2: second string for append
* \retval Returns dst
*/
char *BLI_strdupcat(const char *__restrict str1, char *BLI_strdupcat(const char *__restrict str1,
const char *__restrict str2) ATTR_WARN_UNUSED_RESULT const char *__restrict str2) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL() ATTR_MALLOC; ATTR_NONNULL() ATTR_MALLOC;
/**
* Like strncpy but ensures dst is always
* '\0' terminated.
*
* \param dst: Destination for copy
* \param src: Source string to copy
* \param maxncpy: Maximum number of characters to copy (generally
* the size of dst)
* \retval Returns dst
*/
char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) char *BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy)
ATTR_NONNULL(); ATTR_NONNULL();
/**
* Like BLI_strncpy but ensures dst is always padded by given char,
* on both sides (unless src is empty).
*
* \param dst: Destination for copy
* \param src: Source string to copy
* \param pad: the char to use for padding
* \param maxncpy: Maximum number of characters to copy (generally the size of dst)
* \retval Returns dst
*/
char *BLI_strncpy_ensure_pad(char *__restrict dst, char *BLI_strncpy_ensure_pad(char *__restrict dst,
const char *__restrict src, const char *__restrict src,
const char pad, const char pad,
size_t maxncpy) ATTR_NONNULL(); size_t maxncpy) ATTR_NONNULL();
/**
* Like strncpy but ensures dst is always
* '\0' terminated.
*
* \note This is a duplicate of #BLI_strncpy that returns bytes copied.
* And is a drop in replacement for 'snprintf(str, sizeof(str), "%s", arg);'
*
* \param dst: Destination for copy
* \param src: Source string to copy
* \param maxncpy: Maximum number of characters to copy (generally
* the size of dst)
* \retval The number of bytes copied (The only difference from BLI_strncpy).
*/
size_t BLI_strncpy_rlen(char *__restrict dst, size_t BLI_strncpy_rlen(char *__restrict dst,
const char *__restrict src, const char *__restrict src,
const size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); const size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -57,6 +112,18 @@ size_t BLI_strncpy_rlen(char *__restrict dst,
size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src) ATTR_WARN_UNUSED_RESULT size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(); ATTR_NONNULL();
/**
* Return the range of the quoted string (excluding quotes) `str` after `prefix`.
*
* A version of #BLI_str_quoted_substrN that calculates the range
* instead of un-escaping and allocating the result.
*
* \param str: String potentially including `prefix`.
* \param prefix: Quoted string prefix.
* \param r_start: The start of the quoted string (after the first quote).
* \param r_end: The end of the quoted string (before the last quote).
* \return True when a quoted string range could be found after `prefix`.
*/
bool BLI_str_quoted_substr_range(const char *__restrict str, bool BLI_str_quoted_substr_range(const char *__restrict str,
const char *__restrict prefix, const char *__restrict prefix,
int *__restrict r_start, int *__restrict r_start,
@@ -67,91 +134,328 @@ char *BLI_str_quoted_substrN(const char *__restrict str,
const char *__restrict prefix) ATTR_WARN_UNUSED_RESULT const char *__restrict prefix) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL() ATTR_MALLOC; ATTR_NONNULL() ATTR_MALLOC;
#endif #endif
/**
* Fills \a result with text within "" that appear after some the contents of \a prefix.
* i.e. for string `pose["apples"]` with prefix `pose[`, it will return `apples`.
*
* \param str: is the entire string to chop.
* \param prefix: is the part of the string to step over.
* \param result: The buffer to fill.
* \param result_maxlen: The maximum size of the buffer (including nil terminator).
* \return True if the prefix was found and the entire quoted string was copied into result.
*
* Assume that the strings returned must be freed afterwards,
* and that the inputs will contain data we want.
*/
bool BLI_str_quoted_substr(const char *__restrict str, bool BLI_str_quoted_substr(const char *__restrict str,
const char *__restrict prefix, const char *__restrict prefix,
char *result, char *result,
size_t result_maxlen); size_t result_maxlen);
/**
* string with all instances of substr_old replaced with substr_new,
* Returns a copy of the c-string \a str into a newly #MEM_mallocN'd
* and returns it.
*
* \note A rather wasteful string-replacement utility, though this shall do for now.
* Feel free to replace this with an even safe + nicer alternative
*
* \param str: The string to replace occurrences of substr_old in
* \param substr_old: The text in the string to find and replace
* \param substr_new: The text in the string to find and replace
* \retval Returns the duplicated string
*/
char *BLI_str_replaceN(const char *__restrict str, char *BLI_str_replaceN(const char *__restrict str,
const char *__restrict substr_old, const char *__restrict substr_old,
const char *__restrict substr_new) ATTR_WARN_UNUSED_RESULT const char *__restrict substr_new) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL() ATTR_MALLOC; ATTR_NONNULL() ATTR_MALLOC;
/**
* In-place replace every \a src to \a dst in \a str.
*
* \param str: The string to operate on.
* \param src: The character to replace.
* \param dst: The character to replace with.
*/
void BLI_str_replace_char(char *string, char src, char dst) ATTR_NONNULL(); void BLI_str_replace_char(char *string, char src, char dst) ATTR_NONNULL();
/**
* Simple exact-match string replacement.
*
* \param replace_table: Array of source, destination pairs.
*
* \note Larger tables should use a hash table.
*/
bool BLI_str_replace_table_exact(char *string, bool BLI_str_replace_table_exact(char *string,
const size_t string_len, const size_t string_len,
const char *replace_table[][2], const char *replace_table[][2],
int replace_table_len); int replace_table_len);
/**
* Portable replacement for #snprintf
*/
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...) size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4); ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
/**
* A version of #BLI_snprintf that returns `strlen(dst)`
*/
size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...) size_t BLI_snprintf_rlen(char *__restrict dst, size_t maxncpy, const char *__restrict format, ...)
ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4); ATTR_NONNULL(1, 3) ATTR_PRINTF_FORMAT(3, 4);
/**
* Portable replacement for `vsnprintf`.
*/
size_t BLI_vsnprintf(char *__restrict buffer, size_t BLI_vsnprintf(char *__restrict buffer,
size_t maxncpy, size_t maxncpy,
const char *__restrict format, const char *__restrict format,
va_list arg) ATTR_PRINTF_FORMAT(3, 0); va_list arg) ATTR_PRINTF_FORMAT(3, 0);
/**
* A version of #BLI_vsnprintf that returns `strlen(buffer)`
*/
size_t BLI_vsnprintf_rlen(char *__restrict buffer, size_t BLI_vsnprintf_rlen(char *__restrict buffer,
size_t maxncpy, size_t maxncpy,
const char *__restrict format, const char *__restrict format,
va_list arg) ATTR_PRINTF_FORMAT(3, 0); va_list arg) ATTR_PRINTF_FORMAT(3, 0);
/**
* Print formatted string into a newly #MEM_mallocN'd string
* and return it.
*/
char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1, 2); ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1, 2);
/**
* This roughly matches C and Python's string escaping with double quotes - `"`.
*
* Since every character may need escaping,
* it's common to create a buffer twice as large as the input.
*
* \param dst: The destination string, at least \a dst_maxncpy, typically `(strlen(src) * 2) + 1`.
* \param src: The un-escaped source string.
* \param dst_maxncpy: The maximum number of bytes allowable to copy.
*
* \note This is used for creating animation paths in blend files.
*/
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy) size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, const size_t dst_maxncpy)
ATTR_NONNULL(); ATTR_NONNULL();
/**
* This roughly matches C and Python's string escaping with double quotes - `"`.
*
* The destination will never be larger than the source, it will either be the same
* or up to half when all characters are escaped.
*
* \param dst: The destination string, at least the size of `strlen(src) + 1`.
* \param src: The escaped source string.
* \param src_maxncpy: The maximum number of bytes allowable to copy from `src`.
* \param dst_maxncpy: The maximum number of bytes allowable to copy into `dst`.
* \param r_is_complete: Set to true when
*/
size_t BLI_str_unescape_ex(char *__restrict dst, size_t BLI_str_unescape_ex(char *__restrict dst,
const char *__restrict src, const char *__restrict src,
const size_t src_maxncpy, const size_t src_maxncpy,
/* Additional arguments. */ /* Additional arguments. */
const size_t dst_maxncpy, const size_t dst_maxncpy,
bool *r_is_complete) ATTR_NONNULL(); bool *r_is_complete) ATTR_NONNULL();
/**
* See #BLI_str_unescape_ex doc-string.
*
* This function makes the assumption that `dst` always has
* at least `src_maxncpy` bytes available.
*
* Use #BLI_str_unescape_ex if `dst` has a smaller fixed size.
*
* \note This is used for parsing animation paths in blend files (runs often).
*/
size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy) size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, const size_t src_maxncpy)
ATTR_NONNULL(); ATTR_NONNULL();
/**
* Find the first un-escaped quote in the string (to find the end of the string).
*
* \param str: Typically this is the first character in a quoted string.
* Where the character before `*str` would be `"`.
* \return The pointer to the first un-escaped quote.
*/
const char *BLI_str_escape_find_quote(const char *str) ATTR_NONNULL(); const char *BLI_str_escape_find_quote(const char *str) ATTR_NONNULL();
/**
* Format ints with decimal grouping.
* 1000 -> 1,000
*
* \param dst: The resulting string
* \param num: Number to format
* \return The length of \a dst
*/
size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL(); size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL();
/**
* Format uint64_t with decimal grouping.
* 1000 -> 1,000
*
* \param dst: The resulting string
* \param num: Number to format
* \return The length of \a dst
*/
size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num) ATTR_NONNULL(); size_t BLI_str_format_uint64_grouped(char dst[16], uint64_t num) ATTR_NONNULL();
/**
* Format a size in bytes using binary units.
* 1000 -> 1 KB
* Number of decimal places grows with the used unit (e.g. 1.5 MB, 1.55 GB, 1.545 TB).
*
* \param dst: The resulting string.
* Dimension of 14 to support largest possible value for \a bytes (#LLONG_MAX).
* \param bytes: Number to format.
* \param base_10: Calculate using base 10 (GB, MB, ...) or 2 (GiB, MiB, ...).
*/
void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10) void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10)
ATTR_NONNULL(); ATTR_NONNULL();
/**
* Format a count to up to 6 places (plus '\0' terminator) string using long number
* names abbreviations. Used to produce a compact representation of large numbers.
*
* 1 -> 1
* 15 -> 15
* 155 -> 155
* 1555 -> 1.6K
* 15555 -> 15.6K
* 155555 -> 156K
* 1555555 -> 1.6M
* 15555555 -> 15.6M
* 155555555 -> 156M
* 1000000000 -> 1B
* ...
*
* Length of 7 is the maximum of the resulting string, for example, `-15.5K\0`.
*/
void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format) ATTR_NONNULL(); void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format) ATTR_NONNULL();
/**
* Compare two strings without regard to case.
*
* \retval True if the strings are equal, false otherwise.
*/
int BLI_strcaseeq(const char *a, const char *b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BLI_strcaseeq(const char *a, const char *b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Portable replacement for `strcasestr` (not available in MSVC)
*/
char *BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); char *BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Variation of #BLI_strcasestr with string length limited to \a len
*/
char *BLI_strncasestr(const char *s, const char *find, size_t len) ATTR_WARN_UNUSED_RESULT char *BLI_strncasestr(const char *s, const char *find, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(); ATTR_NONNULL();
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_strncasecmp(const char *s1, const char *s2, size_t len) ATTR_WARN_UNUSED_RESULT int BLI_strncasecmp(const char *s1, const char *s2, size_t len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(); ATTR_NONNULL();
/**
* Case insensitive, *natural* string comparison,
* keeping numbers in order.
*/
int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Like strcmp, but will ignore any heading/trailing pad char for comparison.
* So e.g. if pad is '*', '*world' and 'world*' will compare equal.
*/
int BLI_strcmp_ignore_pad(const char *str1, int BLI_strcmp_ignore_pad(const char *str1,
const char *str2, const char *str2,
const char pad) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); const char pad) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* Determine the length of a fixed-size string.
*/
size_t BLI_strnlen(const char *str, const size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); size_t BLI_strnlen(const char *str, const size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void BLI_str_tolower_ascii(char *str, const size_t len) ATTR_NONNULL(); void BLI_str_tolower_ascii(char *str, const size_t len) ATTR_NONNULL();
void BLI_str_toupper_ascii(char *str, const size_t len) ATTR_NONNULL(); void BLI_str_toupper_ascii(char *str, const size_t len) ATTR_NONNULL();
/**
* Strip white-space from end of the string.
*/
void BLI_str_rstrip(char *str) ATTR_NONNULL(); void BLI_str_rstrip(char *str) ATTR_NONNULL();
/**
* Strip trailing zeros from a float, eg:
* 0.0000 -> 0.0
* 2.0010 -> 2.001
*
* \param str:
* \param pad:
* \return The number of zeros stripped.
*/
int BLI_str_rstrip_float_zero(char *str, const char pad) ATTR_NONNULL(); int BLI_str_rstrip_float_zero(char *str, const char pad) ATTR_NONNULL();
/**
* Return index of a string in a string array.
*
* \param str: The string to find.
* \param str_array: Array of strings.
* \param str_array_len: The length of the array, or -1 for a NULL-terminated array.
* \return The index of str in str_array or -1.
*/
int BLI_str_index_in_array_n(const char *__restrict str, int BLI_str_index_in_array_n(const char *__restrict str,
const char **__restrict str_array, const char **__restrict str_array,
const int str_array_len) ATTR_NONNULL(); const int str_array_len) ATTR_NONNULL();
/**
* Return index of a string in a string array.
*
* \param str: The string to find.
* \param str_array: Array of strings, (must be NULL-terminated).
* \return The index of str in str_array or -1.
*/
int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array) int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
ATTR_NONNULL(); ATTR_NONNULL();
/**
* Find if a string starts with another string.
*
* \param str: The string to search within.
* \param start: The string we look for at the start.
* \return If str starts with start.
*/
bool BLI_str_startswith(const char *__restrict str, const char *__restrict start) ATTR_NONNULL(); bool BLI_str_startswith(const char *__restrict str, const char *__restrict start) ATTR_NONNULL();
/**
* Find if a string ends with another string.
*
* \param str: The string to search within.
* \param end: The string we look for at the end.
* \return If str ends with end.
*/
bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL(); bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL();
bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t length) bool BLI_strn_endswith(const char *__restrict str, const char *__restrict end, size_t length)
ATTR_NONNULL(); ATTR_NONNULL();
/**
* Find the first char matching one of the chars in \a delim, from left.
*
* \param str: The string to search within.
* \param delim: The set of delimiters to search for, as unicode values.
* \param sep: Return value, set to the first delimiter found (or NULL if none found).
* \param suf: Return value, set to next char after the first delimiter found
* (or NULL if none found).
* \return The length of the prefix (i.e. *sep - str).
*/
size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf) size_t BLI_str_partition(const char *str, const char delim[], const char **sep, const char **suf)
ATTR_NONNULL(); ATTR_NONNULL();
/**
* Find the first char matching one of the chars in \a delim, from right.
*
* \param str: The string to search within.
* \param delim: The set of delimiters to search for, as unicode values.
* \param sep: Return value, set to the first delimiter found (or NULL if none found).
* \param suf: Return value, set to next char after the first delimiter found
* (or NULL if none found).
* \return The length of the prefix (i.e. *sep - str).
*/
size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf) size_t BLI_str_rpartition(const char *str, const char delim[], const char **sep, const char **suf)
ATTR_NONNULL(); ATTR_NONNULL();
/**
* Find the first char matching one of the chars in \a delim, either from left or right.
*
* \param str: The string to search within.
* \param end: If non-NULL, the right delimiter of the string.
* \param delim: The set of delimiters to search for, as unicode values.
* \param sep: Return value, set to the first delimiter found (or NULL if none found).
* \param suf: Return value, set to next char after the first delimiter found
* (or NULL if none found).
* \param from_right: If %true, search from the right of \a str, else, search from its left.
* \return The length of the prefix (i.e. *sep - str).
*/
size_t BLI_str_partition_ex(const char *str, size_t BLI_str_partition_ex(const char *str,
const char *end, const char *end,
const char delim[], const char delim[],
@@ -166,6 +470,16 @@ bool BLI_string_all_words_matched(const char *name,
int (*words)[2], int (*words)[2],
const int words_len); const int words_len);
/**
* Find the ranges needed to split \a str into its individual words.
*
* \param str: The string to search for words.
* \param len: Size of the string to search.
* \param delim: Character to use as a delimiter.
* \param r_words: Info about the words found. Set to [index, len] pairs.
* \param words_max: Max number of words to find
* \return The number of words found in \a str
*/
int BLI_string_find_split_words(const char *str, int BLI_string_find_split_words(const char *str,
const size_t len, const size_t len,
const char delim, const char delim,

View File

@@ -23,7 +23,16 @@ extern "C" {
typedef struct StringSearch StringSearch; typedef struct StringSearch StringSearch;
StringSearch *BLI_string_search_new(void); StringSearch *BLI_string_search_new(void);
/**
* Add a new possible result to the search.
* The caller keeps ownership of all parameters.
*/
void BLI_string_search_add(StringSearch *search, const char *str, void *user_data); void BLI_string_search_add(StringSearch *search, const char *str, void *user_data);
/**
* Filter and sort all previously added search items.
* Returns an array containing the filtered user data.
* The caller has to free the returned array.
*/
int BLI_string_search_query(StringSearch *search, const char *query, void ***r_data); int BLI_string_search_query(StringSearch *search, const char *query, void ***r_data);
void BLI_string_search_free(StringSearch *search); void BLI_string_search_free(StringSearch *search);
@@ -40,8 +49,24 @@ void BLI_string_search_free(StringSearch *search);
namespace blender::string_search { namespace blender::string_search {
/**
* Computes the cost of transforming string a into b. The cost/distance is the minimal number of
* operations that need to be executed. Valid operations are deletion, insertion, substitution and
* transposition.
*
* This function is utf8 aware in the sense that it works at the level of individual code points
* (1-4 bytes long) instead of on individual bytes.
*/
int damerau_levenshtein_distance(StringRef a, StringRef b); int damerau_levenshtein_distance(StringRef a, StringRef b);
/**
* Returns -1 when this is no reasonably good match.
* Otherwise returns the number of errors in the match.
*/
int get_fuzzy_match_errors(StringRef query, StringRef full); int get_fuzzy_match_errors(StringRef query, StringRef full);
/**
* Splits a string into words and normalizes them (currently that just means converting to lower
* case). The returned strings are allocated in the given allocator.
*/
void extract_normalized_words(StringRef str, void extract_normalized_words(StringRef str,
LinearAllocator<> &allocator, LinearAllocator<> &allocator,
Vector<StringRef, 64> &r_words); Vector<StringRef, 64> &r_words);

View File

@@ -32,23 +32,84 @@ char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t
size_t BLI_strncpy_utf8_rlen(char *__restrict dst, size_t BLI_strncpy_utf8_rlen(char *__restrict dst,
const char *__restrict src, const char *__restrict src,
size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); size_t maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
/**
* Find first UTF-8 invalid byte in given \a str, of \a length bytes.
*
* \return the offset of the first invalid byte.
*/
ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL(1); ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL(1);
/**
* Remove any invalid UTF-8 byte (taking into account multi-bytes sequence of course).
*
* \return number of stripped bytes.
*/
int BLI_str_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL(1); int BLI_str_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL(1);
/* warning, can return -1 on bad chars */ /**
* \return The size (in bytes) of a single UTF-8 char.
* \warning Can return -1 on bad chars.
*/
int BLI_str_utf8_size(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); int BLI_str_utf8_size(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Use when we want to skip errors.
*/
int BLI_str_utf8_size_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); int BLI_str_utf8_size_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/* copied from glib */ /**
* \param p: a pointer to Unicode character encoded as UTF-8
*
* Converts a sequence of bytes encoded as UTF-8 to a Unicode character.
* If \a p does not point to a valid UTF-8 encoded character, results are
* undefined. If you are not sure that the bytes are complete
* valid Unicode characters, you should use g_utf8_get_char_validated()
* instead.
*
* Return value: the resulting character
*/
unsigned int BLI_str_utf8_as_unicode(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); unsigned int BLI_str_utf8_as_unicode(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* UTF8 decoding that steps over the index (unless an error is encountered).
*
* \param p: The text to step over.
* \param p_len: The length of `p`.
* \param index: Index of `p` to step over.
* \return the code-point `(p + *index)` if there is a decoding error.
*
* \note Falls back to `LATIN1` for text drawing.
*/
unsigned int BLI_str_utf8_as_unicode_step(const char *__restrict p, unsigned int BLI_str_utf8_as_unicode_step(const char *__restrict p,
size_t p_len, size_t p_len,
size_t *__restrict index) ATTR_WARN_UNUSED_RESULT size_t *__restrict index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 3); ATTR_NONNULL(1, 3);
/**
* UTF8 decoding that steps over the index (unless an error is encountered).
*
* \param p: The text to step over.
* \param p_len: The length of `p`.
* \param index: Index of `p` to step over.
* \return the code-point or #BLI_UTF8_ERR if there is a decoding error.
*
* \note The behavior for clipped text (where `p_len` limits decoding trailing bytes)
* must have the same behavior is encountering a nil byte,
* so functions that only use the first part of a string has matching behavior to functions
* that null terminate the text.
*/
unsigned int BLI_str_utf8_as_unicode_step_or_error( unsigned int BLI_str_utf8_as_unicode_step_or_error(
const char *__restrict p, size_t p_len, size_t *__restrict index) ATTR_WARN_UNUSED_RESULT const char *__restrict p, size_t p_len, size_t *__restrict index) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1, 3); ATTR_NONNULL(1, 3);
size_t BLI_str_utf8_from_unicode_len(unsigned int c) ATTR_WARN_UNUSED_RESULT; size_t BLI_str_utf8_from_unicode_len(unsigned int c) ATTR_WARN_UNUSED_RESULT;
/**
* BLI_str_utf8_from_unicode:
*
* \param c: a Unicode character code
* \param outbuf: output buffer, must have at least `outbuf_len` bytes of space.
* If the length required by `c` exceeds `outbuf_len`,
* the bytes available bytes will be zeroed and `outbuf_len` returned.
*
* Converts a single character to UTF-8.
*
* \return number of bytes written.
*/
size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf, const size_t outbuf_len) size_t BLI_str_utf8_from_unicode(unsigned int c, char *outbuf, const size_t outbuf_len)
ATTR_NONNULL(2); ATTR_NONNULL(2);
size_t BLI_str_utf8_as_utf32(char32_t *__restrict dst_w, size_t BLI_str_utf8_as_utf32(char32_t *__restrict dst_w,
@@ -57,19 +118,57 @@ size_t BLI_str_utf8_as_utf32(char32_t *__restrict dst_w,
size_t BLI_str_utf32_as_utf8(char *__restrict dst, size_t BLI_str_utf32_as_utf8(char *__restrict dst,
const char32_t *__restrict src, const char32_t *__restrict src,
const size_t maxncpy) ATTR_NONNULL(1, 2); const size_t maxncpy) ATTR_NONNULL(1, 2);
/**
* \return The UTF-32 len in UTF-8.
*/
size_t BLI_str_utf32_as_utf8_len(const char32_t *src) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); size_t BLI_str_utf32_as_utf8_len(const char32_t *src) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* BLI_str_find_prev_char_utf8:
* \param str: pointer to the beginning of a UTF-8 encoded string
* \param p: pointer to some position within \a str
*
* Given a position \a p with a UTF-8 encoded string \a str, find the start
* of the previous UTF-8 character starting before. \a p Returns \a str_start if no
* UTF-8 characters are present in \a str_start before \a p.
*
* \a p does not have to be at the beginning of a UTF-8 character. No check
* is made to see if the character found is actually valid other than
* it starts with an appropriate byte.
*
* \return A pointer to the found character.
*/
const char *BLI_str_find_prev_char_utf8(const char *p, const char *str_start) const char *BLI_str_find_prev_char_utf8(const char *p, const char *str_start)
ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1, 2); ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1, 2);
/**
* \param p: a pointer to a position within a UTF-8 encoded string
* \param end: a pointer to the byte following the end of the string.
*
* Finds the start of the next UTF-8 character in the string after \a p
*
* \a p does not have to be at the beginning of a UTF-8 character. No check
* is made to see if the character found is actually valid other than
* it starts with an appropriate byte.
*
* \return a pointer to the found character or a pointer to the null terminating character '\0'.
*/
const char *BLI_str_find_next_char_utf8(const char *p, const char *str_end) const char *BLI_str_find_next_char_utf8(const char *p, const char *str_end)
ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1, 2); ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1, 2);
/**
* \return the `wchar_t` length in UTF-8.
*/
size_t BLI_wstrlen_utf8(const wchar_t *src) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; size_t BLI_wstrlen_utf8(const wchar_t *src) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strlen_utf8_ex(const char *strc, size_t *r_len_bytes) size_t BLI_strlen_utf8_ex(const char *strc, size_t *r_len_bytes)
ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT; ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strlen_utf8(const char *strc) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; size_t BLI_strlen_utf8(const char *strc) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, size_t *r_len_bytes) size_t BLI_strnlen_utf8_ex(const char *strc, const size_t maxlen, size_t *r_len_bytes)
ATTR_NONNULL(1, 3); ATTR_NONNULL(1, 3);
/**
* \param strc: the string to measure the length.
* \param maxlen: the string length (in bytes)
* \return the unicode length (not in bytes!)
*/
size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen) size_t BLI_strnlen_utf8(const char *strc, const size_t maxlen)
ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst, size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst,
@@ -79,10 +178,14 @@ size_t BLI_strncpy_wchar_from_utf8(wchar_t *__restrict dst,
const char *__restrict src, const char *__restrict src,
const size_t maxncpy) ATTR_NONNULL(1, 2); const size_t maxncpy) ATTR_NONNULL(1, 2);
/* count columns that character/string occupies, based on wcwidth.c */ /**
* Count columns that character/string occupies (based on `wcwidth.co`).
*/
int BLI_wcwidth(char32_t ucs) ATTR_WARN_UNUSED_RESULT; int BLI_wcwidth(char32_t ucs) ATTR_WARN_UNUSED_RESULT;
int BLI_wcswidth(const char32_t *pwcs, size_t n) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); int BLI_wcswidth(const char32_t *pwcs, size_t n) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/* warning, can return -1 on bad chars */ /**
* \warning can return -1 on bad chars.
*/
int BLI_str_utf8_char_width(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); int BLI_str_utf8_char_width(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
int BLI_str_utf8_char_width_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); int BLI_str_utf8_char_width_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
@@ -111,7 +214,8 @@ int BLI_str_utf8_offset_to_column(const char *str, int offset) ATTR_WARN_UNUSED_
int BLI_str_utf8_offset_from_column(const char *str, int column) ATTR_WARN_UNUSED_RESULT int BLI_str_utf8_offset_from_column(const char *str, int column) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1); ATTR_NONNULL(1);
#define BLI_UTF8_MAX 6 /* mem */ /** Size in bytes. */
#define BLI_UTF8_MAX 6
#define BLI_UTF8_WIDTH_MAX 2 /* columns */ #define BLI_UTF8_WIDTH_MAX 2 /* columns */
#define BLI_UTF8_ERR ((unsigned int)-1) #define BLI_UTF8_ERR ((unsigned int)-1)

View File

@@ -36,33 +36,71 @@ struct ListBase;
typedef bool (*UniquenameCheckCallback)(void *arg, const char *name); typedef bool (*UniquenameCheckCallback)(void *arg, const char *name);
/**
* Looks for a numeric suffix preceded by `delim` character on the end of
* name, puts preceding part into *left and value of suffix into *nr.
* Returns the length of *left.
*
* Foo.001 -> "Foo", 1
* Returning the length of "Foo"
*
* \param left: Where to return copy of part preceding `delim`.
* \param nr: Where to return value of numeric suffix`.
* \param name: String to split`.
* \param delim: Delimiter character`.
* \return Length of \a left.
*/
size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim); size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim);
bool BLI_string_is_decimal(const char *string) ATTR_NONNULL(); bool BLI_string_is_decimal(const char *string) ATTR_NONNULL();
/**
* Based on `BLI_split_dirfile()` / `os.path.splitext()`,
* `"a.b.c"` -> (`"a.b"`, `".c"`).
*/
void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len); void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len);
/**
* `"a.b.c"` -> (`"a."`, `"b.c"`).
*/
void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len); void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len);
/* Join strings, return newly allocated string. */ /**
* Join strings, return newly allocated string.
*/
char *BLI_string_join_array(char *result, char *BLI_string_join_array(char *result,
size_t result_len, size_t result_len,
const char *strings[], const char *strings[],
uint strings_len) ATTR_NONNULL(); uint strings_len) ATTR_NONNULL();
/**
* A version of #BLI_string_join that takes a separator which can be any character including '\0'.
*/
char *BLI_string_join_array_by_sep_char(char *result, char *BLI_string_join_array_by_sep_char(char *result,
size_t result_len, size_t result_len,
char sep, char sep,
const char *strings[], const char *strings[],
uint strings_len) ATTR_NONNULL(); uint strings_len) ATTR_NONNULL();
/**
* Join an array of strings into a newly allocated, null terminated string.
*/
char *BLI_string_join_arrayN(const char *strings[], uint strings_len) ATTR_WARN_UNUSED_RESULT char *BLI_string_join_arrayN(const char *strings[], uint strings_len) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(); ATTR_NONNULL();
/**
* A version of #BLI_string_joinN that takes a separator which can be any character including '\0'.
*/
char *BLI_string_join_array_by_sep_charN(char sep, char *BLI_string_join_array_by_sep_charN(char sep,
const char *strings[], const char *strings[],
uint strings_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); uint strings_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/**
* A version of #BLI_string_join_array_by_sep_charN that takes a table array.
* The new location of each string is written into this array.
*/
char *BLI_string_join_array_by_sep_char_with_tableN(char sep, char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
char *table[], char *table[],
const char *strings[], const char *strings[],
uint strings_len) ATTR_NONNULL(); uint strings_len) ATTR_NONNULL();
/* Take multiple arguments, pass as (array, length). */ /**
* Take multiple arguments, pass as (array, length).
*/
#define BLI_string_join(result, result_len, ...) \ #define BLI_string_join(result, result_len, ...) \
BLI_string_join_array( \ BLI_string_join_array( \
result, result_len, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) result, result_len, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
@@ -75,17 +113,51 @@ char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
BLI_string_join_array_by_sep_char_with_tableN( \ BLI_string_join_array_by_sep_char_with_tableN( \
sep, table, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__)) sep, table, ((const char *[]){__VA_ARGS__}), VA_NARGS_COUNT(__VA_ARGS__))
/**
* Finds the best possible flipped (left/right) name.
* For renaming; check for unique names afterwards.
*
* \param r_name: flipped name,
* assumed to be a pointer to a string of at least \a name_len size.
* \param from_name: original name,
* assumed to be a pointer to a string of at least \a name_len size.
* \param strip_number: If set, remove number extensions.
* \return The number of bytes written into \a r_name.
*/
size_t BLI_string_flip_side_name(char *r_name, size_t BLI_string_flip_side_name(char *r_name,
const char *from_name, const char *from_name,
const bool strip_number, const bool strip_number,
const size_t name_len); const size_t name_len);
/**
* Ensures name is unique (according to criteria specified by caller in unique_check callback),
* incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
*
* \param unique_check: Return true if name is not unique
* \param arg: Additional arg to unique_check--meaning is up to caller
* \param defname: To initialize name if latter is empty
* \param delim: Delimits numeric suffix in name
* \param name: Name to be ensured unique
* \param name_len: Maximum length of name area
* \return true if there if the name was changed
*/
bool BLI_uniquename_cb(UniquenameCheckCallback unique_check, bool BLI_uniquename_cb(UniquenameCheckCallback unique_check,
void *arg, void *arg,
const char *defname, const char *defname,
char delim, char delim,
char *name, char *name,
size_t name_len); size_t name_len);
/**
* Ensures that the specified block has a unique name within the containing list,
* incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
*
* \param list: List containing the block
* \param vlink: The block to check the name for
* \param defname: To initialize block name if latter is empty
* \param delim: Delimits numeric suffix in name
* \param name_offset: Offset of name within block structure
* \param name_len: Maximum length of name area
*/
bool BLI_uniquename(struct ListBase *list, bool BLI_uniquename(struct ListBase *list,
void *vlink, void *vlink,
const char *defname, const char *defname,

View File

@@ -35,20 +35,24 @@ extern "C" {
struct BLI_mempool; struct BLI_mempool;
/* Task Scheduler /* -------------------------------------------------------------------- */
/** \name Task Scheduler
* *
* Central scheduler that holds running threads ready to execute tasks. A single * Central scheduler that holds running threads ready to execute tasks.
* queue holds the task from all pools. * A single queue holds the task from all pools.
* *
* Init/exit must be called before/after any task pools are created/freed, and * Initialize/exit must be called before/after any task pools are created/freed, and must
* must be called from the main threads. All other scheduler and pool functions * be called from the main threads. All other scheduler and pool functions are thread-safe.
* are thread-safe. */ * \{ */
void BLI_task_scheduler_init(void); void BLI_task_scheduler_init(void);
void BLI_task_scheduler_exit(void); void BLI_task_scheduler_exit(void);
int BLI_task_scheduler_num_threads(void); int BLI_task_scheduler_num_threads(void);
/* Task Pool /** \} */
/* -------------------------------------------------------------------- */
/** \name Task Pool
* *
* Pool of tasks that will be executed by the central task scheduler. For each * Pool of tasks that will be executed by the central task scheduler. For each
* pool, we can wait for all tasks to be done, or cancel them before they are * pool, we can wait for all tasks to be done, or cancel them before they are
@@ -60,7 +64,7 @@ int BLI_task_scheduler_num_threads(void);
* pool with smaller tasks. When other threads are busy they will continue * pool with smaller tasks. When other threads are busy they will continue
* working on their own tasks, if not they will join in, no new threads will * working on their own tasks, if not they will join in, no new threads will
* be launched. * be launched.
*/ * \{ */
typedef enum eTaskPriority { typedef enum eTaskPriority {
TASK_PRIORITY_LOW, TASK_PRIORITY_LOW,
@@ -71,25 +75,34 @@ typedef struct TaskPool TaskPool;
typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata); typedef void (*TaskRunFunction)(TaskPool *__restrict pool, void *taskdata);
typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata); typedef void (*TaskFreeFunction)(TaskPool *__restrict pool, void *taskdata);
/* Regular task pool that immediately starts executing tasks as soon as they /**
* are pushed, either on the current or another thread. */ * Regular task pool that immediately starts executing tasks as soon as they
* are pushed, either on the current or another thread.
*/
TaskPool *BLI_task_pool_create(void *userdata, eTaskPriority priority); TaskPool *BLI_task_pool_create(void *userdata, eTaskPriority priority);
/* Background: always run tasks in a background thread, never immediately /**
* execute them. For running background jobs. */ * Background: always run tasks in a background thread, never immediately
* execute them. For running background jobs.
*/
TaskPool *BLI_task_pool_create_background(void *userdata, eTaskPriority priority); TaskPool *BLI_task_pool_create_background(void *userdata, eTaskPriority priority);
/* Background Serial: run tasks one after the other in the background, /**
* without parallelization between the tasks. */ * Background Serial: run tasks one after the other in the background,
* without parallelization between the tasks.
*/
TaskPool *BLI_task_pool_create_background_serial(void *userdata, eTaskPriority priority); TaskPool *BLI_task_pool_create_background_serial(void *userdata, eTaskPriority priority);
/* Suspended: don't execute tasks until work_and_wait is called. This is slower /**
* Suspended: don't execute tasks until work_and_wait is called. This is slower
* as threads can't immediately start working. But it can be used if the data * as threads can't immediately start working. But it can be used if the data
* structures the threads operate on are not fully initialized until all tasks * structures the threads operate on are not fully initialized until all tasks are created.
* are created. */ */
TaskPool *BLI_task_pool_create_suspended(void *userdata, eTaskPriority priority); TaskPool *BLI_task_pool_create_suspended(void *userdata, eTaskPriority priority);
/* No threads: immediately executes tasks on the same thread. For debugging. */ /**
* No threads: immediately executes tasks on the same thread. For debugging.
*/
TaskPool *BLI_task_pool_create_no_threads(void *userdata); TaskPool *BLI_task_pool_create_no_threads(void *userdata);
void BLI_task_pool_free(TaskPool *pool); void BLI_task_pool_free(TaskPool *pool);
@@ -100,28 +113,45 @@ void BLI_task_pool_push(TaskPool *pool,
bool free_taskdata, bool free_taskdata,
TaskFreeFunction freedata); TaskFreeFunction freedata);
/* work and wait until all tasks are done */ /**
* Work and wait until all tasks are done.
*/
void BLI_task_pool_work_and_wait(TaskPool *pool); void BLI_task_pool_work_and_wait(TaskPool *pool);
/* cancel all tasks, keep worker threads running */ /**
* Cancel all tasks, keep worker threads running.
*/
void BLI_task_pool_cancel(TaskPool *pool); void BLI_task_pool_cancel(TaskPool *pool);
/* for worker threads, test if current task pool canceled. this function may /**
* For worker threads, test if current task pool canceled. this function may
* only be called from worker threads and pool must be the task pool that the * only be called from worker threads and pool must be the task pool that the
* thread is currently executing a task from. */ * thread is currently executing a task from.
*/
bool BLI_task_pool_current_canceled(TaskPool *pool); bool BLI_task_pool_current_canceled(TaskPool *pool);
/* optional userdata pointer to pass along to run function */ /**
* Optional `userdata` pointer to pass along to run function.
*/
void *BLI_task_pool_user_data(TaskPool *pool); void *BLI_task_pool_user_data(TaskPool *pool);
/* optional mutex to use from run function */ /**
* Optional mutex to use from run function.
*/
ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool); ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool);
/* Parallel for routines */ /** \} */
/* Per-thread specific data passed to the callback. */ /* -------------------------------------------------------------------- */
/** \name Parallel for Routines
* \{ */
/**
* Per-thread specific data passed to the callback.
*/
typedef struct TaskParallelTLS { typedef struct TaskParallelTLS {
/* Copy of user-specifier chunk, which is copied from original chunk to all /**
* worker threads. This is similar to OpenMP's firstprivate. * Copy of user-specifier chunk, which is copied from original chunk to all worker threads.
* This is similar to OpenMP's `firstprivate`.
*/ */
void *userdata_chunk; void *userdata_chunk;
} TaskParallelTLS; } TaskParallelTLS;
@@ -186,7 +216,8 @@ void BLI_task_parallel_range(const int start,
TaskParallelRangeFunc func, TaskParallelRangeFunc func,
const TaskParallelSettings *settings); const TaskParallelSettings *settings);
/* This data is shared between all tasks, its access needs thread lock or similar protection. /**
* This data is shared between all tasks, its access needs thread lock or similar protection.
*/ */
typedef struct TaskParallelIteratorStateShared { typedef struct TaskParallelIteratorStateShared {
/* Maximum amount of items to acquire at once. */ /* Maximum amount of items to acquire at once. */
@@ -222,6 +253,17 @@ void BLI_task_parallel_iterator(void *userdata,
TaskParallelIteratorFunc func, TaskParallelIteratorFunc func,
const TaskParallelSettings *settings); const TaskParallelSettings *settings);
/**
* This function allows to parallelize for loops over ListBase items.
*
* \param listbase: The double linked list to loop over.
* \param userdata: Common userdata passed to all instances of \a func.
* \param func: Callback function.
* \param settings: See public API doc of ParallelRangeSettings for description of all settings.
*
* \note There is no static scheduling here,
* since it would need another full loop over items to count them.
*/
void BLI_task_parallel_listbase(struct ListBase *listbase, void BLI_task_parallel_listbase(struct ListBase *listbase,
void *userdata, void *userdata,
TaskParallelIteratorFunc func, TaskParallelIteratorFunc func,
@@ -232,6 +274,16 @@ typedef struct MempoolIterData MempoolIterData;
typedef void (*TaskParallelMempoolFunc)(void *userdata, typedef void (*TaskParallelMempoolFunc)(void *userdata,
MempoolIterData *iter, MempoolIterData *iter,
const TaskParallelTLS *__restrict tls); const TaskParallelTLS *__restrict tls);
/**
* This function allows to parallelize for loops over Mempool items.
*
* \param mempool: The iterable BLI_mempool to loop over.
* \param userdata: Common userdata passed to all instances of \a func.
* \param func: Callback function.
* \param settings: See public API doc of TaskParallelSettings for description of all settings.
*
* \note There is no static scheduling here.
*/
void BLI_task_parallel_mempool(struct BLI_mempool *mempool, void BLI_task_parallel_mempool(struct BLI_mempool *mempool,
void *userdata, void *userdata,
TaskParallelMempoolFunc func, TaskParallelMempoolFunc func,
@@ -252,14 +304,21 @@ BLI_INLINE void BLI_parallel_mempool_settings_defaults(TaskParallelSettings *set
settings->use_threading = true; settings->use_threading = true;
} }
/* Don't use this, store any thread specific data in tls->userdata_chunk instead. /**
* Only here for code to be removed. */ * Don't use this, store any thread specific data in `tls->userdata_chunk` instead.
* Only here for code to be removed.
*/
int BLI_task_parallel_thread_id(const TaskParallelTLS *tls); int BLI_task_parallel_thread_id(const TaskParallelTLS *tls);
/* Task Graph Scheduling */ /** \} */
/* Task Graphs can be used to create a forest of directional trees and schedule work to any tree.
/* -------------------------------------------------------------------- */
/** \name Task Graph Scheduling
*
* Task Graphs can be used to create a forest of directional trees and schedule work to any tree.
* The nodes in the graph can be run in separate threads. * The nodes in the graph can be run in separate threads.
* *
* \code{.unparsed}
* +---- [root] ----+ * +---- [root] ----+
* | | * | |
* v v * v v
@@ -267,55 +326,61 @@ int BLI_task_parallel_thread_id(const TaskParallelTLS *tls);
* | | * | |
* v v * v v
* [node_3] [node_4] * [node_3] [node_4]
* \endcode
* *
* TaskGraph *task_graph = BLI_task_graph_create(); * \code{.c}
* TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, NULL, NULL); * TaskGraph *task_graph = BLI_task_graph_create();
* TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL); * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, NULL, NULL);
* TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL); * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
* TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL); * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
* TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL); * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
* TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, NULL, NULL);
* *
* BLI_task_graph_edge_create(root, node_1); * BLI_task_graph_edge_create(root, node_1);
* BLI_task_graph_edge_create(root, node_2); * BLI_task_graph_edge_create(root, node_2);
* BLI_task_graph_edge_create(node_2, node_3); * BLI_task_graph_edge_create(node_2, node_3);
* BLI_task_graph_edge_create(node_2, node_4); * BLI_task_graph_edge_create(node_2, node_4);
* \endcode
* *
* Any node can be triggered to start a chain of tasks. Normally you would trigger a root node but * Any node can be triggered to start a chain of tasks. Normally you would trigger a root node but
* it is supported to start the chain of tasks anywhere in the forest or tree. When a node * it is supported to start the chain of tasks anywhere in the forest or tree. When a node
* completes, the execution flow is forwarded via the created edges. * completes, the execution flow is forwarded via the created edges.
* When a child node has multiple parents the child node will be triggered once for each parent. * When a child node has multiple parents the child node will be triggered once for each parent.
* *
* BLI_task_graph_node_push_work(root); * `BLI_task_graph_node_push_work(root);`
* *
* In this example After `root` is finished, `node_1` and `node_2` will be started. * In this example After `root` is finished, `node_1` and `node_2` will be started.
* Only after `node_2` is finished `node_3` and `node_4` will be started. * Only after `node_2` is finished `node_3` and `node_4` will be started.
* *
* After scheduling work we need to wait until all the tasks have been finished. * After scheduling work we need to wait until all the tasks have been finished.
* *
* BLI_task_graph_work_and_wait(); * `BLI_task_graph_work_and_wait();`
* *
* When finished you can clean up all the resources by freeing the task_graph. Nodes are owned by * When finished you can clean up all the resources by freeing the task_graph. Nodes are owned by
* the graph and are freed task_data will only be freed if a free_func was given. * the graph and are freed task_data will only be freed if a free_func was given.
* *
* BLI_task_graph_free(task_graph); * `BLI_task_graph_free(task_graph);`
* *
* Work can enter a tree on any node. Normally this would be the root_node. * Work can enter a tree on any node. Normally this would be the root_node.
* A `task_graph` can be reused, but the caller needs to make sure the task_data is reset. * A `task_graph` can be reused, but the caller needs to make sure the task_data is reset.
* *
* ** Task-Data ** * Task-Data
* ---------
* *
* Typically you want give a task data to work on. * Typically you want give a task data to work on.
* Task data can be shared with other nodes, but be careful not to free the data multiple times. * Task data can be shared with other nodes, but be careful not to free the data multiple times.
* Task data is freed when calling `BLI_task_graph_free`. * Task data is freed when calling #BLI_task_graph_free.
* *
* MyData *task_data = MEM_callocN(sizeof(MyData), __func__); * \code{.c}
* TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, task_data, MEM_freeN); * MyData *task_data = MEM_callocN(sizeof(MyData), __func__);
* TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL); * TaskNode *root = BLI_task_graph_node_create(task_graph, root_exec, task_data, MEM_freeN);
* TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL); * TaskNode *node_1 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
* TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL); * TaskNode *node_2 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
* TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL); * TaskNode *node_3 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
* * TaskNode *node_4 = BLI_task_graph_node_create(task_graph, node_exec, task_data, NULL);
*/ * \endcode
* \{ */
struct TaskGraph; struct TaskGraph;
struct TaskNode; struct TaskNode;
@@ -332,7 +397,10 @@ struct TaskNode *BLI_task_graph_node_create(struct TaskGraph *task_graph,
bool BLI_task_graph_node_push_work(struct TaskNode *task_node); bool BLI_task_graph_node_push_work(struct TaskNode *task_node);
void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node); void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node);
/* Task Isolation /** \} */
/* -------------------------------------------------------------------- */
/** \name Task Isolation
* *
* Task isolation helps avoid unexpected task scheduling decisions that can lead to bugs if wrong * Task isolation helps avoid unexpected task scheduling decisions that can lead to bugs if wrong
* assumptions were made. Typically that happens when doing "nested threading", i.e. one thread * assumptions were made. Typically that happens when doing "nested threading", i.e. one thread
@@ -359,9 +427,12 @@ void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_
* multiple threads, another thread will typically run the task and avoid the deadlock. However, if * multiple threads, another thread will typically run the task and avoid the deadlock. However, if
* this situation happens on all threads at the same time, all threads will deadlock. This happened * this situation happens on all threads at the same time, all threads will deadlock. This happened
* in T88598. * in T88598.
*/ * \{ */
void BLI_task_isolate(void (*func)(void *userdata), void *userdata); void BLI_task_isolate(void (*func)(void *userdata), void *userdata);
/** \} */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -38,12 +38,24 @@ struct ListBase;
/* Threading API */ /* Threading API */
/* This is run once at startup. */ /**
* This is run once at startup.
*/
void BLI_threadapi_init(void); void BLI_threadapi_init(void);
void BLI_threadapi_exit(void); void BLI_threadapi_exit(void);
/**
* \param tot: When 0 only initializes malloc mutex in a safe way (see sequence.c)
* problem otherwise: scene render will kill of the mutex!
*/
void BLI_threadpool_init(struct ListBase *threadbase, void *(*do_thread)(void *), int tot); void BLI_threadpool_init(struct ListBase *threadbase, void *(*do_thread)(void *), int tot);
/**
* Amount of available threads.
*/
int BLI_available_threads(struct ListBase *threadbase); int BLI_available_threads(struct ListBase *threadbase);
/**
* Returns thread number, for sample patterns or threadsafe tables.
*/
int BLI_threadpool_available_thread_index(struct ListBase *threadbase); int BLI_threadpool_available_thread_index(struct ListBase *threadbase);
void BLI_threadpool_insert(struct ListBase *threadbase, void *callerdata); void BLI_threadpool_insert(struct ListBase *threadbase, void *callerdata);
void BLI_threadpool_remove(struct ListBase *threadbase, void *callerdata); void BLI_threadpool_remove(struct ListBase *threadbase, void *callerdata);
@@ -54,7 +66,10 @@ int BLI_thread_is_main(void);
/* System Information */ /* System Information */
int BLI_system_thread_count(void); /* gets the number of threads the system can make use of */ /**
* \return the number of threads the system can make use of.
*/
int BLI_system_thread_count(void);
void BLI_system_num_threads_override_set(int num); void BLI_system_num_threads_override_set(int num);
int BLI_system_num_threads_override_get(void); int BLI_system_num_threads_override_get(void);
@@ -198,6 +213,7 @@ void BLI_thread_queue_nowait(ThreadQueue *queue);
/* **** Special functions to help performance on crazy NUMA setups. **** */ /* **** Special functions to help performance on crazy NUMA setups. **** */
/* Make sure process/thread is using NUMA node with fast memory access. */ /* Make sure process/thread is using NUMA node with fast memory access. */
void BLI_thread_put_process_on_fast_node(void); void BLI_thread_put_process_on_fast_node(void);
void BLI_thread_put_thread_on_fast_node(void); void BLI_thread_put_thread_on_fast_node(void);

View File

@@ -29,6 +29,18 @@
extern "C" { extern "C" {
#endif #endif
/**
* Generate time-code/frame number string and store in \a str
*
* \param str: destination string
* \param maxncpy: maximum number of characters to copy `sizeof(str)`
* \param brevity_level: special setting for #View2D grid drawing,
* used to specify how detailed we need to be
* \param time_seconds: time total time in seconds
* \param fps: frames per second, typically from the #FPS macro
* \param timecode_style: enum from #eTimecodeStyles
* \return length of \a str
*/
size_t BLI_timecode_string_from_time(char *str, size_t BLI_timecode_string_from_time(char *str,
const size_t maxncpy, const size_t maxncpy,
const int brevity_level, const int brevity_level,
@@ -36,10 +48,30 @@ size_t BLI_timecode_string_from_time(char *str,
const double scene_fps, const double scene_fps,
const short timecode_style) ATTR_NONNULL(); const short timecode_style) ATTR_NONNULL();
/**
* Generate time string and store in \a str
*
* \param str: destination string
* \param maxncpy: maximum number of characters to copy `sizeof(str)`
* \param time_seconds: time total time in seconds
* \return length of \a str
*/
size_t BLI_timecode_string_from_time_simple(char *str, size_t BLI_timecode_string_from_time_simple(char *str,
const size_t maxncpy, const size_t maxncpy,
const double time_seconds) ATTR_NONNULL(); const double time_seconds) ATTR_NONNULL();
/**
* Generate time string and store in \a str
*
* \param str: destination string
* \param maxncpy: maximum number of characters to copy `sizeof(str)`
* \param brevity_level: special setting for #View2D grid drawing,
* used to specify how detailed we need to be
* \param time_seconds: time total time in seconds
* \return length of \a str
*
* \note in some cases this is used to print non-seconds values.
*/
size_t BLI_timecode_string_from_time_seconds(char *str, size_t BLI_timecode_string_from_time_seconds(char *str,
const size_t maxncpy, const size_t maxncpy,
const int brevity_level, const int brevity_level,

View File

@@ -635,6 +635,9 @@ extern "C" {
/* defined /* defined
* in memory_utils.c for now. I do not know where we should put it actually... */ * in memory_utils.c for now. I do not know where we should put it actually... */
#ifndef __BLI_MEMORY_UTILS_H__ #ifndef __BLI_MEMORY_UTILS_H__
/**
* Check if memory is zeroed, as with `memset(arr, 0, arr_size)`.
*/
extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size); extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size);
#endif #endif

View File

@@ -26,16 +26,26 @@ extern "C" {
struct Object; struct Object;
struct ProjCameraInfo; struct ProjCameraInfo;
/* create uv info from the camera, needs to be freed */ /**
* Create UV info from the camera, needs to be freed.
*
* \param rotmat: can be `obedit->obmat` when uv project is used.
* \param winx, winy: can be from `scene->r.xsch / ysch`.
*/
struct ProjCameraInfo *BLI_uvproject_camera_info(struct Object *ob, struct ProjCameraInfo *BLI_uvproject_camera_info(struct Object *ob,
float rotmat[4][4], float rotmat[4][4],
float winx, float winx,
float winy); float winy);
/* apply uv from uvinfo (camera) */ /**
* Apply UV from uvinfo (camera).
*/
void BLI_uvproject_from_camera(float target[2], float source[3], struct ProjCameraInfo *uci); void BLI_uvproject_from_camera(float target[2], float source[3], struct ProjCameraInfo *uci);
/* apply uv from perspective matrix */ /**
* Apply uv from perspective matrix.
* \param persmat: Can be `rv3d->persmat`.
*/
void BLI_uvproject_from_view(float target[2], void BLI_uvproject_from_view(float target[2],
float source[3], float source[3],
float persmat[4][4], float persmat[4][4],
@@ -43,10 +53,14 @@ void BLI_uvproject_from_view(float target[2],
float winx, float winx,
float winy); float winy);
/* apply ortho uv's */ /**
* Apply orthographic UV's.
*/
void BLI_uvproject_from_view_ortho(float target[2], float source[3], const float rotmat[4][4]); void BLI_uvproject_from_view_ortho(float target[2], float source[3], const float rotmat[4][4]);
/* so we can adjust scale with keeping the struct private */ /**
* So we can adjust scale with keeping the struct private.
*/
void BLI_uvproject_camera_info_scale(struct ProjCameraInfo *uci, float scale_x, float scale_y); void BLI_uvproject_camera_info_scale(struct ProjCameraInfo *uci, float scale_x, float scale_y);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -27,13 +27,13 @@
extern "C" { extern "C" {
#endif #endif
/** Find the index number of a voxel, given x/y/z integer coords and resolution vector. */ /** Calculate the index number of a voxel, given x/y/z integer coords and resolution vector. */
#define BLI_VOXEL_INDEX(x, y, z, res) \ #define BLI_VOXEL_INDEX(x, y, z, res) \
((int64_t)(x) + (int64_t)(y) * (int64_t)(res)[0] + \ ((int64_t)(x) + (int64_t)(y) * (int64_t)(res)[0] + \
(int64_t)(z) * (int64_t)(res)[0] * (int64_t)(res)[1]) (int64_t)(z) * (int64_t)(res)[0] * (int64_t)(res)[1])
/* all input coordinates must be in bounding box 0.0 - 1.0 */ /* All input coordinates must be in bounding box 0.0 - 1.0. */
float BLI_voxel_sample_nearest(const float *data, const int res[3], const float co[3]); float BLI_voxel_sample_nearest(const float *data, const int res[3], const float co[3]);
float BLI_voxel_sample_trilinear(const float *data, const int res[3], const float co[3]); float BLI_voxel_sample_trilinear(const float *data, const int res[3], const float co[3]);
float BLI_voxel_sample_triquadratic(const float *data, const int res[3], const float co[3]); float BLI_voxel_sample_triquadratic(const float *data, const int res[3], const float co[3]);

View File

@@ -54,11 +54,6 @@
#include "MEM_guardedalloc.h" #include "MEM_guardedalloc.h"
/**
* This function is only to be called via macros.
*
* \note The caller must adjust \a arr_len
*/
void _bli_array_grow_func(void **arr_p, void _bli_array_grow_func(void **arr_p,
const void *arr_static, const void *arr_static,
const int sizeof_arr_p, const int sizeof_arr_p,

View File

@@ -49,14 +49,13 @@ void _BLI_assert_print_backtrace(void)
#endif #endif
} }
/**
* Wrap to remove 'noreturn' attribute since this suppresses missing return statements,
* allowing changes to debug builds to accidentally to break release builds.
*
* For example `BLI_assert(0);` at the end of a function that returns a value,
* will hide that it's missing a return.
*/
void _BLI_assert_abort(void) void _BLI_assert_abort(void)
{ {
/* Wrap to remove 'noreturn' attribute since this suppresses missing return statements,
* allowing changes to debug builds to accidentally to break release builds.
*
* For example `BLI_assert(0);` at the end of a function that returns a value,
* will hide that it's missing a return. */
abort(); abort();
} }

View File

@@ -63,11 +63,6 @@ struct DynStr {
/***/ /***/
/**
* Create a new DynStr.
*
* \return Pointer to a new DynStr.
*/
DynStr *BLI_dynstr_new(void) DynStr *BLI_dynstr_new(void)
{ {
DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr"); DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
@@ -78,11 +73,6 @@ DynStr *BLI_dynstr_new(void)
return ds; return ds;
} }
/**
* Create a new DynStr.
*
* \return Pointer to a new DynStr.
*/
DynStr *BLI_dynstr_new_memarena(void) DynStr *BLI_dynstr_new_memarena(void)
{ {
DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr"); DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
@@ -98,12 +88,6 @@ BLI_INLINE void *dynstr_alloc(DynStr *__restrict ds, size_t size)
return ds->memarena ? BLI_memarena_alloc(ds->memarena, size) : malloc(size); return ds->memarena ? BLI_memarena_alloc(ds->memarena, size) : malloc(size);
} }
/**
* Append a c-string to a DynStr.
*
* \param ds: The DynStr to append to.
* \param cstr: The c-string to append.
*/
void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
{ {
DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse)); DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
@@ -123,13 +107,6 @@ void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
ds->curlen += cstrlen; ds->curlen += cstrlen;
} }
/**
* Append a length clamped c-string to a DynStr.
*
* \param ds: The DynStr to append to.
* \param cstr: The c-string to append.
* \param len: The maximum length of the c-string to copy.
*/
void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len)
{ {
DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse)); DynStrElem *dse = dynstr_alloc(ds, sizeof(*dse));
@@ -209,12 +186,6 @@ void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, v
} }
} }
/**
* Append a c-string to a DynStr, but with formatting like printf.
*
* \param ds: The DynStr to append to.
* \param format: The printf format string to use.
*/
void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...) void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...)
{ {
va_list args; va_list args;
@@ -277,25 +248,11 @@ void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ..
} }
} }
/**
* Find the length of a DynStr.
*
* \param ds: The DynStr of interest.
* \return The length of \a ds.
*/
int BLI_dynstr_get_len(const DynStr *ds) int BLI_dynstr_get_len(const DynStr *ds)
{ {
return ds->curlen; return ds->curlen;
} }
/**
* Get a DynStr's contents as a c-string.
* The \a rets argument must be allocated to be at
* least the size of `BLI_dynstr_get_len(ds) + 1`.
*
* \param ds: The DynStr of interest.
* \param rets: The string to fill.
*/
void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict rets) void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict rets)
{ {
char *s; char *s;
@@ -312,14 +269,6 @@ void BLI_dynstr_get_cstring_ex(const DynStr *__restrict ds, char *__restrict ret
rets[ds->curlen] = '\0'; rets[ds->curlen] = '\0';
} }
/**
* Get a DynStr's contents as a c-string.
* <i> The returned c-string should be freed
* using MEM_freeN. </i>
*
* \param ds: The DynStr of interest.
* \return The contents of \a ds as a c-string.
*/
char *BLI_dynstr_get_cstring(const DynStr *ds) char *BLI_dynstr_get_cstring(const DynStr *ds)
{ {
char *rets = MEM_mallocN(ds->curlen + 1, "dynstr_cstring"); char *rets = MEM_mallocN(ds->curlen + 1, "dynstr_cstring");
@@ -327,11 +276,6 @@ char *BLI_dynstr_get_cstring(const DynStr *ds)
return rets; return rets;
} }
/**
* Clear the DynStr
*
* \param ds: The DynStr to clear.
*/
void BLI_dynstr_clear(DynStr *ds) void BLI_dynstr_clear(DynStr *ds)
{ {
if (ds->memarena) { if (ds->memarena) {
@@ -350,11 +294,6 @@ void BLI_dynstr_clear(DynStr *ds)
ds->curlen = 0; ds->curlen = 0;
} }
/**
* Free the DynStr
*
* \param ds: The DynStr to free.
*/
void BLI_dynstr_free(DynStr *ds) void BLI_dynstr_free(DynStr *ds)
{ {
if (ds->memarena) { if (ds->memarena) {

View File

@@ -229,12 +229,6 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
} }
} }
/**
* Scans the contents of the directory named *dirname, and allocates and fills in an
* array of entries describing them in *filelist.
*
* \return The length of filelist array.
*/
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist) unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
{ {
struct BuildDirCtx dir_ctx; struct BuildDirCtx dir_ctx;
@@ -256,9 +250,6 @@ unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_
return dir_ctx.nrfiles; return dir_ctx.nrfiles;
} }
/**
* Convert given entry's size into human-readable strings.
*/
void BLI_filelist_entry_size_to_string(const struct stat *st, void BLI_filelist_entry_size_to_string(const struct stat *st,
const uint64_t sz, const uint64_t sz,
/* Used to change MB -> M, etc. - is that really useful? */ /* Used to change MB -> M, etc. - is that really useful? */
@@ -278,9 +269,6 @@ void BLI_filelist_entry_size_to_string(const struct stat *st,
#endif #endif
} }
/**
* Convert given entry's modes into human-readable strings.
*/
void BLI_filelist_entry_mode_to_string(const struct stat *st, void BLI_filelist_entry_mode_to_string(const struct stat *st,
const bool UNUSED(compact), const bool UNUSED(compact),
char r_mode1[FILELIST_DIRENTRY_MODE_LEN], char r_mode1[FILELIST_DIRENTRY_MODE_LEN],
@@ -328,9 +316,6 @@ void BLI_filelist_entry_mode_to_string(const struct stat *st,
#endif #endif
} }
/**
* Convert given entry's owner into human-readable strings.
*/
void BLI_filelist_entry_owner_to_string(const struct stat *st, void BLI_filelist_entry_owner_to_string(const struct stat *st,
const bool UNUSED(compact), const bool UNUSED(compact),
char r_owner[FILELIST_DIRENTRY_OWNER_LEN]) char r_owner[FILELIST_DIRENTRY_OWNER_LEN])
@@ -349,12 +334,6 @@ void BLI_filelist_entry_owner_to_string(const struct stat *st,
#endif #endif
} }
/**
* Convert given entry's time into human-readable strings.
*
* \param r_is_today: optional, returns true if the date matches today's.
* \param r_is_yesterday: optional, returns true if the date matches yesterday's.
*/
void BLI_filelist_entry_datetime_to_string(const struct stat *st, void BLI_filelist_entry_datetime_to_string(const struct stat *st,
const int64_t ts, const int64_t ts,
const bool compact, const bool compact,
@@ -417,9 +396,6 @@ void BLI_filelist_entry_datetime_to_string(const struct stat *st,
} }
} }
/**
* Deep-duplicate of a single direntry.
*/
void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src) void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src)
{ {
*dst = *src; *dst = *src;
@@ -431,9 +407,6 @@ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *s
} }
} }
/**
* Deep-duplicate of a #direntry array including the array itself.
*/
void BLI_filelist_duplicate(struct direntry **dest_filelist, void BLI_filelist_duplicate(struct direntry **dest_filelist,
struct direntry *const src_filelist, struct direntry *const src_filelist,
const unsigned int nrentries) const unsigned int nrentries)
@@ -448,9 +421,6 @@ void BLI_filelist_duplicate(struct direntry **dest_filelist,
} }
} }
/**
* frees storage for a single direntry, not the direntry itself.
*/
void BLI_filelist_entry_free(struct direntry *entry) void BLI_filelist_entry_free(struct direntry *entry)
{ {
if (entry->relname) { if (entry->relname) {
@@ -461,9 +431,6 @@ void BLI_filelist_entry_free(struct direntry *entry)
} }
} }
/**
* Frees storage for an array of #direntry, including the array itself.
*/
void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries) void BLI_filelist_free(struct direntry *filelist, const unsigned int nrentries)
{ {
unsigned int i; unsigned int i;

View File

@@ -694,16 +694,6 @@ static GHash *ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopy
/** \name GHash Public API /** \name GHash Public API
* \{ */ * \{ */
/**
* Creates a new, empty GHash.
*
* \param hashfp: Hash callback.
* \param cmpfp: Comparison callback.
* \param info: Identifier string for the GHash.
* \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
* Use this to avoid resizing buckets if the size is known or can be closely approximated.
* \return An empty GHash.
*/
GHash *BLI_ghash_new_ex(GHashHashFP hashfp, GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
GHashCmpFP cmpfp, GHashCmpFP cmpfp,
const char *info, const char *info,
@@ -712,72 +702,38 @@ GHash *BLI_ghash_new_ex(GHashHashFP hashfp,
return ghash_new(hashfp, cmpfp, info, nentries_reserve, 0); return ghash_new(hashfp, cmpfp, info, nentries_reserve, 0);
} }
/**
* Wraps #BLI_ghash_new_ex with zero entries reserved.
*/
GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info) GHash *BLI_ghash_new(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info)
{ {
return BLI_ghash_new_ex(hashfp, cmpfp, info, 0); return BLI_ghash_new_ex(hashfp, cmpfp, info, 0);
} }
/**
* Copy given GHash. Keys and values are also copied if relevant callback is provided,
* else pointers remain the same.
*/
GHash *BLI_ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp) GHash *BLI_ghash_copy(const GHash *gh, GHashKeyCopyFP keycopyfp, GHashValCopyFP valcopyfp)
{ {
return ghash_copy(gh, keycopyfp, valcopyfp); return ghash_copy(gh, keycopyfp, valcopyfp);
} }
/**
* Reserve given amount of entries (resize \a gh accordingly if needed).
*/
void BLI_ghash_reserve(GHash *gh, const uint nentries_reserve) void BLI_ghash_reserve(GHash *gh, const uint nentries_reserve)
{ {
ghash_buckets_expand(gh, nentries_reserve, true); ghash_buckets_expand(gh, nentries_reserve, true);
ghash_buckets_contract(gh, nentries_reserve, true, false); ghash_buckets_contract(gh, nentries_reserve, true, false);
} }
/**
* \return size of the GHash.
*/
uint BLI_ghash_len(const GHash *gh) uint BLI_ghash_len(const GHash *gh)
{ {
return gh->nentries; return gh->nentries;
} }
/**
* Insert a key/value pair into the \a gh.
*
* \note Duplicates are not checked,
* the caller is expected to ensure elements are unique unless
* GHASH_FLAG_ALLOW_DUPES flag is set.
*/
void BLI_ghash_insert(GHash *gh, void *key, void *val) void BLI_ghash_insert(GHash *gh, void *key, void *val)
{ {
ghash_insert(gh, key, val); ghash_insert(gh, key, val);
} }
/**
* Inserts a new value to a key that may already be in ghash.
*
* Avoids #BLI_ghash_remove, #BLI_ghash_insert calls (double lookups)
*
* \returns true if a new key has been added.
*/
bool BLI_ghash_reinsert( bool BLI_ghash_reinsert(
GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) GHash *gh, void *key, void *val, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{ {
return ghash_insert_safe(gh, key, val, true, keyfreefp, valfreefp); return ghash_insert_safe(gh, key, val, true, keyfreefp, valfreefp);
} }
/**
* Replaces the key of an item in the \a gh.
*
* Use when a key is re-allocated or its memory location is changed.
*
* \returns The previous key or NULL if not found, the caller may free if it's needed.
*/
void *BLI_ghash_replace_key(GHash *gh, void *key) void *BLI_ghash_replace_key(GHash *gh, void *key)
{ {
const uint hash = ghash_keyhash(gh, key); const uint hash = ghash_keyhash(gh, key);
@@ -791,15 +747,6 @@ void *BLI_ghash_replace_key(GHash *gh, void *key)
return NULL; return NULL;
} }
/**
* Lookup the value of \a key in \a gh.
*
* \param key: The key to lookup.
* \returns the value for \a key or NULL.
*
* \note When NULL is a valid value, use #BLI_ghash_lookup_p to differentiate a missing key
* from a key with a NULL value. (Avoids calling #BLI_ghash_haskey before #BLI_ghash_lookup)
*/
void *BLI_ghash_lookup(const GHash *gh, const void *key) void *BLI_ghash_lookup(const GHash *gh, const void *key)
{ {
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key); GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
@@ -807,9 +754,6 @@ void *BLI_ghash_lookup(const GHash *gh, const void *key)
return e ? e->val : NULL; return e ? e->val : NULL;
} }
/**
* A version of #BLI_ghash_lookup which accepts a fallback argument.
*/
void *BLI_ghash_lookup_default(const GHash *gh, const void *key, void *val_default) void *BLI_ghash_lookup_default(const GHash *gh, const void *key, void *val_default)
{ {
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key); GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
@@ -817,16 +761,6 @@ void *BLI_ghash_lookup_default(const GHash *gh, const void *key, void *val_defau
return e ? e->val : val_default; return e ? e->val : val_default;
} }
/**
* Lookup a pointer to the value of \a key in \a gh.
*
* \param key: The key to lookup.
* \returns the pointer to value for \a key or NULL.
*
* \note This has 2 main benefits over #BLI_ghash_lookup.
* - A NULL return always means that \a key isn't in \a gh.
* - The value can be modified in-place without further function calls (faster).
*/
void **BLI_ghash_lookup_p(GHash *gh, const void *key) void **BLI_ghash_lookup_p(GHash *gh, const void *key)
{ {
GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key); GHashEntry *e = (GHashEntry *)ghash_lookup_entry(gh, key);
@@ -834,20 +768,6 @@ void **BLI_ghash_lookup_p(GHash *gh, const void *key)
return e ? &e->val : NULL; return e ? &e->val : NULL;
} }
/**
* Ensure \a key is exists in \a gh.
*
* This handles the common situation where the caller needs ensure a key is added to \a gh,
* constructing a new value in the case the key isn't found.
* Otherwise use the existing value.
*
* Such situations typically incur multiple lookups, however this function
* avoids them by ensuring the key is added,
* returning a pointer to the value so it can be used or initialized by the caller.
*
* \returns true when the value didn't need to be added.
* (when false, the caller _must_ initialize the value).
*/
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val)
{ {
const uint hash = ghash_keyhash(gh, key); const uint hash = ghash_keyhash(gh, key);
@@ -864,12 +784,6 @@ bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val)
return haskey; return haskey;
} }
/**
* A version of #BLI_ghash_ensure_p that allows caller to re-assign the key.
* Typically used when the key is to be duplicated.
*
* \warning Caller _must_ write to \a r_key when returning false.
*/
bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val) bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_val)
{ {
const uint hash = ghash_keyhash(gh, key); const uint hash = ghash_keyhash(gh, key);
@@ -889,14 +803,6 @@ bool BLI_ghash_ensure_p_ex(GHash *gh, const void *key, void ***r_key, void ***r_
return haskey; return haskey;
} }
/**
* Remove \a key from \a gh, or return false if the key wasn't found.
*
* \param key: The key to remove.
* \param keyfreefp: Optional callback to free the key.
* \param valfreefp: Optional callback to free the value.
* \return true if \a key was removed from \a gh.
*/
bool BLI_ghash_remove(GHash *gh, bool BLI_ghash_remove(GHash *gh,
const void *key, const void *key,
GHashKeyFreeFP keyfreefp, GHashKeyFreeFP keyfreefp,
@@ -912,17 +818,11 @@ bool BLI_ghash_remove(GHash *gh,
return false; return false;
} }
/* same as above but return the value,
* no free value argument since it will be returned */
/**
* Remove \a key from \a gh, returning the value or NULL if the key wasn't found.
*
* \param key: The key to remove.
* \param keyfreefp: Optional callback to free the key.
* \return the value of \a key int \a gh or NULL.
*/
void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp) void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp)
{ {
/* Same as above but return the value,
* no free value argument since it will be returned. */
const uint hash = ghash_keyhash(gh, key); const uint hash = ghash_keyhash(gh, key);
const uint bucket_index = ghash_bucket_index(gh, hash); const uint bucket_index = ghash_bucket_index(gh, hash);
GHashEntry *e = (GHashEntry *)ghash_remove_ex(gh, key, keyfreefp, NULL, bucket_index); GHashEntry *e = (GHashEntry *)ghash_remove_ex(gh, key, keyfreefp, NULL, bucket_index);
@@ -935,23 +835,11 @@ void *BLI_ghash_popkey(GHash *gh, const void *key, GHashKeyFreeFP keyfreefp)
return NULL; return NULL;
} }
/**
* \return true if the \a key is in \a gh.
*/
bool BLI_ghash_haskey(const GHash *gh, const void *key) bool BLI_ghash_haskey(const GHash *gh, const void *key)
{ {
return (ghash_lookup_entry(gh, key) != NULL); return (ghash_lookup_entry(gh, key) != NULL);
} }
/**
* Remove a random entry from \a gh, returning true
* if a key/value pair could be removed, false otherwise.
*
* \param r_key: The removed key.
* \param r_val: The removed value.
* \param state: Used for efficient removal.
* \return true if there was something to pop, false if ghash was already empty.
*/
bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val) bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
{ {
GHashEntry *e = (GHashEntry *)ghash_pop(gh, state); GHashEntry *e = (GHashEntry *)ghash_pop(gh, state);
@@ -970,13 +858,6 @@ bool BLI_ghash_pop(GHash *gh, GHashIterState *state, void **r_key, void **r_val)
return false; return false;
} }
/**
* Reset \a gh clearing all entries.
*
* \param keyfreefp: Optional callback to free the key.
* \param valfreefp: Optional callback to free the value.
* \param nentries_reserve: Optionally reserve the number of members that the hash will hold.
*/
void BLI_ghash_clear_ex(GHash *gh, void BLI_ghash_clear_ex(GHash *gh,
GHashKeyFreeFP keyfreefp, GHashKeyFreeFP keyfreefp,
GHashValFreeFP valfreefp, GHashValFreeFP valfreefp,
@@ -990,21 +871,11 @@ void BLI_ghash_clear_ex(GHash *gh,
BLI_mempool_clear_ex(gh->entrypool, nentries_reserve ? (int)nentries_reserve : -1); BLI_mempool_clear_ex(gh->entrypool, nentries_reserve ? (int)nentries_reserve : -1);
} }
/**
* Wraps #BLI_ghash_clear_ex with zero entries reserved.
*/
void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) void BLI_ghash_clear(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{ {
BLI_ghash_clear_ex(gh, keyfreefp, valfreefp, 0); BLI_ghash_clear_ex(gh, keyfreefp, valfreefp, 0);
} }
/**
* Frees the GHash and its members.
*
* \param gh: The GHash to free.
* \param keyfreefp: Optional callback to free the key.
* \param valfreefp: Optional callback to free the value.
*/
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp) void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
{ {
BLI_assert((int)gh->nentries == BLI_mempool_len(gh->entrypool)); BLI_assert((int)gh->nentries == BLI_mempool_len(gh->entrypool));
@@ -1017,17 +888,11 @@ void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreef
MEM_freeN(gh); MEM_freeN(gh);
} }
/**
* Sets a GHash flag.
*/
void BLI_ghash_flag_set(GHash *gh, uint flag) void BLI_ghash_flag_set(GHash *gh, uint flag)
{ {
gh->flag |= flag; gh->flag |= flag;
} }
/**
* Clear a GHash flag.
*/
void BLI_ghash_flag_clear(GHash *gh, uint flag) void BLI_ghash_flag_clear(GHash *gh, uint flag)
{ {
gh->flag &= ~flag; gh->flag &= ~flag;
@@ -1039,14 +904,6 @@ void BLI_ghash_flag_clear(GHash *gh, uint flag)
/** \name GHash Iterator API /** \name GHash Iterator API
* \{ */ * \{ */
/**
* Create a new GHashIterator. The hash table must not be mutated
* while the iterator is in use, and the iterator will step exactly
* #BLI_ghash_len(gh) times before becoming done.
*
* \param gh: The GHash to iterate over.
* \return Pointer to a new iterator.
*/
GHashIterator *BLI_ghashIterator_new(GHash *gh) GHashIterator *BLI_ghashIterator_new(GHash *gh)
{ {
GHashIterator *ghi = MEM_mallocN(sizeof(*ghi), "ghash iterator"); GHashIterator *ghi = MEM_mallocN(sizeof(*ghi), "ghash iterator");
@@ -1054,14 +911,6 @@ GHashIterator *BLI_ghashIterator_new(GHash *gh)
return ghi; return ghi;
} }
/**
* Init an already allocated GHashIterator. The hash table must not
* be mutated while the iterator is in use, and the iterator will
* step exactly #BLI_ghash_len(gh) times before becoming done.
*
* \param ghi: The GHashIterator to initialize.
* \param gh: The GHash to iterate over.
*/
void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh) void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
{ {
ghi->gh = gh; ghi->gh = gh;
@@ -1078,11 +927,6 @@ void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
} }
} }
/**
* Steps the iterator to the next index.
*
* \param ghi: The iterator.
*/
void BLI_ghashIterator_step(GHashIterator *ghi) void BLI_ghashIterator_step(GHashIterator *ghi)
{ {
if (ghi->curEntry) { if (ghi->curEntry) {
@@ -1097,11 +941,6 @@ void BLI_ghashIterator_step(GHashIterator *ghi)
} }
} }
/**
* Free a GHashIterator.
*
* \param ghi: The iterator to free.
*/
void BLI_ghashIterator_free(GHashIterator *ghi) void BLI_ghashIterator_free(GHashIterator *ghi)
{ {
MEM_freeN(ghi); MEM_freeN(ghi);
@@ -1110,10 +949,7 @@ void BLI_ghashIterator_free(GHashIterator *ghi)
/** \} */ /** \} */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/** \name GSet Public API
*
* Use ghash API to give 'set' functionality
* \{ */
GSet *BLI_gset_new_ex(GSetHashFP hashfp, GSet *BLI_gset_new_ex(GSetHashFP hashfp,
GSetCmpFP cmpfp, GSetCmpFP cmpfp,
const char *info, const char *info,
@@ -1127,9 +963,6 @@ GSet *BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info)
return BLI_gset_new_ex(hashfp, cmpfp, info, 0); return BLI_gset_new_ex(hashfp, cmpfp, info, 0);
} }
/**
* Copy given GSet. Keys are also copied if callback is provided, else pointers remain the same.
*/
GSet *BLI_gset_copy(const GSet *gs, GHashKeyCopyFP keycopyfp) GSet *BLI_gset_copy(const GSet *gs, GHashKeyCopyFP keycopyfp)
{ {
return (GSet *)ghash_copy((const GHash *)gs, keycopyfp, NULL); return (GSet *)ghash_copy((const GHash *)gs, keycopyfp, NULL);
@@ -1140,10 +973,6 @@ uint BLI_gset_len(const GSet *gs)
return ((GHash *)gs)->nentries; return ((GHash *)gs)->nentries;
} }
/**
* Adds the key to the set (no checks for unique keys!).
* Matching #BLI_ghash_insert
*/
void BLI_gset_insert(GSet *gs, void *key) void BLI_gset_insert(GSet *gs, void *key)
{ {
const uint hash = ghash_keyhash((GHash *)gs, key); const uint hash = ghash_keyhash((GHash *)gs, key);
@@ -1151,23 +980,11 @@ void BLI_gset_insert(GSet *gs, void *key)
ghash_insert_ex_keyonly((GHash *)gs, key, bucket_index); ghash_insert_ex_keyonly((GHash *)gs, key, bucket_index);
} }
/**
* A version of BLI_gset_insert which checks first if the key is in the set.
* \returns true if a new key has been added.
*
* \note GHash has no equivalent to this because typically the value would be different.
*/
bool BLI_gset_add(GSet *gs, void *key) bool BLI_gset_add(GSet *gs, void *key)
{ {
return ghash_insert_safe_keyonly((GHash *)gs, key, false, NULL); return ghash_insert_safe_keyonly((GHash *)gs, key, false, NULL);
} }
/**
* Set counterpart to #BLI_ghash_ensure_p_ex.
* similar to BLI_gset_add, except it returns the key pointer.
*
* \warning Caller _must_ write to \a r_key when returning false.
*/
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key) bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
{ {
const uint hash = ghash_keyhash((GHash *)gs, key); const uint hash = ghash_keyhash((GHash *)gs, key);
@@ -1186,23 +1003,11 @@ bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
return haskey; return haskey;
} }
/**
* Adds the key to the set (duplicates are managed).
* Matching #BLI_ghash_reinsert
*
* \returns true if a new key has been added.
*/
bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp) bool BLI_gset_reinsert(GSet *gs, void *key, GSetKeyFreeFP keyfreefp)
{ {
return ghash_insert_safe_keyonly((GHash *)gs, key, true, keyfreefp); return ghash_insert_safe_keyonly((GHash *)gs, key, true, keyfreefp);
} }
/**
* Replaces the key to the set if it's found.
* Matching #BLI_ghash_replace_key
*
* \returns The old key or NULL if not found.
*/
void *BLI_gset_replace_key(GSet *gs, void *key) void *BLI_gset_replace_key(GSet *gs, void *key)
{ {
return BLI_ghash_replace_key((GHash *)gs, key); return BLI_ghash_replace_key((GHash *)gs, key);
@@ -1218,13 +1023,6 @@ bool BLI_gset_haskey(const GSet *gs, const void *key)
return (ghash_lookup_entry((const GHash *)gs, key) != NULL); return (ghash_lookup_entry((const GHash *)gs, key) != NULL);
} }
/**
* Remove a random entry from \a gs, returning true if a key could be removed, false otherwise.
*
* \param r_key: The removed key.
* \param state: Used for efficient removal.
* \return true if there was something to pop, false if gset was already empty.
*/
bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key) bool BLI_gset_pop(GSet *gs, GSetIterState *state, void **r_key)
{ {
GSetEntry *e = (GSetEntry *)ghash_pop((GHash *)gs, (GHashIterState *)state); GSetEntry *e = (GSetEntry *)ghash_pop((GHash *)gs, (GHashIterState *)state);
@@ -1274,19 +1072,12 @@ void BLI_gset_flag_clear(GSet *gs, uint flag)
* This can be useful when the key references data stored outside the GSet. * This can be useful when the key references data stored outside the GSet.
* \{ */ * \{ */
/**
* Returns the pointer to the key if it's found.
*/
void *BLI_gset_lookup(const GSet *gs, const void *key) void *BLI_gset_lookup(const GSet *gs, const void *key)
{ {
Entry *e = ghash_lookup_entry((const GHash *)gs, key); Entry *e = ghash_lookup_entry((const GHash *)gs, key);
return e ? e->key : NULL; return e ? e->key : NULL;
} }
/**
* Returns the pointer to the key if it's found, removing it from the GSet.
* \note Caller must handle freeing.
*/
void *BLI_gset_pop_key(GSet *gs, const void *key) void *BLI_gset_pop_key(GSet *gs, const void *key)
{ {
const uint hash = ghash_keyhash((GHash *)gs, key); const uint hash = ghash_keyhash((GHash *)gs, key);
@@ -1308,9 +1099,6 @@ void *BLI_gset_pop_key(GSet *gs, const void *key)
#include "BLI_math.h" #include "BLI_math.h"
/**
* \return number of buckets in the GHash.
*/
int BLI_ghash_buckets_len(const GHash *gh) int BLI_ghash_buckets_len(const GHash *gh)
{ {
return (int)gh->nbuckets; return (int)gh->nbuckets;
@@ -1320,13 +1108,6 @@ int BLI_gset_buckets_len(const GSet *gs)
return BLI_ghash_buckets_len((const GHash *)gs); return BLI_ghash_buckets_len((const GHash *)gs);
} }
/**
* Measure how well the hash function performs (1.0 is approx as good as random distribution),
* and return a few other stats like load,
* variance of the distribution of the entries in the buckets, etc.
*
* Smaller is better!
*/
double BLI_ghash_calc_quality_ex(GHash *gh, double BLI_ghash_calc_quality_ex(GHash *gh,
double *r_load, double *r_load,
double *r_variance, double *r_variance,

View File

@@ -46,9 +46,10 @@ uint BLI_ghashutil_ptrhash(const void *key)
return (uint)(intptr_t)key; return (uint)(intptr_t)key;
} }
#else #else
/* Based Python3.7's pointer hashing function. */
uint BLI_ghashutil_ptrhash(const void *key) uint BLI_ghashutil_ptrhash(const void *key)
{ {
/* Based Python3.7's pointer hashing function. */
size_t y = (size_t)key; size_t y = (size_t)key;
/* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid /* bottom 3 or 4 bits are likely to be 0; rotate y by 4 to avoid
* excessive hash collisions for dicts and sets */ * excessive hash collisions for dicts and sets */
@@ -134,15 +135,6 @@ size_t BLI_ghashutil_combine_hash(size_t hash_a, size_t hash_b)
return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2)); return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
} }
/**
* This function implements the widely used "djb" hash apparently posted
* by Daniel Bernstein to comp.lang.c some time ago. The 32 bit
* unsigned hash value starts at 5381 and for each byte 'c' in the
* string, is updated: `hash = hash * 33 + c`.
* This function uses the signed value of each byte.
*
* NOTE: this is the same hash method that glib 2.34.0 uses.
*/
uint BLI_ghashutil_strhash_n(const char *key, size_t n) uint BLI_ghashutil_strhash_n(const char *key, size_t n)
{ {
const signed char *p; const signed char *p;

View File

@@ -193,11 +193,6 @@ static void heap_node_free(Heap *heap, HeapNode *node)
/** \name Public Heap API /** \name Public Heap API
* \{ */ * \{ */
/**
* Creates a new heap. Removed nodes are recycled, so memory usage will not shrink.
*
* \note Use when the size of the heap is known in advance.
*/
Heap *BLI_heap_new_ex(uint tot_reserve) Heap *BLI_heap_new_ex(uint tot_reserve)
{ {
Heap *heap = MEM_mallocN(sizeof(Heap), __func__); Heap *heap = MEM_mallocN(sizeof(Heap), __func__);
@@ -261,10 +256,6 @@ void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp)
heap->nodes.free = NULL; heap->nodes.free = NULL;
} }
/**
* Insert heap node with a value (often a 'cost') and pointer into the heap,
* duplicate values are allowed.
*/
HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
{ {
HeapNode *node; HeapNode *node;
@@ -289,9 +280,6 @@ HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr)
return node; return node;
} }
/**
* Convenience function since this is a common pattern.
*/
void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr) void BLI_heap_insert_or_update(Heap *heap, HeapNode **node_p, float value, void *ptr)
{ {
if (*node_p == NULL) { if (*node_p == NULL) {
@@ -312,19 +300,11 @@ uint BLI_heap_len(const Heap *heap)
return heap->size; return heap->size;
} }
/**
* Return the top node of the heap.
* This is the node with the lowest value.
*/
HeapNode *BLI_heap_top(const Heap *heap) HeapNode *BLI_heap_top(const Heap *heap)
{ {
return heap->tree[0]; return heap->tree[0];
} }
/**
* Return the value of top node of the heap.
* This is the node with the lowest value.
*/
float BLI_heap_top_value(const Heap *heap) float BLI_heap_top_value(const Heap *heap)
{ {
BLI_assert(heap->size != 0); BLI_assert(heap->size != 0);
@@ -332,9 +312,6 @@ float BLI_heap_top_value(const Heap *heap)
return heap->tree[0]->value; return heap->tree[0]->value;
} }
/**
* Pop the top node off the heap and return its pointer.
*/
void *BLI_heap_pop_min(Heap *heap) void *BLI_heap_pop_min(Heap *heap)
{ {
BLI_assert(heap->size != 0); BLI_assert(heap->size != 0);
@@ -366,11 +343,6 @@ void BLI_heap_remove(Heap *heap, HeapNode *node)
BLI_heap_pop_min(heap); BLI_heap_pop_min(heap);
} }
/**
* Can be used to avoid #BLI_heap_remove, #BLI_heap_insert calls,
* balancing the tree still has a performance cost,
* but is often much less than remove/insert, difference is most noticeable with large heaps.
*/
void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value) void BLI_heap_node_value_update(Heap *heap, HeapNode *node, float value)
{ {
if (value < node->value) { if (value < node->value) {
@@ -427,9 +399,6 @@ static bool heap_is_minheap(const Heap *heap, uint root)
} }
return true; return true;
} }
/**
* Only for checking internal errors (gtest).
*/
bool BLI_heap_is_valid(const Heap *heap) bool BLI_heap_is_valid(const Heap *heap)
{ {
return heap_is_minheap(heap, 0); return heap_is_minheap(heap, 0);

View File

@@ -147,11 +147,6 @@ static void heapsimple_up(HeapSimple *heap, uint i, float active_val, void *acti
/** \name Public HeapSimple API /** \name Public HeapSimple API
* \{ */ * \{ */
/**
* Creates a new simple heap, which only supports insertion and removal from top.
*
* \note Use when the size of the heap is known in advance.
*/
HeapSimple *BLI_heapsimple_new_ex(uint tot_reserve) HeapSimple *BLI_heapsimple_new_ex(uint tot_reserve)
{ {
HeapSimple *heap = MEM_mallocN(sizeof(HeapSimple), __func__); HeapSimple *heap = MEM_mallocN(sizeof(HeapSimple), __func__);
@@ -190,10 +185,6 @@ void BLI_heapsimple_clear(HeapSimple *heap, HeapSimpleFreeFP ptrfreefp)
heap->size = 0; heap->size = 0;
} }
/**
* Insert heap node with a value (often a 'cost') and pointer into the heap,
* duplicate values are allowed.
*/
void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr) void BLI_heapsimple_insert(HeapSimple *heap, float value, void *ptr)
{ {
if (UNLIKELY(heap->size >= heap->bufsize)) { if (UNLIKELY(heap->size >= heap->bufsize)) {
@@ -214,9 +205,6 @@ uint BLI_heapsimple_len(const HeapSimple *heap)
return heap->size; return heap->size;
} }
/**
* Return the lowest value of the heap.
*/
float BLI_heapsimple_top_value(const HeapSimple *heap) float BLI_heapsimple_top_value(const HeapSimple *heap)
{ {
BLI_assert(heap->size != 0); BLI_assert(heap->size != 0);
@@ -224,9 +212,6 @@ float BLI_heapsimple_top_value(const HeapSimple *heap)
return heap->tree[0].value; return heap->tree[0].value;
} }
/**
* Pop the top node off the heap and return its pointer.
*/
void *BLI_heapsimple_pop_min(HeapSimple *heap) void *BLI_heapsimple_pop_min(HeapSimple *heap)
{ {
BLI_assert(heap->size != 0); BLI_assert(heap->size != 0);

View File

@@ -867,9 +867,6 @@ static void non_recursive_bvh_div_nodes(const BVHTree *tree,
/** \name BLI_bvhtree API /** \name BLI_bvhtree API
* \{ */ * \{ */
/**
* \note many callers don't check for `NULL` return.
*/
BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis) BVHTree *BLI_bvhtree_new(int maxsize, float epsilon, char tree_type, char axis)
{ {
BVHTree *tree; BVHTree *tree;
@@ -1013,7 +1010,6 @@ void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoin
bvhtree_node_inflate(tree, node, tree->epsilon); bvhtree_node_inflate(tree, node, tree->epsilon);
} }
/* call before BLI_bvhtree_update_tree() */
bool BLI_bvhtree_update_node( bool BLI_bvhtree_update_node(
BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints) BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints)
{ {
@@ -1038,9 +1034,6 @@ bool BLI_bvhtree_update_node(
return true; return true;
} }
/**
* Call #BLI_bvhtree_update_node() first for every node/point/triangle.
*/
void BLI_bvhtree_update_tree(BVHTree *tree) void BLI_bvhtree_update_tree(BVHTree *tree)
{ {
/* Update bottom=>top /* Update bottom=>top
@@ -1054,18 +1047,11 @@ void BLI_bvhtree_update_tree(BVHTree *tree)
node_join(tree, *index); node_join(tree, *index);
} }
} }
/**
* Number of times #BLI_bvhtree_insert has been called.
* mainly useful for asserts functions to check we added the correct number.
*/
int BLI_bvhtree_get_len(const BVHTree *tree) int BLI_bvhtree_get_len(const BVHTree *tree)
{ {
return tree->totleaf; return tree->totleaf;
} }
/**
* Maximum number of children that a node can have.
*/
int BLI_bvhtree_get_tree_type(const BVHTree *tree) int BLI_bvhtree_get_tree_type(const BVHTree *tree)
{ {
return tree->tree_type; return tree->tree_type;
@@ -1076,9 +1062,6 @@ float BLI_bvhtree_get_epsilon(const BVHTree *tree)
return tree->epsilon; return tree->epsilon;
} }
/**
* This function returns the bounding box of the BVH tree.
*/
void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3]) void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3])
{ {
BVHNode *root = tree->nodes[tree->totleaf]; BVHNode *root = tree->nodes[tree->totleaf];
@@ -1264,11 +1247,6 @@ static bool tree_overlap_traverse_num(BVHOverlapData_Thread *data_thread,
return false; return false;
} }
/**
* Use to check the total number of threads #BLI_bvhtree_overlap will use.
*
* \warning Must be the first tree passed to #BLI_bvhtree_overlap!
*/
int BLI_bvhtree_overlap_thread_num(const BVHTree *tree) int BLI_bvhtree_overlap_thread_num(const BVHTree *tree)
{ {
return (int)MIN2(tree->tree_type, tree->nodes[tree->totleaf]->totnode); return (int)MIN2(tree->tree_type, tree->nodes[tree->totleaf]->totnode);
@@ -1717,10 +1695,6 @@ static bool dfs_find_duplicate_fast_dfs(BVHNearestData *data, BVHNode *node)
return false; return false;
} }
/**
* Find the first node nearby.
* Favors speed over quality since it doesn't find the best target node.
*/
int BLI_bvhtree_find_nearest_first(BVHTree *tree, int BLI_bvhtree_find_nearest_first(BVHTree *tree,
const float co[3], const float co[3],
const float dist_sq, const float dist_sq,
@@ -2020,15 +1994,6 @@ float BLI_bvhtree_bb_raycast(const float bv[6],
return dist; return dist;
} }
/**
* Calls the callback for every ray intersection
*
* \note Using a \a callback which resets or never sets the #BVHTreeRayHit index & dist works too,
* however using this function means existing generic callbacks can be used from custom callbacks
* without having to handle resetting the hit beforehand.
* It also avoid redundant argument and return value which aren't meaningful
* when collecting multiple hits.
*/
void BLI_bvhtree_ray_cast_all_ex(BVHTree *tree, void BLI_bvhtree_ray_cast_all_ex(BVHTree *tree,
const float co[3], const float co[3],
const float dir[3], const float dir[3],
@@ -2395,18 +2360,6 @@ static bool bvhtree_walk_dfs_recursive(BVHTree_WalkData *walk_data, const BVHNod
return true; return true;
} }
/**
* This is a generic function to perform a depth first search on the #BVHTree
* where the search order and nodes traversed depend on callbacks passed in.
*
* \param tree: Tree to walk.
* \param walk_parent_cb: Callback on a parents bound-box to test if it should be traversed.
* \param walk_leaf_cb: Callback to test leaf nodes, callback must store its own result,
* returning false exits early.
* \param walk_order_cb: Callback that indicates which direction to search,
* either from the node with the lower or higher K-DOP axis value.
* \param userdata: Argument passed to all callbacks.
*/
void BLI_bvhtree_walk_dfs(BVHTree *tree, void BLI_bvhtree_walk_dfs(BVHTree *tree,
BVHTree_WalkParentCallback walk_parent_cb, BVHTree_WalkParentCallback walk_parent_cb,
BVHTree_WalkLeafCallback walk_leaf_cb, BVHTree_WalkLeafCallback walk_leaf_cb,

View File

@@ -100,10 +100,6 @@ void BLI_linklist_reverse(LinkNode **listp)
*listp = rhead; *listp = rhead;
} }
/**
* Move an item from its current position to a new one inside a single-linked list.
* Note *listp may be modified.
*/
void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index) void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index)
{ {
LinkNode *lnk, *lnk_psrc = NULL, *lnk_pdst = NULL; LinkNode *lnk, *lnk_psrc = NULL, *lnk_pdst = NULL;
@@ -171,9 +167,6 @@ void BLI_linklist_move_item(LinkNode **listp, int curr_index, int new_index)
} }
} }
/**
* A version of prepend that takes the allocated link.
*/
void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink) void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink)
{ {
nlink->link = ptr; nlink->link = ptr;
@@ -199,9 +192,6 @@ void BLI_linklist_prepend_pool(LinkNode **listp, void *ptr, BLI_mempool *mempool
BLI_linklist_prepend_nlink(listp, ptr, nlink); BLI_linklist_prepend_nlink(listp, ptr, nlink);
} }
/**
* A version of append that takes the allocated link.
*/
void BLI_linklist_append_nlink(LinkNodePair *list_pair, void *ptr, LinkNode *nlink) void BLI_linklist_append_nlink(LinkNodePair *list_pair, void *ptr, LinkNode *nlink)
{ {
nlink->link = ptr; nlink->link = ptr;

View File

@@ -179,16 +179,6 @@ void *BLI_memarena_calloc(MemArena *ma, size_t size)
return ptr; return ptr;
} }
/**
* Transfer ownership of allocated blocks from `ma_src` into `ma_dst`,
* cleaning the contents of `ma_src`.
*
* \note Useful for multi-threaded tasks that need a thread-local #MemArena
* that is kept after the multi-threaded operation is completed.
*
* \note Avoid accumulating memory pools where possible
* as any unused memory in `ma_src` is wasted every merge.
*/
void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src) void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src)
{ {
/* Memory arenas must be compatible. */ /* Memory arenas must be compatible. */
@@ -231,10 +221,6 @@ void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src)
VALGRIND_CREATE_MEMPOOL(ma_src, 0, false); VALGRIND_CREATE_MEMPOOL(ma_src, 0, false);
} }
/**
* Clear for reuse, avoids re-allocation when an arena may
* otherwise be free'd and recreated.
*/
void BLI_memarena_clear(MemArena *ma) void BLI_memarena_clear(MemArena *ma)
{ {
if (ma->bufs) { if (ma->bufs) {

View File

@@ -99,8 +99,6 @@ void BLI_memblock_destroy(BLI_memblock *mblk, MemblockValFreeFP free_callback)
MEM_freeN(mblk); MEM_freeN(mblk);
} }
/* Reset elem count to 0 but keep as much memory allocated needed for at least the previous elem
* count. */
void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP free_callback) void BLI_memblock_clear(BLI_memblock *mblk, MemblockValFreeFP free_callback)
{ {
int elem_per_chunk = mblk->chunk_size / mblk->elem_size; int elem_per_chunk = mblk->chunk_size / mblk->elem_size;
@@ -191,9 +189,6 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter)
return ptr; return ptr;
} }
/* Direct access. elem is element index inside the chosen chunk.
* Double usage: You can set chunk to 0 and set the absolute elem index.
* The correct chunk will be retrieve. */
void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem)
{ {
BLI_assert(chunk < mblk->chunk_len); BLI_assert(chunk < mblk->chunk_len);

View File

@@ -125,15 +125,6 @@ static void memiter_init(BLI_memiter *mi)
/** \name Public API's /** \name Public API's
* \{ */ * \{ */
/**
* \param chunk_size_min: Should be a power of two and
* significantly larger than the average element size used.
*
* While allocations of any size are supported, they won't be efficient
* (effectively becoming a single-linked list).
*
* Its intended that many elements can be stored per chunk.
*/
BLI_memiter *BLI_memiter_create(uint chunk_size_min) BLI_memiter *BLI_memiter_create(uint chunk_size_min)
{ {
BLI_memiter *mi = MEM_mallocN(sizeof(BLI_memiter), "BLI_memiter"); BLI_memiter *mi = MEM_mallocN(sizeof(BLI_memiter), "BLI_memiter");
@@ -261,7 +252,6 @@ uint BLI_memiter_count(const BLI_memiter *mi)
/** \name Helper API's /** \name Helper API's
* \{ */ * \{ */
/* Support direct lookup for first. */
void *BLI_memiter_elem_first(BLI_memiter *mi) void *BLI_memiter_elem_first(BLI_memiter *mi)
{ {
if (mi->head != NULL) { if (mi->head != NULL) {

View File

@@ -367,11 +367,6 @@ void *BLI_mempool_calloc(BLI_mempool *pool)
return retval; return retval;
} }
/**
* Free an element from the mempool.
*
* \note doesn't protect against double frees, take care!
*/
void BLI_mempool_free(BLI_mempool *pool, void *addr) void BLI_mempool_free(BLI_mempool *pool, void *addr)
{ {
BLI_freenode *newhead = addr; BLI_freenode *newhead = addr;
@@ -475,13 +470,6 @@ void *BLI_mempool_findelem(BLI_mempool *pool, uint index)
return NULL; return NULL;
} }
/**
* Fill in \a data with pointers to each element of the mempool,
* to create lookup table.
*
* \param pool: Pool to create a table from.
* \param data: array of pointers at least the size of 'pool->totused'
*/
void BLI_mempool_as_table(BLI_mempool *pool, void **data) void BLI_mempool_as_table(BLI_mempool *pool, void **data)
{ {
BLI_mempool_iter iter; BLI_mempool_iter iter;
@@ -495,9 +483,6 @@ void BLI_mempool_as_table(BLI_mempool *pool, void **data)
BLI_assert((uint)(p - data) == pool->totused); BLI_assert((uint)(p - data) == pool->totused);
} }
/**
* A version of #BLI_mempool_as_table that allocates and returns the data.
*/
void **BLI_mempool_as_tableN(BLI_mempool *pool, const char *allocstr) void **BLI_mempool_as_tableN(BLI_mempool *pool, const char *allocstr)
{ {
void **data = MEM_mallocN((size_t)pool->totused * sizeof(void *), allocstr); void **data = MEM_mallocN((size_t)pool->totused * sizeof(void *), allocstr);
@@ -505,9 +490,6 @@ void **BLI_mempool_as_tableN(BLI_mempool *pool, const char *allocstr)
return data; return data;
} }
/**
* Fill in \a data with the contents of the mempool.
*/
void BLI_mempool_as_array(BLI_mempool *pool, void *data) void BLI_mempool_as_array(BLI_mempool *pool, void *data)
{ {
const uint esize = pool->esize; const uint esize = pool->esize;
@@ -522,9 +504,6 @@ void BLI_mempool_as_array(BLI_mempool *pool, void *data)
BLI_assert((uint)(p - (char *)data) == pool->totused * esize); BLI_assert((uint)(p - (char *)data) == pool->totused * esize);
} }
/**
* A version of #BLI_mempool_as_array that allocates and returns the data.
*/
void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr) void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr)
{ {
char *data = MEM_malloc_arrayN(pool->totused, pool->esize, allocstr); char *data = MEM_malloc_arrayN(pool->totused, pool->esize, allocstr);
@@ -532,9 +511,6 @@ void *BLI_mempool_as_arrayN(BLI_mempool *pool, const char *allocstr)
return data; return data;
} }
/**
* Initialize a new mempool iterator, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
*/
void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter) void BLI_mempool_iternew(BLI_mempool *pool, BLI_mempool_iter *iter)
{ {
BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER); BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
@@ -550,19 +526,6 @@ static void mempool_threadsafe_iternew(BLI_mempool *pool, BLI_mempool_threadsafe
ts_iter->curchunk_threaded_shared = NULL; ts_iter->curchunk_threaded_shared = NULL;
} }
/**
* Initialize an array of mempool iterators, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
*
* This is used in threaded code, to generate as much iterators as needed
* (each task should have its own),
* such that each iterator goes over its own single chunk,
* and only getting the next chunk to iterate over has to be
* protected against concurrency (which can be done in a lockless way).
*
* To be used when creating a task for each single item in the pool is totally overkill.
*
* See BLI_task_parallel_mempool implementation for detailed usage example.
*/
ParallelMempoolTaskData *mempool_iter_threadsafe_create(BLI_mempool *pool, const size_t num_iter) ParallelMempoolTaskData *mempool_iter_threadsafe_create(BLI_mempool *pool, const size_t num_iter)
{ {
BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER); BLI_assert(pool->flag & BLI_MEMPOOL_ALLOW_ITER);
@@ -625,13 +588,8 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
return ret; return ret;
} }
#else #else /* Optimized version of code above. */
/* optimized version of code above */
/**
* Step over the iterator, returning the mempool item or NULL.
*/
void *BLI_mempool_iterstep(BLI_mempool_iter *iter) void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
{ {
if (UNLIKELY(iter->curchunk == NULL)) { if (UNLIKELY(iter->curchunk == NULL)) {
@@ -660,11 +618,6 @@ void *BLI_mempool_iterstep(BLI_mempool_iter *iter)
return ret; return ret;
} }
/**
* A version of #BLI_mempool_iterstep that uses
* #BLI_mempool_threadsafe_iter.curchunk_threaded_shared for threaded iteration support.
* (threaded section noted in comments).
*/
void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *ts_iter) void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *ts_iter)
{ {
BLI_mempool_iter *iter = &ts_iter->iter; BLI_mempool_iter *iter = &ts_iter->iter;
@@ -710,12 +663,6 @@ void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *ts_iter)
#endif #endif
/**
* Empty the pool, as if it were just created.
*
* \param pool: The pool to clear.
* \param totelem_reserve: Optionally reserve how many items should be kept from clearing.
*/
void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve) void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve)
{ {
BLI_mempool_chunk *mpchunk; BLI_mempool_chunk *mpchunk;
@@ -768,17 +715,11 @@ void BLI_mempool_clear_ex(BLI_mempool *pool, const int totelem_reserve)
} }
} }
/**
* Wrap #BLI_mempool_clear_ex with no reserve set.
*/
void BLI_mempool_clear(BLI_mempool *pool) void BLI_mempool_clear(BLI_mempool *pool)
{ {
BLI_mempool_clear_ex(pool, -1); BLI_mempool_clear_ex(pool, -1);
} }
/**
* Free the mempool its self (and all elements).
*/
void BLI_mempool_destroy(BLI_mempool *pool) void BLI_mempool_destroy(BLI_mempool *pool)
{ {
mempool_chunk_free_all(pool->chunks); mempool_chunk_free_all(pool->chunks);

View File

@@ -41,10 +41,28 @@ typedef struct ParallelMempoolTaskData {
TaskParallelTLS tls; TaskParallelTLS tls;
} ParallelMempoolTaskData; } ParallelMempoolTaskData;
/**
* Initialize an array of mempool iterators, #BLI_MEMPOOL_ALLOW_ITER flag must be set.
*
* This is used in threaded code, to generate as much iterators as needed
* (each task should have its own),
* such that each iterator goes over its own single chunk,
* and only getting the next chunk to iterate over has to be
* protected against concurrency (which can be done in a lockless way).
*
* To be used when creating a task for each single item in the pool is totally overkill.
*
* See #BLI_task_parallel_mempool implementation for detailed usage example.
*/
ParallelMempoolTaskData *mempool_iter_threadsafe_create(BLI_mempool *pool, const size_t num_iter) ParallelMempoolTaskData *mempool_iter_threadsafe_create(BLI_mempool *pool, const size_t num_iter)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
void mempool_iter_threadsafe_destroy(ParallelMempoolTaskData *iter_arr) ATTR_NONNULL(); void mempool_iter_threadsafe_destroy(ParallelMempoolTaskData *iter_arr) ATTR_NONNULL();
/**
* A version of #BLI_mempool_iterstep that uses
* #BLI_mempool_threadsafe_iter.curchunk_threaded_shared for threaded iteration support.
* (threaded section noted in comments).
*/
void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *iter); void *mempool_iter_threadsafe_step(BLI_mempool_threadsafe_iter *iter);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -29,14 +29,12 @@
/* *********************************************** */ /* *********************************************** */
/* Tree API */ /* Tree API */
/* Create a new tree, and initialize as necessary */
DLRBT_Tree *BLI_dlrbTree_new(void) DLRBT_Tree *BLI_dlrbTree_new(void)
{ {
/* just allocate for now */ /* just allocate for now */
return MEM_callocN(sizeof(DLRBT_Tree), "DLRBT_Tree"); return MEM_callocN(sizeof(DLRBT_Tree), "DLRBT_Tree");
} }
/* Just zero out the pointers used */
void BLI_dlrbTree_init(DLRBT_Tree *tree) void BLI_dlrbTree_init(DLRBT_Tree *tree)
{ {
if (tree == NULL) { if (tree == NULL) {
@@ -62,7 +60,6 @@ static void recursive_tree_free_nodes(DLRBT_Node *node)
MEM_freeN(node); MEM_freeN(node);
} }
/* Free the given tree's data but not the tree itself */
void BLI_dlrbTree_free(DLRBT_Tree *tree) void BLI_dlrbTree_free(DLRBT_Tree *tree)
{ {
if (tree == NULL) { if (tree == NULL) {
@@ -109,7 +106,6 @@ static void linkedlist_sync_add_node(DLRBT_Tree *tree, DLRBT_Node *node)
linkedlist_sync_add_node(tree, node->right); linkedlist_sync_add_node(tree, node->right);
} }
/* Make sure the tree's Double-Linked list representation is valid */
void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree) void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree)
{ {
/* sanity checks */ /* sanity checks */
@@ -127,7 +123,6 @@ void BLI_dlrbTree_linkedlist_sync(DLRBT_Tree *tree)
/* *********************************************** */ /* *********************************************** */
/* Tree Search Utilities */ /* Tree Search Utilities */
/* Find the node which matches or is the closest to the requested node */
DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree, DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb, DLRBT_Comparator_FP cmp_cb,
void *search_data) void *search_data)
@@ -175,7 +170,6 @@ DLRBT_Node *BLI_dlrbTree_search(const DLRBT_Tree *tree,
return node; return node;
} }
/* Find the node which exactly matches the required data */
DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree, DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb, DLRBT_Comparator_FP cmp_cb,
void *search_data) void *search_data)
@@ -223,7 +217,6 @@ DLRBT_Node *BLI_dlrbTree_search_exact(const DLRBT_Tree *tree,
return (found == 1) ? (node) : (NULL); return (found == 1) ? (node) : (NULL);
} }
/* Find the node which occurs immediately before the best matching node */
DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree, DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb, DLRBT_Comparator_FP cmp_cb,
void *search_data) void *search_data)
@@ -254,7 +247,6 @@ DLRBT_Node *BLI_dlrbTree_search_prev(const DLRBT_Tree *tree,
return NULL; return NULL;
} }
/* Find the node which occurs immediately after the best matching node */
DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree, DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb, DLRBT_Comparator_FP cmp_cb,
void *search_data) void *search_data)
@@ -285,7 +277,6 @@ DLRBT_Node *BLI_dlrbTree_search_next(const DLRBT_Tree *tree,
return NULL; return NULL;
} }
/* Check whether there is a node matching the requested node */
short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data) short BLI_dlrbTree_contains(DLRBT_Tree *tree, DLRBT_Comparator_FP cmp_cb, void *search_data)
{ {
/* check if an exact search throws up anything... */ /* check if an exact search throws up anything... */
@@ -522,9 +513,6 @@ static void insert_check_3(DLRBT_Tree *tree, DLRBT_Node *node)
/* ----- */ /* ----- */
/* Balance the tree after the given element has been added to it
* (using custom code, in the Binary Tree way).
*/
void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node) void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node)
{ {
/* sanity checks */ /* sanity checks */
@@ -541,9 +529,6 @@ void BLI_dlrbTree_insert(DLRBT_Tree *tree, DLRBT_Node *node)
/* ----- */ /* ----- */
/* Add the given data to the tree, and return the node added */
/* NOTE: for duplicates, the update_cb is called (if available),
* and the existing node is returned */
DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree, DLRBT_Node *BLI_dlrbTree_add(DLRBT_Tree *tree,
DLRBT_Comparator_FP cmp_cb, DLRBT_Comparator_FP cmp_cb,
DLRBT_NAlloc_FP new_cb, DLRBT_NAlloc_FP new_cb,

View File

@@ -1399,26 +1399,6 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info,
/** \name Main Array Storage API /** \name Main Array Storage API
* \{ */ * \{ */
/**
* Create a new array store, which can store any number of arrays
* as long as their stride matches.
*
* \param stride: `sizeof()` each element,
*
* \note while a stride of `1` will always work,
* its less efficient since duplicate chunks of memory will be searched
* at positions unaligned with the array data.
*
* \param chunk_count: Number of elements to split each chunk into.
* - A small value increases the ability to de-duplicate chunks,
* but adds overhead by increasing the number of chunks to look up when searching for duplicates,
* as well as some overhead constructing the original array again, with more calls to `memcpy`.
* - Larger values reduce the *book keeping* overhead,
* but increase the chance a small,
* isolated change will cause a larger amount of data to be duplicated.
*
* \return A new array store, to be freed with #BLI_array_store_destroy.
*/
BArrayStore *BLI_array_store_create(uint stride, uint chunk_count) BArrayStore *BLI_array_store_create(uint stride, uint chunk_count)
{ {
BArrayStore *bs = MEM_callocN(sizeof(BArrayStore), __func__); BArrayStore *bs = MEM_callocN(sizeof(BArrayStore), __func__);
@@ -1472,9 +1452,6 @@ static void array_store_free_data(BArrayStore *bs)
} }
} }
/**
* Free the #BArrayStore, including all states and chunks.
*/
void BLI_array_store_destroy(BArrayStore *bs) void BLI_array_store_destroy(BArrayStore *bs)
{ {
array_store_free_data(bs); array_store_free_data(bs);
@@ -1486,9 +1463,6 @@ void BLI_array_store_destroy(BArrayStore *bs)
MEM_freeN(bs); MEM_freeN(bs);
} }
/**
* Clear all contents, allowing reuse of \a bs.
*/
void BLI_array_store_clear(BArrayStore *bs) void BLI_array_store_clear(BArrayStore *bs)
{ {
array_store_free_data(bs); array_store_free_data(bs);
@@ -1506,9 +1480,6 @@ void BLI_array_store_clear(BArrayStore *bs)
/** \name BArrayStore Statistics /** \name BArrayStore Statistics
* \{ */ * \{ */
/**
* \return the total amount of memory that would be used by getting the arrays for all states.
*/
size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs) size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs)
{ {
size_t size_accum = 0; size_t size_accum = 0;
@@ -1518,10 +1489,6 @@ size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs)
return size_accum; return size_accum;
} }
/**
* \return the amount of memory used by all #BChunk.data
* (duplicate chunks are only counted once).
*/
size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs) size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs)
{ {
size_t size_total = 0; size_t size_total = 0;
@@ -1541,18 +1508,6 @@ size_t BLI_array_store_calc_size_compacted_get(const BArrayStore *bs)
/** \name BArrayState Access /** \name BArrayState Access
* \{ */ * \{ */
/**
*
* \param data: Data used to create
* \param state_reference: The state to use as a reference when adding the new state,
* typically this is the previous state,
* however it can be any previously created state from this \a bs.
*
* \return The new state,
* which is used by the caller as a handle to get back the contents of \a data.
* This may be removed using #BLI_array_store_state_remove,
* otherwise it will be removed with #BLI_array_store_destroy.
*/
BArrayState *BLI_array_store_state_add(BArrayStore *bs, BArrayState *BLI_array_store_state_add(BArrayStore *bs,
const void *data, const void *data,
const size_t data_len, const size_t data_len,
@@ -1601,11 +1556,6 @@ BArrayState *BLI_array_store_state_add(BArrayStore *bs,
return state; return state;
} }
/**
* Remove a state and free any unused #BChunk data.
*
* The states can be freed in any order.
*/
void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state) void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state)
{ {
#ifdef USE_PARANOID_CHECKS #ifdef USE_PARANOID_CHECKS
@@ -1618,18 +1568,11 @@ void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state)
MEM_freeN(state); MEM_freeN(state);
} }
/**
* \return the expanded size of the array,
* use this to know how much memory to allocate #BLI_array_store_state_data_get's argument.
*/
size_t BLI_array_store_state_size_get(BArrayState *state) size_t BLI_array_store_state_size_get(BArrayState *state)
{ {
return state->chunk_list->total_size; return state->chunk_list->total_size;
} }
/**
* Fill in existing allocated memory with the contents of \a state.
*/
void BLI_array_store_state_data_get(BArrayState *state, void *data) void BLI_array_store_state_data_get(BArrayState *state, void *data)
{ {
#ifdef USE_PARANOID_CHECKS #ifdef USE_PARANOID_CHECKS
@@ -1648,9 +1591,6 @@ void BLI_array_store_state_data_get(BArrayState *state, void *data)
} }
} }
/**
* Allocate an array for \a state and return it.
*/
void *BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len) void *BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len)
{ {
void *data = MEM_mallocN(state->chunk_list->total_size, __func__); void *data = MEM_mallocN(state->chunk_list->total_size, __func__);

View File

@@ -35,11 +35,6 @@
#include "BLI_array_utils.h" #include "BLI_array_utils.h"
/**
*In-place array reverse.
*
* Access via #BLI_array_reverse
*/
void _bli_array_reverse(void *arr_v, uint arr_len, size_t arr_stride) void _bli_array_reverse(void *arr_v, uint arr_len, size_t arr_stride)
{ {
const uint arr_stride_uint = (uint)arr_stride; const uint arr_stride_uint = (uint)arr_stride;
@@ -56,12 +51,6 @@ void _bli_array_reverse(void *arr_v, uint arr_len, size_t arr_stride)
} }
} }
/**
* In-place array wrap.
* (rotate the array one step forward or backwards).
*
* Access via #BLI_array_wrap
*/
void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir) void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir)
{ {
char *arr = arr_v; char *arr = arr_v;
@@ -82,12 +71,6 @@ void _bli_array_wrap(void *arr_v, uint arr_len, size_t arr_stride, int dir)
} }
} }
/**
*In-place array permute.
* (re-arrange elements based on an array of indices).
*
* Access via #BLI_array_wrap
*/
void _bli_array_permute( void _bli_array_permute(
void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp) void *arr, const uint arr_len, const size_t arr_stride, const uint *order, void *arr_temp)
{ {
@@ -117,13 +100,6 @@ void _bli_array_permute(
} }
} }
/**
* In-place array de-duplication of an ordered array.
*
* \return The new length of the array.
*
* Access via #BLI_array_deduplicate_ordered
*/
uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride) uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride)
{ {
if (UNLIKELY(arr_len <= 1)) { if (UNLIKELY(arr_len <= 1)) {
@@ -146,13 +122,6 @@ uint _bli_array_deduplicate_ordered(void *arr, uint arr_len, size_t arr_stride)
return j + 1; return j + 1;
} }
/**
* Find the first index of an item in an array.
*
* Access via #BLI_array_findindex
*
* \note Not efficient, use for error checks/asserts.
*/
int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p) int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const void *p)
{ {
const char *arr_step = (const char *)arr; const char *arr_step = (const char *)arr;
@@ -164,9 +133,6 @@ int _bli_array_findindex(const void *arr, uint arr_len, size_t arr_stride, const
return -1; return -1;
} }
/**
* A version of #BLI_array_findindex that searches from the end of the list.
*/
int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p) int _bli_array_rfindindex(const void *arr, uint arr_len, size_t arr_stride, const void *p)
{ {
const char *arr_step = (const char *)arr + (arr_stride * arr_len); const char *arr_step = (const char *)arr + (arr_stride * arr_len);
@@ -205,22 +171,6 @@ void _bli_array_binary_or(
} }
} }
/**
* Utility function to iterate over contiguous items in an array.
*
* \param use_wrap: Detect contiguous ranges across the first/last points.
* In this case the second index of \a span_step may be lower than the first,
* which indicates the values are wrapped.
* \param use_delimit_bounds: When false,
* ranges that defined by the start/end indices are excluded.
* This option has no effect when \a use_wrap is enabled.
* \param test_fn: Function to test if the item should be included in the range.
* \param user_data: User data for \a test_fn.
* \param span_step: Indices to iterate over,
* initialize both values to the array length to initialize iteration.
* \param r_span_len: The length of the span, useful when \a use_wrap is enabled,
* where calculating the length isn't a simple subtraction.
*/
bool _bli_array_iter_span(const void *arr, bool _bli_array_iter_span(const void *arr,
uint arr_len, uint arr_len,
size_t arr_stride, size_t arr_stride,
@@ -330,9 +280,6 @@ bool _bli_array_iter_span(const void *arr,
return false; return false;
} }
/**
* Simple utility to check memory is zeroed.
*/
bool _bli_array_is_zeroed(const void *arr_v, uint arr_len, size_t arr_stride) bool _bli_array_is_zeroed(const void *arr_v, uint arr_len, size_t arr_stride)
{ {
const char *arr_step = (const char *)arr_v; const char *arr_step = (const char *)arr_v;
@@ -345,13 +292,6 @@ bool _bli_array_is_zeroed(const void *arr_v, uint arr_len, size_t arr_stride)
return true; return true;
} }
/**
* Smart function to sample a rect spiraling outside.
* Nice for selection ID.
*
* \param arr_shape: dimensions [w, h].
* \param center: coordinates [x, y] indicating where to start traversing.
*/
bool _bli_array_iter_spiral_square(const void *arr_v, bool _bli_array_iter_spiral_square(const void *arr_v,
const int arr_shape[2], const int arr_shape[2],
size_t elem_size, size_t elem_size,

View File

@@ -53,25 +53,11 @@
#include "BLI_astar.h" #include "BLI_astar.h"
/**
* Init a node in A* graph.
*
* \param custom_data: an opaque pointer attached to this link,
* available e.g. to cost callback function.
*/
void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data) void BLI_astar_node_init(BLI_AStarGraph *as_graph, const int node_index, void *custom_data)
{ {
as_graph->nodes[node_index].custom_data = custom_data; as_graph->nodes[node_index].custom_data = custom_data;
} }
/**
* Add a link between two nodes of our A* graph.
*
* \param cost: the 'length' of the link
* (actual distance between two vertices or face centers e.g.).
* \param custom_data: an opaque pointer attached to this link,
* available e.g. to cost callback function.
*/
void BLI_astar_node_link_add(BLI_AStarGraph *as_graph, void BLI_astar_node_link_add(BLI_AStarGraph *as_graph,
const int node1_index, const int node1_index,
const int node2_index, const int node2_index,
@@ -93,22 +79,11 @@ void BLI_astar_node_link_add(BLI_AStarGraph *as_graph,
BLI_addtail(&(as_graph->nodes[node2_index].neighbor_links), &ld[1]); BLI_addtail(&(as_graph->nodes[node2_index].neighbor_links), &ld[1]);
} }
/**
* \return The index of the other node of given link.
*/
int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx) int BLI_astar_node_link_other_node(BLI_AStarGNLink *lnk, const int idx)
{ {
return (lnk->nodes[0] == idx) ? lnk->nodes[1] : lnk->nodes[0]; return (lnk->nodes[0] == idx) ? lnk->nodes[1] : lnk->nodes[0];
} }
/**
* Initialize a solution data for given A* graph. Does not compute anything!
*
* \param custom_data: an opaque pointer attached to this link, available e.g
* . to cost callback function.
*
* \note BLI_AStarSolution stores nearly all data needed during solution compute.
*/
void BLI_astar_solution_init(BLI_AStarGraph *as_graph, void BLI_astar_solution_init(BLI_AStarGraph *as_graph,
BLI_AStarSolution *as_solution, BLI_AStarSolution *as_solution,
void *custom_data) void *custom_data)
@@ -133,12 +108,6 @@ void BLI_astar_solution_init(BLI_AStarGraph *as_graph,
as_solution->g_steps = BLI_memarena_alloc(mem, sizeof(*as_solution->g_steps) * node_num); as_solution->g_steps = BLI_memarena_alloc(mem, sizeof(*as_solution->g_steps) * node_num);
} }
/**
* Clear given solution's data, but does not release its memory. Avoids having to recreate/allocate
* a memarena in loops, e.g.
*
* \note This *has to be called* between each path solving.
*/
void BLI_astar_solution_clear(BLI_AStarSolution *as_solution) void BLI_astar_solution_clear(BLI_AStarSolution *as_solution)
{ {
if (as_solution->mem) { if (as_solution->mem) {
@@ -156,9 +125,6 @@ void BLI_astar_solution_clear(BLI_AStarSolution *as_solution)
as_solution->g_steps = NULL; as_solution->g_steps = NULL;
} }
/**
* Release the memory allocated for this solution.
*/
void BLI_astar_solution_free(BLI_AStarSolution *as_solution) void BLI_astar_solution_free(BLI_AStarSolution *as_solution)
{ {
if (as_solution->mem) { if (as_solution->mem) {
@@ -167,14 +133,6 @@ void BLI_astar_solution_free(BLI_AStarSolution *as_solution)
} }
} }
/**
* Init an A* graph. Total number of nodes must be known.
*
* Nodes might be e.g. vertices, faces, ...
*
* \param custom_data: an opaque pointer attached to this link,
* available e.g. to cost callback function.
*/
void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data) void BLI_astar_graph_init(BLI_AStarGraph *as_graph, const int node_num, void *custom_data)
{ {
MemArena *mem = as_graph->mem; MemArena *mem = as_graph->mem;
@@ -199,14 +157,6 @@ void BLI_astar_graph_free(BLI_AStarGraph *as_graph)
} }
} }
/**
* Solve a path in given graph, using given 'cost' callback function.
*
* \param max_steps: maximum number of nodes the found path may have.
* Useful in performance-critical usages.
* If no path is found within given steps, returns false too.
* \return true if a path was found, false otherwise.
*/
bool BLI_astar_graph_solve(BLI_AStarGraph *as_graph, bool BLI_astar_graph_solve(BLI_AStarGraph *as_graph,
const int node_index_src, const int node_index_src,
const int node_index_dst, const int node_index_dst,

View File

@@ -29,13 +29,11 @@
#include "BLI_bitmap.h" #include "BLI_bitmap.h"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
/** Set or clear all bits in the bitmap. */
void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits) void BLI_bitmap_set_all(BLI_bitmap *bitmap, bool set, size_t bits)
{ {
memset(bitmap, set ? UCHAR_MAX : 0, BLI_BITMAP_SIZE(bits)); memset(bitmap, set ? UCHAR_MAX : 0, BLI_BITMAP_SIZE(bits));
} }
/** Invert all bits in the bitmap. */
void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits) void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits)
{ {
size_t num_blocks = _BITMAP_NUM_BLOCKS(bits); size_t num_blocks = _BITMAP_NUM_BLOCKS(bits);
@@ -44,13 +42,11 @@ void BLI_bitmap_flip_all(BLI_bitmap *bitmap, size_t bits)
} }
} }
/** Copy all bits from one bitmap to another. */
void BLI_bitmap_copy_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits) void BLI_bitmap_copy_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
{ {
memcpy(dst, src, BLI_BITMAP_SIZE(bits)); memcpy(dst, src, BLI_BITMAP_SIZE(bits));
} }
/** Combine two bitmaps with boolean AND. */
void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits) void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
{ {
size_t num_blocks = _BITMAP_NUM_BLOCKS(bits); size_t num_blocks = _BITMAP_NUM_BLOCKS(bits);
@@ -59,7 +55,6 @@ void BLI_bitmap_and_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
} }
} }
/** Combine two bitmaps with boolean OR. */
void BLI_bitmap_or_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits) void BLI_bitmap_or_all(BLI_bitmap *dst, const BLI_bitmap *src, size_t bits)
{ {
size_t num_blocks = _BITMAP_NUM_BLOCKS(bits); size_t num_blocks = _BITMAP_NUM_BLOCKS(bits);

View File

@@ -41,11 +41,6 @@
/** \name Draw Line /** \name Draw Line
* \{ */ * \{ */
/**
* Plot a line from \a p1 to \a p2 (inclusive).
*
* \note For clipped line drawing, see: http://stackoverflow.com/a/40902741/432509
*/
void BLI_bitmap_draw_2d_line_v2v2i(const int p1[2], void BLI_bitmap_draw_2d_line_v2v2i(const int p1[2],
const int p2[2], const int p2[2],
bool (*callback)(int, int, void *), bool (*callback)(int, int, void *),
@@ -223,9 +218,6 @@ static void draw_tri_flat_min(const int p[2],
} }
} }
/**
* \note Unclipped (clipped version can be added if needed).
*/
void BLI_bitmap_draw_2d_tri_v2i( void BLI_bitmap_draw_2d_tri_v2i(
/* all 2d */ /* all 2d */
const int p1[2], const int p1[2],
@@ -338,18 +330,6 @@ static int draw_poly_v2i_n__span_y_sort(const void *a_p, const void *b_p, void *
return 0; return 0;
} }
/**
* Draws a filled polygon with support for self intersections.
*
* \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive),
* note that \a x_end will always be greater than \a x, so we can use:
*
* \code{.c}
* do {
* func(x, y);
* } while (++x != x_end);
* \endcode
*/
void BLI_bitmap_draw_2d_poly_v2i_n(const int xmin, void BLI_bitmap_draw_2d_poly_v2i_n(const int xmin,
const int ymin, const int ymin,
const int xmax, const int xmax,

View File

@@ -277,20 +277,6 @@ static int vertex_sort(const void *p1, const void *p2, void *vs_ctx_p)
} }
/** \} */ /** \} */
/**
* Main box-packing function accessed from other functions
* This sets boxes x,y to positive values, sorting from 0,0 outwards.
* There is no limit to the space boxes may take, only that they will be packed
* tightly into the lower left hand corner (0,0)
*
* \param boxarray: a pre-allocated array of boxes.
* only the 'box->x' and 'box->y' are set, 'box->w' and 'box->h' are used,
* 'box->index' is not used at all, the only reason its there
* is that the box array is sorted by area and programs need to be able
* to have some way of writing the boxes back to the original data.
* \param len: the number of boxes in the array.
* \param r_tot_x, r_tot_y: set so you can normalize the data.
*/
void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r_tot_y) void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r_tot_y)
{ {
uint box_index, verts_pack_len, i, j, k; uint box_index, verts_pack_len, i, j, k;
@@ -678,18 +664,6 @@ void BLI_box_pack_2d(BoxPack *boxarray, const uint len, float *r_tot_x, float *r
MEM_freeN(vs_ctx.vertarray); MEM_freeN(vs_ctx.vertarray);
} }
/* Packs boxes into a fixed area.
* boxes and packed are linked lists containing structs that can be cast to
* FixedSizeBoxPack (i.e. contains a FixedSizeBoxPack as its first element).
* Boxes that were packed successfully are placed into *packed and removed from *boxes.
*
* The algorithm is a simplified version of https://github.com/TeamHypersomnia/rectpack2D.
* Better ones could be used, but for the current use case (packing Image tiles into GPU
* textures) this is fine.
*
* Note that packing efficiency depends on the order of the input boxes. Generally speaking,
* larger boxes should come first, though how exactly size is best defined (e.g. area,
* perimeter) depends on the particular application. */
void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, int height, ListBase *packed) void BLI_box_pack_2d_fixedarea(ListBase *boxes, int width, int height, ListBase *packed)
{ {
ListBase spaces = {NULL}; ListBase spaces = {NULL};

View File

@@ -86,11 +86,6 @@ void BLI_buffer_resize(BLI_Buffer *buffer, const size_t new_count)
buffer->count = new_count; buffer->count = new_count;
} }
/**
* Similar to #BLI_buffer_resize, but use when the existing data can be:
* - Ignored (malloc'd)
* - Cleared (when BLI_BUFFER_USE_CALLOC is set)
*/
void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count) void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count)
{ {
if (UNLIKELY(new_count > buffer->alloc_count)) { if (UNLIKELY(new_count > buffer->alloc_count)) {
@@ -114,7 +109,6 @@ void BLI_buffer_reinit(BLI_Buffer *buffer, const size_t new_count)
buffer->count = new_count; buffer->count = new_count;
} }
/* Callers use BLI_buffer_append_array. */
void _bli_buffer_append_array(BLI_Buffer *buffer, void *new_data, size_t count) void _bli_buffer_append_array(BLI_Buffer *buffer, void *new_data, size_t count)
{ {
size_t size = buffer->count; size_t size = buffer->count;
@@ -124,7 +118,6 @@ void _bli_buffer_append_array(BLI_Buffer *buffer, void *new_data, size_t count)
memcpy(bytes + size * buffer->elem_size, new_data, count * buffer->elem_size); memcpy(bytes + size * buffer->elem_size, new_data, count * buffer->elem_size);
} }
/* callers use BLI_buffer_free */
void _bli_buffer_free(BLI_Buffer *buffer) void _bli_buffer_free(BLI_Buffer *buffer)
{ {
if ((buffer->flag & BLI_BUFFER_USE_STATIC) == 0) { if ((buffer->flag & BLI_BUFFER_USE_STATIC) == 0) {

View File

@@ -53,14 +53,6 @@ static float is_left(const float p0[2], const float p1[2], const float p2[2])
return (p1[0] - p0[0]) * (p2[1] - p0[1]) - (p2[0] - p0[0]) * (p1[1] - p0[1]); return (p1[0] - p0[0]) * (p2[1] - p0[1]) - (p2[0] - p0[0]) * (p1[1] - p0[1]);
} }
/**
* A.M. Andrew's monotone chain 2D convex hull algorithm
*
* \param points: An array of 2D points presorted by increasing x and y-coords.
* \param n: The number of points in points.
* \param r_points: An array of the convex hull vertex indices (max is n).
* \returns the number of points in r_points.
*/
int BLI_convexhull_2d_sorted(const float (*points)[2], const int n, int r_points[]) int BLI_convexhull_2d_sorted(const float (*points)[2], const int n, int r_points[])
{ {
/* the output array r_points[] will be used as the stack */ /* the output array r_points[] will be used as the stack */
@@ -182,16 +174,6 @@ static int pointref_cmp_yx(const void *a_, const void *b_)
return 0; return 0;
} }
/**
* A.M. Andrew's monotone chain 2D convex hull algorithm
*
* \param points: An array of 2D points.
* \param n: The number of points in points.
* \param r_points: An array of the convex hull vertex indices (max is n).
* _must_ be allocated as `n * 2` because of how its used internally,
* even though the final result will be no more than \a n in size.
* \returns the number of points in r_points.
*/
int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[]) int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[])
{ {
struct PointRef *points_ref = MEM_mallocN(sizeof(*points_ref) * (size_t)n, __func__); struct PointRef *points_ref = MEM_mallocN(sizeof(*points_ref) * (size_t)n, __func__);
@@ -234,16 +216,6 @@ int BLI_convexhull_2d(const float (*points)[2], const int n, int r_points[])
/** \name Utility Convex-Hull Functions /** \name Utility Convex-Hull Functions
* \{ */ * \{ */
/**
* \return The best angle for fitting the convex hull to an axis aligned bounding box.
*
* Intended to be used with #BLI_convexhull_2d
*
* \param points_hull: Ordered hull points
* (result of #BLI_convexhull_2d mapped to a contiguous array).
*
* \note we could return the index of the best edge too if its needed.
*/
float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned int n) float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned int n)
{ {
unsigned int i, i_prev; unsigned int i, i_prev;
@@ -291,11 +263,6 @@ float BLI_convexhull_aabb_fit_hull_2d(const float (*points_hull)[2], unsigned in
return (area_best != FLT_MAX) ? atan2f(dvec_best[0], dvec_best[1]) : 0.0f; return (area_best != FLT_MAX) ? atan2f(dvec_best[0], dvec_best[1]) : 0.0f;
} }
/**
* Wrap #BLI_convexhull_aabb_fit_hull_2d and do the convex hull calculation.
*
* \param points: arbitrary 2d points.
*/
float BLI_convexhull_aabb_fit_points_2d(const float (*points)[2], unsigned int n) float BLI_convexhull_aabb_fit_points_2d(const float (*points)[2], unsigned int n)
{ {
int *index_map; int *index_map;

View File

@@ -272,10 +272,6 @@ void BLI_edgehash_print(EdgeHash *eh)
} }
} }
/**
* Insert edge (\a v0, \a v1) into hash with given value, does
* not check for duplicates.
*/
void BLI_edgehash_insert(EdgeHash *eh, uint v0, uint v1, void *value) void BLI_edgehash_insert(EdgeHash *eh, uint v0, uint v1, void *value)
{ {
edgehash_ensure_can_insert(eh); edgehash_ensure_can_insert(eh);
@@ -283,9 +279,6 @@ void BLI_edgehash_insert(EdgeHash *eh, uint v0, uint v1, void *value)
edgehash_insert(eh, edge, value); edgehash_insert(eh, edge, value);
} }
/**
* Assign a new value to a key that may already be in edgehash.
*/
bool BLI_edgehash_reinsert(EdgeHash *eh, uint v0, uint v1, void *value) bool BLI_edgehash_reinsert(EdgeHash *eh, uint v0, uint v1, void *value)
{ {
Edge edge = init_edge(v0, v1); Edge edge = init_edge(v0, v1);
@@ -307,51 +300,24 @@ bool BLI_edgehash_reinsert(EdgeHash *eh, uint v0, uint v1, void *value)
} }
} }
/**
* A version of #BLI_edgehash_lookup which accepts a fallback argument.
*/
void *BLI_edgehash_lookup_default(const EdgeHash *eh, uint v0, uint v1, void *default_value) void *BLI_edgehash_lookup_default(const EdgeHash *eh, uint v0, uint v1, void *default_value)
{ {
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1); EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
return entry ? entry->value : default_value; return entry ? entry->value : default_value;
} }
/**
* Return value for given edge (\a v0, \a v1), or NULL if
* if key does not exist in hash. (If need exists
* to differentiate between key-value being NULL and
* lack of key then see #BLI_edgehash_lookup_p().
*/
void *BLI_edgehash_lookup(const EdgeHash *eh, uint v0, uint v1) void *BLI_edgehash_lookup(const EdgeHash *eh, uint v0, uint v1)
{ {
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1); EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
return entry ? entry->value : NULL; return entry ? entry->value : NULL;
} }
/**
* Return pointer to value for given edge (\a v0, \a v1),
* or NULL if key does not exist in hash.
*/
void **BLI_edgehash_lookup_p(EdgeHash *eh, uint v0, uint v1) void **BLI_edgehash_lookup_p(EdgeHash *eh, uint v0, uint v1)
{ {
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1); EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
return entry ? &entry->value : NULL; return entry ? &entry->value : NULL;
} }
/**
* Ensure \a (v0, v1) is exists in \a eh.
*
* This handles the common situation where the caller needs ensure a key is added to \a eh,
* constructing a new value in the case the key isn't found.
* Otherwise use the existing value.
*
* Such situations typically incur multiple lookups, however this function
* avoids them by ensuring the key is added,
* returning a pointer to the value so it can be used or initialized by the caller.
*
* \returns true when the value didn't need to be added.
* (when false, the caller _must_ initialize the value).
*/
bool BLI_edgehash_ensure_p(EdgeHash *eh, uint v0, uint v1, void ***r_value) bool BLI_edgehash_ensure_p(EdgeHash *eh, uint v0, uint v1, void ***r_value)
{ {
Edge edge = init_edge(v0, v1); Edge edge = init_edge(v0, v1);
@@ -373,13 +339,6 @@ bool BLI_edgehash_ensure_p(EdgeHash *eh, uint v0, uint v1, void ***r_value)
} }
} }
/**
* Remove \a key (v0, v1) from \a eh, or return false if the key wasn't found.
*
* \param v0, v1: The key to remove.
* \param free_value: Optional callback to free the value.
* \return true if \a key was removed from \a eh.
*/
bool BLI_edgehash_remove(EdgeHash *eh, uint v0, uint v1, EdgeHashFreeFP free_value) bool BLI_edgehash_remove(EdgeHash *eh, uint v0, uint v1, EdgeHashFreeFP free_value)
{ {
uint old_length = eh->length; uint old_length = eh->length;
@@ -390,16 +349,11 @@ bool BLI_edgehash_remove(EdgeHash *eh, uint v0, uint v1, EdgeHashFreeFP free_val
return old_length > eh->length; return old_length > eh->length;
} }
/* same as above but return the value,
* no free value argument since it will be returned */
/**
* Remove \a key (v0, v1) from \a eh, returning the value or NULL if the key wasn't found.
*
* \param v0, v1: The key to remove.
* \return the value of \a key int \a eh or NULL.
*/
void *BLI_edgehash_popkey(EdgeHash *eh, uint v0, uint v1) void *BLI_edgehash_popkey(EdgeHash *eh, uint v0, uint v1)
{ {
/* Same as #BLI_edgehash_remove but return the value,
* no free value argument since it will be returned */
Edge edge = init_edge(v0, v1); Edge edge = init_edge(v0, v1);
ITER_SLOTS (eh, edge, slot, index) { ITER_SLOTS (eh, edge, slot, index) {
@@ -420,25 +374,16 @@ void *BLI_edgehash_popkey(EdgeHash *eh, uint v0, uint v1)
} }
} }
/**
* Return boolean true/false if edge (v0,v1) in hash.
*/
bool BLI_edgehash_haskey(const EdgeHash *eh, uint v0, uint v1) bool BLI_edgehash_haskey(const EdgeHash *eh, uint v0, uint v1)
{ {
return edgehash_lookup_entry(eh, v0, v1) != NULL; return edgehash_lookup_entry(eh, v0, v1) != NULL;
} }
/**
* Return number of keys in hash.
*/
int BLI_edgehash_len(const EdgeHash *eh) int BLI_edgehash_len(const EdgeHash *eh)
{ {
return (int)eh->length; return (int)eh->length;
} }
/**
* Remove all edges from hash.
*/
void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint UNUSED(reserve)) void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint UNUSED(reserve))
{ {
/* TODO: handle reserve */ /* TODO: handle reserve */
@@ -449,9 +394,6 @@ void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint U
CLEAR_MAP(eh); CLEAR_MAP(eh);
} }
/**
* Wraps #BLI_edgehash_clear_ex with zero entries reserved.
*/
void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value) void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value)
{ {
BLI_edgehash_clear_ex(eh, free_value, 0); BLI_edgehash_clear_ex(eh, free_value, 0);
@@ -463,11 +405,6 @@ void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value)
/** \name Edge Hash Iterator API /** \name Edge Hash Iterator API
* \{ */ * \{ */
/**
* Create a new EdgeHashIterator. The hash table must not be mutated
* while the iterator is in use, and the iterator will step exactly
* BLI_edgehash_len(eh) times before becoming done.
*/
EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh)
{ {
EdgeHashIterator *ehi = MEM_mallocN(sizeof(EdgeHashIterator), __func__); EdgeHashIterator *ehi = MEM_mallocN(sizeof(EdgeHashIterator), __func__);
@@ -475,14 +412,6 @@ EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh)
return ehi; return ehi;
} }
/**
* Init an already allocated EdgeHashIterator. The hash table must not
* be mutated while the iterator is in use, and the iterator will
* step exactly BLI_edgehash_len(eh) times before becoming done.
*
* \param ehi: The EdgeHashIterator to initialize.
* \param eh: The EdgeHash to iterate over.
*/
void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh) void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh)
{ {
ehi->entries = eh->entries; ehi->entries = eh->entries;
@@ -490,9 +419,6 @@ void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh)
ehi->index = 0; ehi->index = 0;
} }
/**
* Free an EdgeHashIterator.
*/
void BLI_edgehashIterator_free(EdgeHashIterator *ehi) void BLI_edgehashIterator_free(EdgeHashIterator *ehi)
{ {
MEM_freeN(ehi); MEM_freeN(ehi);
@@ -569,12 +495,6 @@ BLI_INLINE void edgeset_insert_at_slot(EdgeSet *es, uint slot, Edge edge)
es->length++; es->length++;
} }
/**
* A version of BLI_edgeset_insert which checks first if the key is in the set.
* \returns true if a new key has been added.
*
* \note EdgeHash has no equivalent to this because typically the value would be different.
*/
bool BLI_edgeset_add(EdgeSet *es, uint v0, uint v1) bool BLI_edgeset_add(EdgeSet *es, uint v0, uint v1)
{ {
edgeset_ensure_can_insert(es); edgeset_ensure_can_insert(es);
@@ -591,10 +511,6 @@ bool BLI_edgeset_add(EdgeSet *es, uint v0, uint v1)
} }
} }
/**
* Adds the key to the set (no checks for unique keys!).
* Matching #BLI_edgehash_insert
*/
void BLI_edgeset_insert(EdgeSet *es, uint v0, uint v1) void BLI_edgeset_insert(EdgeSet *es, uint v0, uint v1)
{ {
edgeset_ensure_can_insert(es); edgeset_ensure_can_insert(es);

View File

@@ -124,7 +124,6 @@ struct ExprPyLike_Parsed {
/** \name Public API /** \name Public API
* \{ */ * \{ */
/** Free the parsed data; NULL argument is ok. */
void BLI_expr_pylike_free(ExprPyLike_Parsed *expr) void BLI_expr_pylike_free(ExprPyLike_Parsed *expr)
{ {
if (expr != NULL) { if (expr != NULL) {
@@ -132,19 +131,16 @@ void BLI_expr_pylike_free(ExprPyLike_Parsed *expr)
} }
} }
/** Check if the parsing result is valid for evaluation. */
bool BLI_expr_pylike_is_valid(ExprPyLike_Parsed *expr) bool BLI_expr_pylike_is_valid(ExprPyLike_Parsed *expr)
{ {
return expr != NULL && expr->ops_count > 0; return expr != NULL && expr->ops_count > 0;
} }
/** Check if the parsed expression always evaluates to the same value. */
bool BLI_expr_pylike_is_constant(ExprPyLike_Parsed *expr) bool BLI_expr_pylike_is_constant(ExprPyLike_Parsed *expr)
{ {
return expr != NULL && expr->ops_count == 1 && expr->ops[0].opcode == OPCODE_CONST; return expr != NULL && expr->ops_count == 1 && expr->ops[0].opcode == OPCODE_CONST;
} }
/** Check if the parsed expression uses the parameter with the given index. */
bool BLI_expr_pylike_is_using_param(ExprPyLike_Parsed *expr, int index) bool BLI_expr_pylike_is_using_param(ExprPyLike_Parsed *expr, int index)
{ {
int i; int i;
@@ -168,10 +164,6 @@ bool BLI_expr_pylike_is_using_param(ExprPyLike_Parsed *expr, int index)
/** \name Stack Machine Evaluation /** \name Stack Machine Evaluation
* \{ */ * \{ */
/**
* Evaluate the expression with the given parameters.
* The order and number of parameters must match the names given to parse.
*/
eExprPyLike_EvalStatus BLI_expr_pylike_eval(ExprPyLike_Parsed *expr, eExprPyLike_EvalStatus BLI_expr_pylike_eval(ExprPyLike_Parsed *expr,
const double *param_values, const double *param_values,
int param_values_len, int param_values_len,
@@ -1073,12 +1065,6 @@ static bool parse_expr(ExprParseState *state)
/** \name Main Parsing Function /** \name Main Parsing Function
* \{ */ * \{ */
/**
* Compile the expression and return the result.
*
* Parse the expression for evaluation later.
* Returns non-NULL even on failure; use is_valid to check.
*/
ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression, ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression,
const char **param_names, const char **param_names,
int param_names_len) int param_names_len)

View File

@@ -180,13 +180,6 @@ bool BLI_file_magic_is_zstd(const char header[4])
return false; return false;
} }
/**
* Returns true if the file with the specified name can be written.
* This implementation uses access(2), which makes the check according
* to the real UID and GID of the process, not its effective UID and GID.
* This shouldn't matter for Blender, which is not going to run privileged
* anyway.
*/
bool BLI_file_is_writable(const char *filename) bool BLI_file_is_writable(const char *filename)
{ {
bool writable; bool writable;
@@ -212,10 +205,6 @@ bool BLI_file_is_writable(const char *filename)
return writable; return writable;
} }
/**
* Creates the file with nothing in it, or updates its last-modified date if it already exists.
* Returns true if successful (like the unix touch command).
*/
bool BLI_file_touch(const char *file) bool BLI_file_touch(const char *file)
{ {
FILE *f = BLI_fopen(file, "r+b"); FILE *f = BLI_fopen(file, "r+b");
@@ -954,12 +943,6 @@ int BLI_access(const char *filename, int mode)
return access(filename, mode); return access(filename, mode);
} }
/**
* Deletes the specified file or directory (depending on dir), optionally
* doing recursive delete of directory contents.
*
* \return zero on success (matching 'remove' behavior).
*/
int BLI_delete(const char *file, bool dir, bool recursive) int BLI_delete(const char *file, bool dir, bool recursive)
{ {
BLI_assert(!BLI_path_is_rel(file)); BLI_assert(!BLI_path_is_rel(file));
@@ -973,12 +956,6 @@ int BLI_delete(const char *file, bool dir, bool recursive)
return remove(file); return remove(file);
} }
/**
* Soft deletes the specified file or directory (depending on dir) by moving the files to the
* recycling bin, optionally doing recursive delete of directory contents.
*
* \return zero on success (matching 'remove' behavior).
*/
int BLI_delete_soft(const char *file, const char **error_message) int BLI_delete_soft(const char *file, const char **error_message)
{ {
BLI_assert(!BLI_path_is_rel(file)); BLI_assert(!BLI_path_is_rel(file));
@@ -1251,7 +1228,6 @@ int BLI_create_symlink(const char *file, const char *to)
} }
# endif # endif
/** \return true on success (i.e. given path now exists on FS), false otherwise. */
bool BLI_dir_create_recursive(const char *dirname) bool BLI_dir_create_recursive(const char *dirname)
{ {
char *lslash; char *lslash;
@@ -1301,9 +1277,6 @@ bool BLI_dir_create_recursive(const char *dirname)
return ret; return ret;
} }
/**
* \return zero on success (matching 'rename' behavior).
*/
int BLI_rename(const char *from, const char *to) int BLI_rename(const char *from, const char *to)
{ {
if (!BLI_exists(from)) { if (!BLI_exists(from)) {

View File

@@ -101,9 +101,6 @@ static void queue_free_chunk(struct QueueChunk *data)
} }
} }
/**
* Free the queue's data and the queue itself
*/
void BLI_gsqueue_free(GSQueue *queue) void BLI_gsqueue_free(GSQueue *queue)
{ {
queue_free_chunk(queue->chunk_first); queue_free_chunk(queue->chunk_first);
@@ -111,14 +108,6 @@ void BLI_gsqueue_free(GSQueue *queue)
MEM_freeN(queue); MEM_freeN(queue);
} }
/**
* Copies the source value onto the end of the queue
*
* \note This copies #GSQueue.elem_size bytes from \a item,
* (the pointer itself is not stored).
*
* \param item: source data to be copied to the queue.
*/
void BLI_gsqueue_push(GSQueue *queue, const void *item) void BLI_gsqueue_push(GSQueue *queue, const void *item)
{ {
queue->chunk_last_index++; queue->chunk_last_index++;
@@ -153,12 +142,6 @@ void BLI_gsqueue_push(GSQueue *queue, const void *item)
memcpy(queue_get_last_elem(queue), item, queue->elem_size); memcpy(queue_get_last_elem(queue), item, queue->elem_size);
} }
/**
* Retrieves and removes the first element from the queue.
* The value is copies to \a r_item, which must be at least \a elem_size bytes.
*
* Does not reduce amount of allocated memory.
*/
void BLI_gsqueue_pop(GSQueue *queue, void *r_item) void BLI_gsqueue_pop(GSQueue *queue, void *r_item)
{ {
BLI_assert(BLI_gsqueue_is_empty(queue) == false); BLI_assert(BLI_gsqueue_is_empty(queue) == false);
@@ -187,9 +170,6 @@ size_t BLI_gsqueue_len(const GSQueue *queue)
return queue->totelem; return queue->totelem;
} }
/**
* Returns true if the queue is empty, false otherwise
*/
bool BLI_gsqueue_is_empty(const GSQueue *queue) bool BLI_gsqueue_is_empty(const GSQueue *queue)
{ {
return (queue->chunk_first == NULL); return (queue->chunk_first == NULL);

View File

@@ -284,11 +284,6 @@ static void *md5_read_ctx(const struct md5_ctx *ctx, void *resbuf)
/* Top level public functions. */ /* Top level public functions. */
/**
* Compute MD5 message digest for bytes read from 'stream'.
* The resulting message digest number will be written into the 16 bytes beginning at 'resblock'.
* \return Non-zero if an error occurred.
*/
int BLI_hash_md5_stream(FILE *stream, void *resblock) int BLI_hash_md5_stream(FILE *stream, void *resblock)
{ {
#define BLOCKSIZE 4096 /* Important: must be a multiple of 64. */ #define BLOCKSIZE 4096 /* Important: must be a multiple of 64. */
@@ -362,11 +357,6 @@ int BLI_hash_md5_stream(FILE *stream, void *resblock)
return 0; return 0;
} }
/**
* Compute MD5 message digest for 'len' bytes beginning at 'buffer'.
* The result is always in little endian byte order,
* so that a byte-wise output yields to the wanted ASCII representation of the message digest.
*/
void *BLI_hash_md5_buffer(const char *buffer, size_t len, void *resblock) void *BLI_hash_md5_buffer(const char *buffer, size_t len, void *resblock)
{ {
struct md5_ctx ctx; struct md5_ctx ctx;

View File

@@ -110,7 +110,6 @@ uint32_t BLI_hash_mm2a_end(BLI_HashMurmur2A *mm2)
return mm2->hash; return mm2->hash;
} }
/* Non-incremental version, quicker for small keys. */
uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed) uint32_t BLI_hash_mm2(const unsigned char *data, size_t len, uint32_t seed)
{ {
/* Initialize the hash to a 'random' value */ /* Initialize the hash to a 'random' value */

View File

@@ -23,21 +23,6 @@ IndexMask IndexMask::slice(IndexRange slice) const
return IndexMask(indices_.slice(slice)); return IndexMask(indices_.slice(slice));
} }
/**
* Create a sub-mask that is also shifted to the beginning. The shifting to the beginning allows
* code to work with smaller indices, which is more memory efficient.
*
* \return New index mask with the size of #slice. It is either empty or starts with 0. It might
* reference indices that have been appended to #r_new_indices.
*
* Example:
* this: [2, 3, 5, 7, 8, 9, 10]
* slice: ^--------^
* output: [0, 2, 4, 5]
*
* All the indices in the sub-mask are shifted by 3 towards zero, so that the first index in the
* output is zero.
*/
IndexMask IndexMask::slice_and_offset(const IndexRange slice, Vector<int64_t> &r_new_indices) const IndexMask IndexMask::slice_and_offset(const IndexRange slice, Vector<int64_t> &r_new_indices) const
{ {
const int slice_size = slice.size(); const int slice_size = slice.size();

View File

@@ -65,7 +65,6 @@ bool BLI_lasso_is_point_inside(const int mcoords[][2],
return isect_point_poly_v2_int(pt, mcoords, mcoords_len, true); return isect_point_poly_v2_int(pt, mcoords, mcoords_len, true);
} }
/* edge version for lasso select. we assume boundbox check was done */
bool BLI_lasso_is_edge_inside(const int mcoords[][2], bool BLI_lasso_is_edge_inside(const int mcoords[][2],
const unsigned int mcoords_len, const unsigned int mcoords_len,
int x0, int x0,

View File

@@ -36,11 +36,6 @@
#include "BLI_strict_flags.h" #include "BLI_strict_flags.h"
/* implementation */
/**
* moves the entire contents of \a src onto the end of \a dst.
*/
void BLI_movelisttolist(ListBase *dst, ListBase *src) void BLI_movelisttolist(ListBase *dst, ListBase *src)
{ {
if (src->first == NULL) { if (src->first == NULL) {
@@ -59,9 +54,6 @@ void BLI_movelisttolist(ListBase *dst, ListBase *src)
src->first = src->last = NULL; src->first = src->last = NULL;
} }
/**
* moves the entire contents of \a src at the beginning of \a dst.
*/
void BLI_movelisttolist_reverse(ListBase *dst, ListBase *src) void BLI_movelisttolist_reverse(ListBase *dst, ListBase *src)
{ {
if (src->first == NULL) { if (src->first == NULL) {
@@ -81,9 +73,6 @@ void BLI_movelisttolist_reverse(ListBase *dst, ListBase *src)
src->first = src->last = NULL; src->first = src->last = NULL;
} }
/**
* Prepends \a vlink (assumed to begin with a Link) onto listbase.
*/
void BLI_addhead(ListBase *listbase, void *vlink) void BLI_addhead(ListBase *listbase, void *vlink)
{ {
Link *link = vlink; Link *link = vlink;
@@ -104,9 +93,6 @@ void BLI_addhead(ListBase *listbase, void *vlink)
listbase->first = link; listbase->first = link;
} }
/**
* Appends \a vlink (assumed to begin with a Link) onto listbase.
*/
void BLI_addtail(ListBase *listbase, void *vlink) void BLI_addtail(ListBase *listbase, void *vlink)
{ {
Link *link = vlink; Link *link = vlink;
@@ -127,9 +113,6 @@ void BLI_addtail(ListBase *listbase, void *vlink)
listbase->last = link; listbase->last = link;
} }
/**
* Removes \a vlink from \a listbase. Assumes it is linked into there!
*/
void BLI_remlink(ListBase *listbase, void *vlink) void BLI_remlink(ListBase *listbase, void *vlink)
{ {
Link *link = vlink; Link *link = vlink;
@@ -153,9 +136,6 @@ void BLI_remlink(ListBase *listbase, void *vlink)
} }
} }
/**
* Checks that \a vlink is linked into listbase, removing it from there if so.
*/
bool BLI_remlink_safe(ListBase *listbase, void *vlink) bool BLI_remlink_safe(ListBase *listbase, void *vlink)
{ {
if (BLI_findindex(listbase, vlink) != -1) { if (BLI_findindex(listbase, vlink) != -1) {
@@ -166,9 +146,6 @@ bool BLI_remlink_safe(ListBase *listbase, void *vlink)
return false; return false;
} }
/**
* Swaps \a vlinka and \a vlinkb in the list. Assumes they are both already in the list!
*/
void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb) void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
{ {
Link *linka = vlinka; Link *linka = vlinka;
@@ -222,10 +199,6 @@ void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
} }
} }
/**
* Swaps \a vlinka and \a vlinkb from their respective lists.
* Assumes they are both already in their \a listbasea!
*/
void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vlinka, void *vlinkb) void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vlinka, void *vlinkb)
{ {
Link *linka = vlinka; Link *linka = vlinka;
@@ -251,9 +224,6 @@ void BLI_listbases_swaplinks(ListBase *listbasea, ListBase *listbaseb, void *vli
BLI_remlink(listbasea, &linkc); BLI_remlink(listbasea, &linkc);
} }
/**
* Removes the head from \a listbase and returns it.
*/
void *BLI_pophead(ListBase *listbase) void *BLI_pophead(ListBase *listbase)
{ {
Link *link; Link *link;
@@ -263,9 +233,6 @@ void *BLI_pophead(ListBase *listbase)
return link; return link;
} }
/**
* Removes the tail from \a listbase and returns it.
*/
void *BLI_poptail(ListBase *listbase) void *BLI_poptail(ListBase *listbase)
{ {
Link *link; Link *link;
@@ -275,9 +242,6 @@ void *BLI_poptail(ListBase *listbase)
return link; return link;
} }
/**
* Removes \a vlink from listbase and disposes of it. Assumes it is linked into there!
*/
void BLI_freelinkN(ListBase *listbase, void *vlink) void BLI_freelinkN(ListBase *listbase, void *vlink)
{ {
Link *link = vlink; Link *link = vlink;
@@ -320,11 +284,6 @@ static void listbase_double_from_single(Link *iter, ListBase *listbase)
#undef SORT_IMPL_LINKTYPE #undef SORT_IMPL_LINKTYPE
/**
* Sorts the elements of listbase into the order defined by cmp
* (which should return 1 if its first arg should come after its second arg).
* This uses insertion sort, so NOT ok for large list.
*/
void BLI_listbase_sort(ListBase *listbase, int (*cmp)(const void *, const void *)) void BLI_listbase_sort(ListBase *listbase, int (*cmp)(const void *, const void *))
{ {
if (listbase->first != listbase->last) { if (listbase->first != listbase->last) {
@@ -345,10 +304,6 @@ void BLI_listbase_sort_r(ListBase *listbase,
} }
} }
/**
* Inserts \a vnewlink immediately following \a vprevlink in \a listbase.
* Or, if \a vprevlink is NULL, puts \a vnewlink at the front of the list.
*/
void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink) void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
{ {
Link *prevlink = vprevlink; Link *prevlink = vprevlink;
@@ -388,10 +343,6 @@ void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
} }
} }
/**
* Inserts \a vnewlink immediately preceding \a vnextlink in listbase.
* Or, if \a vnextlink is NULL, puts \a vnewlink at the end of the list.
*/
void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink) void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
{ {
Link *nextlink = vnextlink; Link *nextlink = vnextlink;
@@ -431,13 +382,6 @@ void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
} }
} }
/**
* Insert a link in place of another, without changing its position in the list.
*
* Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`.
* - `vreplacelink` *must* be in the list.
* - `vnewlink` *must not* be in the list.
*/
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink) void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
{ {
Link *l_old = vreplacelink; Link *l_old = vreplacelink;
@@ -464,14 +408,6 @@ void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlin
} }
} }
/**
* Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
* item if new position would exceed list (could optionally move to head/tail).
*
* \param step: Absolute value defines step size, sign defines direction. E.g pass -1
* to move \a vlink before previous, or 1 to move behind next.
* \return If position of \a vlink has changed.
*/
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
{ {
Link *link = vlink; Link *link = vlink;
@@ -503,11 +439,6 @@ bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step)
return true; return true;
} }
/**
* Move the link at the index \a from to the position at index \a to.
*
* \return If the move was successful.
*/
bool BLI_listbase_move_index(ListBase *listbase, int from, int to) bool BLI_listbase_move_index(ListBase *listbase, int from, int to)
{ {
if (from == to) { if (from == to) {
@@ -524,9 +455,6 @@ bool BLI_listbase_move_index(ListBase *listbase, int from, int to)
return BLI_listbase_link_move(listbase, link, to - from); return BLI_listbase_link_move(listbase, link, to - from);
} }
/**
* Removes and disposes of the entire contents of listbase using direct free(3).
*/
void BLI_freelist(ListBase *listbase) void BLI_freelist(ListBase *listbase)
{ {
Link *link, *next; Link *link, *next;
@@ -541,9 +469,6 @@ void BLI_freelist(ListBase *listbase)
BLI_listbase_clear(listbase); BLI_listbase_clear(listbase);
} }
/**
* Removes and disposes of the entire contents of \a listbase using guardedalloc.
*/
void BLI_freelistN(ListBase *listbase) void BLI_freelistN(ListBase *listbase)
{ {
Link *link, *next; Link *link, *next;
@@ -558,11 +483,6 @@ void BLI_freelistN(ListBase *listbase)
BLI_listbase_clear(listbase); BLI_listbase_clear(listbase);
} }
/**
* Returns the number of elements in \a listbase, up until (and including count_max)
*
* \note Use to avoid redundant looping.
*/
int BLI_listbase_count_at_most(const ListBase *listbase, const int count_max) int BLI_listbase_count_at_most(const ListBase *listbase, const int count_max)
{ {
Link *link; Link *link;
@@ -575,9 +495,6 @@ int BLI_listbase_count_at_most(const ListBase *listbase, const int count_max)
return count; return count;
} }
/**
* Returns the number of elements in \a listbase.
*/
int BLI_listbase_count(const ListBase *listbase) int BLI_listbase_count(const ListBase *listbase)
{ {
Link *link; Link *link;
@@ -590,9 +507,6 @@ int BLI_listbase_count(const ListBase *listbase)
return count; return count;
} }
/**
* Returns the nth element of \a listbase, numbering from 0.
*/
void *BLI_findlink(const ListBase *listbase, int number) void *BLI_findlink(const ListBase *listbase, int number)
{ {
Link *link = NULL; Link *link = NULL;
@@ -608,9 +522,6 @@ void *BLI_findlink(const ListBase *listbase, int number)
return link; return link;
} }
/**
* Returns the nth-last element of \a listbase, numbering from 0.
*/
void *BLI_rfindlink(const ListBase *listbase, int number) void *BLI_rfindlink(const ListBase *listbase, int number)
{ {
Link *link = NULL; Link *link = NULL;
@@ -626,9 +537,6 @@ void *BLI_rfindlink(const ListBase *listbase, int number)
return link; return link;
} }
/**
* Returns the position of \a vlink within \a listbase, numbering from 0, or -1 if not found.
*/
int BLI_findindex(const ListBase *listbase, const void *vlink) int BLI_findindex(const ListBase *listbase, const void *vlink)
{ {
Link *link = NULL; Link *link = NULL;
@@ -651,10 +559,6 @@ int BLI_findindex(const ListBase *listbase, const void *vlink)
return -1; return -1;
} }
/**
* Finds the first element of \a listbase which contains the null-terminated
* string \a id at the specified offset, returning NULL if not found.
*/
void *BLI_findstring(const ListBase *listbase, const char *id, const int offset) void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
{ {
Link *link = NULL; Link *link = NULL;
@@ -674,13 +578,10 @@ void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
return NULL; return NULL;
} }
/* same as above but find reverse */
/**
* Finds the last element of \a listbase which contains the
* null-terminated string \a id at the specified offset, returning NULL if not found.
*/
void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset) void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset)
{ {
/* Same as #BLI_findstring but find reverse. */
Link *link = NULL; Link *link = NULL;
const char *id_iter; const char *id_iter;
@@ -695,10 +596,6 @@ void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset
return NULL; return NULL;
} }
/**
* Finds the first element of \a listbase which contains a pointer to the
* null-terminated string \a id at the specified offset, returning NULL if not found.
*/
void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int offset) void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int offset)
{ {
Link *link = NULL; Link *link = NULL;
@@ -715,13 +612,10 @@ void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int off
return NULL; return NULL;
} }
/* same as above but find reverse */
/**
* Finds the last element of \a listbase which contains a pointer to the
* null-terminated string \a id at the specified offset, returning NULL if not found.
*/
void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int offset) void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int offset)
{ {
/* Same as #BLI_findstring_ptr but find reverse. */
Link *link = NULL; Link *link = NULL;
const char *id_iter; const char *id_iter;
@@ -737,10 +631,6 @@ void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int of
return NULL; return NULL;
} }
/**
* Finds the first element of listbase which contains the specified pointer value
* at the specified offset, returning NULL if not found.
*/
void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset) void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
{ {
Link *link = NULL; Link *link = NULL;
@@ -757,13 +647,10 @@ void *BLI_findptr(const ListBase *listbase, const void *ptr, const int offset)
return NULL; return NULL;
} }
/* same as above but find reverse */
/**
* Finds the last element of listbase which contains the specified pointer value
* at the specified offset, returning NULL if not found.
*/
void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset) void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
{ {
/* Same as #BLI_findptr but find reverse. */
Link *link = NULL; Link *link = NULL;
const void *ptr_iter; const void *ptr_iter;
@@ -779,10 +666,6 @@ void *BLI_rfindptr(const ListBase *listbase, const void *ptr, const int offset)
return NULL; return NULL;
} }
/**
* Finds the first element of listbase which contains the specified bytes
* at the specified offset, returning NULL if not found.
*/
void *BLI_listbase_bytes_find(const ListBase *listbase, void *BLI_listbase_bytes_find(const ListBase *listbase,
const void *bytes, const void *bytes,
const size_t bytes_size, const size_t bytes_size,
@@ -801,16 +684,13 @@ void *BLI_listbase_bytes_find(const ListBase *listbase,
return NULL; return NULL;
} }
/* same as above but find reverse */
/**
* Finds the last element of listbase which contains the specified bytes
* at the specified offset, returning NULL if not found.
*/
void *BLI_listbase_bytes_rfind(const ListBase *listbase, void *BLI_listbase_bytes_rfind(const ListBase *listbase,
const void *bytes, const void *bytes,
const size_t bytes_size, const size_t bytes_size,
const int offset) const int offset)
{ {
/* Same as #BLI_listbase_bytes_find but find reverse. */
Link *link = NULL; Link *link = NULL;
const void *ptr_iter; const void *ptr_iter;
@@ -825,13 +705,6 @@ void *BLI_listbase_bytes_rfind(const ListBase *listbase,
return NULL; return NULL;
} }
/**
* Find the first item in the list that matches the given string, or the given index as fallback.
*
* \note The string is only used is non-NULL and non-empty.
*
* \return The found item, or NULL.
*/
void *BLI_listbase_string_or_index_find(const ListBase *listbase, void *BLI_listbase_string_or_index_find(const ListBase *listbase,
const char *string, const char *string,
const size_t string_offset, const size_t string_offset,
@@ -856,10 +729,6 @@ void *BLI_listbase_string_or_index_find(const ListBase *listbase,
return link_at_index; return link_at_index;
} }
/**
* Returns the 0-based index of the first element of listbase which contains the specified
* null-terminated string at the specified offset, or -1 if not found.
*/
int BLI_findstringindex(const ListBase *listbase, const char *id, const int offset) int BLI_findstringindex(const ListBase *listbase, const char *id, const int offset)
{ {
Link *link = NULL; Link *link = NULL;
@@ -880,9 +749,6 @@ int BLI_findstringindex(const ListBase *listbase, const char *id, const int offs
return -1; return -1;
} }
/**
* Sets dst to a duplicate of the entire contents of src. dst may be the same as src.
*/
void BLI_duplicatelist(ListBase *dst, const ListBase *src) void BLI_duplicatelist(ListBase *dst, const ListBase *src)
{ {
struct Link *dst_link, *src_link; struct Link *dst_link, *src_link;
@@ -918,9 +784,6 @@ void BLI_listbase_reverse(ListBase *lb)
lb->last = curr; lb->last = curr;
} }
/**
* \param vlink: Link to make first.
*/
void BLI_listbase_rotate_first(ListBase *lb, void *vlink) void BLI_listbase_rotate_first(ListBase *lb, void *vlink)
{ {
/* make circular */ /* make circular */
@@ -934,9 +797,6 @@ void BLI_listbase_rotate_first(ListBase *lb, void *vlink)
((Link *)lb->last)->next = NULL; ((Link *)lb->last)->next = NULL;
} }
/**
* \param vlink: Link to make last.
*/
void BLI_listbase_rotate_last(ListBase *lb, void *vlink) void BLI_listbase_rotate_last(ListBase *lb, void *vlink)
{ {
/* make circular */ /* make circular */
@@ -950,7 +810,6 @@ void BLI_listbase_rotate_last(ListBase *lb, void *vlink)
((Link *)lb->last)->next = NULL; ((Link *)lb->last)->next = NULL;
} }
/* create a generic list node containing link to provided data */
LinkData *BLI_genericNodeN(void *data) LinkData *BLI_genericNodeN(void *data)
{ {
LinkData *ld; LinkData *ld;

View File

@@ -42,10 +42,10 @@ int pow_i(int base, int exp)
return result; return result;
} }
/* from python 3.1 floatobject.c
* ndigits must be between 0 and 21 */
double double_round(double x, int ndigits) double double_round(double x, int ndigits)
{ {
/* From Python 3.1 `floatobject.c`. */
double pow1, pow2, y, z; double pow1, pow2, y, z;
if (ndigits >= 0) { if (ndigits >= 0) {
pow1 = pow(10.0, (double)ndigits); pow1 = pow(10.0, (double)ndigits);
@@ -79,15 +79,6 @@ double double_round(double x, int ndigits)
return z; return z;
} }
/**
* Floor to the nearest power of 10, e.g.:
* - 15.0 -> 10.0
* - 0.015 -> 0.01
* - 1.0 -> 1.0
*
* \param f: Value to floor, must be over 0.0.
* \note If we wanted to support signed values we could if this becomes necessary.
*/
float floor_power_of_10(float f) float floor_power_of_10(float f)
{ {
BLI_assert(!(f < 0.0f)); BLI_assert(!(f < 0.0f));
@@ -97,15 +88,6 @@ float floor_power_of_10(float f)
return 0.0f; return 0.0f;
} }
/**
* Ceiling to the nearest power of 10, e.g.:
* - 15.0 -> 100.0
* - 0.015 -> 0.1
* - 1.0 -> 1.0
*
* \param f: Value to ceiling, must be over 0.0.
* \note If we wanted to support signed values we could if this becomes necessary.
*/
float ceil_power_of_10(float f) float ceil_power_of_10(float f)
{ {
BLI_assert(!(f < 0.0f)); BLI_assert(!(f < 0.0f));

View File

@@ -45,7 +45,6 @@ extern "C" {
# define UNLIKELY(x) (x) # define UNLIKELY(x) (x)
#endif #endif
/* powf is really slow for raising to integer powers. */
MINLINE float pow2f(float x) MINLINE float pow2f(float x)
{ {
return x * x; return x * x;
@@ -192,21 +191,18 @@ MINLINE double ratiod(double min, double max, double pos)
return range == 0 ? 0 : ((pos - min) / range); return range == 0 ? 0 : ((pos - min) / range);
} }
/* Map a normalized value, i.e. from interval [0, 1] to interval [a, b]. */
MINLINE float scalenorm(float a, float b, float x) MINLINE float scalenorm(float a, float b, float x)
{ {
BLI_assert(x <= 1 && x >= 0); BLI_assert(x <= 1 && x >= 0);
return (x * (b - a)) + a; return (x * (b - a)) + a;
} }
/* Map a normalized value, i.e. from interval [0, 1] to interval [a, b]. */
MINLINE double scalenormd(double a, double b, double x) MINLINE double scalenormd(double a, double b, double x)
{ {
BLI_assert(x <= 1 && x >= 0); BLI_assert(x <= 1 && x >= 0);
return (x * (b - a)) + a; return (x * (b - a)) + a;
} }
/* Used for zoom values. */
MINLINE float power_of_2(float val) MINLINE float power_of_2(float val)
{ {
return (float)pow(2.0, ceil(log((double)val) / M_LN2)); return (float)pow(2.0, ceil(log((double)val) / M_LN2));
@@ -363,16 +359,11 @@ MINLINE signed char round_db_to_char_clamp(double a){
#undef _round_clamp_fl_impl #undef _round_clamp_fl_impl
#undef _round_clamp_db_impl #undef _round_clamp_db_impl
/**
* Round to closest even number, halfway cases are rounded away from zero.
*/
MINLINE float round_to_even(float f) MINLINE float round_to_even(float f)
{ {
return roundf(f * 0.5f) * 2.0f; return roundf(f * 0.5f) * 2.0f;
} }
/* integer division that rounds 0.5 up, particularly useful for color blending
* with integers, to avoid gradual darkening when rounding down */
MINLINE int divide_round_i(int a, int b) MINLINE int divide_round_i(int a, int b)
{ {
return (2 * a + b) / (2 * b); return (2 * a + b) / (2 * b);
@@ -397,9 +388,6 @@ MINLINE uint divide_ceil_u(uint a, uint b)
return (a + b - 1) / b; return (a + b - 1) / b;
} }
/**
* modulo that handles negative numbers, works the same as Python's.
*/
MINLINE int mod_i(int i, int n) MINLINE int mod_i(int i, int n)
{ {
return (i % n + n) % n; return (i % n + n) % n;
@@ -629,27 +617,11 @@ MINLINE size_t clamp_z(size_t value, size_t min, size_t max)
return min_zz(max_zz(value, min), max); return min_zz(max_zz(value, min), max);
} }
/**
* Almost-equal for IEEE floats, using absolute difference method.
*
* \param max_diff: the maximum absolute difference.
*/
MINLINE int compare_ff(float a, float b, const float max_diff) MINLINE int compare_ff(float a, float b, const float max_diff)
{ {
return fabsf(a - b) <= max_diff; return fabsf(a - b) <= max_diff;
} }
/**
* Almost-equal for IEEE floats, using their integer representation
* (mixing ULP and absolute difference methods).
*
* \param max_diff: is the maximum absolute difference (allows to take care of the near-zero area,
* where relative difference methods cannot really work).
* \param max_ulps: is the 'maximum number of floats + 1'
* allowed between \a a and \a b to consider them equal.
*
* \see https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
*/
MINLINE int compare_ff_relative(float a, float b, const float max_diff, const int max_ulps) MINLINE int compare_ff_relative(float a, float b, const float max_diff, const int max_ulps)
{ {
union { union {
@@ -728,19 +700,11 @@ MINLINE int signum_i(float a)
} }
} }
/**
* Returns number of (base ten) *significant* digits of integer part of given float
* (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
*/
MINLINE int integer_digits_f(const float f) MINLINE int integer_digits_f(const float f)
{ {
return (f == 0.0f) ? 0 : (int)floor(log10(fabs(f))) + 1; return (f == 0.0f) ? 0 : (int)floor(log10(fabs(f))) + 1;
} }
/**
* Returns number of (base ten) *significant* digits of integer part of given double
* (negative in case of decimal-only floats, 0.01 returns -1 e.g.).
*/
MINLINE int integer_digits_d(const double d) MINLINE int integer_digits_d(const double d)
{ {
return (d == 0.0) ? 0 : (int)floor(log10(fabs(d))) + 1; return (d == 0.0) ? 0 : (int)floor(log10(fabs(d))) + 1;

View File

@@ -33,10 +33,6 @@
namespace blender { namespace blender {
#ifdef WITH_GMP #ifdef WITH_GMP
/**
* Return +1 if a, b, c are in CCW order around a circle in the plane.
* Return -1 if they are in CW order, and 0 if they are in line.
*/
int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c) int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c)
{ {
mpq_class detleft = (a[0] - c[0]) * (b[1] - c[1]); mpq_class detleft = (a[0] - c[0]) * (b[1] - c[1]);
@@ -45,11 +41,6 @@ int orient2d(const mpq2 &a, const mpq2 &b, const mpq2 &c)
return sgn(det); return sgn(det);
} }
/**
Return +1 if d is in the oriented circle through a, b, and c.
* The oriented circle goes CCW through a, b, and c.
* Return -1 if d is outside, and 0 if it is on the circle.
*/
int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d) int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d)
{ {
mpq_class adx = a[0] - d[0]; mpq_class adx = a[0] - d[0];
@@ -76,12 +67,6 @@ int incircle(const mpq2 &a, const mpq2 &b, const mpq2 &c, const mpq2 &d)
return sgn(det); return sgn(det);
} }
/**
* Return +1 if d is below the plane containing a, b, c (which appear
* CCW when viewed from above the plane).
* Return -1 if d is above the plane.
* Return 0 if it is on the plane.
*/
int orient3d(const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &d) int orient3d(const mpq3 &a, const mpq3 &b, const mpq3 &c, const mpq3 &d)
{ {
mpq_class adx = a[0] - d[0]; mpq_class adx = a[0] - d[0];

View File

@@ -64,13 +64,11 @@ void hsl_to_rgb(float h, float s, float l, float *r_r, float *r_g, float *r_b)
*r_b = (nb - 0.5f) * chroma + l; *r_b = (nb - 0.5f) * chroma + l;
} }
/* convenience function for now */
void hsv_to_rgb_v(const float hsv[3], float r_rgb[3]) void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
{ {
hsv_to_rgb(hsv[0], hsv[1], hsv[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]); hsv_to_rgb(hsv[0], hsv[1], hsv[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]);
} }
/* convenience function for now */
void hsl_to_rgb_v(const float hsl[3], float r_rgb[3]) void hsl_to_rgb_v(const float hsl[3], float r_rgb[3])
{ {
hsl_to_rgb(hsl[0], hsl[1], hsl[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]); hsl_to_rgb(hsl[0], hsl[1], hsl[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]);
@@ -124,9 +122,6 @@ void yuv_to_rgb(float y, float u, float v, float *r_r, float *r_g, float *r_b, i
*r_b = b; *r_b = b;
} }
/* The RGB inputs are supposed gamma corrected and in the range 0 - 1.0f
*
* Output YCC have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr, int colorspace) void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr, int colorspace)
{ {
float sr, sg, sb; float sr, sg, sb;
@@ -162,12 +157,14 @@ void rgb_to_ycc(float r, float g, float b, float *r_y, float *r_cb, float *r_cr,
*r_cr = cr; *r_cr = cr;
} }
/* YCC input have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255 */
/* RGB outputs are in the range 0 - 1.0f */
/* FIXME comment above must be wrong because BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009 */
void ycc_to_rgb(float y, float cb, float cr, float *r_r, float *r_g, float *r_b, int colorspace) void ycc_to_rgb(float y, float cb, float cr, float *r_r, float *r_g, float *r_b, int colorspace)
{ {
/* FIXME the following comment must be wrong because:
* BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009. */
/* YCC input have a range of 16-235 and 16-240 except with JFIF_0_255 where the range is 0-255
* RGB outputs are in the range 0 - 1.0f. */
float r = 128.0f, g = 128.0f, b = 128.0f; float r = 128.0f, g = 128.0f, b = 128.0f;
switch (colorspace) { switch (colorspace) {
@@ -250,7 +247,6 @@ void rgb_to_hsv(float r, float g, float b, float *r_h, float *r_s, float *r_v)
*r_v = r; *r_v = r;
} }
/* convenience function for now */
void rgb_to_hsv_v(const float rgb[3], float r_hsv[3]) void rgb_to_hsv_v(const float rgb[3], float r_hsv[3])
{ {
rgb_to_hsv(rgb[0], rgb[1], rgb[2], &r_hsv[0], &r_hsv[1], &r_hsv[2]); rgb_to_hsv(rgb[0], rgb[1], rgb[2], &r_hsv[0], &r_hsv[1], &r_hsv[2]);
@@ -311,7 +307,6 @@ void rgb_to_hsl_compat_v(const float rgb[3], float r_hsl[3])
rgb_to_hsl_compat(rgb[0], rgb[1], rgb[2], &r_hsl[0], &r_hsl[1], &r_hsl[2]); rgb_to_hsl_compat(rgb[0], rgb[1], rgb[2], &r_hsl[0], &r_hsl[1], &r_hsl[2]);
} }
/* convenience function for now */
void rgb_to_hsl_v(const float rgb[3], float r_hsl[3]) void rgb_to_hsl_v(const float rgb[3], float r_hsl[3])
{ {
rgb_to_hsl(rgb[0], rgb[1], rgb[2], &r_hsl[0], &r_hsl[1], &r_hsl[2]); rgb_to_hsl(rgb[0], rgb[1], rgb[2], &r_hsl[0], &r_hsl[1], &r_hsl[2]);
@@ -338,13 +333,11 @@ void rgb_to_hsv_compat(float r, float g, float b, float *r_h, float *r_s, float
} }
} }
/* convenience function for now */
void rgb_to_hsv_compat_v(const float rgb[3], float r_hsv[3]) void rgb_to_hsv_compat_v(const float rgb[3], float r_hsv[3])
{ {
rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], &r_hsv[0], &r_hsv[1], &r_hsv[2]); rgb_to_hsv_compat(rgb[0], rgb[1], rgb[2], &r_hsv[0], &r_hsv[1], &r_hsv[2]);
} }
/* clamp hsv to usable values */
void hsv_clamp_v(float hsv[3], float v_max) void hsv_clamp_v(float hsv[3], float v_max)
{ {
if (UNLIKELY(hsv[0] < 0.0f || hsv[0] > 1.0f)) { if (UNLIKELY(hsv[0] < 0.0f || hsv[0] > 1.0f)) {
@@ -354,12 +347,6 @@ void hsv_clamp_v(float hsv[3], float v_max)
CLAMP(hsv[2], 0.0f, v_max); CLAMP(hsv[2], 0.0f, v_max);
} }
/**
* We define a 'cpack' here as a (3 byte color code)
* number that can be expressed like 0xFFAA66 or so.
* For that reason it is sensitive for endianness... with this function it works correctly.
* \see #imm_cpack
*/
unsigned int hsv_to_cpack(float h, float s, float v) unsigned int hsv_to_cpack(float h, float s, float v)
{ {
unsigned int r, g, b; unsigned int r, g, b;
@@ -473,12 +460,6 @@ void minmax_rgb(short c[3])
} }
} }
/* If the requested RGB shade contains a negative weight for
* one of the primaries, it lies outside the color gamut
* accessible from the given triple of primaries. Desaturate
* it by adding white, equal quantities of R, G, and B, enough
* to make RGB all positive. The function returns 1 if the
* components were modified, zero otherwise. */
int constrain_rgb(float *r, float *g, float *b) int constrain_rgb(float *r, float *g, float *b)
{ {
/* Amount of white needed */ /* Amount of white needed */
@@ -520,7 +501,6 @@ void lift_gamma_gain_to_asc_cdl(const float *lift,
/* ************************************* other ************************************************* */ /* ************************************* other ************************************************* */
/* Applies an hue offset to a float rgb color */
void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset) void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset)
{ {
float hsv[3]; float hsv[3];
@@ -538,7 +518,6 @@ void rgb_float_set_hue_float_offset(float rgb[3], float hue_offset)
hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb + 1, rgb + 2); hsv_to_rgb(hsv[0], hsv[1], hsv[2], rgb, rgb + 1, rgb + 2);
} }
/* Applies an hue offset to a byte rgb color */
void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset) void rgb_byte_set_hue_float_offset(unsigned char rgb[3], float hue_offset)
{ {
float rgb_float[3]; float rgb_float[3];

View File

@@ -271,20 +271,6 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack)
* *
* \{ */ * \{ */
/**
* ITU-R BT.709 primaries
* https://en.wikipedia.org/wiki/Relative_luminance
*
* Real values are:
* `Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`
* according to: "Derivation of Basic Television Color Equations", RP 177-1993
*
* As this sums slightly above 1.0, the document recommends to use:
* `0.2126(R) + 0.7152(G) + 0.0722(B)`, as used here.
*
* The high precision values are used to calculate the rounded byte weights so they add up to 255:
* `54(R) + 182(G) + 19(B)`
*/
MINLINE float rgb_to_grayscale(const float rgb[3]) MINLINE float rgb_to_grayscale(const float rgb[3])
{ {
return (0.2126f * rgb[0]) + (0.7152f * rgb[1]) + (0.0722f * rgb[2]); return (0.2126f * rgb[0]) + (0.7152f * rgb[1]) + (0.0722f * rgb[2]);
@@ -317,11 +303,11 @@ MINLINE int compare_rgb_uchar(const unsigned char col_a[3],
return 0; return 0;
} }
/* Using a triangle distribution which gives a more final uniform noise.
* See Banding in Games:A Noisy Rant(revision 5) Mikkel Gjøl, Playdead (slide 27) */
/* Return triangle noise in [-0.5..1.5[ range */
MINLINE float dither_random_value(float s, float t) MINLINE float dither_random_value(float s, float t)
{ {
/* Using a triangle distribution which gives a more final uniform noise.
* See Banding in Games:A Noisy Rant(revision 5) Mikkel Gjøl, Playdead (slide 27) */
/* Uniform noise in [0..1[ range, using common GLSL hash function. /* Uniform noise in [0..1[ range, using common GLSL hash function.
* https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner. */ * https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner. */
float hash0 = sinf(s * 12.9898f + t * 78.233f) * 43758.5453f; float hash0 = sinf(s * 12.9898f + t * 78.233f) * 43758.5453f;

View File

@@ -86,11 +86,6 @@ float normal_quad_v3(
return normalize_v3(n); return normalize_v3(n);
} }
/**
* Computes the normal of a planar
* polygon See Graphics Gems for
* computing newell normal.
*/
float normal_poly_v3(float n[3], const float verts[][3], unsigned int nr) float normal_poly_v3(float n[3], const float verts[][3], unsigned int nr)
{ {
cross_poly_v3(n, verts, nr); cross_poly_v3(n, verts, nr);
@@ -112,7 +107,6 @@ float area_squared_quad_v3(const float v1[3],
return area_squared_poly_v3(verts, 4); return area_squared_poly_v3(verts, 4);
} }
/* Triangles */
float area_tri_v3(const float v1[3], const float v2[3], const float v3[3]) float area_tri_v3(const float v1[3], const float v2[3], const float v3[3])
{ {
float n[3]; float n[3];
@@ -162,12 +156,6 @@ float area_squared_poly_v3(const float verts[][3], unsigned int nr)
return len_squared_v3(n); return len_squared_v3(n);
} }
/**
* Scalar cross product of a 2d polygon.
*
* - equivalent to `area * 2`
* - useful for checking polygon winding (a positive value is clockwise).
*/
float cross_poly_v2(const float verts[][2], unsigned int nr) float cross_poly_v2(const float verts[][2], unsigned int nr)
{ {
unsigned int a; unsigned int a;
@@ -236,28 +224,18 @@ float cotangent_tri_weight_v3(const float v1[3], const float v2[3], const float
/********************************* Planes **********************************/ /********************************* Planes **********************************/
/**
* Calculate a plane from a point and a direction,
* \note \a point_no isn't required to be normalized.
*/
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3]) void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
{ {
copy_v3_v3(r_plane, plane_no); copy_v3_v3(r_plane, plane_no);
r_plane[3] = -dot_v3v3(r_plane, plane_co); r_plane[3] = -dot_v3v3(r_plane, plane_co);
} }
/**
* Get a point and a direction from a plane.
*/
void plane_to_point_vector_v3(const float plane[4], float r_plane_co[3], float r_plane_no[3]) void plane_to_point_vector_v3(const float plane[4], float r_plane_co[3], float r_plane_no[3])
{ {
mul_v3_v3fl(r_plane_co, plane, (-plane[3] / len_squared_v3(plane))); mul_v3_v3fl(r_plane_co, plane, (-plane[3] / len_squared_v3(plane)));
copy_v3_v3(r_plane_no, plane); copy_v3_v3(r_plane_no, plane);
} }
/**
* version of #plane_to_point_vector_v3 that gets a unit length vector.
*/
void plane_to_point_vector_v3_normalized(const float plane[4], void plane_to_point_vector_v3_normalized(const float plane[4],
float r_plane_co[3], float r_plane_co[3],
float r_plane_no[3]) float r_plane_no[3])
@@ -268,9 +246,6 @@ void plane_to_point_vector_v3_normalized(const float plane[4],
/********************************* Volume **********************************/ /********************************* Volume **********************************/
/**
* The volume from a tetrahedron, points can be in any order
*/
float volume_tetrahedron_v3(const float v1[3], float volume_tetrahedron_v3(const float v1[3],
const float v2[3], const float v2[3],
const float v3[3], const float v3[3],
@@ -283,9 +258,6 @@ float volume_tetrahedron_v3(const float v1[3],
return fabsf(determinant_m3_array(m)) / 6.0f; return fabsf(determinant_m3_array(m)) / 6.0f;
} }
/**
* The volume from a tetrahedron, normal pointing inside gives negative volume
*/
float volume_tetrahedron_signed_v3(const float v1[3], float volume_tetrahedron_signed_v3(const float v1[3],
const float v2[3], const float v2[3],
const float v3[3], const float v3[3],
@@ -298,12 +270,6 @@ float volume_tetrahedron_signed_v3(const float v1[3],
return determinant_m3_array(m) / 6.0f; return determinant_m3_array(m) / 6.0f;
} }
/**
* The volume from a triangle that is made into a tetrahedron.
* This uses a simplified formula where the tip of the tetrahedron is in the world origin.
* Using this method, the total volume of a closed triangle mesh can be calculated.
* Note that you need to divide the result by 6 to get the actual volume.
*/
float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3]) float volume_tri_tetrahedron_signed_v3_6x(const float v1[3], const float v2[3], const float v3[3])
{ {
float v_cross[3]; float v_cross[3];
@@ -319,8 +285,6 @@ float volume_tri_tetrahedron_signed_v3(const float v1[3], const float v2[3], con
/********************************* Distance **********************************/ /********************************* Distance **********************************/
/* distance p to line v1-v2
* using Hesse formula, NO LINE PIECE! */
float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2]) float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2])
{ {
float closest[2]; float closest[2];
@@ -334,7 +298,6 @@ float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2])
return sqrtf(dist_squared_to_line_v2(p, l1, l2)); return sqrtf(dist_squared_to_line_v2(p, l1, l2));
} }
/* distance p to line-piece v1-v2 */
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2]) float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
{ {
float closest[2]; float closest[2];
@@ -349,7 +312,6 @@ float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l
return sqrtf(dist_squared_to_line_segment_v2(p, l1, l2)); return sqrtf(dist_squared_to_line_segment_v2(p, l1, l2));
} }
/* point closest to v1 on line v2-v3 in 2D */
void closest_to_line_segment_v2(float r_close[2], void closest_to_line_segment_v2(float r_close[2],
const float p[2], const float p[2],
const float l1[2], const float l1[2],
@@ -371,7 +333,6 @@ void closest_to_line_segment_v2(float r_close[2],
} }
} }
/* point closest to v1 on line v2-v3 in 3D */
void closest_to_line_segment_v3(float r_close[3], void closest_to_line_segment_v3(float r_close[3],
const float p[3], const float p[3],
const float l1[3], const float l1[3],
@@ -393,15 +354,6 @@ void closest_to_line_segment_v3(float r_close[3],
} }
} }
/**
* Find the closest point on a plane.
*
* \param r_close: Return coordinate
* \param plane: The plane to test against.
* \param pt: The point to find the nearest of
*
* \note non-unit-length planes are supported.
*/
void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3]) void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[3])
{ {
const float len_sq = len_squared_v3(plane); const float len_sq = len_squared_v3(plane);
@@ -462,9 +414,6 @@ float dist_squared_to_plane3_v3(const float pt[3], const float plane[3])
return len_sq * (fac * fac); return len_sq * (fac * fac);
} }
/**
* Return the signed distance from the point to the plane.
*/
float dist_signed_to_plane_v3(const float pt[3], const float plane[4]) float dist_signed_to_plane_v3(const float pt[3], const float plane[4])
{ {
const float len_sq = len_squared_v3(plane); const float len_sq = len_squared_v3(plane);
@@ -489,7 +438,6 @@ float dist_to_plane3_v3(const float pt[3], const float plane[3])
return fabsf(dist_signed_to_plane3_v3(pt, plane)); return fabsf(dist_signed_to_plane3_v3(pt, plane));
} }
/* distance v1 to line-piece l1-l2 in 3D */
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3]) float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
{ {
float closest[3]; float closest[3];
@@ -517,29 +465,6 @@ float dist_to_line_v3(const float p[3], const float l1[3], const float l2[3])
return sqrtf(dist_squared_to_line_v3(p, l1, l2)); return sqrtf(dist_squared_to_line_v3(p, l1, l2));
} }
/**
* Check if \a p is inside the 2x planes defined by `(v1, v2, v3)`
* where the 3x points define 2x planes.
*
* \param axis_ref: used when v1,v2,v3 form a line and to check if the corner is concave/convex.
*
* \note the distance from \a v1 & \a v3 to \a v2 doesn't matter
* (it just defines the planes).
*
* \return the lowest squared distance to either of the planes.
* where `(return < 0.0)` is outside.
*
* <pre>
* v1
* +
* /
* x - out / x - inside
* /
* +----+
* v2 v3
* x - also outside
* </pre>
*/
float dist_signed_squared_to_corner_v3v3v3(const float p[3], float dist_signed_squared_to_corner_v3v3v3(const float p[3],
const float v1[3], const float v1[3],
const float v2[3], const float v2[3],
@@ -591,12 +516,6 @@ float dist_signed_squared_to_corner_v3v3v3(const float p[3],
return max_ff(dist_a, dist_b); return max_ff(dist_a, dist_b);
} }
/**
* Compute the squared distance of a point to a line (defined as ray).
* \param ray_origin: A point on the line.
* \param ray_direction: Normalized direction of the line.
* \param co: Point to which the distance is to be calculated.
*/
float dist_squared_to_ray_v3_normalized(const float ray_origin[3], float dist_squared_to_ray_v3_normalized(const float ray_origin[3],
const float ray_direction[3], const float ray_direction[3],
const float co[3]) const float co[3])
@@ -613,12 +532,6 @@ float dist_squared_to_ray_v3_normalized(const float ray_origin[3],
return len_squared_v3v3(co, co_projected_on_ray); return len_squared_v3v3(co, co_projected_on_ray);
} }
/**
* Find the closest point in a seg to a ray and return the distance squared.
* \param r_point: Is the point on segment closest to ray
* (or to ray_origin if the ray and the segment are parallel).
* \param r_depth: the distance of r_point projection on ray to the ray_origin.
*/
float dist_squared_ray_to_seg_v3(const float ray_origin[3], float dist_squared_ray_to_seg_v3(const float ray_origin[3],
const float ray_direction[3], const float ray_direction[3],
const float v0[3], const float v0[3],
@@ -655,8 +568,6 @@ float dist_squared_ray_to_seg_v3(const float ray_origin[3],
return len_squared_v3(dvec) - square_f(depth); return len_squared_v3(dvec) - square_f(depth);
} }
/* Returns the coordinates of the nearest vertex and
* the farthest vertex from a plane (or normal). */
void aabb_get_near_far_from_plane(const float plane_no[3], void aabb_get_near_far_from_plane(const float plane_no[3],
const float bbmin[3], const float bbmin[3],
const float bbmax[3], const float bbmax[3],
@@ -707,9 +618,6 @@ void dist_squared_ray_to_aabb_v3_precalc(struct DistRayAABB_Precalc *neasrest_pr
} }
} }
/**
* Returns the distance from a ray to a bound-box (projected on ray)
*/
float dist_squared_ray_to_aabb_v3(const struct DistRayAABB_Precalc *data, float dist_squared_ray_to_aabb_v3(const struct DistRayAABB_Precalc *data,
const float bb_min[3], const float bb_min[3],
const float bb_max[3], const float bb_max[3],
@@ -816,10 +724,6 @@ float dist_squared_ray_to_aabb_v3_simple(const float ray_origin[3],
/** \name dist_squared_to_projected_aabb and helpers /** \name dist_squared_to_projected_aabb and helpers
* \{ */ * \{ */
/**
* \param projmat: Projection Matrix (usually perspective
* matrix multiplied by object matrix).
*/
void dist_squared_to_projected_aabb_precalc(struct DistProjectedAABBPrecalc *precalc, void dist_squared_to_projected_aabb_precalc(struct DistProjectedAABBPrecalc *precalc,
const float projmat[4][4], const float projmat[4][4],
const float winsize[2], const float winsize[2],
@@ -871,7 +775,6 @@ void dist_squared_to_projected_aabb_precalc(struct DistProjectedAABBPrecalc *pre
} }
} }
/* Returns the distance from a 2d coordinate to a BoundBox (Projected) */
float dist_squared_to_projected_aabb(struct DistProjectedAABBPrecalc *data, float dist_squared_to_projected_aabb(struct DistProjectedAABBPrecalc *data,
const float bbmin[3], const float bbmin[3],
const float bbmax[3], const float bbmax[3],
@@ -1016,13 +919,12 @@ float dist_squared_to_projected_aabb_simple(const float projmat[4][4],
} }
/** \} */ /** \} */
/* Adapted from "Real-Time Collision Detection" by Christer Ericson,
* published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc.
*
* Set 'r' to the point in triangle (a, b, c) closest to point 'p' */
void closest_on_tri_to_point_v3( void closest_on_tri_to_point_v3(
float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3]) float r[3], const float p[3], const float v1[3], const float v2[3], const float v3[3])
{ {
/* Adapted from "Real-Time Collision Detection" by Christer Ericson,
* published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc. */
float ab[3], ac[3], ap[3], d1, d2; float ab[3], ac[3], ap[3], d1, d2;
float bp[3], d3, d4, vc, cp[3], d5, d6, vb, va; float bp[3], d3, d4, vc, cp[3], d5, d6, vb, va;
float denom, v, w; float denom, v, w;
@@ -1100,7 +1002,6 @@ void closest_on_tri_to_point_v3(
/******************************* Intersection ********************************/ /******************************* Intersection ********************************/
/* intersect Line-Line, shorts */
int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2]) int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2])
{ {
float div, lambda, mu; float div, lambda, mu;
@@ -1123,7 +1024,6 @@ int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], cons
return ISECT_LINE_LINE_NONE; return ISECT_LINE_LINE_NONE;
} }
/* intersect Line-Line, floats - gives intersection point */
int isect_line_line_v2_point( int isect_line_line_v2_point(
const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2]) const float v0[2], const float v1[2], const float v2[2], const float v3[2], float r_vi[2])
{ {
@@ -1147,7 +1047,6 @@ int isect_line_line_v2_point(
return ISECT_LINE_LINE_COLINEAR; return ISECT_LINE_LINE_COLINEAR;
} }
/* intersect Line-Line, floats */
int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]) int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
{ {
float div, lambda, mu; float div, lambda, mu;
@@ -1170,7 +1069,6 @@ int isect_seg_seg_v2(const float v1[2], const float v2[2], const float v3[2], co
return ISECT_LINE_LINE_NONE; return ISECT_LINE_LINE_NONE;
} }
/* Returns a point on each segment that is closest to the other. */
void isect_seg_seg_v3(const float a0[3], void isect_seg_seg_v3(const float a0[3],
const float a1[3], const float a1[3],
const float b0[3], const float b0[3],
@@ -1236,19 +1134,6 @@ void isect_seg_seg_v3(const float a0[3],
madd_v3_v3v3fl(r_b, b0, b_dir, fac_b); madd_v3_v3v3fl(r_b, b0, b_dir, fac_b);
} }
/**
* Get intersection point of two 2D segments.
*
* \param endpoint_bias: Bias to use when testing for end-point overlap.
* A positive value considers intersections that extend past the endpoints,
* negative values contract the endpoints.
* Note the bias is applied to a 0-1 factor, not scaled to the length of segments.
*
* \returns intersection type:
* - -1: collinear.
* - 1: intersection.
* - 0: no intersection.
*/
int isect_seg_seg_v2_point_ex(const float v0[2], int isect_seg_seg_v2_point_ex(const float v0[2],
const float v1[2], const float v1[2],
const float v2[2], const float v2[2],
@@ -1369,18 +1254,6 @@ bool isect_seg_seg_v2_simple(const float v1[2],
#undef CCW #undef CCW
} }
/**
* If intersection == ISECT_LINE_LINE_CROSS or ISECT_LINE_LINE_NONE:
* <pre>
* pt = v1 + lambda * (v2 - v1) = v3 + mu * (v4 - v3)
* </pre>
* \returns intersection type:
* - ISECT_LINE_LINE_COLINEAR: collinear.
* - ISECT_LINE_LINE_EXACT: intersection at an endpoint of either.
* - ISECT_LINE_LINE_CROSS: interaction, not at an endpoint.
* - ISECT_LINE_LINE_NONE: no intersection.
* Also returns lambda and mu in r_lambda and r_mu.
*/
int isect_seg_seg_v2_lambda_mu_db(const double v1[2], int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
const double v2[2], const double v2[2],
const double v3[2], const double v3[2],
@@ -1415,19 +1288,6 @@ int isect_seg_seg_v2_lambda_mu_db(const double v1[2],
return ISECT_LINE_LINE_NONE; return ISECT_LINE_LINE_NONE;
} }
/**
* \param l1, l2: Coordinates (point of line).
* \param sp, r: Coordinate and radius (sphere).
* \return r_p1, r_p2: Intersection coordinates.
*
* \note The order of assignment for intersection points (\a r_p1, \a r_p2) is predictable,
* based on the direction defined by `l2 - l1`,
* this direction compared with the normal of each point on the sphere:
* \a r_p1 always has a >= 0.0 dot product.
* \a r_p2 always has a <= 0.0 dot product.
* For example, when \a l1 is inside the sphere and \a l2 is outside,
* \a r_p1 will always be between \a l1 and \a l2.
*/
int isect_line_sphere_v3(const float l1[3], int isect_line_sphere_v3(const float l1[3],
const float l2[3], const float l2[3],
const float sp[3], const float sp[3],
@@ -1490,7 +1350,6 @@ int isect_line_sphere_v3(const float l1[3],
return -1; return -1;
} }
/* keep in sync with isect_line_sphere_v3 */
int isect_line_sphere_v2(const float l1[2], int isect_line_sphere_v2(const float l1[2],
const float l2[2], const float l2[2],
const float sp[2], const float sp[2],
@@ -1498,6 +1357,8 @@ int isect_line_sphere_v2(const float l1[2],
float r_p1[2], float r_p1[2],
float r_p2[2]) float r_p2[2])
{ {
/* Keep in sync with #isect_line_sphere_v3. */
const float ldir[2] = {l2[0] - l1[0], l2[1] - l1[1]}; const float ldir[2] = {l2[0] - l1[0], l2[1] - l1[1]};
const float a = dot_v2v2(ldir, ldir); const float a = dot_v2v2(ldir, ldir);
@@ -1537,12 +1398,13 @@ int isect_line_sphere_v2(const float l1[2],
return -1; return -1;
} }
/* point in polygon (keep float and int versions in sync) */
bool isect_point_poly_v2(const float pt[2], bool isect_point_poly_v2(const float pt[2],
const float verts[][2], const float verts[][2],
const unsigned int nr, const unsigned int nr,
const bool UNUSED(use_holes)) const bool UNUSED(use_holes))
{ {
/* Keep in sync with #isect_point_poly_v2_int. */
unsigned int i, j; unsigned int i, j;
bool isect = false; bool isect = false;
for (i = 0, j = nr - 1; i < nr; j = i++) { for (i = 0, j = nr - 1; i < nr; j = i++) {
@@ -1560,6 +1422,8 @@ bool isect_point_poly_v2_int(const int pt[2],
const unsigned int nr, const unsigned int nr,
const bool UNUSED(use_holes)) const bool UNUSED(use_holes))
{ {
/* Keep in sync with #isect_point_poly_v2. */
unsigned int i, j; unsigned int i, j;
bool isect = false; bool isect = false;
for (i = 0, j = nr - 1; i < nr; j = i++) { for (i = 0, j = nr - 1; i < nr; j = i++) {
@@ -1575,7 +1439,6 @@ bool isect_point_poly_v2_int(const int pt[2],
/* point in tri */ /* point in tri */
/* only single direction */
bool isect_point_tri_v2_cw(const float pt[2], bool isect_point_tri_v2_cw(const float pt[2],
const float v1[2], const float v1[2],
const float v2[2], const float v2[2],
@@ -1612,7 +1475,6 @@ int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2],
return 0; return 0;
} }
/* point in quad - only convex quads */
int isect_point_quad_v2( int isect_point_quad_v2(
const float pt[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2]) const float pt[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2])
{ {
@@ -1638,10 +1500,6 @@ int isect_point_quad_v2(
return 0; return 0;
} }
/* moved from effect.c
* test if the line starting at p1 ending at p2 intersects the triangle v0..v2
* return non zero if it does
*/
bool isect_line_segment_tri_v3(const float p1[3], bool isect_line_segment_tri_v3(const float p1[3],
const float p2[3], const float p2[3],
const float v0[3], const float v0[3],
@@ -1692,7 +1550,6 @@ bool isect_line_segment_tri_v3(const float p1[3],
return true; return true;
} }
/* like isect_line_segment_tri_v3, but allows epsilon tolerance around triangle */
bool isect_line_segment_tri_epsilon_v3(const float p1[3], bool isect_line_segment_tri_epsilon_v3(const float p1[3],
const float p2[3], const float p2[3],
const float v0[3], const float v0[3],
@@ -1744,10 +1601,6 @@ bool isect_line_segment_tri_epsilon_v3(const float p1[3],
return true; return true;
} }
/* moved from effect.c
* test if the ray starting at p1 going in d direction intersects the triangle v0..v2
* return non zero if it does
*/
bool isect_ray_tri_v3(const float ray_origin[3], bool isect_ray_tri_v3(const float ray_origin[3],
const float ray_direction[3], const float ray_direction[3],
const float v0[3], const float v0[3],
@@ -1799,12 +1652,6 @@ bool isect_ray_tri_v3(const float ray_origin[3],
return true; return true;
} }
/**
* if clip is nonzero, will only return true if lambda is >= 0.0
* (i.e. intersection point is along positive \a ray_direction)
*
* \note #line_plane_factor_v3() shares logic.
*/
bool isect_ray_plane_v3(const float ray_origin[3], bool isect_ray_plane_v3(const float ray_origin[3],
const float ray_direction[3], const float ray_direction[3],
const float plane[4], const float plane[4],
@@ -2146,9 +1993,6 @@ bool isect_ray_line_v3(const float ray_origin[3],
return true; return true;
} }
/**
* Check if a point is behind all planes.
*/
bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3]) bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3])
{ {
int i; int i;
@@ -2162,10 +2006,6 @@ bool isect_point_planes_v3(float (*planes)[4], int totplane, const float p[3])
return true; return true;
} }
/**
* Check if a point is in front all planes.
* Same as isect_point_planes_v3 but with planes facing the opposite direction.
*/
bool isect_point_planes_v3_negated(const float (*planes)[4], const int totplane, const float p[3]) bool isect_point_planes_v3_negated(const float (*planes)[4], const int totplane, const float p[3])
{ {
for (int i = 0; i < totplane; i++) { for (int i = 0; i < totplane; i++) {
@@ -2177,17 +2017,6 @@ bool isect_point_planes_v3_negated(const float (*planes)[4], const int totplane,
return true; return true;
} }
/**
* Intersect line/plane.
*
* \param r_isect_co: The intersection point.
* \param l1: The first point of the line.
* \param l2: The second point of the line.
* \param plane_co: A point on the plane to intersect with.
* \param plane_no: The direction of the plane (does not need to be normalized).
*
* \note #line_plane_factor_v3() shares logic.
*/
bool isect_line_plane_v3(float r_isect_co[3], bool isect_line_plane_v3(float r_isect_co[3],
const float l1[3], const float l1[3],
const float l2[3], const float l2[3],
@@ -2211,13 +2040,6 @@ bool isect_line_plane_v3(float r_isect_co[3],
return false; return false;
} }
/**
* Intersect three planes, return the point where all 3 meet.
* See Graphics Gems 1 pg 305
*
* \param plane_a, plane_b, plane_c: Planes.
* \param r_isect_co: The resulting intersection point.
*/
bool isect_plane_plane_plane_v3(const float plane_a[4], bool isect_plane_plane_plane_v3(const float plane_a[4],
const float plane_b[4], const float plane_b[4],
const float plane_c[4], const float plane_c[4],
@@ -2251,17 +2073,6 @@ bool isect_plane_plane_plane_v3(const float plane_a[4],
return false; return false;
} }
/**
* Intersect two planes, return a point on the intersection and a vector
* that runs on the direction of the intersection.
* \note this is a slightly reduced version of #isect_plane_plane_plane_v3
*
* \param plane_a, plane_b: Planes.
* \param r_isect_co: The resulting intersection point.
* \param r_isect_no: The resulting vector of the intersection.
*
* \note \a r_isect_no isn't unit length.
*/
bool isect_plane_plane_v3(const float plane_a[4], bool isect_plane_plane_v3(const float plane_a[4],
const float plane_b[4], const float plane_b[4],
float r_isect_co[3], float r_isect_co[3],
@@ -2296,19 +2107,6 @@ bool isect_plane_plane_v3(const float plane_a[4],
return false; return false;
} }
/**
* Intersect all planes, calling `callback_fn` for each point that intersects
* 3 of the planes that isn't outside any of the other planes.
*
* This can be thought of as calculating a convex-hull from an array of planes.
*
* \param eps_coplanar: Epsilon for testing if two planes are aligned (co-planar).
* \param eps_isect: Epsilon for testing of a point is behind any of the planes.
*
* \warning As complexity is a little under `O(N^3)`, this is only suitable for small arrays.
*
* \note This function could be optimized by some spatial structure.
*/
bool isect_planes_v3_fn( bool isect_planes_v3_fn(
const float planes[][4], const float planes[][4],
const int planes_len, const int planes_len,
@@ -2371,16 +2169,6 @@ bool isect_planes_v3_fn(
return found; return found;
} }
/**
* Intersect two triangles.
*
* \param r_i1, r_i2: Retrieve the overlapping edge between the 2 triangles.
* \param r_tri_a_edge_isect_count: Indicates how many edges in the first triangle are intersected.
* \return true when the triangles intersect.
*
* \note If it exists, \a r_i1 will be a point on the edge of the 1st triangle.
* \note intersections between coplanar triangles are currently undetected.
*/
bool isect_tri_tri_v3_ex(const float tri_a[3][3], bool isect_tri_tri_v3_ex(const float tri_a[3][3],
const float tri_b[3][3], const float tri_b[3][3],
float r_i1[3], float r_i1[3],
@@ -2755,14 +2543,6 @@ static bool getLowestRoot(
return false; return false;
} }
/**
* Checks status of an AABB in relation to a list of planes.
*
* \returns intersection type:
* - ISECT_AABB_PLANE_BEHIND_ONE (0): AABB is completely behind at least 1 plane;
* - ISECT_AABB_PLANE_CROSS_ANY (1): AABB intersects at least 1 plane;
* - ISECT_AABB_PLANE_IN_FRONT_ALL (2): AABB is completely in front of all planes;
*/
int isect_aabb_planes_v3(const float (*planes)[4], int isect_aabb_planes_v3(const float (*planes)[4],
const int totplane, const int totplane,
const float bbmin[3], const float bbmin[3],
@@ -3030,12 +2810,6 @@ bool isect_axial_line_segment_tri_v3(const int axis,
return true; return true;
} }
/**
* \return The number of point of interests
* 0 - lines are collinear
* 1 - lines are coplanar, i1 is set to intersection
* 2 - i1 and i2 are the nearest points on line 1 (v1, v2) and line 2 (v3, v4) respectively
*/
int isect_line_line_epsilon_v3(const float v1[3], int isect_line_line_epsilon_v3(const float v1[3],
const float v2[3], const float v2[3],
const float v3[3], const float v3[3],
@@ -3111,10 +2885,6 @@ int isect_line_line_v3(const float v1[3],
return isect_line_line_epsilon_v3(v1, v2, v3, v4, r_i1, r_i2, epsilon); return isect_line_line_epsilon_v3(v1, v2, v3, v4, r_i1, r_i2, epsilon);
} }
/**
* Intersection point strictly between the two lines
* \return false when no intersection is found.
*/
bool isect_line_line_strict_v3(const float v1[3], bool isect_line_line_strict_v3(const float v1[3],
const float v2[3], const float v2[3],
const float v3[3], const float v3[3],
@@ -3165,12 +2935,6 @@ bool isect_line_line_strict_v3(const float v1[3],
return false; return false;
} }
/**
* Check if two rays are not parallel and returns a factor that indicates
* the distance from \a ray_origin_b to the closest point on ray-a to ray-b.
*
* \note Neither directions need to be normalized.
*/
bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3], bool isect_ray_ray_epsilon_v3(const float ray_origin_a[3],
const float ray_direction_a[3], const float ray_direction_a[3],
const float ray_origin_b[3], const float ray_origin_b[3],
@@ -3247,12 +3011,13 @@ void isect_ray_aabb_v3_precalc(struct IsectRayAABB_Precalc *data,
data->sign[2] = data->ray_inv_dir[2] < 0.0f; data->sign[2] = data->ray_inv_dir[2] < 0.0f;
} }
/* Adapted from http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */
bool isect_ray_aabb_v3(const struct IsectRayAABB_Precalc *data, bool isect_ray_aabb_v3(const struct IsectRayAABB_Precalc *data,
const float bb_min[3], const float bb_min[3],
const float bb_max[3], const float bb_max[3],
float *tmin_out) float *tmin_out)
{ {
/* Adapted from http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */
float bbox[2][3]; float bbox[2][3];
copy_v3_v3(bbox[0], bb_min); copy_v3_v3(bbox[0], bb_min);
@@ -3298,13 +3063,6 @@ bool isect_ray_aabb_v3(const struct IsectRayAABB_Precalc *data,
return true; return true;
} }
/**
* Test a bounding box (AABB) for ray intersection.
* Assumes the ray is already local to the boundbox space.
*
* \note \a direction should be normalized
* if you intend to use the \a tmin or \a tmax distance results!
*/
bool isect_ray_aabb_v3_simple(const float orig[3], bool isect_ray_aabb_v3_simple(const float orig[3],
const float dir[3], const float dir[3],
const float bb_min[3], const float bb_min[3],
@@ -3357,10 +3115,6 @@ float closest_to_ray_v3(float r_close[3],
return lambda; return lambda;
} }
/**
* Find closest point to p on line through (l1, l2) and return lambda,
* where (0 <= lambda <= 1) when cp is in the line segment (l1, l2).
*/
float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]) float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3])
{ {
float u[3]; float u[3];
@@ -3424,13 +3178,6 @@ float ray_point_factor_v3(const float p[3],
return ray_point_factor_v3_ex(p, ray_origin, ray_direction, 0.0f, 0.0f); return ray_point_factor_v3_ex(p, ray_origin, ray_direction, 0.0f, 0.0f);
} }
/**
* A simplified version of #closest_to_line_v3
* we only need to return the `lambda`
*
* \param epsilon: avoid approaching divide-by-zero.
* Passing a zero will just check for nonzero division.
*/
float line_point_factor_v3_ex(const float p[3], float line_point_factor_v3_ex(const float p[3],
const float l1[3], const float l1[3],
const float l2[3], const float l2[3],
@@ -3471,9 +3218,6 @@ float line_point_factor_v2(const float p[2], const float l1[2], const float l2[2
return line_point_factor_v2_ex(p, l1, l2, 0.0f, 0.0f); return line_point_factor_v2_ex(p, l1, l2, 0.0f, 0.0f);
} }
/**
* \note #isect_line_plane_v3() shares logic
*/
float line_plane_factor_v3(const float plane_co[3], float line_plane_factor_v3(const float plane_co[3],
const float plane_no[3], const float plane_no[3],
const float l1[3], const float l1[3],
@@ -3487,10 +3231,6 @@ float line_plane_factor_v3(const float plane_co[3],
return (dot != 0.0f) ? -dot_v3v3(plane_no, h) / dot : 0.0f; return (dot != 0.0f) ? -dot_v3v3(plane_no, h) / dot : 0.0f;
} }
/**
* Ensure the distance between these points is no greater than 'dist'.
* If it is, scale them both into the center.
*/
void limit_dist_v3(float v1[3], float v2[3], const float dist) void limit_dist_v3(float v1[3], float v2[3], const float dist)
{ {
const float dist_old = len_v3v3(v1, v2); const float dist_old = len_v3v3(v1, v2);
@@ -3508,13 +3248,6 @@ void limit_dist_v3(float v1[3], float v2[3], const float dist)
} }
} }
/*
* x1,y2
* | \
* | \ .(a,b)
* | \
* x1,y1-- x2,y1
*/
int isect_point_tri_v2_int( int isect_point_tri_v2_int(
const int x1, const int y1, const int x2, const int y2, const int a, const int b) const int x1, const int y1, const int x2, const int y2, const int a, const int b)
{ {
@@ -3603,12 +3336,6 @@ bool isect_point_tri_prism_v3(const float p[3],
return true; return true;
} }
/**
* \param r_isect_co: The point \a p projected onto the triangle.
* \return True when \a p is inside the triangle.
* \note Its up to the caller to check the distance between \a p and \a r_vi
* against an error margin.
*/
bool isect_point_tri_v3( bool isect_point_tri_v3(
const float p[3], const float v1[3], const float v2[3], const float v3[3], float r_isect_co[3]) const float p[3], const float v1[3], const float v2[3], const float v3[3], float r_isect_co[3])
{ {
@@ -3739,16 +3466,6 @@ bool clip_segment_v3_plane_n(const float p1[3],
/****************************** Axis Utils ********************************/ /****************************** Axis Utils ********************************/
/**
* \brief Normal to x,y matrix
*
* Creates a 3x3 matrix from a normal.
* This matrix can be applied to vectors so their 'z' axis runs along \a normal.
* In practice it means you can use x,y as 2d coords. \see
*
* \param r_mat: The matrix to return.
* \param normal: A unit length vector.
*/
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3]) void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
{ {
BLI_ASSERT_UNIT_V3(normal); BLI_ASSERT_UNIT_V3(normal);
@@ -3766,9 +3483,6 @@ void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
is_zero_v3(normal)); is_zero_v3(normal));
} }
/**
* Same as axis_dominant_v3_to_m3, but flips the normal
*/
void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3]) void axis_dominant_v3_to_m3_negate(float r_mat[3][3], const float normal[3])
{ {
BLI_ASSERT_UNIT_V3(normal); BLI_ASSERT_UNIT_V3(normal);
@@ -3888,12 +3602,6 @@ void interp_weights_quad_v3(float w[4],
} }
} }
/**
* \return
* - 0 if the point is outside of triangle.
* - 1 if the point is inside triangle.
* - 2 if it's on the edge.
*/
int barycentric_inside_triangle_v2(const float w[3]) int barycentric_inside_triangle_v2(const float w[3])
{ {
if (IN_RANGE(w[0], 0.0f, 1.0f) && IN_RANGE(w[1], 0.0f, 1.0f) && IN_RANGE(w[2], 0.0f, 1.0f)) { if (IN_RANGE(w[0], 0.0f, 1.0f) && IN_RANGE(w[1], 0.0f, 1.0f) && IN_RANGE(w[2], 0.0f, 1.0f)) {
@@ -3907,9 +3615,6 @@ int barycentric_inside_triangle_v2(const float w[3])
return 0; return 0;
} }
/**
* \return false for degenerated triangles.
*/
bool barycentric_coords_v2( bool barycentric_coords_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]) const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{ {
@@ -3934,12 +3639,6 @@ bool barycentric_coords_v2(
return false; return false;
} }
/**
* \note Using #cross_tri_v2 means locations outside the triangle are correctly weighted.
*
* \note This is *exactly* the same calculation as #resolve_tri_uv_v2,
* although it has double precision and is used for texture baking, so keep both.
*/
void barycentric_weights_v2( void barycentric_weights_v2(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]) const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{ {
@@ -3963,11 +3662,6 @@ void barycentric_weights_v2(
copy_v3_fl(w, 1.0f / 3.0f); copy_v3_fl(w, 1.0f / 3.0f);
} }
/**
* A version of #barycentric_weights_v2 that doesn't allow negative weights.
* Useful when negative values cause problems and points are only
* ever slightly outside of the triangle.
*/
void barycentric_weights_v2_clamped( void barycentric_weights_v2_clamped(
const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3]) const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{ {
@@ -3991,10 +3685,6 @@ void barycentric_weights_v2_clamped(
copy_v3_fl(w, 1.0f / 3.0f); copy_v3_fl(w, 1.0f / 3.0f);
} }
/**
* still use 2D X,Y space but this works for verts transformed by a perspective matrix,
* using their 4th component as a weight
*/
void barycentric_weights_v2_persp( void barycentric_weights_v2_persp(
const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3]) const float v1[4], const float v2[4], const float v3[4], const float co[2], float w[3])
{ {
@@ -4018,11 +3708,6 @@ void barycentric_weights_v2_persp(
copy_v3_fl(w, 1.0f / 3.0f); copy_v3_fl(w, 1.0f / 3.0f);
} }
/**
* same as #barycentric_weights_v2 but works with a quad,
* NOTE: untested for values outside the quad's bounds
* this is #interp_weights_poly_v2 expanded for quads only
*/
void barycentric_weights_v2_quad(const float v1[2], void barycentric_weights_v2_quad(const float v1[2],
const float v2[2], const float v2[2],
const float v3[2], const float v3[2],
@@ -4116,9 +3801,6 @@ void barycentric_weights_v2_quad(const float v1[2],
} }
} }
/* given 2 triangles in 3D space, and a point in relation to the first triangle.
* calculate the location of a point in relation to the second triangle.
* Useful for finding relative positions with geometry */
void transform_point_by_tri_v3(float pt_tar[3], void transform_point_by_tri_v3(float pt_tar[3],
float const pt_src[3], float const pt_src[3],
const float tri_tar_p1[3], const float tri_tar_p1[3],
@@ -4163,10 +3845,6 @@ void transform_point_by_tri_v3(float pt_tar[3],
madd_v3_v3v3fl(pt_tar, pt_tar, no_tar, (z_ofs_src / area_src) * area_tar); madd_v3_v3v3fl(pt_tar, pt_tar, no_tar, (z_ofs_src / area_src) * area_tar);
} }
/**
* Simply re-interpolates,
* assumes p_src is between \a l_src_p1-l_src_p2
*/
void transform_point_by_seg_v3(float p_dst[3], void transform_point_by_seg_v3(float p_dst[3],
const float p_src[3], const float p_src[3],
const float l_dst_p1[3], const float l_dst_p1[3],
@@ -4178,8 +3856,6 @@ void transform_point_by_seg_v3(float p_dst[3],
interp_v3_v3v3(p_dst, l_dst_p1, l_dst_p2, t); interp_v3_v3v3(p_dst, l_dst_p1, l_dst_p2, t);
} }
/* given an array with some invalid values this function interpolates valid values
* replacing the invalid ones */
int interp_sparse_array(float *array, const int list_size, const float skipval) int interp_sparse_array(float *array, const int list_size, const float skipval)
{ {
int found_invalid = 0; int found_invalid = 0;
@@ -4516,7 +4192,6 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[
/** \} */ /** \} */
/* (x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t) */
void interp_cubic_v3(float x[3], void interp_cubic_v3(float x[3],
float v[3], float v[3],
const float x1[3], const float x1[3],
@@ -4552,13 +4227,6 @@ void interp_cubic_v3(float x[3],
#define IS_ZERO(x) ((x > (-DBL_EPSILON) && x < DBL_EPSILON) ? 1 : 0) #define IS_ZERO(x) ((x > (-DBL_EPSILON) && x < DBL_EPSILON) ? 1 : 0)
/**
* Barycentric reverse
*
* Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
*
* \note same basic result as #barycentric_weights_v2, see its comment for details.
*/
void resolve_tri_uv_v2( void resolve_tri_uv_v2(
float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2]) float r_uv[2], const float st[2], const float st0[2], const float st1[2], const float st2[2])
{ {
@@ -4581,11 +4249,6 @@ void resolve_tri_uv_v2(
} }
} }
/**
* Barycentric reverse 3d
*
* Compute coordinates (u, v) for point \a st with respect to triangle (\a st0, \a st1, \a st2)
*/
void resolve_tri_uv_v3( void resolve_tri_uv_v3(
float r_uv[2], const float st[3], const float st0[3], const float st1[3], const float st2[3]) float r_uv[2], const float st[3], const float st0[3], const float st1[3], const float st2[3])
{ {
@@ -4617,7 +4280,6 @@ void resolve_tri_uv_v3(
} }
} }
/* bilinear reverse */
void resolve_quad_uv_v2(float r_uv[2], void resolve_quad_uv_v2(float r_uv[2],
const float st[2], const float st[2],
const float st0[2], const float st0[2],
@@ -4628,7 +4290,6 @@ void resolve_quad_uv_v2(float r_uv[2],
resolve_quad_uv_v2_deriv(r_uv, NULL, st, st0, st1, st2, st3); resolve_quad_uv_v2_deriv(r_uv, NULL, st, st0, st1, st2, st3);
} }
/* bilinear reverse with derivatives */
void resolve_quad_uv_v2_deriv(float r_uv[2], void resolve_quad_uv_v2_deriv(float r_uv[2],
float r_deriv[2][2], float r_deriv[2][2],
const float st[2], const float st[2],
@@ -4719,7 +4380,6 @@ void resolve_quad_uv_v2_deriv(float r_uv[2],
} }
} }
/* a version of resolve_quad_uv_v2 that only calculates the 'u' */
float resolve_quad_u_v2(const float st[2], float resolve_quad_u_v2(const float st[2],
const float st0[2], const float st0[2],
const float st1[2], const float st1[2],
@@ -4763,7 +4423,6 @@ float resolve_quad_u_v2(const float st[2],
#undef IS_ZERO #undef IS_ZERO
/* reverse of the functions above */
void interp_bilinear_quad_v3(float data[4][3], float u, float v, float res[3]) void interp_bilinear_quad_v3(float data[4][3], float u, float v, float res[3])
{ {
float vec[3]; float vec[3];
@@ -4797,9 +4456,6 @@ void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3])
/***************************** View & Projection *****************************/ /***************************** View & Projection *****************************/
/**
* Matches `glOrtho` result.
*/
void orthographic_m4(float matrix[4][4], void orthographic_m4(float matrix[4][4],
const float left, const float left,
const float right, const float right,
@@ -4825,9 +4481,6 @@ void orthographic_m4(float matrix[4][4],
matrix[3][2] = -(farClip + nearClip) / Zdelta; matrix[3][2] = -(farClip + nearClip) / Zdelta;
} }
/**
* Matches `glFrustum` result.
*/
void perspective_m4(float mat[4][4], void perspective_m4(float mat[4][4],
const float left, const float left,
const float right, const float right,
@@ -4873,8 +4526,6 @@ void perspective_m4_fov(float mat[4][4],
mat[1][1] /= nearClip; mat[1][1] /= nearClip;
} }
/* translate a matrix created by orthographic_m4 or perspective_m4 in XY coords
* (used to jitter the view) */
void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x, const float y) void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x, const float y)
{ {
if (winmat[2][3] == -1.0f) { if (winmat[2][3] == -1.0f) {
@@ -4903,12 +4554,6 @@ void window_translate_m4(float winmat[4][4], float perspmat[4][4], const float x
} }
} }
/**
* Frustum planes extraction from a projection matrix
* (homogeneous 4d vector representations of planes).
*
* plane parameters can be NULL if you do not need them.
*/
void planes_from_projmat(const float mat[4][4], void planes_from_projmat(const float mat[4][4],
float left[4], float left[4],
float right[4], float right[4],
@@ -5021,14 +4666,6 @@ void projmat_dimensions_db(const float winmat_fl[4][4],
} }
} }
/**
* Creates a projection matrix for a small region of the viewport.
*
* \param projmat: Projection Matrix.
* \param win_size: Viewport Size.
* \param x_min, x_max, y_min, y_max: Coordinates of the subregion.
* \return r_projmat: Resulting Projection Matrix.
*/
void projmat_from_subregion(const float projmat[4][4], void projmat_from_subregion(const float projmat[4][4],
const int win_size[2], const int win_size[2],
const int x_min, const int x_min,
@@ -5363,8 +5000,6 @@ void accumulate_vertex_normals_v3(float n1[3],
} }
} }
/* Add weighted face normal component into normals of the face vertices.
* Caller must pass pre-allocated vdiffs of nverts length. */
void accumulate_vertex_normals_poly_v3(float **vertnos, void accumulate_vertex_normals_poly_v3(float **vertnos,
const float polyno[3], const float polyno[3],
const float **vertcos, const float **vertcos,
@@ -5444,25 +5079,6 @@ void tangent_from_uv_v3(const float uv1[2],
/****************************** Vector Clouds ********************************/ /****************************** Vector Clouds ********************************/
/* vector clouds */ /* vector clouds */
/**
* input
*
* \param list_size: 4 lists as pointer to array[list_size]
* \param pos: current pos array of 'new' positions
* \param weight: current weight array of 'new'weights (may be NULL pointer if you have no weights)
* \param rpos: Reference rpos array of 'old' positions
* \param rweight: Reference rweight array of 'old'weights
* (may be NULL pointer if you have no weights).
*
* output
*
* \param lloc: Center of mass pos.
* \param rloc: Center of mass rpos.
* \param lrot: Rotation matrix.
* \param lscale: Scale matrix.
*
* pointers may be NULL if not needed
*/
void vcloud_estimate_transform_v3(const int list_size, void vcloud_estimate_transform_v3(const int list_size,
const float (*pos)[3], const float (*pos)[3],
@@ -6057,11 +5673,6 @@ float form_factor_hemi_poly(
return contrib; return contrib;
} }
/**
* Check if the edge is convex or concave
* (depends on face winding)
* Copied from BM_edge_is_convex().
*/
bool is_edge_convex_v3(const float v1[3], bool is_edge_convex_v3(const float v1[3],
const float v2[3], const float v2[3],
const float f1_no[3], const float f1_no[3],
@@ -6078,9 +5689,6 @@ bool is_edge_convex_v3(const float v1[3],
return false; return false;
} }
/**
* Evaluate if entire quad is a proper convex quad
*/
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]) bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{ {
/** /**
@@ -6176,12 +5784,6 @@ bool is_poly_convex_v2(const float verts[][2], unsigned int nr)
return true; return true;
} }
/**
* Check if either of the diagonals along this quad create flipped triangles
* (normals pointing away from eachother).
* - (1 << 0): (v1-v3) is flipped.
* - (1 << 1): (v2-v4) is flipped.
*/
int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]) int is_quad_flip_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
{ {
float d_12[3], d_23[3], d_34[3], d_41[3]; float d_12[3], d_23[3], d_34[3], d_41[3];
@@ -6232,14 +5834,6 @@ bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
return (dot_v3v3(v4, tangent) >= dot) || (dot_v3v3(v2, tangent) <= dot); return (dot_v3v3(v4, tangent) >= dot) || (dot_v3v3(v2, tangent) <= dot);
} }
/**
* Return the value which the distance between points will need to be scaled by,
* to define a handle, given both points are on a perfect circle.
*
* Use when we want a bezier curve to match a circle as closely as possible.
*
* \note the return value will need to be divided by 0.75 for correct results.
*/
float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3]) float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
{ {
BLI_ASSERT_UNIT_V3(tan_l); BLI_ASSERT_UNIT_V3(tan_l);
@@ -6267,14 +5861,6 @@ float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
return ((1.0f - angle_cos) / (angle_sin * 2.0f)) / angle_sin; return ((1.0f - angle_cos) / (angle_sin * 2.0f)) / angle_sin;
} }
/**
* Utility for computing approximate geodesic distances on triangle meshes.
*
* Given triangle with vertex coordinates v0, v1, v2, and known geodesic distances
* dist1 and dist2 at v1 and v2, estimate a geodesic distance at vertex v0.
*
* From "Dart Throwing on Surfaces", EGSR 2009. Section 7, Geodesic Dart Throwing.
*/
float geodesic_distance_propagate_across_triangle( float geodesic_distance_propagate_across_triangle(
const float v0[3], const float v1[3], const float v2[3], const float dist1, const float dist2) const float v0[3], const float v1[3], const float v2[3], const float dist1, const float dist2)
{ {

Some files were not shown because too many files have changed in this diff Show More