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