1 /*
2 * This file is part of libplacebo.
3 *
4 * libplacebo is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * libplacebo is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <math.h>
19
20 #include "common.h"
21
pl_fix_ver()22 int pl_fix_ver()
23 {
24 return BUILD_FIX_VER;
25 }
26
pl_version()27 const char *pl_version()
28 {
29 return BUILD_VERSION;
30 }
31
pl_rect2d_normalize(struct pl_rect2d * rc)32 void pl_rect2d_normalize(struct pl_rect2d *rc)
33 {
34 *rc = (struct pl_rect2d) {
35 .x0 = PL_MIN(rc->x0, rc->x1),
36 .x1 = PL_MAX(rc->x0, rc->x1),
37 .y0 = PL_MIN(rc->y0, rc->y1),
38 .y1 = PL_MAX(rc->y0, rc->y1),
39 };
40 }
41
pl_rect3d_normalize(struct pl_rect3d * rc)42 void pl_rect3d_normalize(struct pl_rect3d *rc)
43 {
44 *rc = (struct pl_rect3d) {
45 .x0 = PL_MIN(rc->x0, rc->x1),
46 .x1 = PL_MAX(rc->x0, rc->x1),
47 .y0 = PL_MIN(rc->y0, rc->y1),
48 .y1 = PL_MAX(rc->y0, rc->y1),
49 .z0 = PL_MIN(rc->z0, rc->z1),
50 .z1 = PL_MAX(rc->z0, rc->z1),
51 };
52 }
53
pl_rect2df_normalize(struct pl_rect2df * rc)54 void pl_rect2df_normalize(struct pl_rect2df *rc)
55 {
56 *rc = (struct pl_rect2df) {
57 .x0 = PL_MIN(rc->x0, rc->x1),
58 .x1 = PL_MAX(rc->x0, rc->x1),
59 .y0 = PL_MIN(rc->y0, rc->y1),
60 .y1 = PL_MAX(rc->y0, rc->y1),
61 };
62 }
63
pl_rect3df_normalize(struct pl_rect3df * rc)64 void pl_rect3df_normalize(struct pl_rect3df *rc)
65 {
66 *rc = (struct pl_rect3df) {
67 .x0 = PL_MIN(rc->x0, rc->x1),
68 .x1 = PL_MAX(rc->x0, rc->x1),
69 .y0 = PL_MIN(rc->y0, rc->y1),
70 .y1 = PL_MAX(rc->y0, rc->y1),
71 .z0 = PL_MIN(rc->z0, rc->z1),
72 .z1 = PL_MAX(rc->z0, rc->z1),
73 };
74 }
75
pl_rect2df_round(const struct pl_rect2df * rc)76 struct pl_rect2d pl_rect2df_round(const struct pl_rect2df *rc)
77 {
78 return (struct pl_rect2d) {
79 .x0 = roundf(rc->x0),
80 .x1 = roundf(rc->x1),
81 .y0 = roundf(rc->y0),
82 .y1 = roundf(rc->y1),
83 };
84 }
85
pl_rect3df_round(const struct pl_rect3df * rc)86 struct pl_rect3d pl_rect3df_round(const struct pl_rect3df *rc)
87 {
88 return (struct pl_rect3d) {
89 .x0 = roundf(rc->x0),
90 .x1 = roundf(rc->x1),
91 .y0 = roundf(rc->y0),
92 .y1 = roundf(rc->y1),
93 .z0 = roundf(rc->z0),
94 .z1 = roundf(rc->z1),
95 };
96 }
97
98 const struct pl_matrix3x3 pl_matrix3x3_identity = {{
99 { 1, 0, 0 },
100 { 0, 1, 0 },
101 { 0, 0, 1 },
102 }};
103
pl_matrix3x3_apply(const struct pl_matrix3x3 * mat,float vec[3])104 void pl_matrix3x3_apply(const struct pl_matrix3x3 *mat, float vec[3])
105 {
106 float x = vec[0], y = vec[1], z = vec[2];
107
108 for (int i = 0; i < 3; i++)
109 vec[i] = mat->m[i][0] * x + mat->m[i][1] * y + mat->m[i][2] * z;
110 }
111
pl_matrix3x3_apply_rc(const struct pl_matrix3x3 * mat,struct pl_rect3df * rc)112 void pl_matrix3x3_apply_rc(const struct pl_matrix3x3 *mat, struct pl_rect3df *rc)
113 {
114 float x0 = rc->x0, x1 = rc->x1,
115 y0 = rc->y0, y1 = rc->y1,
116 z0 = rc->z0, z1 = rc->z1;
117
118 rc->x0 = mat->m[0][0] * x0 + mat->m[0][1] * y0 + mat->m[0][2] * z0;
119 rc->y0 = mat->m[1][0] * x0 + mat->m[1][1] * y0 + mat->m[1][2] * z0;
120 rc->z0 = mat->m[2][0] * x0 + mat->m[2][1] * y0 + mat->m[2][2] * z0;
121
122 rc->x1 = mat->m[0][0] * x1 + mat->m[0][1] * y1 + mat->m[0][2] * z1;
123 rc->y1 = mat->m[1][0] * x1 + mat->m[1][1] * y1 + mat->m[1][2] * z1;
124 rc->z1 = mat->m[2][0] * x1 + mat->m[2][1] * y1 + mat->m[2][2] * z1;
125 }
126
pl_matrix3x3_scale(struct pl_matrix3x3 * mat,float scale)127 void pl_matrix3x3_scale(struct pl_matrix3x3 *mat, float scale)
128 {
129 for (int i = 0; i < 3; i++) {
130 for (int j = 0; j < 3; j++)
131 mat->m[i][j] *= scale;
132 }
133 }
134
pl_matrix3x3_invert(struct pl_matrix3x3 * mat)135 void pl_matrix3x3_invert(struct pl_matrix3x3 *mat)
136 {
137 float m00 = mat->m[0][0], m01 = mat->m[0][1], m02 = mat->m[0][2],
138 m10 = mat->m[1][0], m11 = mat->m[1][1], m12 = mat->m[1][2],
139 m20 = mat->m[2][0], m21 = mat->m[2][1], m22 = mat->m[2][2];
140
141 // calculate the adjoint
142 mat->m[0][0] = (m11 * m22 - m21 * m12);
143 mat->m[0][1] = -(m01 * m22 - m21 * m02);
144 mat->m[0][2] = (m01 * m12 - m11 * m02);
145 mat->m[1][0] = -(m10 * m22 - m20 * m12);
146 mat->m[1][1] = (m00 * m22 - m20 * m02);
147 mat->m[1][2] = -(m00 * m12 - m10 * m02);
148 mat->m[2][0] = (m10 * m21 - m20 * m11);
149 mat->m[2][1] = -(m00 * m21 - m20 * m01);
150 mat->m[2][2] = (m00 * m11 - m10 * m01);
151
152 // calculate the determinant (as inverse == 1/det * adjoint,
153 // adjoint * m == identity * det, so this calculates the det)
154 float det = m00 * mat->m[0][0] + m10 * mat->m[0][1] + m20 * mat->m[0][2];
155 det = 1.0f / det;
156
157 for (int i = 0; i < 3; i++) {
158 for (int j = 0; j < 3; j++)
159 mat->m[i][j] *= det;
160 }
161 }
162
pl_matrix3x3_mul(struct pl_matrix3x3 * a,const struct pl_matrix3x3 * b)163 void pl_matrix3x3_mul(struct pl_matrix3x3 *a, const struct pl_matrix3x3 *b)
164 {
165 float a00 = a->m[0][0], a01 = a->m[0][1], a02 = a->m[0][2],
166 a10 = a->m[1][0], a11 = a->m[1][1], a12 = a->m[1][2],
167 a20 = a->m[2][0], a21 = a->m[2][1], a22 = a->m[2][2];
168
169 for (int i = 0; i < 3; i++) {
170 a->m[0][i] = a00 * b->m[0][i] + a01 * b->m[1][i] + a02 * b->m[2][i];
171 a->m[1][i] = a10 * b->m[0][i] + a11 * b->m[1][i] + a12 * b->m[2][i];
172 a->m[2][i] = a20 * b->m[0][i] + a21 * b->m[1][i] + a22 * b->m[2][i];
173 }
174 }
175
pl_matrix3x3_rmul(const struct pl_matrix3x3 * a,struct pl_matrix3x3 * b)176 void pl_matrix3x3_rmul(const struct pl_matrix3x3 *a, struct pl_matrix3x3 *b)
177 {
178 struct pl_matrix3x3 m = *a;
179 pl_matrix3x3_mul(&m, b);
180 *b = m;
181 }
182
183 const struct pl_transform3x3 pl_transform3x3_identity = {
184 .mat = {{
185 { 1, 0, 0 },
186 { 0, 1, 0 },
187 { 0, 0, 1 },
188 }},
189 };
190
pl_transform3x3_apply(const struct pl_transform3x3 * t,float vec[3])191 void pl_transform3x3_apply(const struct pl_transform3x3 *t, float vec[3])
192 {
193 pl_matrix3x3_apply(&t->mat, vec);
194
195 for (int i = 0; i < 3; i++)
196 vec[i] += t->c[i];
197 }
198
pl_transform3x3_apply_rc(const struct pl_transform3x3 * t,struct pl_rect3df * rc)199 void pl_transform3x3_apply_rc(const struct pl_transform3x3 *t, struct pl_rect3df *rc)
200 {
201 pl_matrix3x3_apply_rc(&t->mat, rc);
202
203 rc->x0 += t->c[0];
204 rc->x1 += t->c[0];
205 rc->y0 += t->c[1];
206 rc->y1 += t->c[1];
207 rc->z0 += t->c[2];
208 rc->z1 += t->c[2];
209 }
210
pl_transform3x3_scale(struct pl_transform3x3 * t,float scale)211 void pl_transform3x3_scale(struct pl_transform3x3 *t, float scale)
212 {
213 pl_matrix3x3_scale(&t->mat, scale);
214
215 for (int i = 0; i < 3; i++)
216 t->c[i] *= scale;
217 }
218
219 // based on DarkPlaces engine (relicensed from GPL to LGPL)
pl_transform3x3_invert(struct pl_transform3x3 * t)220 void pl_transform3x3_invert(struct pl_transform3x3 *t)
221 {
222 pl_matrix3x3_invert(&t->mat);
223
224 float m00 = t->mat.m[0][0], m01 = t->mat.m[0][1], m02 = t->mat.m[0][2],
225 m10 = t->mat.m[1][0], m11 = t->mat.m[1][1], m12 = t->mat.m[1][2],
226 m20 = t->mat.m[2][0], m21 = t->mat.m[2][1], m22 = t->mat.m[2][2];
227
228 // fix the constant coefficient
229 // rgb = M * yuv + C
230 // M^-1 * rgb = yuv + M^-1 * C
231 // yuv = M^-1 * rgb - M^-1 * C
232 // ^^^^^^^^^^
233 float c0 = t->c[0], c1 = t->c[1], c2 = t->c[2];
234 t->c[0] = -(m00 * c0 + m01 * c1 + m02 * c2);
235 t->c[1] = -(m10 * c0 + m11 * c1 + m12 * c2);
236 t->c[2] = -(m20 * c0 + m21 * c1 + m22 * c2);
237 }
238
239 const struct pl_matrix2x2 pl_matrix2x2_identity = {{
240 { 1, 0 },
241 { 0, 1 },
242 }};
243
pl_matrix2x2_apply(const struct pl_matrix2x2 * mat,float vec[2])244 void pl_matrix2x2_apply(const struct pl_matrix2x2 *mat, float vec[2])
245 {
246 float x = vec[0], y = vec[1];
247
248 for (int i = 0; i < 2; i++)
249 vec[i] = mat->m[i][0] * x + mat->m[i][1] * y;
250 }
251
pl_matrix2x2_apply_rc(const struct pl_matrix2x2 * mat,struct pl_rect2df * rc)252 void pl_matrix2x2_apply_rc(const struct pl_matrix2x2 *mat, struct pl_rect2df *rc)
253 {
254 float x0 = rc->x0, x1 = rc->x1,
255 y0 = rc->y0, y1 = rc->y1;
256
257 rc->x0 = mat->m[0][0] * x0 + mat->m[0][1] * y0;
258 rc->y0 = mat->m[1][0] * x0 + mat->m[1][1] * y0;
259
260 rc->x1 = mat->m[0][0] * x1 + mat->m[0][1] * y1;
261 rc->y1 = mat->m[1][0] * x1 + mat->m[1][1] * y1;
262 }
263
264 const struct pl_transform2x2 pl_transform2x2_identity = {
265 .mat = {{
266 { 1, 0 },
267 { 0, 1 },
268 }},
269 };
270
pl_transform2x2_apply(const struct pl_transform2x2 * t,float vec[2])271 void pl_transform2x2_apply(const struct pl_transform2x2 *t, float vec[2])
272 {
273 pl_matrix2x2_apply(&t->mat, vec);
274
275 for (int i = 0; i < 2; i++)
276 vec[i] += t->c[i];
277 }
278
pl_transform2x2_apply_rc(const struct pl_transform2x2 * t,struct pl_rect2df * rc)279 void pl_transform2x2_apply_rc(const struct pl_transform2x2 *t, struct pl_rect2df *rc)
280 {
281 pl_matrix2x2_apply_rc(&t->mat, rc);
282
283 rc->x0 += t->c[0];
284 rc->x1 += t->c[0];
285 rc->y0 += t->c[1];
286 rc->y1 += t->c[1];
287 }
288
pl_rect2df_aspect(const struct pl_rect2df * rc)289 float pl_rect2df_aspect(const struct pl_rect2df *rc)
290 {
291 float w = fabs(pl_rect_w(*rc)), h = fabs(pl_rect_h(*rc));
292 return h ? (w / h) : 0.0;
293 }
294
pl_rect2df_aspect_set(struct pl_rect2df * rc,float aspect,float panscan)295 void pl_rect2df_aspect_set(struct pl_rect2df *rc, float aspect, float panscan)
296 {
297 pl_assert(aspect >= 0);
298 float orig_aspect = pl_rect2df_aspect(rc);
299 if (!aspect || !orig_aspect)
300 return;
301
302 float scale_x, scale_y;
303 if (aspect > orig_aspect) {
304 // New aspect is wider than the original, so we need to either grow in
305 // scale_x (panscan=1) or shrink in scale_y (panscan=0)
306 scale_x = powf(aspect / orig_aspect, panscan);
307 scale_y = powf(aspect / orig_aspect, panscan - 1.0);
308 } else if (aspect < orig_aspect) {
309 // New aspect is taller, so either grow in scale_y (panscan=1) or
310 // shrink in scale_x (panscan=0)
311 scale_x = powf(orig_aspect / aspect, panscan - 1.0);
312 scale_y = powf(orig_aspect / aspect, panscan);
313 } else {
314 return; // No change in aspect
315 }
316
317 pl_rect2df_stretch(rc, scale_x, scale_y);
318 }
319
pl_rect2df_aspect_fit(struct pl_rect2df * rc,const struct pl_rect2df * src,float panscan)320 void pl_rect2df_aspect_fit(struct pl_rect2df *rc, const struct pl_rect2df *src,
321 float panscan)
322 {
323 float orig_w = fabs(pl_rect_w(*rc)),
324 orig_h = fabs(pl_rect_h(*rc));
325 if (!orig_w || !orig_h)
326 return;
327
328 // If either one of these is larger than 1, then we need to shrink to fit,
329 // otherwise we can just directly stretch the rect.
330 float scale_x = fabs(pl_rect_w(*src)) / orig_w,
331 scale_y = fabs(pl_rect_h(*src)) / orig_h;
332
333 if (scale_x > 1.0 || scale_y > 1.0) {
334 pl_rect2df_aspect_copy(rc, src, panscan);
335 } else {
336 pl_rect2df_stretch(rc, scale_x, scale_y);
337 }
338 }
339
pl_rect2df_stretch(struct pl_rect2df * rc,float stretch_x,float stretch_y)340 void pl_rect2df_stretch(struct pl_rect2df *rc, float stretch_x, float stretch_y)
341 {
342 float midx = (rc->x0 + rc->x1) / 2.0,
343 midy = (rc->y0 + rc->y1) / 2.0;
344
345 rc->x0 = rc->x0 * stretch_x + midx * (1.0 - stretch_x);
346 rc->x1 = rc->x1 * stretch_x + midx * (1.0 - stretch_x);
347 rc->y0 = rc->y0 * stretch_y + midy * (1.0 - stretch_y);
348 rc->y1 = rc->y1 * stretch_y + midy * (1.0 - stretch_y);
349 }
350
pl_rect2df_offset(struct pl_rect2df * rc,float offset_x,float offset_y)351 void pl_rect2df_offset(struct pl_rect2df *rc, float offset_x, float offset_y)
352 {
353 if (rc->x1 < rc->x0)
354 offset_x = -offset_x;
355 if (rc->y1 < rc->y0)
356 offset_y = -offset_y;
357
358 rc->x0 += offset_x;
359 rc->x1 += offset_x;
360 rc->y0 += offset_y;
361 rc->y1 += offset_y;
362 }
363