summaryrefslogtreecommitdiffstats
path: root/src/include/libplacebo/common.h
blob: 806730cfc371804663b07968b149034a340e71ce (plain)
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/*
 * This file is part of libplacebo.
 *
 * libplacebo is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * libplacebo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with libplacebo.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef LIBPLACEBO_COMMON_H_
#define LIBPLACEBO_COMMON_H_

#include <stdbool.h>

#include <libplacebo/config.h>

PL_API_BEGIN

// Some common utility types. These are overloaded to support 2D, 3D and
// integer/float variants.
typedef struct pl_rect2d {
    int x0, y0;
    int x1, y1;
} pl_rect2d;

typedef struct pl_rect3d {
    int x0, y0, z0;
    int x1, y1, z1;
} pl_rect3d;

typedef struct pl_rect2df {
    float x0, y0;
    float x1, y1;
} pl_rect2df;

typedef struct pl_rect3df {
    float x0, y0, z0;
    float x1, y1, z1;
} pl_rect3df;

// These macros will work for any of the above pl_rect variants (with enough
// dimensions). Careful: double-evaluation hazard
#define pl_rect_w(r) ((r).x1 - (r).x0)
#define pl_rect_h(r) ((r).y1 - (r).y0)
#define pl_rect_d(r) ((r).z1 - (r).z0)

#define pl_rect2d_eq(a, b) \
    ((a).x0 == (b).x0 && (a).x1 == (b).x1 && \
     (a).y0 == (b).y0 && (a).y1 == (b).y1)

#define pl_rect3d_eq(a, b) \
    ((a).x0 == (b).x0 && (a).x1 == (b).x1 && \
     (a).y0 == (b).y0 && (a).y1 == (b).y1 && \
     (a).z0 == (b).z0 && (a).z1 == (b).z1)

// "Normalize" a rectangle: This ensures d1 >= d0 for all dimensions.
PL_API void pl_rect2d_normalize(pl_rect2d *rc);
PL_API void pl_rect3d_normalize(pl_rect3d *rc);

PL_API void pl_rect2df_normalize(pl_rect2df *rc);
PL_API void pl_rect3df_normalize(pl_rect3df *rc);

// Return the rounded form of a rect.
PL_API pl_rect2d pl_rect2df_round(const pl_rect2df *rc);
PL_API pl_rect3d pl_rect3df_round(const pl_rect3df *rc);

// Represents a row-major matrix, i.e. the following matrix
//     [ a11 a12 a13 ]
//     [ a21 a22 a23 ]
//     [ a31 a32 a33 ]
// is represented in C like this:
//   { { a11, a12, a13 },
//     { a21, a22, a23 },
//     { a31, a32, a33 } };
typedef struct pl_matrix3x3 {
    float m[3][3];
} pl_matrix3x3;

PL_API extern const pl_matrix3x3 pl_matrix3x3_identity;

// Applies a matrix to a float vector in-place.
PL_API void pl_matrix3x3_apply(const pl_matrix3x3 *mat, float vec[3]);

// Applies a matrix to a pl_rect3df
PL_API void pl_matrix3x3_apply_rc(const pl_matrix3x3 *mat, pl_rect3df *rc);

// Scales a color matrix by a linear factor.
PL_API void pl_matrix3x3_scale(pl_matrix3x3 *mat, float scale);

// Inverts a matrix. Only use where precision is not that important.
PL_API void pl_matrix3x3_invert(pl_matrix3x3 *mat);

// Composes/multiplies two matrices. Multiples B into A, i.e.
// A := A * B
PL_API void pl_matrix3x3_mul(pl_matrix3x3 *a, const pl_matrix3x3 *b);

// Flipped version of `pl_matrix3x3_mul`.
// B := A * B
PL_API void pl_matrix3x3_rmul(const pl_matrix3x3 *a, pl_matrix3x3 *b);

// Represents an affine transformation, which is basically a 3x3 matrix
// together with a column vector to add onto the output.
typedef struct pl_transform3x3 {
    pl_matrix3x3 mat;
    float c[3];
} pl_transform3x3;

PL_API extern const pl_transform3x3 pl_transform3x3_identity;

// Applies a transform to a float vector in-place.
PL_API void pl_transform3x3_apply(const pl_transform3x3 *t, float vec[3]);

// Applies a transform to a pl_rect3df
PL_API void pl_transform3x3_apply_rc(const pl_transform3x3 *t, pl_rect3df *rc);

// Scales the output of a transform by a linear factor. Since an affine
// transformation is non-linear, this does not commute. If you want to scale
// the *input* of a transform, use pl_matrix3x3_scale on `t.mat`.
PL_API void pl_transform3x3_scale(pl_transform3x3 *t, float scale);

// Inverts a transform. Only use where precision is not that important.
PL_API void pl_transform3x3_invert(pl_transform3x3 *t);

// 2D analog of the above structs. Since these are featured less prominently,
// we omit some of the other helper functions.
typedef struct pl_matrix2x2 {
    float m[2][2];
} pl_matrix2x2;

PL_API extern const pl_matrix2x2 pl_matrix2x2_identity;
PL_API pl_matrix2x2 pl_matrix2x2_rotation(float angle);

PL_API void pl_matrix2x2_apply(const pl_matrix2x2 *mat, float vec[2]);
PL_API void pl_matrix2x2_apply_rc(const pl_matrix2x2 *mat, pl_rect2df *rc);

PL_API void pl_matrix2x2_mul(pl_matrix2x2 *a, const pl_matrix2x2 *b);
PL_API void pl_matrix2x2_rmul(const pl_matrix2x2 *a, pl_matrix2x2 *b);

PL_API void pl_matrix2x2_scale(pl_matrix2x2 *mat, float scale);
PL_API void pl_matrix2x2_invert(pl_matrix2x2 *mat);

typedef struct pl_transform2x2 {
    pl_matrix2x2 mat;
    float c[2];
} pl_transform2x2;

PL_API extern const pl_transform2x2 pl_transform2x2_identity;

PL_API void pl_transform2x2_apply(const pl_transform2x2 *t, float vec[2]);
PL_API void pl_transform2x2_apply_rc(const pl_transform2x2 *t, pl_rect2df *rc);

PL_API void pl_transform2x2_mul(pl_transform2x2 *a, const pl_transform2x2 *b);
PL_API void pl_transform2x2_rmul(const pl_transform2x2 *a, pl_transform2x2 *b);

PL_API void pl_transform2x2_scale(pl_transform2x2 *t, float scale);
PL_API void pl_transform2x2_invert(pl_transform2x2 *t);

// Compute new bounding box of a transformation (as applied to a given rect).
PL_API pl_rect2df pl_transform2x2_bounds(const pl_transform2x2 *t,
                                         const pl_rect2df *rc);

// Helper functions for dealing with aspect ratios and stretched/scaled rects.

// Return the (absolute) aspect ratio (width/height) of a given pl_rect2df.
// This will always be a positive number, even if `rc` is flipped.
PL_API float pl_rect2df_aspect(const pl_rect2df *rc);

// Set the aspect of a `rc` to a given aspect ratio with an extra 'panscan'
// factor choosing the balance between shrinking and growing the `rc` to meet
// this aspect ratio.
//
// Notes:
// - If `panscan` is 0.0, this function will only ever shrink the `rc`.
// - If `panscan` is 1.0, this function will only ever grow the `rc`.
// - If `panscan` is 0.5, this function is area-preserving.
PL_API void pl_rect2df_aspect_set(pl_rect2df *rc, float aspect, float panscan);

// Set one rect's aspect to that of another
#define pl_rect2df_aspect_copy(rc, src, panscan) \
    pl_rect2df_aspect_set((rc), pl_rect2df_aspect(src), (panscan))

// 'Fit' one rect inside another. `rc` will be set to the same size and aspect
// ratio as `src`, but with the size limited to fit inside the original `rc`.
// Like `pl_rect2df_aspect_set`, `panscan` controls the pan&scan factor.
PL_API void pl_rect2df_aspect_fit(pl_rect2df *rc, const pl_rect2df *src, float panscan);

// Scale rect in each direction while keeping it centered.
PL_API void pl_rect2df_stretch(pl_rect2df *rc, float stretch_x, float stretch_y);

// Offset rect by an arbitrary offset factor. If the corresponding dimension
// of a rect is flipped, so too is the applied offset.
PL_API void pl_rect2df_offset(pl_rect2df *rc, float offset_x, float offset_y);

// Scale a rect uniformly in both dimensions.
#define pl_rect2df_zoom(rc, zoom) pl_rect2df_stretch((rc), (zoom), (zoom))

// Rotation in degrees clockwise
typedef int pl_rotation;
enum {
    PL_ROTATION_0   = 0,
    PL_ROTATION_90  = 1,
    PL_ROTATION_180 = 2,
    PL_ROTATION_270 = 3,
    PL_ROTATION_360 = 4, // equivalent to PL_ROTATION_0

    // Note: Values outside the range [0,4) are legal, including negatives.
};

// Constrains to the interval [PL_ROTATION_0, PL_ROTATION_360).
static inline pl_rotation pl_rotation_normalize(pl_rotation rot)
{
    return (rot % PL_ROTATION_360 + PL_ROTATION_360) % PL_ROTATION_360;
}

// Rotates the coordinate system of a `pl_rect2d(f)` in a certain direction.
// For example, calling this with PL_ROTATION_90 will correspond to rotating
// the coordinate system 90° to the right (so the x axis becomes the y axis).
//
// The resulting rect is re-normalized in the same coordinate system.
PL_API void pl_rect2df_rotate(pl_rect2df *rc, pl_rotation rot);

// Returns the aspect ratio in a rotated frame of reference.
static inline float pl_aspect_rotate(float aspect, pl_rotation rot)
{
    return (rot % PL_ROTATION_180) ? 1.0 / aspect : aspect;
}

#define pl_rect2df_aspect_set_rot(rc, aspect, rot, panscan) \
    pl_rect2df_aspect_set((rc), pl_aspect_rotate((aspect), (rot)), (panscan))

#define pl_rect2df_aspect_copy_rot(rc, src, panscan, rot) \
    pl_rect2df_aspect_set_rot((rc), pl_rect2df_aspect(src), (rot), (panscan))

PL_API_END

#endif // LIBPLACEBO_COMMON_H_