1 /* cogl-graphene.c
2  *
3  * Copyright 2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
4  *
5  * Permission is hereby granted, free of charge, to any person
6  * obtaining a copy of this software and associated documentation
7  * files (the "Software"), to deal in the Software without
8  * restriction, including without limitation the rights to use, copy,
9  * modify, merge, publish, distribute, sublicense, and/or sell copies
10  * of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  *
25  * SPDX-License-Identifier: MIT
26  *
27  */
28 
29 #include "cogl/cogl-graphene.h"
30 
31 typedef struct _Point2f
32 {
33   float x;
34   float y;
35 } Point2f;
36 
37 typedef struct _Point3f
38 {
39   float x;
40   float y;
41   float z;
42 } Point3f;
43 
44 typedef struct _Point4f
45 {
46   float x;
47   float y;
48   float z;
49   float w;
50 } Point4f;
51 
52 static void
init_matrix_rows(const graphene_matrix_t * matrix,unsigned int n_rows,graphene_vec4_t * rows)53 init_matrix_rows (const graphene_matrix_t *matrix,
54                   unsigned int             n_rows,
55                   graphene_vec4_t         *rows)
56 {
57   graphene_matrix_t m;
58   unsigned int i;
59 
60   graphene_matrix_transpose (matrix, &m);
61 
62   for (i = 0; i < n_rows; i++)
63     graphene_matrix_get_row (&m, i, &rows[i]);
64 }
65 
66 static void
transform_points_f2(const graphene_matrix_t * matrix,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)67 transform_points_f2 (const graphene_matrix_t *matrix,
68                      size_t                   stride_in,
69                      const void              *points_in,
70                      size_t                   stride_out,
71                      void                    *points_out,
72                      int                      n_points)
73 {
74   graphene_vec4_t rows[3];
75   int i;
76 
77   init_matrix_rows (matrix, G_N_ELEMENTS (rows), rows);
78 
79   for (i = 0; i < n_points; i++)
80     {
81       Point2f p = *(Point2f *)((uint8_t *)points_in + i * stride_in);
82       Point3f *o = (Point3f *)((uint8_t *)points_out + i * stride_out);
83       graphene_vec4_t point;
84 
85       graphene_vec4_init (&point, p.x, p.y, 0.f, 1.f);
86 
87       o->x = graphene_vec4_dot (&rows[0], &point);
88       o->y = graphene_vec4_dot (&rows[1], &point);
89       o->z = graphene_vec4_dot (&rows[2], &point);
90     }
91 }
92 
93 static void
project_points_f2(const graphene_matrix_t * matrix,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)94 project_points_f2 (const graphene_matrix_t *matrix,
95                    size_t                   stride_in,
96                    const void              *points_in,
97                    size_t                   stride_out,
98                    void                    *points_out,
99                    int                      n_points)
100 {
101   graphene_vec4_t rows[4];
102   int i;
103 
104   init_matrix_rows (matrix, G_N_ELEMENTS (rows), rows);
105 
106   for (i = 0; i < n_points; i++)
107     {
108       Point2f p = *(Point2f *)((uint8_t *)points_in + i * stride_in);
109       Point4f *o = (Point4f *)((uint8_t *)points_out + i * stride_out);
110       graphene_vec4_t point;
111 
112       graphene_vec4_init (&point, p.x, p.y, 0.f, 1.f);
113 
114       o->x = graphene_vec4_dot (&rows[0], &point);
115       o->y = graphene_vec4_dot (&rows[1], &point);
116       o->z = graphene_vec4_dot (&rows[2], &point);
117       o->w = graphene_vec4_dot (&rows[3], &point);
118     }
119 }
120 
121 static void
transform_points_f3(const graphene_matrix_t * matrix,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)122 transform_points_f3 (const graphene_matrix_t *matrix,
123                      size_t                   stride_in,
124                      const void              *points_in,
125                      size_t                   stride_out,
126                      void                    *points_out,
127                      int                      n_points)
128 {
129   graphene_vec4_t rows[3];
130   int i;
131 
132   init_matrix_rows (matrix, G_N_ELEMENTS (rows), rows);
133 
134   for (i = 0; i < n_points; i++)
135     {
136       Point3f p = *(Point3f *)((uint8_t *)points_in + i * stride_in);
137       Point3f *o = (Point3f *)((uint8_t *)points_out + i * stride_out);
138       graphene_vec4_t point;
139 
140       graphene_vec4_init (&point, p.x, p.y, p.z, 1.f);
141 
142       o->x = graphene_vec4_dot (&rows[0], &point);
143       o->y = graphene_vec4_dot (&rows[1], &point);
144       o->z = graphene_vec4_dot (&rows[2], &point);
145     }
146 }
147 
148 static void
project_points_f3(const graphene_matrix_t * matrix,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)149 project_points_f3 (const graphene_matrix_t *matrix,
150                    size_t                   stride_in,
151                    const void              *points_in,
152                    size_t                   stride_out,
153                    void                    *points_out,
154                    int                      n_points)
155 {
156   graphene_vec4_t rows[4];
157   int i;
158 
159   init_matrix_rows (matrix, G_N_ELEMENTS (rows), rows);
160 
161   for (i = 0; i < n_points; i++)
162     {
163       Point3f p = *(Point3f *)((uint8_t *)points_in + i * stride_in);
164       Point4f *o = (Point4f *)((uint8_t *)points_out + i * stride_out);
165       graphene_vec4_t point;
166 
167       graphene_vec4_init (&point, p.x, p.y, p.z, 1.f);
168 
169       o->x = graphene_vec4_dot (&rows[0], &point);
170       o->y = graphene_vec4_dot (&rows[1], &point);
171       o->z = graphene_vec4_dot (&rows[2], &point);
172       o->w = graphene_vec4_dot (&rows[3], &point);
173     }
174 }
175 
176 static void
project_points_f4(const graphene_matrix_t * matrix,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)177 project_points_f4 (const graphene_matrix_t *matrix,
178                    size_t                   stride_in,
179                    const void              *points_in,
180                    size_t                   stride_out,
181                    void                    *points_out,
182                    int                      n_points)
183 {
184   graphene_vec4_t rows[4];
185   int i;
186 
187   init_matrix_rows (matrix, G_N_ELEMENTS (rows), rows);
188 
189   for (i = 0; i < n_points; i++)
190     {
191       Point4f p = *(Point4f *)((uint8_t *)points_in + i * stride_in);
192       Point4f *o = (Point4f *)((uint8_t *)points_out + i * stride_out);
193       graphene_vec4_t point;
194 
195       graphene_vec4_init (&point, p.x, p.y, p.z, p.w);
196 
197       o->x = graphene_vec4_dot (&rows[0], &point);
198       o->y = graphene_vec4_dot (&rows[1], &point);
199       o->z = graphene_vec4_dot (&rows[2], &point);
200       o->w = graphene_vec4_dot (&rows[3], &point);
201     }
202 }
203 
204 void
cogl_graphene_matrix_project_point(const graphene_matrix_t * matrix,float * x,float * y,float * z,float * w)205 cogl_graphene_matrix_project_point (const graphene_matrix_t *matrix,
206                                     float                   *x,
207                                     float                   *y,
208                                     float                   *z,
209                                     float                   *w)
210 {
211   graphene_vec4_t p;
212 
213   graphene_vec4_init (&p, *x, *y, *z, *w);
214   graphene_matrix_transform_vec4 (matrix, &p, &p);
215 
216   *x = graphene_vec4_get_x (&p);
217   *y = graphene_vec4_get_y (&p);
218   *z = graphene_vec4_get_z (&p);
219   *w = graphene_vec4_get_w (&p);
220 }
221 
222 void
cogl_graphene_matrix_transform_points(const graphene_matrix_t * matrix,int n_components,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)223 cogl_graphene_matrix_transform_points (const graphene_matrix_t *matrix,
224                                        int                      n_components,
225                                        size_t                   stride_in,
226                                        const void              *points_in,
227                                        size_t                   stride_out,
228                                        void                    *points_out,
229                                        int                      n_points)
230 {
231   /* The results of transforming always have three components... */
232   g_return_if_fail (stride_out >= sizeof (Point3f));
233 
234   if (n_components == 2)
235     {
236       transform_points_f2 (matrix,
237                            stride_in, points_in,
238                            stride_out, points_out,
239                            n_points);
240     }
241   else
242     {
243       g_return_if_fail (n_components == 3);
244 
245       transform_points_f3 (matrix,
246                            stride_in, points_in,
247                            stride_out, points_out,
248                            n_points);
249     }
250 }
251 
252 void
cogl_graphene_matrix_project_points(const graphene_matrix_t * matrix,int n_components,size_t stride_in,const void * points_in,size_t stride_out,void * points_out,int n_points)253 cogl_graphene_matrix_project_points (const graphene_matrix_t *matrix,
254                                      int                      n_components,
255                                      size_t                   stride_in,
256                                      const void              *points_in,
257                                      size_t                   stride_out,
258                                      void                    *points_out,
259                                      int                      n_points)
260 {
261   if (n_components == 2)
262     {
263       project_points_f2 (matrix,
264                          stride_in, points_in,
265                          stride_out, points_out,
266                          n_points);
267     }
268   else if (n_components == 3)
269     {
270       project_points_f3 (matrix,
271                          stride_in, points_in,
272                          stride_out, points_out,
273                          n_points);
274     }
275   else
276     {
277       g_return_if_fail (n_components == 4);
278 
279       project_points_f4 (matrix,
280                          stride_in, points_in,
281                          stride_out, points_out,
282                          n_points);
283     }
284 }
285