Repository navigation
Expand file tree
/
Copy pathdgx_matrix_morph.h
More file actions
140 lines (126 loc) · 3.74 KB
/
Copy pathdgx_matrix_morph.h
File metadata and controls
140 lines (126 loc) · 3.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Packed 1-bit-per-cell grid used as a morphing "scene".
*
* Cell (x, y) is stored in bit (y * width + x) & 7 of byte
* (y * width + x) / 8 (LSB-first). number_of_set_cells is kept in sync by
* dgx_matrix_set_point().
*/
typedef struct {
uint16_t width;
uint16_t height;
uint8_t *bits;
size_t number_of_set_cells;
} dgx_bit_matrix_t;
/**
* @brief Allocate an all-zero bit matrix.
* @param width Grid width in cells.
* @param height Grid height in cells.
* @return Owned matrix, or NULL on failure. Release with dgx_matrix_destroy().
*/
dgx_bit_matrix_t *dgx_matrix_init(
uint16_t width,
uint16_t height
);
/**
* @brief Release a matrix and set its pointer to NULL.
* @param matrix Address of a matrix pointer. NULL and pointers to NULL are valid.
*/
void dgx_matrix_destroy(dgx_bit_matrix_t **matrix);
/** @brief Clear every cell. NULL is a no-op. */
void dgx_matrix_clear(dgx_bit_matrix_t *matrix);
/**
* @brief Allocate a copy of a matrix.
* @return Owned matrix, or NULL for NULL source or allocation failure.
*/
dgx_bit_matrix_t *dgx_matrix_clone(const dgx_bit_matrix_t *src);
/**
* @brief Copy cells between matrices of equal size.
* @return false for NULL arguments or different sizes; dst is then unchanged.
*/
bool dgx_matrix_copy(dgx_bit_matrix_t *dst, const dgx_bit_matrix_t *src);
/**
* @brief Compare size and cells.
* @return true when both are NULL or both have equal size and cells.
*/
bool dgx_matrix_equals(const dgx_bit_matrix_t *a, const dgx_bit_matrix_t *b);
/**
* @brief Read one cell.
* @param matrix Source matrix.
* @param x,y Cell coordinates.
* @return Cell value; false for out-of-range coordinates or NULL matrix.
*/
static inline bool dgx_matrix_get_point(
const dgx_bit_matrix_t *matrix,
int x,
int y
)
{
if (matrix == NULL || x < 0 || x >= matrix->width || y < 0 || y >= matrix->height) {
return false;
}
size_t idx = (size_t)y * matrix->width + (size_t)x;
return (matrix->bits[idx / 8u] & (uint8_t)(1u << (idx % 8u))) != 0;
}
/**
* @brief Write one cell and update number_of_set_cells.
* @param matrix Target matrix.
* @param x,y Cell coordinates.
* @param value New cell value.
* @return true when written; false for out-of-range coordinates or NULL matrix.
*/
static inline bool dgx_matrix_set_point(
dgx_bit_matrix_t *matrix,
int x,
int y,
bool value
)
{
if (matrix == NULL || x < 0 || x >= matrix->width || y < 0 || y >= matrix->height) {
return false;
}
size_t idx = (size_t)y * matrix->width + (size_t)x;
uint8_t mask = (uint8_t)(1u << (idx % 8u));
bool old = (matrix->bits[idx / 8u] & mask) != 0;
if (value != old) {
if (value) {
matrix->bits[idx / 8u] |= mask;
matrix->number_of_set_cells++;
} else {
matrix->bits[idx / 8u] &= (uint8_t)~mask;
matrix->number_of_set_cells--;
}
}
return true;
}
/**
* @brief Callback for dgx_matrix_foreach_set().
* @param user_data Caller context.
* @param x,y Set cell coordinates.
* @return false to stop iteration early.
*/
typedef bool (*dgx_matrix_cell_func_t)(
void *user_data,
int x,
int y
);
/**
* @brief Invoke a callback for every set cell in scan order.
* @param matrix Source matrix.
* @param func Callback; NULL is a no-op.
* @param user_data Opaque context passed to the callback.
*/
void dgx_matrix_foreach_set(
const dgx_bit_matrix_t *matrix,
dgx_matrix_cell_func_t func,
void *user_data
);
#ifdef __cplusplus
}
#endif